Skip to main content
Version: 0.5

Acornfile

Root

The root level elements are, args containers, jobs, routers, volumes, secrets, and localData.

containers, jobs, and routers are all maps where the keys must be unique across all types. For example, it is not possible to have a container named foo and a job named foo, they will conflict and fail. Additional the keys could be using in a DNS name so the keys must only contain the characters a-z, 0-9 and -.

// User configurable values that can be changed at build or run time.
args: {
}

// Definition of containers to run
containers: {
}

// Defintion of jobs to run
jobs: {
}

// Defintion of HTTP routes to services
routers: {
}

// Definition of volumes that this acorn needs to run
volumes: {
}

// Definition of secrets that this acorn needs to run
secrets: {
}

// Arbitrary information that can be embedded to help render this Acornfile
localData: {
}

containers

containers defines the templates of containers to be ran. Depending on the scale parameter 1 or more containers can be created from each template (including their sidecars).

containers: web: {
image: "nginx"
ports: publish: "80/http"
}

dirs, directories

dirs configures one or more volumes to be mounted to the specified folder. The dirs parameter is a map structure where the key is the folder name in the container and the value is the referenced volume. Refer to the volumes section for more information on volume types.

containers: default: {
image: "nginx"
dirs: {
// A volume named "volume-name" will be mounted at /var/tmp
"/var/tmp": "volume-name"

// A volume named "volume-name" will be mounted at /var/tmp-full with the size of 20G and an
// access mode of readWriteMany
"/var/tmp-full": "volume://volume-name?size=20G,accessMode=readWriteMany"

// An ephemeral volume will be created and mounted to "/var/tmp-ephemeral"
"/var/tmp-ephemeral": "ephemeral://"

// An ephemeral volume named "shared" will be created and mounted to "/var/tmp-ephemeral"
"/var/tmp-ephemeral-named": "ephemeral://shared"

// A folder will be created at /var/tmp-secret/ where the filenames are the
// key names of the secret "sec-name" and the contents of each file is the corresponding
// secret data value
"/var/tmp-secret": "secret://sec-nam"

// The local folder ./www will be copied during build into the container image
// as /var/www. If running in dev mode the directory will be syncronized live with
// changes. Local folders must start with "./".
"/var/www": "./www"
}
sidecars: sidecar: {
image: "ubuntu"
dirs: {
// An ephemeral volume named "shared" will be mounted to /var/tmp with the contents of
// the volume shared with the main containers /var/tmp-ephemeral-named folder
"/var/tmp": "ephemeral://shared"
}
}

files

files will create files in the container with content from the Acornfile or the value of a secret. The files parameter is a map structure with the key being the file name and the value being the text of the file or a reference to a secret value. The default mode for files is 0644 unless the file ends with .sh or contains /bin/ or /sbin/. In those situations the mode will be 0755.

containers: default: {
image: "nginx"
files: {
// A file named /var/tmp/file.txt will be created with mode 0644
"/var/tmp/file.txt": "some file contents"

// A file named /run/secret/password will be created with mode 0400 with the
// contents of from the secret named "sec-name" and the value of the data
// key named "key".
"/run/secret/password": "secret://sec-name/key?mode=0400"

// By default if a secret value changes the application will be restarted.
// the following example will cause the container to not be restarted when
// the secret value changes, but instead the container is dynamically updated
"/run/secret/password-reload": "secret://sec-name/key?onchange=no-action"

// A file /var/tmp/other.txt will be created with a custom mode value "0600"
"/var/tmp/other.txt": {
content: "file content"
mode: "0600"
}

}
}

image

image refers to the OCI (Docker) image to run for this container.

containers: web: {
image: "nginx"
}

build

build contains the information need to build an OCI image to run for this container

containers: build1: {
// Build the Docker image using the context dir "." and the "./Dockerfile".
build: "."
}

containers: build2: {
build: {
// Build using the context dir "./subdir"
context: "./subdir"
// Build using the "./subdir/Dockerfile"
dockerfile: "./subdir/Dockerfile"
// Build with the multi-stage target named "multistage-target"
target: "multistage-target"
// Pass the following build arguements to the dockerfile
buildArgs: {
"arg1": "value1"
"arg2": "value2"
}
}
}

command, cmd

command will overwrite the CMD value set in the Dockerfile for the running container

containers: arg1: {
image: "nginx"
// This command will be parsed as a shell expression and turned into an array and ran
cmd: #"/bin/sh -c "echo hi""#
}

containers: arg2: {
image: "nginx"
// The following will not be parsed and will be ran as defined.
cmd: ["/bin/sh", "-c", "echo hi"]
}

entrypoint

entrypoint will overwrite the ENTRYPOINT value set in the Dockerfile for this running container

containers: arg1: {
image: "nginx"
// This command will be parsed as a shell expression and turned into an array and ran
entrypoint: #"/bin/sh -c "echo hi""#
}

containers: arg2: {
image: "nginx"
// The following will not be parsed and will be ran as defined.
entrypoint: ["/bin/sh", "-c", "echo hi"]
}

env, environment

env will set environment variables on the defined container. The value of the environment variable may be static text or a value from a secret.

containers: env1: {
image: "nginx"
env: [
// An environment variable of name "NAME" and value "VALUE" will be set
"NAME=VALUE",

// An environment variable of name "SECRET" and value of the key "key" in the
// secret named "sec-name" will be set. When this secret changes the container
// will not be restarted.
"SECRET=secret://sec-name/key?onchange=no-action"
]
}

containers: env1: {
image: "nginx"
// The same configuration as above but in map form
env: [
NAME: "VALUE"
SECRET: "secret://sec-name/key?onchange=no-action"
]
}

workDir, workingDir

workDir sets the current working directory of the running process defined in cmd and entrypoint

containers: env1: {
image: "nginx"
command: "ls"
// Run the command "ls", as defined above, in the directory "/tmp"
workDir: "/tmp"
}

dependsOn

dependsOn will prevent a container from being created and/or updated until all of it's dependencies are considered ready. Ready service are considered ready as soon as their ready probe passes. If there is no ready probe it is as soon as the containers have started.

containers: web: {
image: "nginx"
dependsOn: ["db"]
}
containers: db: {
// ...
image: "mariadb"
}

ports

ports defines which ports are available on the container and the default level of access. Ports are defined with three different access modes: internal, expose, publish. Internal ports are only available to the containers within an Acorn. Expose(d) ports are available to services within the cluster. And publish ports are available publicly outside the cluster. The access mode defined in the Acornfile is just the default behavior and can be changed at deploy time.

containers: web: {
image: "nginx"

// Define internal TCP port 80 available internally as DNS web:80
ports: 80

// Define internal HTTP port 80 available internally as DNS web:80
// Valid protocols are tcp, udp, and http
ports: "80/http"

// Define internal HTTP port 80 that maps to the container port 8080
// available internally as DNS web:80
ports: "80:8080/http"

// Define internal TCP port 80 that maps to the container port 8080
// available internally as DNS web:80
ports: "80:8080"

// Define internal TCP port 80 that maps to the container port 8080
// available internally as DNS web-alias:80
ports: "web-alias:80:8080"

// The similar ports as above but just in a list
ports: [
80,
"80/http",
"80:8080/http",
]

ports: {
// Define publically accessible HTTP port 80 that maps to the container port 8080
// available publically as a DNS assigned at runtime
publish: ["80:8080/http"]

// Define cluster accessible HTTP port 80 that maps to the container port 8080
// available publically as a DNS assigned at runtime
expose: ["80:8080/http"]

// Define internal HTTP port 80 that maps to the container port 8080
// available internally as DNS web:80
internal: ["80:8080/http"]
}

// Define publically accessible HTTP port 80 that maps to the container port 8080
// available publically as a DNS assigned at runtime
ports: publish: "80:8080/http"
}

probes, probe

probes configure probes that can signal when the container is ready, alive, and started. There are three probe types: readiness, liveness, and startup. readiness probes indicate when an application is available to handle requests. Ports will not be accessible until the readiness probe passes. liveness probes indicate if a running process is healthy. If the liveness probe fails, the container will be deleted and restarted. startup probe indicates that the container has started for the first time.

containers: web: {
image: "nginx"

// Configure readiness probe to run probe.sh
probe: "probe.sh"

// Configure readiness probe to look for a HTTP 200 response from localhost port 80
probe: "http://localhost:80"

// Configure readiness probe to connect to TCP port 1234
probe: "tcp://localhost:1234"

probes: {
"readiness": {
// Configure a HTTP readiness probe
http: {
url: "http://localhost:80"
headers: {
"X-SOMETHING": "some-value"
}
}
// Below are the default values for the following parameters
initialDelaySeconds: 0
timeoutSeconds: 1
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
}
"liveness": {
// Configure an Exec liveness probe
exec: {
command: ["probe.sh"]
}
}
"startup": {
// Configure a TCP startup liveness probe
tcp: {
url: "tcp://localhost:1234"
}
}
}
}

scale

scale configures the number of container replicas based on this configuration that should be ran.

containers: web: {
image: "nginx"
scale: 2
}

sidecars

sidecars are containers that run colocated with the parent container and share the same network address. Sidecars accept all the same parameters as a container and one additional parameter init

containers: web: {
image: "nginx"
sidecars: sidecar: {
image: "someother-image"
}
}

init

init tells the container runtime that this sidecar must be ran first on startup and the main container will not run until this container is done

containers: web: {
image: "nginx"
dirs: "/run/startup/": "ephemeral://startup-info"
sidecars: "stage-data": {
// This sidecar will run first and only when it exits with exit code 0 will the
// parent "web" container start
init: true
image: "ubuntu"
dirs: "/run/startup/": "ephemeral://startup-info"
command: "./stage-data-to /run/startup"
}
}

permissions

permissions allow you to define what resources the container can interact with on-cluster and what it can do with them.

containers: web: {
image: "nginx"
permissions: {
// These are permissions that will only be granted for this container in its namespace.
rules: [{
// Configure what actions you can do on the defined resources
verbs: [
"get",
"list",
"watch",
"create",
]
// Define what API group the resources belong to
apiGroups: [
"api.sample.io"
]
// Configure which resources in the above apiGroups to apply the above verbs to
resources: [
"fooresource"
]
}]
// These are permissions that will be granted for this container in all namespaces.
clusterRules: [{
verbs: [
"get",
"list",
"watch",
]
apiGroups: [
"api.sample.io"
]
resources: [
"fooresource"
]
// Optionally restrict permissions to a specific namespace and not globally
namespaces: [
"other-namespace"
]
}]
}
}

memory

memory allows you to specify how much memory the container should run with. It can be abbreviated to mem. If left unspecified, it will be defaulted to the installation default (see the reference documentation for memory for more information).

containers: {
nginx: {
image: "nginx"
ports: publish: "80/http"
files: {
"/usr/share/nginx/html/index.html": "<h1>My first Acorn!</h1>"
}
memory: 512Mi
}
}

jobs

jobs are containers that are run once to completion. If the configuration of the job changes, the will be ran once again. All fields that apply to containers also apply to jobs.

jobs: "setup-volume": {
image: "my-app"
command: "init-data.sh"
dirs: "/mnt/data": "data"
}

schedule

schedule field will configure your job to run on a cron schedule. The format is the standard cron format.

 ┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of the month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday;
│ │ │ │ │ 7 is also Sunday on some systems)
│ │ │ │ │ OR sun, mon, tue, wed, thu, fri, sat
│ │ │ │ │
* * * * *

