Provisioning

Container Linux automates machine provisioning with a specialized system for applying initial configuration. This system implements a process of (trans)compilation and validation for machine configs, and an atomic service to apply validated configurations to machines.

Container Linux Config

Container Linux admins define these configurations in a format called the Container Linux Config, which is specific to Container Linux, structured as YAML, and intended to be human-readable. The Container Linux Config has features devoted to configuring Container Linux services such as etcd, rkt, Docker, flannel, and locksmith. The defining feature of the config is that is cannot be sent directly to a Container Linux provisioning target. Instead, it is first validated and transformed into a machine-readable and wire-efficient form.

The following examples demonstrate the simplicity of the Container Linux Config format.

This extremely simple Container Linux Config will fetch and run the current release of etcd:

# This config is meant to be consumed by the config transpiler, which will
# generate the corresponding Ignition config. Do not pass this config directly
# to instances of Container Linux.

etcd:
This is the human-readable, Container Linux Config. This should not be immediately passed to Container Linux. Learn more.

Extend the definition to specify the version of etcd to run. The following example will provision a new Container Linux machine to fetch and run the etcd service, version 3.1.6:

# This config is meant to be consumed by the config transpiler, which will
# generate the corresponding Ignition config. Do not pass this config directly
# to instances of Container Linux.

etcd:
  version: 3.1.6
This is the human-readable, Container Linux Config. This should not be immediately passed to Container Linux. Learn more.

Use variable replacement to configure the etcd service with the provisioning target's public and private IPv4 addresses, making it repeatable across a group of machines.

# This config is meant to be consumed by the config transpiler, which will
# generate the corresponding Ignition config. Do not pass this config directly
# to instances of Container Linux.

etcd:
  advertise_client_urls:       http://{PUBLIC_IPV4}:2379
  initial_advertise_peer_urls: http://{PRIVATE_IPV4}:2380
  listen_client_urls:          http://0.0.0.0:2379
  listen_peer_urls:            http://{PRIVATE_IPV4}:2380
  discovery:                   https://discovery.etcd.io/<token>
This is the human-readable, Container Linux Config. This should not be immediately passed to Container Linux. Learn more.

PUBLIC_IPV4 and PRIVATE_IPV4 are automatically populated from the environment in which Container Linux runs, if this metadata exists. Given the many different environments in which Container Linux can run, it's difficult if not impossible to accurately determine these variables in every instance. Be certain to check this value as a troubleshooting measure.

For example, the default metadata for an EC2 environment would be used: public_ipv4 and local_ipv4. On Azure, either the virtual IP or public IP could be used for the PUBLIC_IPV4 (ct makes a best guess and uses the virtual IP, but this could change in the future), and the dynamic IP would be used for the PRIVATE_IPV4. On bare metal, this information cannot be reliably derived in a general manner, so these variables cannot be used.

Because variable expansion is unpredictable and complex, and because it is also common for users to inadvertently write invalid configs, the use of a transformation tool is strongly encouraged. The default tool recommended for this task is the Config Transpiler (ct for short). The Config Transpiler will validate and transform a Container Linux Config into the format that Container Linux can consume: the Ignition Config.

Ignition Config

Ignition, the utility in Container Linux responsible for provisioning the machine, fetches and executes the Ignition Config. Container Linux directly consumes the Ignition Config configuration format.

Ignition Configs are mostly static, distro-agnostic, and meant to be generated by a machine rather than a human. While they can be written directly by users, it is highly discouraged due to the ease with which errors may be introduced. Rather than writing Ignition Configs directly, users are encouraged to use provisioning tools like Matchbox, which transparently translate Container Linux Configs to Ignition Configs, or to use the Config Transpiler itself.

visual overview of the alternate ct workflows

As shown in this diagram, ct is manually invoked only when users are manually provisioning machines. If a provisioning tool like Matchbox is used, ct will transparently be incorporated into the deployment pipeline. In which case, the user only needs to prepare a Container Linux Config - Ignition and the Ignition Config are merely an implementation detail.

Config Transpiler

The Container Linux Config Transpiler abstracts the details of configuring Container Linux. It's responsible for transforming a Container Linux Config written by a user into an Ignition Config to be consumed by instances of Container Linux.

The following config will configure an etcd cluster using the machine's public and private IP addresses:

