I didn’t see much out there that describes how to set up a Flatcar Container Linux VM at Linode. What follows is what I came up with; it’ll put up a basic system that’s accessible via SSH.
You’ll need a Linux system to prep the installation, as well as about 12 GB of free space. The QEMU-compatible image that is available for download is in qcow2 format; Linode needs a raw-format image. You can download and convert the most recent image as follows (you’ll need QEMU installed, however your distro provides for that):
wget https://stable.release.flatcar-linux.net/amd64-usr/current/flatcar_production_qemu_image.img.bz2 && bunzip2 flatcar_production_qemu_image.img.bz2 && qemu-img convert -f qcow2 -O raw flatcar_production_qemu_image.img tmp.img && mv tmp.img flatcar_production_qemu_image.img && bzip2 -9 flatcar_production_qemu_image.img
You also need a couple of installation tools for Flatcar Container Linux: the installation script and the configuration transpiler. The most recent script is available on GitHub:
wget https://raw.githubusercontent.com/flatcar-linux/init/flatcar-master/bin/flatcar-install -O flatcar-install.sh && chmod +x flatcar-install.sh
So’s the transpiler…you can grab the binary from the releases page. You’ll want to grab the latest ct-v*-x86_64-unknown-linux-gnu and rename it to ct.
Next, we need a configuration script. Here’s a basic YAML file that enables SSH login. You’ll want to substitute your own username and SSH public key for mine. Setting the hostname and timezone to appropriate values for you might also be a good idea. Save this as config.yaml:
passwd:
users:
- name: salfter
groups:
- sudo
- wheel
- docker # or else Docker won't work
ssh_authorized_keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBJQgbySEtaT8SqZ37tT7S4Z/gZeGH+V5vGZ9i9ELpmU salfter@janeway
etcd:
# go to https://discovery.etcd.io/new to get a new ID
discovery: https://discovery.etcd.io/c4e7dd71d5a3eae58b6b5eb45fcba490
storage:
disks:
- device: /dev/sda
- device: /dev/sdb
filesystems:
- name: "storage"
mount:
device: "/dev/sdb"
format: "ext4"
label: "storage"
# wipe_filesystem: true
directories:
- filesystem: "storage"
path: "/docker"
mode: 0755
- filesystem: "storage"
path: "/containerd"
mode: 0755
- filesystem: "storage"
path: "/container-state"
mode: 0755
files:
# set hostname
- path: /etc/hostname
filesystem: root
mode: 0644
contents:
inline: |
flatcar
# /etc/resolv.conf needs to be a file, not a symlink
- path: /etc/resolv.conf
filesystem: root
mode: 0644
contents:
inline: |
links:
# set timezone
- path: /etc/localtime
filesystem: root
overwrite: true
target: /usr/share/zoneinfo/US/Pacific
systemd:
units:
# mount the spinning rust
- name: mnt-storage.mount
enabled: true
contents: |
[Unit]
Before=local-fs.target
[Mount]
What=/dev/disk/by-label/storage
Where=/mnt/storage
Type=ext4
[Install]
WantedBy=local-fs.target
# store containers on spinning rust
- name: var-lib-docker.mount
enabled: true
contents: |
[Unit]
Before=local-fs.target
[Mount]
What=/mnt/storage/docker
Where=/var/lib/docker
Type=none
Options=bind
[Install]
WantedBy=local-fs.target
- name: var-lib-containerd.mount
enabled: true
contents: |
[Unit]
Before=local-fs.target
[Mount]
What=/mnt/storage/containerd
Where=/var/lib/containerd
Type=none
Options=bind
[Install]
WantedBy=local-fs.target
# Ensure docker starts automatically instead of being socket-activated
- name: docker.socket
enabled: false
- name: docker.service
enabled: true
docker:
Use ct to compile config.yaml to config.json, which is what the Flatcar installer will use:
./ct --in-file config.yaml >config.json
Now it’s time to set up a new Linode. Get whatever size you want. Set it up with any available distro; we’re not going to use it. (I initially intended to leave a small Alpine Linux configuration up to bootstrap and update the system, but you really don’t need it. Uploading and installation can be done with the Finnix rescue system Linode provides.) Shut down the new host, delete both the root and swap filesystems disks that Linode creates, and create two new ones: a 10-GB Flatcar boot disk and a data disk that uses the rest of your available space. Configure the boot disk as /dev/sda and the data disk as /dev/sdb.
Reboot the node in rescue mode. This will (as of this writing, at least) bring it up in Finnix from a CD image. Launch the Lish console and enable SSH login:
passwd root && systemctl start sshd && ifconfig
Mount the storage partition so we can upload to it:
mkdir /mnt/storage && mount /dev/sdb /mnt/storage && mkdir /mnt/storage/install
Make note of the node’s IP address; you’ll need it. I’ll use 12.34.56.78 as an example below.
Back on your computer, upload the needed files to the node…it’ll take a few minutes:
scp config.json flatcar-install.sh flatcar_production_qemu_image.img.bz2 root@12.34.56.78:/mnt/storage/install/
Back at the node, begin the installation…it’ll take a few more minutes:
./flatcar-install.sh -f flatcar_production_qemu_image.img.bz2 -d /dev/sda -i config.json
Once the installation is complete, shut down the node. In the Linode Manager page for your node, go to the Configurations tab and edit the configuration. For “Select a Kernel” under “Boot Settings,” change from the default “GRUB 2” to “Direct Disk.” /dev/sda is a hard-drive image, not a filesystem image; this will tell Linode to run the MBR on /dev/sda, which will start the provided GRUB and load the kernel.
Now, you can bring up your new Flatcar node. If you still have the console window up, you should see that it doesn’t take long at all to boot…maybe 15 seconds or so once it gets going. Once it’s up, you can SSH in with the key you configured.
From here, you can reconfigure more or less like any other Flatcar installation. If you need to redo the configuration, probably the easiest way to do that is to upload your config.json to /usr/share/oem/config.ign, touch /boot/flatcar/first_boot, and reboot. This will reread the configuration, which is useful for adding new containers, creating a persistent SSH configuration, etc.