Fedora CoreOS: A minimalistic OS for Containers

Fedora CoreOS: A minimalistic OS for Containers

Fedora CoreOS (ie. FCOS) is a minimalistic OS suitable for running containerized workloads securely and at scale. It is an open source project supported by Fedora community.

CoreOS Features

  1. Automatically Updating: By default, the OS continually and automatically downloads new updates, applies them “atomically” (in the background without breaking the system), and reboots into the new version when ready.
  2. Minimalistic OS: It strips away traditional OS bulk, providing only the bare essentials needed to boot and run Docker or Podman containers.
  3. Monolithic: It is Delivered, managed, and updated as a single, indivisible image rather than being built from thousands of individual packages.
  4. Container Focused: Everything runs inside containers, which makes the system incredibly stable, secure, and uniform.
  5. Optimized OS: It is optimized for clusters but works standalone, providing the ideal host for tools like Kubernetes, Docker, and Podman.

There are three Fedora CoreOS (FCOS) update streams available: stable, testing, and next. Each stream has a canonical URL representing its current state in JSON format, known as “stream metadata”.

  1. Stable Stream: The recommended default for production environments. It provides a highly reliable, worry-free experience, featuring updates that have been heavily tested for several weeks in the Testing stream.
  2. Testing Stream: A staging channel where updates are evaluated for roughly two weeks before being promoted to the Stable stream. It is ideal for pre-production environments to catch potential breaking issues early.
  3. Next Stream: The most bleeding-edge channel. It contains the latest features, major Fedora re-bases, and early experimental builds. It is used for evaluating upcoming changes and providing feedback.

Disadvantages

  1. It is immutable, the root filesystem is read only by design and any updates to the configuration or software packages need to be delivered via containers or provisioned via Ignition (FCOS’s declarative configuration tool).
  2. The automatic update model requires system reboot due to which the applications need to resilient to these rolling restarts.
  3. Due to its minimalistic footprint, Base OS lacks many common debugging, compilation, or administrative tools. If you require kernel headers or specialized drivers, you must use layered containers or custom image builds.
  4. FCOS follows a continuous release stream. Organizations that need a highly static, long-term support (LTS) environment often find these constant underlying changes difficult to track and maintain.

Fedora CoreOS does not have a separate install disk. Instead, every instance starts from a generic disk image which is customized on first boot via Ignition.

Each platform has specific logic to retrieve and apply the first boot configuration. For cloud deployments, Ignition gathers the configuration via user-data mechanisms.

In the case of bare metal, Ignition can fetch its configuration from the disk or from a remote source.

Lauch CoreOS instance

Now that we have some basic understanding about Fedora CoreOS, let’s try to spin up an FCOS instance on AWS cloud platform.

For a list of available AWS FCOS images for each region, you can refer to the “Download Fedora CoreOS” page.

admin@linuxser:~$ NAME='fcos-instance'
SSHKEY='awstechstackprivate'     # the name of your SSH key: `aws ec2 describe-key-pairs`
IMAGE='ami-09b309c3dd9dd9a02'     # the AMI ID found on the download page
DISK='20'           # the size of the hard disk
REGION='your_aws_region'  # the target region
PROFILE='your_aws_profile'
TYPE='m5.large'     # the instance type
SUBNET='your_subnet' # the subnet: `aws ec2 describe-subnets`
SECURITY_GROUPS='your_security_group' # the security group `aws ec2 describe-security-groups`
aws ec2 run-instances                     \
    --region $REGION                      \
    --profile $PROFILE                    \
    --image-id $IMAGE                     \
    --instance-type $TYPE                 \
    --key-name $SSHKEY                    \
    --subnet-id $SUBNET                   \
    --security-group-ids $SECURITY_GROUPS \
    --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=${NAME}}]" \
    --block-device-mappings "VirtualName=/dev/xvda,DeviceName=/dev/xvda,Ebs={VolumeSize=${DISK}}"

Once the instance is launched we can SSH into it using the private key as shown below.

$ ssh -i <your_aws_private_key> core@<instance_ip_address>

Fedora CoreOS (FCOS) configures systems using declarative Ignition configs rather than traditional tools like cloud-init. Because Ignition consumes raw JSON, the official Butane tool is recommended to write human-readable YAML configurations and transpile them into the .ign format.

Provision CoreOS using Custom Ignition Configuration

Fedora CoreOS can be customized using a declarative ignition configuration file. Ignition is a provisioning utility that reads this ignition configuration file (in JSON format) and provisions a Fedora CoreOS system based on that configuration.