The following shorthand syntaxes are supported

EntryDescriptionEquivalent to
@yearly (or @annually)Run once a year at midnight of 1 January0 0 1 1 *
@monthlyRun once a month at midnight of the first day of the month0 0 1 * *
@weeklyRun once a week at midnight on Sunday morning0 0 * * 0
@daily (or @midnight)Run once a day at midnight0 0 * * *
@hourlyRun once an hour at the beginning of the hour0 * * * *

routers

routers support path based HTTP routing so one can expose multiple containers through a single published service. For example, if you have two containers named auth and api they would have to be exposed as two different HTTP services like auth.example.com and api.example.com. The router feature allows you to expose these two containers as myapp.example.com/auth and myapp.example.com/api.

routers: myapp: {
routes: {
// Short syntax to match all prefixes /auth and route to the auth:8080 container
"/auth": "auth:8080"

// Verbose syntax
"/api": {
// can be "exact" or "prefix"
pathType: "exact"
targetServiceName: "api"
targetPort: 8081
}
}
}

containers: auth: {
image: "auth"
ports: "8080/http"
}

containers: api: {
image: "api"
ports: "8081/http"
}

pathType

pathType describes the matching behavior of the route. Currently, "prefix" and "exact" are supported. "exact" will require that the path matches the string and "prefix" requires the path to start with the path string. The short syntax of routes will default to "prefix".