# This config is meant to be consumed by the config transpiler, which will
# generate the corresponding Ignition config. Do not pass this config directly
# to instances of Container Linux.

etcd:
  advertise_client_urls:       http://{PUBLIC_IPV4}:2379
  initial_advertise_peer_urls: http://{PRIVATE_IPV4}:2380
  listen_client_urls:          http://0.0.0.0:2379
  listen_peer_urls:            http://{PRIVATE_IPV4}:2380
  discovery:                   https://discovery.etcd.io/<token>
This is the human-readable, Container Linux Config. This should not be immediately passed to Container Linux. Learn more.

As suggested earlier, ct requires information about the target environment before it can transform configs which use templating. If this config is passed to ct without any other arguments, ct fails with the following error message:

$ bin/ct < example.yml
error: platform must be specified to use templating

This message states that because the config takes advantage of templating (in this case, PUBLIC_IPV4), ct must be invoked with the --platform argument. This extra information is used by ct to make the platform-specific customizations necessary. Keeping the Container Linux Config and the invocation arguments separate allows the Container Linux Config to remain largely platform independent.

CT can be invoked again and given Amazon EC2 as an example:

$ bin/ct --platform=ec2 < example.yml
{"ignition":{"version":"2.0.0","config"...

This time, ct successfully runs and produces the following Ignition Config:

{
  "ignition": { "version": "2.0.0" },
  "systemd": {
    "units": [{
      "name": "etcd-member.service",
      "enable": true,
      "dropins": [{
        "name": "20-clct-etcd-member.conf",
        "contents": "[Unit]\nRequires=coreos-metadata.service\nAfter=coreos-metadata.service\n\n[Service]\nEnvironmentFile=/run/metadata/coreos\nExecStart=\nExecStart=/usr/lib/coreos/etcd-wrapper $ETCD_OPTS \\n  --listen-peer-urls=\"http://${COREOS_EC2_IPV4_LOCAL}:2380\" \\n  --listen-client-urls=\"http://0.0.0.0:2379\" \\n  --initial-advertise-peer-urls=\"http://${COREOS_EC2_IPV4_LOCAL}:2380\" \\n  --advertise-client-urls=\"http://${COREOS_EC2_IPV4_PUBLIC}:2379\" \\n  --discovery=\"https://discovery.etcd.io/\u003ctoken\u003e\""
      }]
    }]
  }
}
Ignition Configs can validated using the online validator.

This Ignition Config enables and configures etcd as specified in the above Container Linux Config. This can be more easily seen if the contents of the etcd drop-in are formatted nicely:

[Unit]
Requires=coreos-metadata.service
After=coreos-metadata.service

[Service]
EnvironmentFile=/run/metadata/coreos
ExecStart=
ExecStart=/usr/lib/coreos/etcd-wrapper $ETCD_OPTS \
  --listen-peer-urls="http://${COREOS_EC2_IPV4_LOCAL}:2380" \
  --listen-client-urls="http://0.0.0.0:2379" \
  --initial-advertise-peer-urls="http://${COREOS_EC2_IPV4_LOCAL}:2380" \
  --advertise-client-urls="http://${COREOS_EC2_IPV4_PUBLIC}:2379" \
  --discovery="https://discovery.etcd.io/<token>"

The details of these changes are covered in depth in Ignition's metadata documentation, but the gist is that coreos-metadata is used to fetch the IP addresses from the Amazon APIs and then systemd is leveraged to substitute the IP addresses into the invocation of etcd. The result is that even though Ignition only runs once, coreos-metadata fetches the IP addresses whenever etcd is run, allowing etcd to use IP addresses that have the potential to change.

Migrating from cloud configs

Previously, the recommended way to provision a Container Linux machine was with a cloud-config. These configs would be given to a Container Linux machine and a utility called coreos-cloudinit would read this file and apply the configuration on every boot.

For a number of reasons, coreos-cloudinit has been deprecated in favor of Container Linux Configs and Ignition. For help migrating from these legacy cloud-configs to Container Linux Configs, refer to the migration guide.

Using Container Linux Configs

Now that the basics of Container Linux Configs have been covered, a good next step is to read through the examples and start experimenting. The troubleshooting guide is a good reference for debugging issues.