Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuration Reference

Every field minienv reads. For explanations and examples, see Configuration.

x-minienv

Top level of the compose file. Configure exactly one of the below deployers — configuring more than one is an error.

k8s

FieldTypeRequiredDefaultDescription
k8s.contextstringyesTargets a specific cluster when deploying
k8s.namespacestringyesTargets a specific namespace when deploying
k8s.deploymentTimeoutdurationno60sHelm timeout for all services; overridable per service
k8s.ngrok.trafficPolicystringno""ngrok on_http_request policy applied to every service that does not set its own

docker

FieldTypeRequiredDefaultDescription
docker.namespacestringyesCompose project name and directory (~/.minienv/<namespace>) on the remote host. Reduced to [a-z0-9_-]
docker.transportmapyesHow to reach the remote host
docker.transport.ssh.hoststringyesTarget host for the SSH connection
docker.transport.ssh.identitystringyesPath to the private key file
docker.transport.ssh.userstringnolocal userUser for the SSH connection
docker.transport.ssh.portintegerno22Port for the SSH connection
docker.ngrok.trafficPolicystringno""ngrok on_http_request policy applied to every service that does not set its own

docker.transport

Exactly one transport must be configured; configuring none, like configuring more than one, is an error.

The host key must already be trusted. minienv verifies against ~/.ssh/known_hosts on the machine running it and offers no prompt or bypass, so connect once by hand before the first deploy. Encrypted identity files are not supported.

x-minienv-k8s-service

Under services.<name>. All fields are optional.

FieldTypeDefaultDescription
affinityk8s schemaPassed through to the pod spec
commandlist of stringscompose commandContainer command
configMapFromlist of stringsFiles, relative to the compose project directory, that become one ConfigMap named after the service
deploymentTimeoutdurationinherits top levelHelm timeout for this service
deploymentTypeservice | jobserviceDeploy as a Deployment or a run-to-completion Job
envk8s schemaContainer env vars as EnvVar entries, merged over compose environment by name
envFromk8s schemaSources to populate container env vars from, as EnvFromSource entries
image.platformslist of strings["linux/amd64"]Platforms to build and push
image.pullPolicystringIfNotPresentKubernetes image pull policy
image.repositorystringfrom compose imageImage repository
image.tagstringfrom compose imageImage tag. +git expands to the short commit SHA
imagePullSecrets[].namestringExisting pull secret in the namespace. See Private registries
livenessProbek8s schemafrom compose healthcheckPassed through to the container spec
manifestslist of stringsPaths, relative to the compose project directory, to extra manifests rendered into this service’s release
ngrok.portintegerContainer port to expose publicly — the container side of a compose mapping. Ignored for a job, a skipped service, and when NGROK_AUTHTOKEN is unset. See Exposing Services
ngrok.trafficPolicystringinherits top levelngrok on_http_request policy
ngrok.urlstringrandomReserved domain for a stable endpoint
nodeSelectork8s schemaPassed through to the pod spec
podAnnotationsmap of string to stringPassed through to the pod template
podLabelsmap of string to stringPassed through to the pod template
podSecurityContextk8s schemaPassed through to the pod spec
readinessProbek8s schemafrom compose healthcheckPassed through to the container spec
recreateboolfalseReplace the pods, and any resource that cannot be patched in place, on every deploy. For fixed tags like latest
replicasinteger1Number of replicas. No effect on a job
resourcesk8s schemaPassed through to the container spec
securityContextk8s schemaPassed through to the container spec
service.createbooltrueWhether to create a Kubernetes Service. Forced to false when the service resolves no ports
service.portslistderived from compose portsExplicit port mappings, merged with the derived ones
service.typestringClusterIPService type
serviceAccount.annotationsmap of string to string{}Extra annotations
serviceAccount.automountbooltrueAutomount the service account token
serviceAccount.createbooltrueWhether to create a ServiceAccount. Forced to false when the service resolves no ports
serviceAccount.namestring""Name. Empty means the generated fullname when creating, otherwise default
skipboolfalseExcludes the service from image builds and deploys. destroy still uninstalls it
startupProbek8s schemafrom compose healthcheckPassed through to the container spec
tolerationsk8s schemaPassed through to the pod spec
volumeMountsk8s schemaPassed through to the container spec
volumesk8s schemaPassed through to the pod spec

Fields marked k8s schema reach the generated manifests exactly as written, so the Kubernetes documentation is the reference for their shape.

configMapFrom

Each file’s base name is a key and its content is the value. Mount the ConfigMap with volumes and volumeMounts:

services:
  postgres:
    image: postgres:15
    x-minienv-k8s-service:
      configMapFrom:
        - db/init/01-schema.sql
        - db/init/02-seed.sql
      volumes:
        - name: init
          configMap:
            name: postgres
      volumeMounts:
        - name: init
          mountPath: /docker-entrypoint-initdb.d