routers: myapp: routes: {
"/api": {
pathType: "exact"
targetServiceName: "api"
targetPort: 8081
}

// Default to "prefix" match for short syntax
"/auth": "auth:8080"
}

targetServiceName

targetServiceName is the destination service of the route. This name typically corresponds to to a container name. Technically it can be any acorn resource that exposes a service name which is currently containers, jobs, routers and linked in services.

targetPort

targetPort is the destination port of the route. The target container or job must have this port defined or else the traffic will be dropped. If you are targeting another router, routers implicitly have the internal port 80

volumes

volumes store persistent data that can be mounted by containers

containers: db: {
image: "mariadb"
dirs: "/var/lib/mysql": "data"
}
volumes: data: {
size: "100G"
accessModes: "readWriteOnce"
class: "default"
}

size

size configures the default size of the volume to be created. At deploy-time this value can be overwritten.

volumes: data: {
// All numbers are assumed to be gigabytes
size: 100

// The following suffixes are understood
// 2^x - Ki | Mi | Gi | Ti | Pi | Ei
// 10^x - m | k | M | G | T | P | E
size: "10G"
}

class

class refers to the storageclass within kubernetes.

volumes: data: {
// either "default" or a storageclass from `kubectl get sc`
class: "longhorn"
}

accessModes

