Getting Started with Flatcar Container Linux

    This guide aims to get you up and running in a few minutes. We’ll cover

    • concepts, configuration, and provisioning
    • writing a basic Flatcar configuration and testing it locally with qemu
    • further reading - where to go from here after learning the basics

    Concepts, Configuration, and Provisioning

    Flatcar Container Linux is configured at provisioning time. There are two configuration languages to set up Flatcar, aimed at different use cases:

    • Butane Config Butane is human-readable / writable YAML and must be converted (transpiled) into Ignition V3 config before Flatcar can use it. It’s the successor of Container Linux Config which is also still supported (Butane is not supported for LTS-2022).
    • Ignition config is machine-readable JSON fed to Flatcar’s ignition service. Ignition is Flatcars “installation service” which configures a Flatcar instance during provisioning. The config file is passed via the “custom data” or “user data” option of cloud providers, and can be supplied by various mechanisms to private cloud VMs and bare metal. Ignition config is rarely written by a human; it’s usually generated by provisioning automation or transpiled from user-written Butane.

    Use Butane to customise your Flatcar deployment, e.g. to

    • add custom users and groups
    • create and manage storage devices, file systems, and swap, and create custom files
    • customise automatic updates and define reboot windows
    • create custom network(d) configurations and systemd units
      • Want to e.g. run a custom operation or start a service each time the instance boots? Define a custom systemd unit via Butane. All above tasks only take a few lines of YAML and are covered in our Butane examples . For a comprehensive discussion of all options available in Butane have a look at the Butane specification .

    To convert Butane into machine-readable Ignition config, just download the latest release of Butane . Alternatively, you can use the up-to-date container image with docker run --rm -i quay.io/coreos/butane:latest.

    Then, after converting Butane to Ignition config, pass the Ignition config along when provisioning your instance(s). The config is then passed via “user data” / “custom data” or similar means to the provisioning logic.

    Writing your first config and testing it locally in a qemu VM

    The way from a small Butane Config YAML or Ignition JSON file to a local QEMU VM on your laptop is not far. Here we will create a systemd service that starts an NGINX container as example configuration for the VM. This is a good starting point for you to modify the Butane YAML file (or the Ignition JSON file) and test it by provisioning a temporary QEMU VM. This should work on most Linux systems and assumes you have an SSH key set up for ssh-agent.

    First download the Flatcar QEMU image and the helper script to start it with QEMU but don’t run it yet.

    AMD64:

    wget https://stable.release.flatcar-linux.net/amd64-usr/current/flatcar_production_qemu.sh
    chmod +x flatcar_production_qemu.sh
    wget https://stable.release.flatcar-linux.net/amd64-usr/current/flatcar_production_qemu_image.img
    

    ARM64:

    wget https://alpha.release.flatcar-linux.net/arm64-usr/current/flatcar_production_qemu_uefi.sh
    chmod +x flatcar_production_qemu_uefi.sh
    wget https://alpha.release.flatcar-linux.net/arm64-usr/current/flatcar_production_qemu_uefi_image.img
    wget https://alpha.release.flatcar-linux.net/arm64-usr/current/flatcar_production_qemu_uefi_efi_code.fd
    wget https://alpha.release.flatcar-linux.net/arm64-usr/current/flatcar_production_qemu_uefi_efi_vars.fd
    

    For Ignition configurations to be recognized we have to make sure that we always boot an unmodified fresh image because Ignition only runs on first boot. Therefore, before trying to use an Ignition config we will always discard the image modifications by using a fresh copy. You can already boot the image with ./flatcar_production_qemu.sh and have a look around in the OS through the QEMU VGA console - you can close the QEMU window or stop the script with Ctrl-C.

    mv flatcar_production_qemu_image.img flatcar_production_qemu_image.img.fresh
    # If you want to have a first look, boot it and wait for the autologin to give you a prompt:
    cp -i --reflink=auto flatcar_production_qemu_image.img.fresh flatcar_production_qemu_image.img
    

    Now we will provision the VM on first boot through Ignition. Instead of writing the JSON config we use Butane YAML and transpile it. Save the following Butane YAML file as cl.yaml (or another name). It contains directives for setting up a systemd service that runs an NGINX Docker container:

    variant: flatcar
    version: 1.0.0
    systemd:
      units:
        - name: nginx.service
          enabled: true
          contents: |
            [Unit]
            Description=NGINX example
            After=docker.service
            Requires=docker.service
            [Service]
            TimeoutStartSec=0
            ExecStartPre=-/usr/bin/docker rm --force nginx1
            ExecStart=/usr/bin/docker run --name nginx1 --pull always --log-driver=journald --net host docker.io/nginx:1
            ExecStop=/usr/bin/docker stop nginx1
            Restart=always
            RestartSec=5s
            [Install]
            WantedBy=multi-user.target        
    

    Before we can use it we have to transpile the Butane YAML to Ignition JSON:

    cat cl.yaml | docker run --rm -i quay.io/coreos/butane:latest > ignition.json
    

    You can also skip this step and copy the resulting JSON file from here to ignition.json (or another name):

    {
      "ignition": {
        "version": "3.3.0"
      },
      "systemd": {
        "units": [
          {
            "contents": "[Unit]\nDescription=NGINX example\nAfter=docker.service\nRequires=docker.service\n[Service]\nTimeoutStartSec=0\nExecStartPre=-/usr/bin/docker rm --force nginx1\nExecStart=/usr/bin/docker run --name nginx1 --pull always --net host docker.io/nginx:1\nExecStop=/usr/bin/docker stop nginx1\nRestart=always\nRestartSec=5s\n[Install]\nWantedBy=multi-user.target\n",
            "enabled": true,
            "name": "nginx.service"
          }
        ]
      }
    }
    

    The final step is to boot the VM and make the Ignition configuration available to it. As said, the provisioning will only be done on first boot and if you want your (changed) Ignition configuration to be used, you have to boot from a fresh copy. You can repeat these combined steps as often as you want to test your Ignition changes.

    # Make sure we boot a fresh copy:
    cp -i --reflink=auto flatcar_production_qemu_image.img.fresh flatcar_production_qemu_image.img
    ./flatcar_production_qemu.sh -i ignition.json
    # Log in via SSH in a new terminal tab:
    ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 [email protected]
    # Check that NGINX is running:
    systemctl status nginx
    curl http://localhost/
    

    NOTE: For SSH access, you can also use the ~/.ssh/config provided in the QEMU section then simply ssh flatcar or scp my-file flatcar:/home/core to send a file on the instance over SSH.

    If you have trouble SSHing into the VM, ./flatcar_production_qemu.sh might have failed to auto-detect your ssh key. If that happens try with a user-supplied SSH key using the yaml snippet below. Alternatively, you can interact with the VM via the VGA console - the console has auto-login enabled and drops right into a shell.

    You can reboot and stop the VM if you like - when you start it later with a plain ./flatcar_production_qemu.sh then our systemd unit will take care of starting NGINX on each boot. Note that the ignition config will only be processed on the very first boot - that’s why we made a copy, so now we can restore our OS image from the pristine copy for successive experiments with Butane.

    As listed in the introduction above there are numerous options available for configuring Flatcar just the way you need it. For instance, you can specify a custom SSH key instead of your default one from your ssh-agent or from ~/.ssh/ in the Butane config, by adding this section to your YAML file:

    variant: flatcar
    version: 1.0.0
    passwd:
      users:
        - name: core
          ssh_authorized_keys:
            - ssh-rsa AAAAB......xyz [email protected]
    

    Afterwards, transpile it again to Ignition JSON, overwrite flatcar_production_qemu_image.img with the fresh image file, and pass the ignition config to ./flatcar_production_qemu.sh once again.

    On automatic updates

    Flatcar has automatic updates enabled by default. Flatcar instances will download and stage (in the background) new OS versions as well as reboot into the updated OS when a new update becomes available. To change this default - for instance, to define reboot windows or even disable reboots - check out the update strategies doc. To disable downloading updates altogether either disable the update-engine service via a user-supplied systemd config, or use an invalid URL in the SERVER field of update.conf .

    More on configuring and operating Flatcar Container Linux

    The documentation includes a whole section on configuration, operation, and maintenance. Have a look at the setup guide for more information.

    Further reading: Platform / vendor specific information

    Check out the guides on running Flatcar Container Linux on most cloud providers:

    With any of these guides you will have machines up and running in a few minutes.


    Cloud Providers

    This section provides information and guidance on running Flatcar instances in different cloud environments.

    Customizing the image

    This section provides information and guidance on customizing Flatcar images by placing files on the root or OEM filesystem or embedding an Ignition config.

    Virtual Machines

    This section provides information and guidance on running Flatcar instances on virtual machines.

    Bare Metal

    This section provides information and guidance on running Flatcar instances in bare-metal environments.

    Community supported platforms