Content is written as-is, not rendered as a template, and must be UTF-8 text. Two entries may not share a base name. A change to any file’s content replaces the pods on the next deploy. A file under manifests must not also produce a ConfigMap named after the service, since the two would collide in the release.

env

Merged over compose environment by name. A literal value is written into the manifest, so do not put secrets there if the manifests are visible to others. Values compose could not resolve (the bare - SOME_VAR form, with nothing set locally) are dropped rather than set empty.

x-minienv-k8s-service:
  env:
    - name: EXAMPLE_VAR
      value: example-value
    - name: EXAMPLE_FROM_VAR
      valueFrom:
        secretKeyRef:
          name: example-secret
          key: example-key

manifests

Files deployed as part of the service’s release — a ConfigMap or Secret behind a volumes entry, an Ingress, a PVC, a Traefik IngressRoute:

services:
  api:
    image: myorg/api:latest
    x-minienv-k8s-service:
      manifests:
        - k8s/configmap.yaml
      volumes:
        - name: config
          configMap:
            name: api-config
      volumeMounts:
        - name: config
          mountPath: /etc/api

Each file is a Helm template. .Values, .Release and .Chart are in scope, alongside the chart’s generated.name, generated.fullname, generated.chart, generated.labels, generated.selectorLabels and generated.serviceAccountName helpers:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "generated.fullname" . }}-config
  labels:
    {{- include "generated.labels" . | nindent 4 }}
data:
  LOG_LEVEL: debug

Every field in the table above is readable as .Values under the same path — replicas as .Values.replicas, image.tag as .Values.image.tag — resolved, so .Values.image.tag carries the tag derived from compose image: with a +git already expanded.

A job’s values are a smaller set. A deploymentType: job chart has no replicas or probes, so a manifest on a job that reads one renders empty rather than failing.

A manifest is created and removed with its service’s release. Two services must not declare manifests producing the same object — the second release to reach it fails on ownership, and the order between them is not fixed.

Probes

livenessProbe, readinessProbe and startupProbe are derived from a compose healthcheck. A curl or wget test against http://localhost[:port][/path] becomes an HTTP probe on the container port; anything else becomes an exec probe. disable: true, an empty test, or test: ["NONE"] produces none.

Set any of the three to write it yourself. The ones you leave unset still come from the compose healthcheck:

x-minienv-k8s-service:
  readinessProbe:
    httpGet:
      path: /ready
      port: 8080
    initialDelaySeconds: 5

Caution: a curl or wget test pointed at anything other than localhost produces no probes at all — silently. Use localhost, write the check as a non-HTTP command, or set the probes yourself.

service.ports

Each entry requires all three fields:

FieldTypeDescription
containerPortNamestringName of the port, on the container and Service
containerPortintegerPort the container listens on
protocolstringTCP or UDP

Ports derived from compose take the container side of the mapping, are named p<port>p8080 for container port 8080 — and default to protocol TCP.

x-minienv-docker-service

Under services.<name>. All fields are optional.

FieldTypeDefaultDescription
copy[].containerPathstringAbsolute path inside the container to mount the copied path at
copy[].hostPathstringPath, relative to the compose project directory, of a file or directory to copy
image.platformslist of strings["linux/amd64"]Platforms to build and push
image.repositorystringfrom compose imageImage repository
image.tagstringfrom compose imageImage tag. +git expands to the short commit SHA
ngrok.portintegerContainer port to expose publicly — the container side of a compose mapping. Ignored for a skipped service and when NGROK_AUTHTOKEN is unset. See Exposing Services
ngrok.trafficPolicystringinherits top levelngrok on_http_request policy
ngrok.urlstringrandomReserved domain for a stable endpoint
skipboolfalseExcludes the service from image builds and deploys

copy

Files and directories sent to the remote host and bind mounted into the container — a config file, a TLS certificate, a seed dataset, a directory of fixtures:

services:
  api:
    image: myorg/api:latest
    x-minienv-docker-service:
      copy:
        - hostPath: conf/api.yml
          containerPath: /etc/api/api.yml
        - hostPath: seed
          containerPath: /var/lib/seed

A directory is copied recursively. hostPath must stay inside the project — an absolute path, a path climbing out with .., and the project directory itself are all rejected. containerPath must be absolute, and two entries on one service cannot name the same one.

The copied paths land under the deployment’s own directory on the remote host, each keeping the relative path it was declared with, so two files that share a base name stay apart. Two services naming the same hostPath share one copy. A service marked skip is not deployed, so nothing it declares is copied.

The whole set is replaced on every deploy. An entry you remove or rename takes its remote copy with it on the next deploy, and minienv destroy removes the deployment directory that holds all of them.

Machine-readable schema

The authoritative schema lives at schema/schema.json in the repository. It wraps the official compose spec and adds the three extension fields (x-minienv, x-minienv-k8s-service and x-minienv-docker-service). Reference it from your compose file for editor autocomplete:

# $schema: https://raw.githubusercontent.com/robgonnella/minienv/refs/heads/main/schema/schema.json