accessModes configures how a volume can be shared among containers.

volumes: data: {
accessModes: [
// Only usable by containers on the same node
"readWriteOnce",
// Usable by containers across many nodes
"readWriteMany",
// Usable by containers across many nodes but read only
"readOnlyMany",
]
}

secrets

secrets store sensitive data that should be encrypted as rest.

secrets: "my-secret": {
type: "opaque"
data: {
key1: ""
key2: ""
}
}

type

The common pattern in Acorn is for secrets to be generated if not supplied. type specifies how the secret can be generated. Refer to the secrets documentation for descriptions of the different secret types and how they are used.

secrets: "a-token": {
// Valid types are "opaque", "token", "basic", "generated", and "template"
type: "opaque"
}

params

params are used to configure the behavior of the secrets generation for different types. Refer to the secrets documentation for descriptions of the different secret types and how their parameters.

secrets: "my-token": {
type: "token"
params: {
length: 32
characters: "abcdedfhifj01234567890"
}
}

data

data defines the keys and non-senstive values that will be used by the secret. Refer to the secrets documentation for descriptions of the different secret types and how to use data keys and values.

secrets: {
"my-template": {
type: "template"
data: {
template: """
a ${secret://my-secret-data/key} value
"""
}
}
"my-secret-data": {
type: "opaque"
data: {
key: "value"
}
}
}

args

args defines arguements that can be modified at build or runtime by the user. Arguments to an Acorn can be standard strings, ints, bools, and other complex types. To define an argument, specify a name and a default value. The type will be inferred from the default value.

args: {
// A description that will be show to the user in `acorn run image --help`
myIntVar: 1
// Another description that will be show to the user in `acorn run image --help`
myStringVar: "somestring"
// Another description that will be show to the user in `acorn run image --help`
myBoolVar: true
}

localData

localData is used by the Acornfile author to store values to assist in scripting in the Acornfile. These values are not directly interpreted by Acorn and are only for the authors use.

containers:{
frontend: {
// ...
env: {
"MY_IMPORTANT_SETTING": localData.myApp.frontendConfig.key
}
// ...
}
database: {
// ...
env: {
"MY_DATABASE_NAME": localData.myApp.databaseConfig.name
}
// ...
}
}
localData: {
myApp:{
frontendConfig: {
key: "value"
}
databaseConfig: {
name: "db-prod"
}
}
}