Ignition runs only once during the first boot of the system (while in the initramfs). Because Ignition runs so early in the boot process, it can re-partition disks, format filesystems, create users, and write files before the userspace begins to boot. As a result, systemd services are already written to disk when systemd starts, speeding the time to boot.

Before creating the ignition configuration file, let’s install Butane.

Butane (formerly known as the Fedora CoreOS Config Transpiler, or FCCT) is a CLI tool that we can use to translates human-readable YAML configuration files into machine-readable JSON files (called Ignition configs) required to provision and configure Fedora CoreOS.

admin@linuxser:~$ sudo dnf install -y butane
...
Package "butane-0.25.1-1.fc41.x86_64" is already installed.

Let’s now write a butane configuration file in yaml format. In this example SSH public key will be provisioned to the Fedora CoreOS machine (via Ignition). The SSH private key needs to be available to your user on the local workstation, in order to remotely authenticate yourself over SSH.

admin@linuxser:~/fcos_custom_demo$ cat config.bu 
variant: fcos
version: 1.6.0
passwd:
  users:
    - name: core
      ssh_authorized_keys:
        - ssh-rsa AAAA...

Now let’s transpile this YAML file into a JSON formatted file using butane.

admin@linuxser:~/fcos_custom_demo$ butane --pretty --strict config.bu > config.ign
admin@linuxser:~/fcos_custom_demo$ ls -ltr
total 8
-rw-r--r--. 1 admin admin 672 Jun 19 15:40 config.bu
-rw-r--r--. 1 admin admin 752 Jun 19 15:41 config.ign

We can now use this custom ignition configuration file to provision the Fedora Core OS instance as shown below.

admin@linuxser:~$ NAME='fcos-custom-instance'
SSHKEY='awstechstackprivate'     # the name of your SSH key: `aws ec2 describe-key-pairs`
IMAGE='ami-09b309c3dd9dd9a02'     # the AMI ID found on the download page
DISK='20'           # the size of the hard disk
REGION='your_aws_region'  # the target region
PROFILE='your_aws_profile'
TYPE='m5.large'     # the instance type
SUBNET='your_subnet' # the subnet: `aws ec2 describe-subnets`
SECURITY_GROUPS='your_security_group' # the security group `aws ec2 describe-security-groups`
USERDATA='./config.ign'
aws ec2 run-instances                     \
    --region $REGION                      \
    --profile $PROFILE                    \
    --image-id $IMAGE                     \
    --instance-type $TYPE                 \
    --key-name $SSHKEY                    \
    --subnet-id $SUBNET                   \
    --security-group-ids $SECURITY_GROUPS \
    --user-data "file://${USERDATA}"      \
    --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=${NAME}}]" \
    --block-device-mappings "VirtualName=/dev/xvda,DeviceName=/dev/xvda,Ebs={VolumeSize=${DISK}}"

Now you should be able to SSH into Fedora Core OS with the private key corresponding to the public key loaded as a part of user data.

Also you should be able to see the uploaded SSH key using the ignition configuration file as shown below.

core@ip-10-x-x-x:~$ ls -ltr ~/.ssh/authorized_keys.d/
total 8
-rw-------. 1 core core 572 Jun 19 08:18 ignition
-rw-------. 1 core core 401 Jun 19 08:19 afterburn

You can verify the version of the booted system using the rpm-ostree as shown below.

core@ip-10-x-x-x:~$ rpm-ostree status
State: idle
AutomaticUpdatesDriver: Zincati
  DriverState: active; periodically polling for updates (last checked Fri 2026-06-19 11:01:37 UTC)
Deployments:
● ostree-image-signed:docker://quay.io/fedora/fedora-coreos:stable
                   Digest: sha256:075bf47207b42f01b0bdf9c9d6705ba6dc6a6e7e87bc0b474c87f0d444357752
                  Version: 44.20260523.3.1 (2026-06-08T22:00:22Z)

Let’s start up the docker service which is pre installed on this OS.

core@ip-10-x-x-x:~$ sudo systemctl start docker.service 
core@ip-10-x-x-x:~$ sudo systemctl status docker.service 

Add the user to the docker group so we can run docker commands without sudo. Restart the shell for the changes to take effect.

core@ip-10-x-x-x:~$ sudo usermod -aG docker $USER

Now you should be able to test docker as shown below.

core@ip-10-x-x-x:~$ docker run hello-world
core@ip-10-x-x-x:~$ docker images
                                                                                                   i Info →   U  In Use
IMAGE                ID             DISK USAGE   CONTENT SIZE   EXTRA
hello-world:latest   96498ffd522e       21.8kB         9.49kB    U   

Hope you enjoyed reading this article. Thank you..