Running Flatcar on STACKIT
STACKIT Cloud
is a european business cloud provider.
This guide shows you how to run Flatcar Container Linux on STACKIT Cloud by uploading a custom image and creating a server instance with it.
These instructions require Flatcar with version 4230.2.1
or newer.
Prerequisites
Before you start, ensure you have the following:
- A STACKIT account, organization, and a project.
- The STACKIT CLI installed and configured on your machine.
Before you start, make sure to define all environment variables in order to reuse them in the next steps:
export PROJECT_ID="your project ID"
export SERVER_NAME="flatcar"
export FLATCAR_IMAGE_PATH="/path/to/your/flatcar_production_stackit_image.img"
export PRIVATE_KEY_PATH="/path/to/your/private/key"
export PUBLIC_KEY_PATH="@${PRIVATE_KEY_PATH}.pub"
export IMAGE_NAME="flatcar-stable"
export FLATCAR_VERSION="4230.2.1"
export KEY_NAME="flatcar-key"
export SECURITY_GROUP_NAME="flatcar-sg"
export NETWORK_NAME="flatcar-network"
export ARCH="x86"
export MACHINE_TYPE="g1a.4d" # change this if you use arm64, e.g. g1r.8d
Load these with source flatcar.env
Step 1: Upload the Flatcar image
First, upload your desired Flatcar image to your STACKIT project.
IMAGE_ID=$(
stackit image create --name "${IMAGE_NAME}" \
--os-version "${FLATCAR_VERSION}" \
--disk-format qcow2 \
--local-file-path "${FLATCAR_IMAGE_PATH}" \
--os linux \
--os-distro flatcar \
--architecture "${ARCH}" \
--project-id "${PROJECT_ID}" \
-o json -y | \
jq -r ".id"
)
You can verify the upload by listing all available images in your project:
stackit image list --project-id "${PROJECT_ID}"
Step 2: Prepare the server environment
Before creating the server, you need to prepare several components: an SSH key for access, a network for connectivity, a security group with a rule to allow SSH, and a public IP address.
1. Create an SSH key
If you don’t have one already, upload your public SSH key to STACKIT. This allows you to securely access your server later.
stackit key-pair create --name "${KEY_NAME}" --public-key "${PUBLIC_KEY_PATH}"
2. Create a network
Your server needs to be attached to a network.
NETWORK_ID=$(
stackit network create --name "${NETWORK_NAME}" \
--project-id "${PROJECT_ID}" \
-o json -y | \
jq -r ".networkId"
)
3. Create a security group and rule
First, create the security group that will contain the firewall rules.
SECURITY_GROUP_ID=$(
stackit security-group create --name "${SECURITY_GROUP_NAME}" \
--project-id "${PROJECT_ID}" \
-o json -y | \
jq -r ".id"
)
Next, add a rule to it to allow incoming SSH traffic on port 22.
stackit security-group rule create --security-group-id "${SECURITY_GROUP_ID}" \
--direction ingress \
--protocol-name tcp \
--port-range-max 22 \
--port-range-min 22 \
--description "Allow SSH access" \
--project-id "${PROJECT_ID}" \
-y
4. Create a public IP address
Create a public IP address that you will later attach to the server.
PUBLIC_IP_ID=$(
stackit public-ip create --project-id "${PROJECT_ID}" -o json -y | jq -r ".id"
)
Get the IP address you created.
PUBLIC_IP=$(
stackit public-ip describe "${PUBLIC_IP_ID}" --project-id "${PROJECT_ID}" -o json -y | jq -r ".ip"
)
5. (Optional) Automatic configuration with Butane and User Data
You can automatically configure your Flatcar Container Linux instances on first boot using Butane configs. Butane is a user-friendly tool that generates a final Ignition configuration file used by the booting machine.
On STACKIT, you provide this final configuration to your server via the User Data field.
5.1 Create the Butane file
As an example, create a file named butane.yaml
that starts an Nginx container and displays the instance hostname:
variant: flatcar
version: 1.0.0
storage:
directories:
- path: /var/www
systemd:
units:
- name: nginx.service
enabled: true
contents: |
[Unit]
Description=NGINX example
After=docker.service coreos-metadata.service
Requires=docker.service coreos-metadata.service
[Service]
EnvironmentFile=/run/metadata/flatcar
TimeoutStartSec=0
ExecStartPre=-/usr/bin/docker rm --force nginx1
ExecStartPre=-/usr/bin/bash -c "echo 'Hello from ${COREOS_OPENSTACK_HOSTNAME}' > /var/www/index.html"
ExecStart=/usr/bin/docker run --name nginx1 --volume "/var/www:/usr/share/nginx/html:ro" --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
5.2 Convert Butane to Ignition
This Butane file must be converted into an Ignition file (ignition.json
) before use:
cat butane.yaml | docker run --rm -i quay.io/coreos/butane:release > ignition.json
Step 3: Create and access the server
Now you have all the necessary components to create your Flatcar server.
1. Create the server
Create your server with all resources you created above.
SERVER_ID=$(
stackit server create --name "${SERVER_NAME}" \
--project-id "${PROJECT_ID}" \
--machine-type "${MACHINE_TYPE}" \
--boot-volume-source-id "${IMAGE_ID}" \
--network-id "${NETWORK_ID}" \
--keypair-name "${KEY_NAME}" \
--availability-zone eu01-2 \
--boot-volume-source-type image \
--boot-volume-size 50 \
--security-groups "${SECURITY_GROUP_ID}" \
-o json -y | \
jq -r ".id"
)
If you created an Ignition file, include the additional --user-data @/path/to/your/ignition.json
flag.
Make sure to use the @
prefix, which tells the CLI to load the contents of your Ignition file.
2. Attach a public IP
Then, attach the IP to your server:
stackit server public-ip attach "${PUBLIC_IP_ID}" --server-id "${SERVER_ID}" --project-id "${PROJECT_ID}" -y
3. Connect to your server
Your Flatcar server is running and your public IP address is attached.
You can now connect to it via SSH using the user core and your private SSH key.
ssh core@"${PUBLIC_IP}" -i "${PRIVATE_KEY_PATH}"
4. (Optional) Verify your nginx configuration
If you configured the server with the example Butane file to run an Nginx container, you can verify that it’s working after you have connected via SSH.
Run the curl
command to check the local web server:
curl localhost
This confirms your User Data script was executed successfully. You should see a “Hello” message from the container, which includes the server’s unique hostname:
Hello from <HOSTNAME>