Flatcar Container Linux を試してみる
先日 2024/10/29 の CNCF blog で Flatcar Container Linux が incubating project に採択されたとの記事がありました。
Flatcar は今まで存在を知らなかったのですが、面白そうだったのでどんなことができるか試してみます。
Flatcar 概要
Flatcar Container Linux (以下 Flatcar と表記) はコンテナワークロードを実行するためにカスタマイズされた軽量なオープンソースの OS です。
Flatcar の元となった CoreOS Container Linux はコンテナワークロード向けの OS として CoreOS (企業) により開発されてきましたが、2018 年に RedHat に買収され、2020 年にサポート終了となりました。後継プロジェクトとしては同じくコンテナワークロード向け OS として Fedora CoreOS が誕生し、こちらは現在でも開発が続けられています。
一方で Flatcar も上記の CoreOS から派生したプロジェクトとなっており、コンテナワークロード用に最適化された軽量・最小限のみのパッケージを含む・immutable な構成の OS として開発されています。
このようなコンセプトを持つ OS は以下のようにいくつかありますが、flatcar もそのような OS の一つとなっています。
特徴
Flatcar の特徴は概要ページにまとまっていますが、Ubuntu や RockyLinux などの汎用的な OS と比較すると特に以下の点が特徴的です。
package manager がない
Flatcar では apt や dnf などのパッケージマネージャーが含まれていないので OS 内で追加のパッケージをインストールすることができません(バイナリを直接ダウンロードしてくることは可能)。必要なパッケージは起動時の userdata で systemd-sysext
を利用した独自のパッケージで追加したりカスタムイメージで対応することになるので、OS 内で色々コマンドを実行してパッケージを追加するのではなく、OS 作成前に構成を宣言的に記述する IaC に近い概念となっています。
/usr が read-only
Flatcar では /usr
ディレクトリ以下が read-only となっており、システムに関連するファイル等を変更できないようにすることでよりセキュアな構成にしています。概要ページの中の Immutable filesystem がこれに対応。
使ってみる
Flatcar は下記ドキュメントの通り様々な環境で動かせるようになっています。
- Cloud Providers
- AWS, Azure, Google Cloud など主要なクラウドプロバイダーで登録済みのマシンイメージを使って仮想マシンとして起動する方法。
- 気軽に試せる。
- Virtualization options
- 仮想マシン用のイメージをダウンロードしてオンプレや手元の環境で Qemu, Vagrant, VirtualBox などで仮想マシンとして起動する方法。
- 手元で試すなら最もコストが低い。
- Bare Metal
- ISO イメージ等をダウンロードして物理マシンに直接インストールする方法。
- 上記のいずれかで済むのであまり使う機会はなさそう。
自宅の環境では Openstack を使っているので、ここでは Openstack の手順に従って仮想マシンとして起動する方法を試してみます。
インストール
Flatcar は用途に合わせて stable, beta, alpha, LTS の 4 つのリリースチャンネルがあります。
チャンネルによって Flatcar のバージョンが異なり、containerd やカーネルのバージョン、リリーススケジュールの差異などがあります。詳細は Managing Releases を参照。
ここでは Stable チャンネルのイメージを使用します。
以下のコマンドで openstack 用のイメージをダウンロード。これにより stable チャンネルにおける最新バージョン 3975.2.2
の flatcar イメージがダウンロードされます。
$ wget https://stable.release.flatcar-linux.net/amd64-usr/current/flatcar_production_openstack_image.img.bz2
$ bunzip2 flatcar_production_openstack_image.img.bz2
openstack (glance) にイメージを登録
openstack image create \
--container-format bare \
--disk-format qcow2 \
--public \
--property hw_qemu_guest_agent=yes \
--file ./flatcar_production_openstack_image.img \
flatcar-3975.2.2-amd64
後は通常の VM と同様にイメージや flavor, ネットワークを指定して作成することで flatcar が起動します。
openstack server create \
--image flatcar-3975.2.2-amd64 \
--key-name kolla_ssh \
--flavor m1.small \
--network demo-net \
flatcar-test
起動したマシンにはデフォルトユーザー core
で SSH できます。
$ ssh -i ~/.ssh/kolla_ssh core@192.168.3.186
Last login: Thu Oct 31 13:25:14 UTC 2024 from 192.168.3.27 on pts/0
Flatcar Container Linux by Kinvolk stable 3975.2.2 for Openstack
core@test ~ $
/usr は read-only になっているので書き込みできません。
core@test /usr $ touch test
touch: cannot touch 'test': Read-only file system
systemd で以下のようなサービスが動いています。
サービス一覧
audit-rules.service loaded active exited Load Security Auditing Rules
clean-ca-certificates.service loaded active exited Clean up broken links in /etc/ssl/certs
containerd.service loaded active running containerd container runtime
coreos-metadata-sshkeys@core.service loaded active exited Flatcar Metadata Agent (SSH Keys)
coreos-metadata.service loaded active exited Flatcar Metadata Agent
dbus.service loaded active running D-Bus System Message Bus
dracut-shutdown.service loaded active exited Restore /run/initramfs on shutdown
ensure-sysext.service loaded active exited ensure-sysext.service
flatcar-tmpfiles.service loaded active exited Create missing system files
getty@tty1.service loaded active running Getty on tty1
kmod-static-nodes.service loaded active exited Create List of Static Device Nodes
kubelet.service loaded active running kubelet: The Kubernetes Node Agent
ldconfig.service loaded active exited Rebuild Dynamic Linker Cache
lvm2-activation-early.service loaded active exited Activation of LVM2 logical volumes
lvm2-activation.service loaded active exited Activation of LVM2 logical volumes
nvidia.service loaded active exited NVIDIA Configure Service
polkit.service loaded active running Authorization Manager
qemu-guest-agent.service loaded active running QEMU Guest Agent
serial-getty@ttyS0.service loaded active running Serial Getty on ttyS0
sshd-keygen.service loaded active exited Generate sshd host keys
sshd@0-10.0.0.254:22-10.0.0.30:47218.service loaded active running OpenSSH per-connection server daemon (10.0.0.30:47218)
sshkeys.service loaded active exited sshkeys.service
systemd-fsck@dev-disk-by\x2dlabel-OEM.service loaded active exited File System Check on /dev/disk/by-label/OEM
systemd-hwdb-update.service loaded active exited Rebuild Hardware Database
systemd-journal-catalog-update.service loaded active exited Rebuild Journal Catalog
systemd-journal-flush.service loaded active exited Flush Journal to Persistent Storage
systemd-journald.service loaded active running Journal Service
systemd-logind.service loaded active running User Login Management
systemd-machine-id-commit.service loaded active exited Commit a transient machine-id on disk
systemd-modules-load.service loaded active exited Load Kernel Modules
systemd-network-generator.service loaded active exited Generate network units from Kernel command line
systemd-networkd-wait-online.service loaded active exited Wait for Network to be Configured
systemd-networkd.service loaded active running Network Configuration
systemd-random-seed.service loaded active exited Load/Save OS Random Seed
systemd-remount-fs.service loaded active exited Remount Root and Kernel File Systems
systemd-resolved.service loaded active running Network Name Resolution
systemd-sysctl.service loaded active exited Apply Kernel Variables
systemd-sysext.service loaded active exited Merge System Extension Images into /usr/ and /opt/
systemd-sysusers.service loaded active exited Create System Users
systemd-timesyncd.service loaded active running Network Time Synchronization
systemd-tmpfiles-setup-dev-early.service loaded active exited Create Static Device Nodes in /dev gracefully
systemd-tmpfiles-setup-dev.service loaded active exited Create Static Device Nodes in /dev
systemd-tmpfiles-setup.service loaded active exited Create Volatile Files and Directories
systemd-udev-settle.service loaded active exited Wait for udev To Complete Device Initialization
systemd-udev-trigger.service loaded active exited Coldplug All udev Devices
systemd-udevd.service loaded active running Rule-based Manager for Device Events and Files
systemd-update-done.service loaded active exited Update is Completed
systemd-update-utmp.service loaded active exited Record System Boot/Shutdown in UTMP
systemd-user-sessions.service loaded active exited Permit User Sessions
systemd-userdbd.service loaded active running User Database Manager
systemd-vconsole-setup.service loaded active exited Virtual Console Setup
update-engine.service loaded active running Update Engine
update-ssh-keys-after-ignition.service loaded active exited Run update-ssh-keys once after Ignition
user-runtime-dir@500.service loaded active exited User Runtime Directory /run/user/500
user@500.service loaded active running User Manager for UID 500
docker, containerd などコンテナ向け CLI の他、curl, wget, top, git などの基本的なコマンドはインストール済みになっています。一方で python や go などのプログラミング言語は入っていません。
core ユーザーの uid が 500 で root, core しかユーザーがいないのは珍しいかもしれません。
core@test ~ $ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
core:x:500:500:Flatcar Admin:/home/core:/bin/bash
Ignition による構成のカスタマイズ
Flatcar では OS 内でコマンドを実行して構成を変更するよりも宣言的に構成を記述する方法が推奨されているため、イメージや起動時の処理をカスタマイズする方法がいくつか提供されています。この中の 1 つである Ignition では OS 起動時にサービスの起動やファイルの作成などを記述できます。OS 起動時に実行したい処理を宣言的に記述するという点で、基本的には cloud-init と同じような感覚で利用できます。
Ignition 用の設定ファイルは json 形式で記述する必要がありますが、例えば nginx の docker コンテナを起動時に systemd で起動させるには以下のように書きます (ドキュメントのサンプルより)。
{
"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"
}
]
}
}
見てわかるように Ignition の設定ファイルは読み書きしたり解読するには非常に分かりづらいので、人間が読み書きしやすい yml 形式で内容を記述し、これを Ignition が認識できる Json に変換するための Butane というユーティリティツールが提供されています。上記の内容を Butane の形式で書くと以下のようになります。
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
意味のあるまとまりごとに改行・インデントされてだいぶ見やすくなりました。
このように Ignition を使って起動時の処理をカスタマイズする場合、基本的にはまず yaml 形式で処理を記述し、Butane で Ignition の json に変換、OS 起動時に userdata として指定することで適用という流れになります。
では実際に上記の ignition 用の yaml ファイルを作成し、OS 起動時に nginx のコンテナが起動する動作を確認してみます。butane は github でバイナリが配布されていますが、コンテナイメージもあるのでここではそれを使います。
Butane では変換対象の yaml を入力として受け取り、変換後の json を出力するので、それをファイルにリダイレクトします、
cat nginx.yml | docker run --rm -i quay.io/coreos/butane:release > ignition.json
作成した json を仮想マシン作成時の userdata に適用することで、OS 起動時に json に記載された処理が実行されます。openstack では VM 作成時に --user-data
にファイルを指定することで userdata として解釈されるので、以下のコマンドで新しい flatcar VM を作成します。イメージやフレーバー、ネットワークは使用している環境に合わせて指定。
openstack server create \
--user-data ./ignition.json \
--image flatcar-3975.2.2-amd64 \
--key-name kolla_ssh \
--flavor m1.small \
--network demo-net \
flatcar-test
起動した VM に SSH ログインすると実際に nginx サービスが稼働していることが確認できます。
systemd 配下で管理されていますが、ignition で記述したとおり実態は nginx イメージを利用した docker コンテナのプロセスが起動しています。
core@flatcar-test ~ $ sudo systemctl status nginx
● nginx.service - NGINX example
Loaded: loaded (/etc/systemd/system/nginx.service; enabled; preset: enabled)
Active: active (running) since Fri 2024-11-01 10:52:28 UTC; 3min 32s ago
Process: 1574 ExecStartPre=/usr/bin/docker rm --force nginx1 (code=exited, status=0/SUCCESS)
Main PID: 1579 (docker)
Tasks: 6 (limit: 15356)
Memory: 49.1M (peak: 49.3M)
CPU: 96ms
CGroup: /system.slice/nginx.service
└─1579 /usr/bin/docker run --name nginx1 --pull always --log-driver=journald --net host docker.io/nginx:1
Nov 01 10:52:52 flatcar-test.novalocal docker[1579]: /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
Nov 01 10:52:52 flatcar-test.novalocal docker[1579]: /docker-entrypoint.sh: Configuration complete; ready for start up
Nov 01 10:52:52 flatcar-test.novalocal docker[1579]: 2024/11/01 10:52:52 [notice] 1#1: using the "epoll" event method
Nov 01 10:52:52 flatcar-test.novalocal docker[1579]: 2024/11/01 10:52:52 [notice] 1#1: nginx/1.27.2
Nov 01 10:52:52 flatcar-test.novalocal docker[1579]: 2024/11/01 10:52:52 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14)
Nov 01 10:52:52 flatcar-test.novalocal docker[1579]: 2024/11/01 10:52:52 [notice] 1#1: OS: Linux 6.6.54-flatcar
Nov 01 10:52:52 flatcar-test.novalocal docker[1579]: 2024/11/01 10:52:52 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
Nov 01 10:52:52 flatcar-test.novalocal docker[1579]: 2024/11/01 10:52:52 [notice] 1#1: start worker processes
Nov 01 10:52:52 flatcar-test.novalocal docker[1579]: 2024/11/01 10:52:52 [notice] 1#1: start worker process 29
Nov 01 10:55:53 flatcar-test.novalocal docker[1579]: ::1 - - [01/Nov/2024:10:55:53 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/8.7.1" "-"
OS 起動時のログを見て Ignition の処理が実際に実行されていることも見ておきます。
/var/log/
配下のログは以下のようになっており、ubuntu 等の通常の OS と比較するとすっきりしている印象を受けます。
core@flatcar-test ~ $ ls -l /var/log/
total 24
drwxr-x---. 2 root root 4096 Nov 1 10:52 audit
-rw-rw----. 1 root utmp 0 Nov 1 10:52 btmp
-rw-r--r--. 1 root root 0 Nov 1 10:52 faillog
drwxr-sr-x. 4 root systemd-journal 4096 Nov 1 10:52 journal
-rw-rw-r--. 1 root utmp 146292 Nov 1 10:55 lastlog
drwx------. 2 root root 4096 Nov 1 10:52 private
drwx------. 2 root root 4096 Nov 1 10:52 sssd
-rw-rw-r--. 1 root utmp 3456 Nov 1 10:55 wtmp
システム関連のログは syslog や messages ではなく systemd-journald
によって journal に出力されます。sudo journalctl > journal.log
でファイルに書き出すと Ignition がいろいろなセットアップを行っていることが確認できます。
Ignition の出力
core@flatcar-test ~ $ cat journal.log | grep ignition
Nov 01 10:52:13 localhost systemd[1]: Starting ignition-setup-pre.service - Ignition env setup...
Nov 01 10:52:13 localhost systemd[1]: Finished ignition-setup-pre.service - Ignition env setup.
Nov 01 10:52:15 localhost systemd[1]: Starting ignition-setup.service - Ignition (setup)...
Nov 01 10:52:15 localhost systemd[1]: Finished ignition-setup.service - Ignition (setup).
Nov 01 10:52:15 localhost systemd[1]: Starting ignition-fetch-offline.service - Ignition (fetch-offline)...
Nov 01 10:52:15 localhost ignition[723]: Ignition 2.18.0
Nov 01 10:52:15 localhost ignition[723]: Stage: fetch-offline
Nov 01 10:52:15 localhost systemd[1]: Finished ignition-fetch-offline.service - Ignition (fetch-offline).
Nov 01 10:52:15 localhost ignition[723]: no configs at "/usr/lib/ignition/base.d"
Nov 01 10:52:15 localhost ignition[723]: no config dir at "/usr/lib/ignition/base.platform.d/openstack"
Nov 01 10:52:15 localhost ignition[723]: parsed url from cmdline: ""
Nov 01 10:52:15 localhost ignition[723]: no config URL provided
Nov 01 10:52:15 localhost ignition[723]: reading system config file "/usr/lib/ignition/user.ign"
Nov 01 10:52:15 localhost ignition[723]: no config at "/usr/lib/ignition/user.ign"
Nov 01 10:52:15 localhost ignition[723]: failed to fetch config: resource requires networking
Nov 01 10:52:15 localhost ignition[723]: Ignition finished successfully
Nov 01 10:52:16 localhost systemd[1]: Starting ignition-fetch.service - Ignition (fetch)...
Nov 01 10:52:16 localhost ignition[739]: Ignition 2.18.0
Nov 01 10:52:16 localhost ignition[739]: Stage: fetch
Nov 01 10:52:16 localhost ignition[739]: no configs at "/usr/lib/ignition/base.d"
Nov 01 10:52:16 localhost ignition[739]: no config dir at "/usr/lib/ignition/base.platform.d/openstack"
Nov 01 10:52:16 localhost ignition[739]: parsed url from cmdline: ""
Nov 01 10:52:16 localhost ignition[739]: no config URL provided
Nov 01 10:52:16 localhost ignition[739]: reading system config file "/usr/lib/ignition/user.ign"
Nov 01 10:52:16 localhost ignition[739]: no config at "/usr/lib/ignition/user.ign"
Nov 01 10:52:16 localhost ignition[739]: config drive ("/dev/disk/by-label/config-2") not found. Waiting...
Nov 01 10:52:16 localhost ignition[739]: config drive ("/dev/disk/by-label/CONFIG-2") not found. Waiting...
Nov 01 10:52:16 localhost ignition[739]: GET http://169.254.169.254/openstack/latest/user_data: attempt #1
Nov 01 10:52:16 localhost ignition[739]: GET result: OK
Nov 01 10:52:16 localhost ignition[739]: parsing config with SHA512: 2b8506e6288fefe7b8410bf75504c5f38e7139d3fbe90e8da6d0918e3993ef2c864e76f5d2caebbdc65687a2711076ade6a150a4a10784cdf4bd9365f02ab2e5
Nov 01 10:52:16 localhost ignition[739]: fetched base config from "system"
Nov 01 10:52:16 localhost ignition[739]: fetch: fetch complete
Nov 01 10:52:16 localhost ignition[739]: fetched base config from "system"
Nov 01 10:52:16 localhost ignition[739]: fetch: fetch passed
Nov 01 10:52:16 localhost ignition[739]: fetched user config from "openstack"
Nov 01 10:52:16 localhost ignition[739]: Ignition finished successfully
Nov 01 10:52:16 localhost systemd[1]: Finished ignition-fetch.service - Ignition (fetch).
Nov 01 10:52:16 localhost systemd[1]: Starting ignition-kargs.service - Ignition (kargs)...
Nov 01 10:52:16 localhost ignition[744]: Ignition 2.18.0
Nov 01 10:52:16 localhost ignition[744]: Stage: kargs
Nov 01 10:52:16 localhost ignition[744]: no configs at "/usr/lib/ignition/base.d"
Nov 01 10:52:16 localhost ignition[744]: no config dir at "/usr/lib/ignition/base.platform.d/openstack"
Nov 01 10:52:16 localhost ignition[744]: kargs: kargs passed
Nov 01 10:52:16 localhost systemd[1]: Finished ignition-kargs.service - Ignition (kargs).
Nov 01 10:52:16 localhost ignition[744]: Ignition finished successfully
Nov 01 10:52:16 localhost systemd[1]: Starting ignition-disks.service - Ignition (disks)...
Nov 01 10:52:16 localhost ignition[749]: Ignition 2.18.0
Nov 01 10:52:16 localhost ignition[749]: Stage: disks
Nov 01 10:52:16 localhost ignition[749]: no configs at "/usr/lib/ignition/base.d"
Nov 01 10:52:16 localhost ignition[749]: no config dir at "/usr/lib/ignition/base.platform.d/openstack"
Nov 01 10:52:16 localhost ignition[749]: disks: disks passed
Nov 01 10:52:16 localhost ignition[749]: Ignition finished successfully
Nov 01 10:52:16 localhost systemd[1]: Finished ignition-disks.service - Ignition (disks).
Nov 01 10:52:16 localhost systemd[1]: ignition-remount-sysroot.service - Remount /sysroot read-write for Ignition was skipped because of an unmet condition check (ConditionPathIsReadWrite=!/sysroot).
Nov 01 10:52:16 localhost systemd[1]: Reached target ignition-diskful.target - Ignition Boot Disk Setup.
Nov 01 10:52:16 localhost systemd[1]: Starting ignition-mount.service - Ignition (mount)...
Nov 01 10:52:16 localhost ignition[881]: INFO : Ignition 2.18.0
Nov 01 10:52:16 localhost ignition[881]: INFO : Stage: mount
Nov 01 10:52:16 localhost ignition[881]: INFO : no configs at "/usr/lib/ignition/base.d"
Nov 01 10:52:16 localhost ignition[881]: INFO : no config dir at "/usr/lib/ignition/base.platform.d/openstack"
Nov 01 10:52:16 localhost ignition[881]: INFO : mount: mount passed
Nov 01 10:52:16 localhost ignition[881]: INFO : Ignition finished successfully
Nov 01 10:52:16 localhost systemd[1]: Finished ignition-mount.service - Ignition (mount).
Nov 01 10:52:23 localhost systemd[1]: Starting ignition-files.service - Ignition (files)...
Nov 01 10:52:23 localhost ignition[913]: INFO : Ignition 2.18.0
Nov 01 10:52:23 localhost ignition[913]: INFO : Stage: files
Nov 01 10:52:23 localhost ignition[913]: INFO : no configs at "/usr/lib/ignition/base.d"
Nov 01 10:52:23 localhost ignition[913]: INFO : no config dir at "/usr/lib/ignition/base.platform.d/openstack"
Nov 01 10:52:23 localhost ignition[913]: DEBUG : files: compiled without relabeling support, skipping
Nov 01 10:52:23 localhost ignition[913]: INFO : files: op(1): [started] processing unit "nginx.service"
Nov 01 10:52:23 localhost ignition[913]: INFO : files: op(1): op(2): [started] writing unit "nginx.service" at "/sysroot/etc/systemd/system/nginx.service"
Nov 01 10:52:23 localhost ignition[913]: INFO : files: op(1): op(2): [finished] writing unit "nginx.service" at "/sysroot/etc/systemd/system/nginx.service"
Nov 01 10:52:23 localhost ignition[913]: INFO : files: op(1): [finished] processing unit "nginx.service"
Nov 01 10:52:23 localhost ignition[913]: INFO : files: op(3): [started] setting preset to enabled for "nginx.service"
Nov 01 10:52:23 localhost ignition[913]: INFO : files: op(3): [finished] setting preset to enabled for "nginx.service"
Nov 01 10:52:23 localhost ignition[913]: INFO : files: createResultFile: createFiles: op(4): [started] writing file "/sysroot/etc/.ignition-result.json"
Nov 01 10:52:23 localhost ignition[913]: INFO : files: createResultFile: createFiles: op(4): [finished] writing file "/sysroot/etc/.ignition-result.json"
Nov 01 10:52:23 localhost ignition[913]: INFO : files: files passed
Nov 01 10:52:23 localhost ignition[913]: INFO : Ignition finished successfully
Nov 01 10:52:23 localhost systemd[1]: Finished ignition-files.service - Ignition (files).
Nov 01 10:52:23 localhost systemd[1]: Starting ignition-quench.service - Ignition (record completion)...
Nov 01 10:52:23 localhost systemd[1]: Starting initrd-setup-root-after-ignition.service - Root filesystem completion...
Nov 01 10:52:23 localhost systemd[1]: ignition-quench.service: Deactivated successfully.
Nov 01 10:52:23 localhost systemd[1]: Finished ignition-quench.service - Ignition (record completion).
Nov 01 10:52:23 localhost initrd-setup-root-after-ignition[933]: grep: /sysroot/etc/flatcar/enabled-sysext.conf: No such file or directory
Nov 01 10:52:23 localhost initrd-setup-root-after-ignition[933]: grep: /sysroot/usr/share/flatcar/enabled-sysext.conf: No such file or directory
Nov 01 10:52:23 localhost initrd-setup-root-after-ignition[937]: grep: /sysroot/etc/flatcar/enabled-sysext.conf: No such file or directory
Nov 01 10:52:23 localhost systemd[1]: Finished initrd-setup-root-after-ignition.service - Root filesystem completion.
Nov 01 10:52:23 localhost systemd[1]: Reached target ignition-complete.target - Ignition Complete.
Nov 01 10:52:23 localhost systemd[1]: Stopped target ignition-complete.target - Ignition Complete.
Nov 01 10:52:23 localhost systemd[1]: Stopped target ignition-diskful.target - Ignition Boot Disk Setup.
Nov 01 10:52:23 localhost systemd[1]: initrd-setup-root-after-ignition.service: Deactivated successfully.
Nov 01 10:52:23 localhost systemd[1]: Stopped initrd-setup-root-after-ignition.service - Root filesystem completion.
Nov 01 10:52:23 localhost systemd[1]: ignition-files.service: Deactivated successfully.
Nov 01 10:52:23 localhost systemd[1]: Stopped ignition-files.service - Ignition (files).
Nov 01 10:52:23 localhost systemd[1]: Stopping ignition-mount.service - Ignition (mount)...
Nov 01 10:52:23 localhost ignition[957]: INFO : Ignition 2.18.0
Nov 01 10:52:23 localhost ignition[957]: INFO : Stage: umount
Nov 01 10:52:23 localhost ignition[957]: INFO : no configs at "/usr/lib/ignition/base.d"
Nov 01 10:52:23 localhost ignition[957]: INFO : no config dir at "/usr/lib/ignition/base.platform.d/openstack"
Nov 01 10:52:23 localhost ignition[957]: INFO : umount: umount passed
Nov 01 10:52:23 localhost ignition[957]: INFO : Ignition finished successfully
Nov 01 10:52:23 localhost systemd[1]: ignition-mount.service: Deactivated successfully.
Nov 01 10:52:23 localhost systemd[1]: Stopped ignition-mount.service - Ignition (mount).
Nov 01 10:52:23 localhost systemd[1]: ignition-disks.service: Deactivated successfully.
Nov 01 10:52:23 localhost systemd[1]: Stopped ignition-disks.service - Ignition (disks).
Nov 01 10:52:23 localhost systemd[1]: ignition-kargs.service: Deactivated successfully.
Nov 01 10:52:23 localhost systemd[1]: Stopped ignition-kargs.service - Ignition (kargs).
Nov 01 10:52:23 localhost systemd[1]: ignition-fetch.service: Deactivated successfully.
Nov 01 10:52:23 localhost systemd[1]: Stopped ignition-fetch.service - Ignition (fetch).
Nov 01 10:52:23 localhost systemd[1]: ignition-fetch-offline.service: Deactivated successfully.
Nov 01 10:52:23 localhost systemd[1]: Stopped ignition-fetch-offline.service - Ignition (fetch-offline).
Nov 01 10:52:23 localhost systemd[1]: ignition-setup.service: Deactivated successfully.
Nov 01 10:52:23 localhost systemd[1]: Stopped ignition-setup.service - Ignition (setup).
Nov 01 10:52:23 localhost systemd[1]: ignition-setup-pre.service: Deactivated successfully.
Nov 01 10:52:23 localhost systemd[1]: Stopped ignition-setup-pre.service - Ignition env setup.
Nov 01 10:52:24 flatcar-test.novalocal systemd[1]: ignition-delete-config.service - Ignition (delete config) was skipped because no trigger condition checks were met.
Nov 01 10:52:25 flatcar-test.novalocal systemd[1]: ignition-delete-config.service - Ignition (delete config) was skipped because no trigger condition checks were met.
Nov 01 10:52:25 flatcar-test.novalocal systemd[1]: ignition-delete-config.service - Ignition (delete config) was skipped because no trigger condition checks were met.
Nov 01 10:52:25 flatcar-test.novalocal systemd[1]: ignition-delete-config.service - Ignition (delete config) was skipped because no trigger condition checks were met.
Nov 01 10:52:25 flatcar-test.novalocal systemd[1]: ignition-delete-config.service - Ignition (delete config) was skipped because no trigger condition checks were met.
Nov 01 10:52:26 flatcar-test.novalocal systemd[1]: Starting update-ssh-keys-after-ignition.service - Run update-ssh-keys once after Ignition...
Nov 01 10:52:26 flatcar-test.novalocal systemd[1]: Finished update-ssh-keys-after-ignition.service - Run update-ssh-keys once after Ignition.
Ignition を使うことで OS 起動時にサービスの追加やファイルの追加・更新、ユーザー追加などを行えます。サポートされているフィールドは以下を参照。
上記で見たように systemd のサービスも追加できますが、package manager がないので一般的な OS でよくある必要なパッケージを userdata 内でインストールするといった使い方はできません。何らかのアプリケーションを起動時に実行するような場合は事前にコンテナ化しておいて docker コンテナとして起動する、もしくは後述の sysext を利用するなどの工夫が必要になります。
Kubernetes で使う
Flatcar はコンテナワークロードを実行するために最適化された OS なのでもちろん k8s クラスタのノードとして使用できます。k8s 用のセットアップについては以下にドキュメントがあるので、こちらを参考に k8s クラスタに組み込んでみます。
worker node として追加する
Flatcar は control plane 用のノード、worker ノードのどちらでも使えます。ここでは ubuntu ノードで構成された既存の k8s クラスタに worker ノードとして参加させる動作を試してみます。
前述のように Flatcar では package manager がないので、kubectl や kubeadm といった k8s 運用に必要なツールは Ignition でインストールするように構成する必要があります。ドキュメントでは systemd-sysext
で kubectl, kubeadm をインストールする方法と、バイナリをダウンロードして /opt/bin
に配置する方法が記載されています。systemd-sysext を使う方法では systemd-sysupdate と組み合わせることでパッケージマネージャーのように機能し、r新しいバージョンが提供された際にノード再起動時に自動で適用されるメリットがあるそうです。
ここではどちらの方法でも特に差はないので systemd-sysext を使う方法を試します。まずドキュメントの通りに Ignition 用の yaml ファイルを用意します。
この Ignition 構成では、起動時に sysext で提供される kubernetes のダウンロードや kubeadm で worker node としてクラスタに参加する処理を実行します。ドキュメントでは k8s バージョンが 1.27 となっていますが 1.30 に書き換えました。提供されているバージョンは https://github.com/flatcar/sysext-bakery の Github Release から確認できます。
---
version: 1.0.0
variant: flatcar
storage:
links:
- target: /opt/extensions/kubernetes/kubernetes-v1.30.0-x86-64.raw
path: /etc/extensions/kubernetes.raw
hard: false
files:
- path: /etc/sysupdate.kubernetes.d/kubernetes-v1.30.conf
contents:
source: https://github.com/flatcar/sysext-bakery/releases/download/latest/kubernetes-v1.30.conf
- path: /etc/sysupdate.d/noop.conf
contents:
source: https://github.com/flatcar/sysext-bakery/releases/download/latest/noop.conf
- path: /opt/extensions/kubernetes/kubernetes-v1.30.0-x86-64.raw
contents:
source: https://github.com/flatcar/sysext-bakery/releases/download/latest/kubernetes-v1.30.0-x86-64.raw
systemd:
units:
- name: systemd-sysupdate.timer
enabled: true
- name: systemd-sysupdate.service
dropins:
- name: kubernetes.conf
contents: |
[Service]
ExecStartPre=/usr/bin/sh -c "readlink --canonicalize /etc/extensions/kubernetes.raw > /tmp/kubernetes"
ExecStartPre=/usr/lib/systemd/systemd-sysupdate -C kubernetes update
ExecStartPost=/usr/bin/sh -c "readlink --canonicalize /etc/extensions/kubernetes.raw > /tmp/kubernetes-new"
ExecStartPost=/usr/bin/sh -c "if ! cmp --silent /tmp/kubernetes /tmp/kubernetes-new; then touch /run/reboot-required; fi"
- name: locksmithd.service
# NOTE: To coordinate the node reboot in this context, we recommend to use Kured.
mask: true
- name: kubeadm.service
enabled: true
contents: |
[Unit]
Description=Kubeadm service
Requires=containerd.service
After=containerd.service
ConditionPathExists=!/etc/kubernetes/kubelet.conf
[Service]
ExecStart=/usr/bin/kubeadm join $(output from 'kubeadm token create --print-join-command')
[Install]
WantedBy=multi-user.target
既存の k8s クラスタでは kubeadm を使ってクラスタを管理しているので、control plane 用のノードで以下のコマンドを実行して worker node を追加するための token を発行します。
$ sudo kubeadm token create --print-join-command
kubeadm join 10.0.0.40:6443 --token di8j2u.ym0uxb5ibhy8xx42 --discovery-token-ca-cert-hash sha256:53909cf7fb4b9a26f0b5b6a36f30c1b43e34d76c02f5b7ce5f3d2a4d1d6c413c
k8s.yml のプレースホルダーの部分を出力されたコマンドで置き換えます。
[Service]
- ExecStart=/usr/bin/kubeadm join $(output from 'kubeadm token create --print-join-command')
+ ExecStart=/usr/bin/kubeadm join 10.0.0.40:6443 --token di8j2u.ym0uxb5ibhy8xx42 --discovery-token-ca-cert-hash sha256:53909cf7fb4b9a26f0b5b6a36f30c1b43e34d76c02f5b7ce5f3d2a4d1d6c413c
butane で json に変換。
cat k8s.yml | docker run --rm -i quay.io/coreos/butane:release > ignition.json
この ignition json を userdata に指定して flatcar VM を作成。
openstack server create \
--user-data ./ignition.json \
--image flatcar-3975.2.2-amd64 \
--key-name kolla_ssh \
--flavor m1.medium \
--network demo-net \
flatcar-test
正常に起動すると、作成した flatcar VM (flatcar-test.novalocal) が既存のクラスタに worker node として追加されていることが確認できます。
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
flatcar-test.novalocal Ready <none> 2m28s v1.30.0 10.0.0.254 <none> Flatcar Container Linux by Kinvolk 3975.2.2 (Oklo) 6.6.54-flatcar containerd://1.7.17
kata-m1 Ready control-plane 34d v1.30.0 10.0.0.30 <none> Ubuntu 22.04.5 LTS 5.15.0-124-generic containerd://1.7.22
kata-w1 Ready <none> 34d v1.30.0 10.0.0.31 <none> Ubuntu 22.04.5 LTS 5.15.0-124-generic containerd://1.7.22
status が ready になるには flatcar node 上に CNI が展開されてクラスタと通信できる必要があります。現時点でテスト済みの CNI は以下のとのこと。
- Cilium
- Flannel
- Calico
あとは通常の OS のノードと同様に pod の配置などが行えます。
通常ノードとの比較
ところで flatcar はコンテナワークロードに適した OS となっていますが、ubuntu などの通常の OS と比較して性能に優劣があるのか気になります。
そこで、以下のような非常に簡単な検証を行って、負荷をかけた際の CPU 使用率などに差があるのかを比較しました。
- nginx pod を 20 台起動する。
- k6s で負荷をかけたときの CPU 使用率の変化を測定する。
検証用ノードは上記の k8s クラスタの worker node を使います。
- Flatcar 3975.2.2
- ubuntu 22.04 LTS
- ノードの VM スペックはいずれも メモリ 8 GB, vCPU 4
各測定における CPU 使用率などは kube-state-metrics の prometheus で収集するメトリクスから計算します。
nginx pod 配置用のマニフェストは以下。始めに ubuntu ノードに配置するため nodeSelector で指定。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 20
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
nodeSelector:
kubernetes.io/hostname: kata-w1
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
まず ubuntu ノードに 20 台の pod を配置してメモリ、CPU の変化を見ます。
デフォルトの状態では平均して CPU 使用率 ~ 2.3 %、メモリ使用量 ~ 1.1 GB 。
20 個の nginx pod を起動すると、CPU 使用率 ~ 3.3 %、メモリ使用量 ~ 1.2 GB に増加。
次に k6 で負荷をかけるために、単に http リクエストを送信するための js ファイルを用意。
import http from 'k6/http';
import { sleep, check } from 'k6';
export default function () {
const url = 'http://10.98.101.228';
const res = http.get(url);
sleep(0.1);
}
k6 は control plane ノードから実行し、service を経由して svc -> pod でリクエストを送信、virtual user 100 で 3 分間負荷をかけます。
k6 run k6.js --duration 3m --vus 100
実行すると、負荷をかけている間の CPU 使用率 ~ 27 %、メモリ使用量 ~ 1.25 GB となりました。
ちなみに k6 の実行結果は以下。
$ k6 run k6.js --duration 3m --vus 100
/\ Grafana /‾‾/
/\ / \ |\ __ / /
/ \/ \ | |/ / / ‾‾\
/ \ | ( | (‾) |
/ __________ \ |_|\_\ \_____/
execution: local
script: k6.js
output: -
scenarios: (100.00%) 1 scenario, 100 max VUs, 3m30s max duration (incl. graceful stop):
* default: 100 looping VUs for 3m0s (gracefulStop: 30s)
data_received..................: 149 MB 830 kB/s
data_sent......................: 14 MB 78 kB/s
http_req_blocked...............: avg=19.73µs min=1.72µs med=5.17µs max=33.83ms p(90)=8.55µs p(95)=12.53µs
http_req_connecting............: avg=10.64µs min=0s med=0s max=33.75ms p(90)=0s p(95)=0s
http_req_duration..............: avg=1.81ms min=344.97µs med=1.32ms max=34.42ms p(90)=3.34ms p(95)=4.58ms
{ expected_response:true }...: avg=1.81ms min=344.97µs med=1.32ms max=34.42ms p(90)=3.34ms p(95)=4.58ms
http_req_failed................: 0.00% 0 out of 175183
http_req_receiving.............: avg=141.34µs min=13.24µs med=49.01µs max=33.16ms p(90)=281.5µs p(95)=575.52µs
http_req_sending...............: avg=163.04µs min=5.51µs med=17.21µs max=22.65ms p(90)=401.95µs p(95)=913.55µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=1.51ms min=266.99µs med=1.1ms max=33.88ms p(90)=2.74ms p(95)=3.85ms
http_reqs......................: 175183 972.691039/s
iteration_duration.............: avg=102.73ms min=100.43ms med=102.14ms max=149.73ms p(90)=104.87ms p(95)=106.51ms
iterations.....................: 175183 972.691039/s
vus............................: 100 min=100 max=100
vus_max........................: 100 min=100 max=100
running (3m00.1s), 000/100 VUs, 175183 complete and 0 interrupted iterations
default ✓ [======================================] 100 VUs 3m0s
次に flatcar node に対しても同様の検証を行うため、deployment の node selector を変更。
nodeSelector:
- kubernetes.io/hostname: kata-w1
+ kubernetes.io/hostname: flatcar-test.novalocal
デフォルトの状態では平均して CPU 使用率 ~ 2.9 %、メモリ使用量 ~ 1.7 GB でした。
20 個の nginx pod を起動すると、CPU 使用率 ~ 3.0 %、メモリ使用量 ~ 2.0 GB に増加。
負荷をかけた際は、CPU 使用率 ~ 20.7 % まで増加。
k6 の実行結果は以下。
/\ Grafana /‾‾/
/\ / \ |\ __ / /
/ \/ \ | |/ / / ‾‾\
/ \ | ( | (‾) |
/ __________ \ |_|\_\ \_____/
execution: local
script: k6.js
output: -
scenarios: (100.00%) 1 scenario, 100 max VUs, 3m30s max duration (incl. graceful stop):
* default: 100 looping VUs for 3m0s (gracefulStop: 30s)
data_received..................: 150 MB 830 kB/s
data_sent......................: 14 MB 78 kB/s
http_req_blocked...............: avg=23.08µs min=1.78µs med=5.15µs max=46.54ms p(90)=8.47µs p(95)=12.21µs
http_req_connecting............: avg=13.94µs min=0s med=0s max=44.41ms p(90)=0s p(95)=0s
http_req_duration..............: avg=1.72ms min=293.83µs med=1.27ms max=53.96ms p(90)=3.05ms p(95)=4.16ms
{ expected_response:true }...: avg=1.72ms min=293.83µs med=1.27ms max=53.96ms p(90)=3.05ms p(95)=4.16ms
http_req_failed................: 0.00% 0 out of 175297
http_req_receiving.............: avg=125.19µs min=13.39µs med=44.75µs max=38.35ms p(90)=222.53µs p(95)=465.59µs
http_req_sending...............: avg=159.96µs min=5.4µs med=16.85µs max=25.32ms p(90)=377.13µs p(95)=856.17µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=1.44ms min=260.46µs med=1.07ms max=39.03ms p(90)=2.52ms p(95)=3.47ms
http_reqs......................: 175297 973.335568/s
iteration_duration.............: avg=102.66ms min=100.44ms med=102.11ms max=164.93ms p(90)=104.59ms p(95)=106.06ms
iterations.....................: 175297 973.335568/s
vus............................: 100 min=100 max=100
vus_max........................: 100 min=100 max=100
running (3m00.1s), 000/100 VUs, 175297 complete and 0 interrupted iterations
default ✓ [======================================] 100 VUs 3m0s
k6 の実行結果を比較すると、いずれも時間あたりのリクエストは ~ 970 req/sec で失敗したリクエストは 0 となっています。特にレスポンスが返ってくるまでの時間は以下のようになりました。
単位が μs なので正直そこまで差はないのですが flatcar のほうが若干早くなっています。
項目 | ubuntu 22.04 | flatcar |
---|---|---|
http_req_receiving avg (μs) | 141.34 | 125.19 |
http_req_receiving p95 (μs) | 575.52 | 465.59 |
POD 起動時、負荷時のメモリ、 CPU 使用率の増加量は以下のようになりました。
項目 | ubuntu 22.04 | flatcar |
---|---|---|
pod 起動時のメモリ増加 (GB) | 0.1 | 0.3 |
pod 起動時の CPU 使用率の増加量 (%) | 1 | 0.1 |
負荷時の CPU 使用率の増加量 (%) | 25 | 17 |
今回の検証の範囲では Flatcar の方が負荷時の CPU 使用率の上昇が低く、リクエストの処理も若干早いという結果になりました。非常に単純な検証なのでこれだけで Flactar のほうが優れているとは言えませんが、少なくともパフォーマンスが顕著に劣っているわけではないことが確認できました。
Cluster API で flatcar クラスタを作成する
Ignition で k8s クラスタにノードを参加させる方法では事前にクラスタ上で登録用の token を発行して構成ファイルに記載しなければならないので、クラスタ作成や worker node のスケールアップを自動化するのは一工夫必要になっています。
そのため、Cluster API を利用して k8s クラスタを構成する方法にもサポートしています。こちらの方法では Cluster API を利用してクラスタ作成や node の追加を行うことができるので、一度セットアップを行えば比較的容易に Flatcar クラスタを管理できるようになっています。
Cluster API とは
Cluster API は k8s クラスタを各クラウド上に容易にプロビジョニング、管理することを目的とした kubernetes のサブプロジェクトです。
各クラウド は provider と呼ばれる形式で提供され、aws, azure, openstack, vcluster など様々なクラウドがサポートされています。cluster API でクラスタを作成すると provider が各クラウド上の操作を実行し、VM やネットワークなどクラスタの作成・運用に必要なリソースをプロビジョニングする動作となっています。例えば AWS の provider は以下で管理されています。
似たようなツールでは、AWS の EKS 上に CLI からクラスタを作成できる eksctl が有名ですが、 provider によって様々なクラウド上に展開できるように拡張したようなものをイメージすればわかりやすいかと思います。
使ってみる
Cluster API は openstack 上へのクラスタ作成もサポートしているので、実際に Cluster API を使って Flatcar クラスタを作成してみます。
image の作成
事前準備として、Cluster API で Flatcar を使用するには Cluster API 用にカスタマイズした Flatcar のマシンイメージを作成する必要があります。
イメージは Image-builder で作成できるようになっているので、こちらを元にビルドします。
手順は https://image-builder.sigs.k8s.io/capi/providers/openstack を参照。ビルド用に適当な ubuntu VM を用意して以下を実行していきます。
必要なパッケージのインストール
sudo apt update
sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients virtinst cpu-checker libguestfs-tools libosinfo-bin
sudo usermod -a -G kvm ubuntu
sudo chown root:kvm /dev/kvm
sudo reboot now
image-builder リポジトリを clone して依存ツールをインストール
git clone --depth 1 https://github.com/kubernetes-sigs/image-builder.git
cd image-builder/images/capi
make deps-qemu
flatcar イメージのビルド
make OEM_ID=openstack build-qemu-flatcar
ビルドはだいぶ時間がかかりますが、完了すると output
以下に qcow2 形式のイメージが作成されます。
file output/flatcar-stable-3975.2.2-kube-v1.30.5/flatcar-stable-3975.2.2-kube-v1.30.5
output/flatcar-stable-3975.2.2-kube-v1.30.5/flatcar-stable-3975.2.2-kube-v1.30.5: QEMU QCOW2 Image (v3), 21474836480 bytes
作成したイメージを openstack に登録。
openstack image create \
--container-format bare \
--disk-format qcow2 \
--public \
--property hw_qemu_guest_agent=yes \
--file ./flatcar-stable-3975.2.2-kube-v1.30.5 \
flatcar-3975.2.2-k8s-1.30.5-amd64\n
これでイメージ側の準備は完了です。
Cluster API のセットアップ
Cluster API で openstack 上にクラスタを作成するには以下の手順に従います。
まずはじめに clusterctl CLI をインストール
curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.8.4/clusterctl-linux-amd64 -o clusterctl
sudo chmod +x clusterctl
sudo mv clusterctl /usr/local/bin
Cluster API を使うには management Cluster と呼ばれる k8s クラスタが必要になります。普通に作成した k8s クラスタに対して clusterctl init
を実行することで management cluster にすることができるので、既存のクラスタ上でコマンドを実行します。
この際、--infrastructure openstack
を指定することで openstack 用にセットアップされます。
また、flatcar のように userdata に Ignition 形式を使用する場合は環境変数 EXP_KUBEADM_BOOTSTRAP_FORMAT_IGNITION=true
を設定する必要があります。
$ export EXP_KUBEADM_BOOTSTRAP_FORMAT_IGNITION=true
$ clusterctl init --infrastructure openstack
Fetching providers
Installing cert-manager version="v1.16.0"
Waiting for cert-manager to be available...
Installing provider="cluster-api" version="v1.8.4" targetNamespace="capi-system"
Installing provider="bootstrap-kubeadm" version="v1.8.4" targetNamespace="capi-kubeadm-bootstrap-system"
Installing provider="control-plane-kubeadm" version="v1.8.4" targetNamespace="capi-kubeadm-control-plane-system"
Installing provider="infrastructure-openstack" version="v0.11.0" targetNamespace="capo-system"
Your management cluster has been initialized successfully!
You can now create your first workload cluster by running the following:
clusterctl generate cluster [name] --kubernetes-version [version] | kubectl apply -f -
clusterctl generate cluster
を実行することでクラスタ作成用のマニフェストが作成されますが、openstack の場合はいくつか設定が必要になります。
まず env.rc を使って clouds.yaml から openstack 認証情報を読み取ります。
source ./env.rc clouds.yaml kolla-admin
読み取ると openstack 認証情報の環境変数が設定されます。内容は base64 encode されるので decode することで内容を確認可能。
$ env
CAPO_CLOUD=openstack
OPENSTACK_CLOUD=openstack
OPENSTACK_CLOUD_YAML_B64=...
OPENSTACK_CLOUD_PROVIDER_CONF_B64=...
OPENSTACK_CLOUD_CACERT_B64=Cg==
clusterctl generate cluster
では cloud 上にクラスタを作成するためのマニフェストを templates から作成しますが、その際にプロビジョン先のネットワークやマシンイメージを環境変数かコマンド実行時の引数から読み取って入力するので事前に設定しておく必要があります。
設定項目は必須と任意のものがありますが、基本的に以下は必須項目です。各パラメータの詳細や他の項目は https://cluster-api-openstack.sigs.k8s.io/clusteropenstack/configuration を参照。
name | Description |
---|---|
OPENSTACK_CONTROL_PLANE_MACHINE_FLAVOR | control plane 用の node に使用される VM の flavor 名 |
OPENSTACK_NODE_MACHINE_FLAVOR | worker node に使用される VM の flavor 名 |
OPENSTACK_DNS_NAMESERVERS | VM で使用する DNS |
OPENSTACK_FAILURE_DOMAIN | openstack の available zone 名 |
OPENSTACK_EXTERNAL_NETWORK_ID | openstack の外部 network の ID |
OPENSTACK_IMAGE_NAME | VM に使用されるマシンイメージ名 |
OPENSTACK_SSH_KEY_NAME | 作成した VM に設定する ssh keypair |
OPENSTACK_FLATCAR_IMAGE_NAME | openstack 上に登録した flatcar image 名 |
使っている環境に合わせて設定。
export OPENSTACK_CONTROL_PLANE_MACHINE_FLAVOR=m1.medium
export OPENSTACK_NODE_MACHINE_FLAVOR=m1.medium
export OPENSTACK_DNS_NAMESERVERS=8.8.8.8
export OPENSTACK_FAILURE_DOMAIN=nova
export OPENSTACK_EXTERNAL_NETWORK_ID=bac31e0e-0804-46cf-a944-5daff4073501
export OPENSTACK_IMAGE_NAME=flatcar-3975.2.2-k8s-1.30.5-amd64
export OPENSTACK_SSH_KEY_NAME=kolla_ssh
export OPENSTACK_FLATCAR_IMAGE_NAME=flatcar-3975.2.2-k8s-1.30.5-amd64
これで準備が整ったのでマニフェストを作成。
clusterctl generate cluster test-op3 --kubernetes-version v1.30.5 --flavor flatcar > template.yml
適用
kubectl apply -f template.yml
これにより Cluster API のカスタムリソースがいろいろ作成されますが、裏では openstack 側にロードバランサーやネットワーク、 control plane 用の VM が作成されます。
kubeadmcontrolplanes リソースを見て replicas が 1 になれば ok.
$ k get kubeadmcontrolplanes.controlplane.cluster.x-k8s.io
NAME CLUSTER INITIALIZED API SERVER AVAILABLE REPLICAS READY UPDATED UNAVAILABLE AGE VERSION
test-op3-control-plane test-op3 true 1 1 1 108s v1.30.5
この時点で flatcar クラスタの control plane が作成されます。 cluster get kubeconfig [cluster_name]
で control plane に通信するための kubeconfig が取得できます。
clusterctl get kubeconfig test-op3 > test-op3.kubeconfig
kubeconfig を指定することで作成した control plane に対して kubectl を実行できます。
$ kubectl --kubeconfig ./test-op3.kubeconfig get node
NAME STATUS ROLES AGE VERSION
test-op3-control-plane-kpwb5 NotReady control-plane 93s v1.30.5
CNI をインストールしないと NotReady のままなので calico をインストール
kubectl --kubeconfig=./test-op3.kubeconfig \
apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml
インストールが完了すると status が Ready になり、flatcar ノードから構成される control plane が完成します。
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
test-op3-control-plane-kpwb5 Ready control-plane 7m7s v1.30.5 10.6.0.102 192.168.3.58 Flatcar Container Linux by Kinvolk 3975.2.2 (Oklo) 6.6.54-flatcar containerd://1.7.20
このクラスターで openstack 側にリソースを作成するには、openstack 用の cloud provider である openstack-cloud-controller-manager をインストールする必要があります。
上記を元に openstack 認証情報を設定した cloud.conf
を作成し、作成した control plane 側に secret を作成します。
kubectl --kubeconfig=./test-op3.kubeconfig -n kube-system create secret generic cloud-config --from-file=cloud.conf
cloud provider 本体をインストール
kubectl apply --kubeconfig=./test-op3.kubeconfig -f https://raw.githubusercontent.com/kubernetes/cloud-provider-openstack/master/manifests/controller-manager/cloud-controller-manager-roles.yaml
kubectl apply --kubeconfig=./test-op3.kubeconfig -f https://raw.githubusercontent.com/kubernetes/cloud-provider-openstack/master/manifests/controller-manager/cloud-controller-manager-role-bindings.yaml
kubectl apply --kubeconfig=./test-op3.kubeconfig -f https://raw.githubusercontent.com/kubernetes/cloud-provider-openstack/master/manifests/controller-manager/openstack-cloud-controller-manager-ds.yaml
インストールが正常に完了すれば openstack 側とも通信できるようになり、k8s クラスタ側のリソース作成に伴い openstack 側でも対応するリソースが作成されるようになります。
上記で作成したクラスタはまだ worker node がありませんが、cluster API の ノードの Scaling を実行することでノードを追加できます。
machinedeployment の replicas を 1 に設定することで worker node を 1 つ追加してみます。
$ kubectl scale machinedeployment test-op3-md-0 --replicas=1
machinedeployment.cluster.x-k8s.io/test-op3-md-0 scaled
少し待つと、Flatcar の worker node がクラスタに追加されていることが確認できます。
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
test-op3-control-plane-kpwb5 Ready control-plane 13m v1.30.5 10.6.0.102 192.168.3.58 Flatcar Container Linux by Kinvolk 3975.2.2 (Oklo) 6.6.54-flatcar containerd://1.7.20
test-op3-md-0-9xskz-kjqc2 Ready <none> 73s v1.30.5 10.6.0.230 <none> Flatcar Container Linux by Kinvolk 3975.2.2 (Oklo) 6.6.54-flatcar containerd://1.7.20
openstack 側でも上記のノードに対応する VM が自動的に作成されます。
$ openstack server list
+--------------------------------------+----------------------------------------------+---------+---------------------------------------------------------------------+-----------------------------------+-----------------------+
| ID | Name | Status | Networks | Image | Flavor |
+--------------------------------------+----------------------------------------------+---------+---------------------------------------------------------------------+-----------------------------------+-----------------------+
| 3ca31781-2fe1-492d-ba9c-2be5ed4d1cd2 | test-op3-md-0-9xskz-kjqc2 | ACTIVE | k8s-clusterapi-cluster-default-test-op3=10.6.0.230 | flatcar-3975.2.2-k8s-1.30.5-amd64 | m1.medium |
| fb7ceac2-c1bf-4464-a4bb-66e5451ed4ea | test-op3-control-plane-kpwb5 | ACTIVE | k8s-clusterapi-cluster-default-test-op3=10.6.0.102, 192.168.3.58 | flatcar-3975.2.2-k8s-1.30.5-amd64 | m1.medium |
ignition 構成で node を追加する方法と比較するとノード追加時の token 処理等が自動で行われるので、cluster API はより大規模な環境でのノード管理を容易に行えるメリットがあります。
sysext
systemd-sysext はシステム起動時に /usr 等に動的にファイルを追加する機能です。これ自体は一般的な systemd の機能として使われているようですが、flatcar でも起動時に追加のパッケージをインストールするための拡張機能として使用されます。
flatcar ではパッケージマネージャーがなく OS 起動後に構成を変更する余地がほとんどないため、以前では torcx と呼ばれる拡張機能でカスタマイズに対応してきました。sysext は torcx に代わる新しい拡張機能で、overlayfs を利用して追加のパッケージや独自パッケージを含むディレクトリをマージしてカスタマイズするようになっています。以下の blog にあるイメージ図がわかりやすいです。
ignition 構成で sysext イメージを利用するには、ダウンロードした sysext イメージ (通常は .raw の拡張子を持つ) を /opt/extensions/[package]/[image]
に配置します。
k8s クラスタにノードを追加する際に使った ignition 構成では、sysext-bakery リポジトリの kubernetes sysext
イメージをダウンロードして /opt/extensions/kubernetes/
に配置することで有効化しています(サービスとして起動するには systemd unit の設定も必要)。
storage:
links:
- target: /opt/extensions/kubernetes/kubernetes-v1.30.0-x86-64.raw
path: /etc/extensions/kubernetes.raw
hard: false
files:
- path: /etc/sysupdate.kubernetes.d/kubernetes-v1.30.conf
contents:
source: https://github.com/flatcar/sysext-bakery/releases/download/latest/kubernetes-v1.30.conf
- path: /etc/sysupdate.d/noop.conf
contents:
source: https://github.com/flatcar/sysext-bakery/releases/download/latest/noop.conf
- path: /opt/extensions/kubernetes/kubernetes-v1.30.0-x86-64.raw
contents:
source: https://github.com/flatcar/sysext-bakery/releases/download/latest/kubernetes-v1.30.0-x86-64.raw
コミュニティによってサポートされている sysext イメージは sysext-bakery で管理されており、現時点では以下のパッケージが sysext でインストールできるようになっています。
Extension | Availability |
---|---|
kubernetes |
released |
docker |
released (includes containerd) |
docker_compose |
released |
nvidia-runtime |
released |
wasmtime |
released |
wasmcloud |
released |
tailscale |
released |
crio |
released |
k3s |
released |
rke2 |
released |
keepalived |
build script |
ollama |
released |
sysext イメージの作り方
独自の sysext イメージを作成する方法はドキュメントには明示的に書いてなさそうですが、sysext-bakery では flatcar 管理でない wasmcloud や k3s の sysext イメージを作成するスクリプトがあるので、これらを参考にすることで他のパッケージにも応用できます。
例えば docker-compose をインストールするための sysext raw ファイルを作成する create_docker_compose_sysext.sh
の中身を見ると、docker compose のリポジトリからバイナリをダウンロードして bake.sh
で作成していることがわかります。
実際にリポジトリを clone してスクリプトを実行すると docker-compose.raw が作成できます。
$ ./create_docker_compose_sysext.sh 2.30.1 docker-compose
Parallel mksquashfs: Using 16 processors
Creating 4.0 filesystem on docker-compose.raw, block size 131072.
[=============================================================================================================================================================================================================================/] 490/490 100%
Exportable Squashfs 4.0 filesystem, gzip compressed, data block size 131072
compressed data, compressed metadata, compressed fragments,
compressed xattrs, compressed ids
duplicates are removed
Filesystem size 18498.03 Kbytes (18.06 Mbytes)
29.58% of uncompressed filesystem size (62541.87 Kbytes)
Inode table size 1503 bytes (1.47 Kbytes)
65.98% of uncompressed inode table size (2278 bytes)
Directory table size 150 bytes (0.15 Kbytes)
56.39% of uncompressed directory table size (266 bytes)
Number of duplicate files found 0
Number of inodes 10
Number of files 2
Number of fragments 1
Number of symbolic links 0
Number of device nodes 0
Number of fifo nodes 0
Number of socket nodes 0
Number of directories 8
Number of hard-links 0
Number of ids (unique uids + gids) 1
Number of uids 1
root (0)
Number of gids 1
root (0)
Created docker-compose.raw
sysextname
ディレクトリをスクリプト内でクリーンアップされないように変更すると、イメージの元となるディレクトリ構造は以下のようになっていることが確認できます。この内 /usr/lib
以下は bake.sh の実行時に自動で作成されます。
docker-compose
└── usr
├── lib
│ └── extension-release.d
│ └── extension-release.docker-compose
└── local
└── lib
└── docker
└── cli-plugins
└── docker-compose
sysext は overlayfs でディレクトリをマージするので、独自のパッケージを sysext イメージにしたい場合はマージ先のディレクトリ構造を作って実行ファイルを配置すれば良いことがわかります。
このやり方で独自パッケージが適用できるか確認するため、ここでは例としてモダンな top コマンドの代替品である bottom をインストールするための sysext イメージを作ってみます。bottom のバイナリを /usr/local/bin
に配置したいので、実行ファイル btm
を github からダウンロードして以下のディレクトリ構造に配置します。sysext-bakery リポジトリにある back.sh
も同ディレクトリに配置。
$ tree
.
├── bake.sh
└── bottom
└── usr
└── local
└── bin
└── btm
bake.sh
にディレクトリ名を渡して実行。
$ ./bake.sh bottom
Parallel mksquashfs: Using 16 processors
Creating 4.0 filesystem on bottom.raw, block size 131072.
[=================================================================================================================================================================================================================================|] 1/1 100%
Exportable Squashfs 4.0 filesystem, gzip compressed, data block size 131072
compressed data, compressed metadata, compressed fragments,
compressed xattrs, compressed ids
duplicates are removed
Filesystem size 0.31 Kbytes (0.00 Mbytes)
66.53% of uncompressed filesystem size (0.47 Kbytes)
Inode table size 65 bytes (0.06 Kbytes)
40.12% of uncompressed inode table size (162 bytes)
Directory table size 81 bytes (0.08 Kbytes)
61.83% of uncompressed directory table size (131 bytes)
Number of duplicate files found 0
Number of inodes 5
Number of files 1
Number of fragments 1
Number of symbolic links 0
Number of device nodes 0
Number of fifo nodes 0
Number of socket nodes 0
Number of directories 4
Number of hard-links 0
Number of ids (unique uids + gids) 1
Number of uids 1
root (0)
Number of gids 1
root (0)
Created bottom.raw
これで bottom をインストールするための sysext イメージ bottom.raw
ができました。
flatcar 起動時には source で指定した URL から sysext イメージをダウンロードする動作となっているため、作成したイメージを Github Release などダウンロード可能な場所に配置する必要があります。ここでは簡単のため raw イメージのあるディレクトリで python http server を使って対応します。
python -m http.server 9999
curl 等で上記サーバーの ip にアクセスしてファイルがダウンロードできれば ok.
ignition 構成ファイルでは raw イメージを取得して /opt 以下に配置する処理と /etc 以下にシンボリックリンクを作成する処理を記述します。
# butane < config.yaml > config.json
# ./flatcar_production_qemu.sh -i ./config.json
variant: flatcar
version: 1.0.0
storage:
files:
- path: /opt/extensions/bottom/bottom.raw
contents:
source: http://192.168.3.30:9999/bottom.raw # 上記 python server が起動している ip, port と botom.raw のパスを指定
links:
- target: /opt/extensions/bottom/bottom.raw
path: /etc/extensions/bottom.raw
hard: false
変換して VM を作成。
cat custom-sysext.yml | docker run --rm -i quay.io/coreos/butane:release > ignition.json
openstack server create \
--user-data ./ignition.json \
--image flatcar-3975.2.2-amd64 \
--key-name kolla_ssh \
--flavor m1.small \
--network demo-net \
flatcar-test-custom
SSH でログインすると実際に /usr/local/bin
に btm のバイナリが配置されて実行できるようになっています。
$ ssh -i ./kolla_ssh core@10.0.0.71
Last login: Sat Nov 2 18:35:31 UTC 2024 from 10.0.0.30 on pts/0
Flatcar Container Linux by Kinvolk stable 3975.2.2 for Openstack
core@flatcar-test-custom ~ $ which btm
/usr/local/bin/btm
core@flatcar-test-custom ~ $ btm -h
bottom 0.10.2
Clement Tsang <cjhtsang@uwaterloo.ca>
A customizable cross-platform graphical process/system monitor for the terminal. Supports Linux, macOS, and Windows.
Usage: btm [OPTIONS]
...
btm を実行している様子
やや手間はかかりますが、独自のパッケージやコマンドを flatcar にインストールしたい場合は上記のように独自のカスタム sysext イメージを作成することで対応できます。
Nebraska で OS 自動アップデートを管理する
Flatcar の特徴の 1 つ Automated Update では、常に安定したセキュアなアップデート方法で最新のバージョンを適用できるとあります。パッケージマネージャがないのにどのようにアップデートを適用するかというと、1 つは Flatcar のバージョン毎にマシンイメージを作成し、新しいバージョンがリリースされたら都度 VM を作成し直すという方法があります。これは原始的な方法ではありますが、マシンイメージ側と実際の OS 側で差分が発生しないので terraform のような IaC と相性の良いアプローチとなっています。
もう一つは flatcar 内にインストール済みのコマンドを利用して Flactar 側のリリース済みバージョンを取得し、新しいバージョンが利用可能になったら更新を適用する方法です。こちらは nebraska と組み合わせることで更新作業を自動化・管理できるのでより大規模な環境に適しています。
nebraska は Flatcar のバージョン更新やロールアウトを管理する update manager となっています。nebraska は公式の Flactar からリリースチャンネル毎の最新バージョンなどを自動で取得できます。一方で各 Flatcar VMは nebraska に接続し、新しいバージョンが利用可能になった際に自動で更新を適用したり、グループ毎に一括で更新を適用するといったことができます。
イメージ図
nebraska は helm でインストールできるので既存の k8s クラスタに入れてみます。
helm repo add nebraska https://flatcar.github.io/nebraska
helm show values nebraska/nebraska > values.yml
helm install -n nebraska nebraska nebraska/nebraska --values values.yml --create-namespace
これにより nebraska 本体とデータ管理用の postgresql が起動します。
NAME READY STATUS RESTARTS AGE
pod/nebraska-776b7654bf-l74cr 1/1 Running 3 (18h ago) 18h
pod/nebraska-postgresql-0 1/1 Running 0 18h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/nebraska ClusterIP 10.96.25.36 <none> 80/TCP 18h
service/nebraska-postgresql ClusterIP 10.101.4.13 <none> 5432/TCP 18h
service/nebraska-postgresql-hl ClusterIP None <none> 5432/TCP 18h
nebraska の svc にブラウザでアクセスすると、リリースチャンネル毎のバージョン情報や nebraska がバージョンを管理している Flactar インスタンスの個数、詳細などが確認できます。
nebraska の webUI
実際に nebraska を使って flatcar のバージョンを上げてみます。
例えば今まで使ってきた stable channel の flatcar ではバージョン 3975.2.2 なので os-release
の中身が以下のようになっています。
core@flatcar-test ~ $ cat /etc/os-release
NAME="Flatcar Container Linux by Kinvolk"
ID=flatcar
ID_LIKE=coreos
VERSION=3975.2.2
VERSION_ID=3975.2.2
BUILD_ID=2024-10-08-1845
SYSEXT_LEVEL=1.0
PRETTY_NAME="Flatcar Container Linux by Kinvolk 3975.2.2 (Oklo)"
ANSI_COLOR="38;5;75"
HOME_URL="https://flatcar.org/"
BUG_REPORT_URL="https://issues.flatcar.org"
FLATCAR_BOARD="amd64-usr"
CPE_NAME="cpe:2.3:o:flatcar-linux:flatcar_linux:3975.2.2:*:*:*:*:*:*:*"
nebraska ではリリースチャンネルを切り替えることも可能なので、alpha チャンネルの最新バージョンを適用してみます。flactar VM を nebraska に接続するには、ignition 構成ファイルで /etc/flatcar/update.conf
に接続先 nebraska の情報を記載します。
- SERVER:
[nebraska の ip アドレス]:[port]/v1/update
を指定 - GROUP: この Flatcar VM が所属するグループを指定。4 つのリリースチャンネルの他、独自のグループを指定することも可能。
variant: flatcar
version: 1.0.0
storage:
files:
- path: /etc/flatcar/update.conf
overwrite: true
mode: 0644
contents:
inline: |
GROUP=alpha
SERVER=http://nebraska.ops.com:32323/v1/update/
- path: /etc/hosts
overwrite: false
mode: 0644
append:
- inline: |
10.0.0.31 nebraska.ops.com
上記の ignition ファイルを使って Flactar VM を作成。起動直後ではまだ更新は実行されず 3975.2.2
のままです。
$ ssh -i ./kolla_ssh core@10.0.0.92
Last login: Sat Nov 2 14:18:58 UTC 2024 on tty1
Flatcar Container Linux by Kinvolk alpha 3975.2.2 for Openstack
core@flatcar-test-alpha ~ $ cat /etc/os-release
NAME="Flatcar Container Linux by Kinvolk"
ID=flatcar
ID_LIKE=coreos
VERSION=3975.2.2
VERSION_ID=3975.2.2
BUILD_ID=2024-10-08-1845
SYSEXT_LEVEL=1.0
PRETTY_NAME="Flatcar Container Linux by Kinvolk 3975.2.2 (Oklo)"
ANSI_COLOR="38;5;75"
HOME_URL="https://flatcar.org/"
BUG_REPORT_URL="https://issues.flatcar.org"
FLATCAR_BOARD="amd64-usr"
CPE_NAME="cpe:2.3:o:flatcar-linux:flatcar_linux:3975.2.2:*:*:*:*:*:*:*"
nebraska からのバージョン取得は定期的に実行されるようですが、update_engine_client -update
を実行することで任意のタイミングでサーバーと接続できます。
以下では alpha チャンネルの最新バージョン 4116.0.0
が取得されていることが確認できます。
取得が完了したタイミングで 5 分後に reboot がスケジュールされ、reboot 後に取得したバージョンに更新されます。
core@flatcar-test-alpha ~ $ update_engine_client -update
I1102 14:22:11.959977 1551 update_engine_client.cc:251] Initiating update check and install.
I1102 14:22:12.016368 1551 update_engine_client.cc:256] Waiting for update to complete.
LAST_CHECKED_TIME=1730557285
PROGRESS=0.270325
CURRENT_OP=UPDATE_STATUS_DOWNLOADING
NEW_VERSION=4116.0.0
NEW_SIZE=505686594
LAST_CHECKED_TIME=1730557285
PROGRESS=0.320383
...
CURRENT_OP=UPDATE_STATUS_DOWNLOADING
NEW_VERSION=4116.0.0
NEW_SIZE=505686594
LAST_CHECKED_TIME=1730557285
PROGRESS=0.000000
CURRENT_OP=UPDATE_STATUS_FINALIZING
NEW_VERSION=4116.0.0
NEW_SIZE=505686594
Broadcast message from locksmithd at 2024-11-02 14:23:39.762143696 +0000 UTC m=
System reboot in 5 minutes!
LAST_CHECKED_TIME=1730557285
PROGRESS=0.000000
CURRENT_OP=UPDATE_STATUS_UPDATED_NEED_REBOOT
NEW_VERSION=4116.0.0
NEW_SIZE=505686594
I1102 14:23:42.049386 1551 update_engine_client.cc:198] Update succeeded -- reboot needed.
再起動後に確認するとバージョンが 4116.0.0
に更新されています。
core@flatcar-test-alpha ~ $ cat /etc/os-release
NAME="Flatcar Container Linux by Kinvolk"
ID=flatcar
ID_LIKE=coreos
VERSION=4116.0.0
VERSION_ID=4116.0.0
BUILD_ID=2024-10-09-0001
SYSEXT_LEVEL=1.0
PRETTY_NAME="Flatcar Container Linux by Kinvolk 4116.0.0 (Oklo)"
ANSI_COLOR="38;5;75"
HOME_URL="https://flatcar.org/"
BUG_REPORT_URL="https://issues.flatcar.org"
FLATCAR_BOARD="amd64-usr"
CPE_NAME="cpe:2.3:o:flatcar-linux:flatcar_linux:4116.0.0:*:*:*:*:*:*:*"
nebraska 側でもバージョンアップデートを実行した Flatcar の情報が確認できます。
Instances 1 となっているので上記の Flatcar VM が更新された
このように nebraska では管理下の Flatcar VM のバージョン更新作業を自動で行うことができます。Flatcar では Automated Updates として常に最新のセキュリティパッチが適用されたバージョンの使用を推奨しているため、nebraska を使うことでこの作業を自動で管理できます。
一方でマシンイメージの情報等も合わせて更新されるわけではないので、例えばイメージ名や terraform 等の構成側で宣言的に flatcar のバージョン等を管理している場合、そのバージョンと OS 内の実際のバージョンが異なるドリフトが発生します。その場合は宣言的に記述する際はバージョン情報を含まないようにする、nebraska ではなく terraform 等を使って常にバージョン更新を行うなどの工夫が必要になります。
その他
Debug
Flatcar 内で何らかの追加コマンドをインストールしてデバッグを行いたい場合にはデフォルトでインストール済みの toolbox が利用できます。
toolbox を実行すると Fedora の docker コンテナが起動します。このコンテナ内では dnf が使えるので dnf でダウンロード可能なパッケージを追加でインストールできます。toolbox 内の環境は /usr read-only の制限を受けないのでデバッグ作業に使えます。
おわりに
最近 CNCF incubating project に採択された Flatcar Container Linux を試しました。コンテナワークロード向けに最適化された OS だけあって必要最小限のパッケージのみが含まれる、ファイルシステムが readonly になっているなど、よりセキュアな環境でコンテナを実行できます。便利な CLI やユーティリティを追加するのが結構大変なので検証しながら使うのは不向きですが、一方で ubuntu 等の汎用的な OS と比較すると以下のようなメリットがあります。
- インストール済みパッケージが少ないため軽量かつ依存パッケージの脆弱性対応が最小限で済む。
- 基本的に OS 内で構成の変更ができないので、宣言的に記述した内容との差分(ドリフト)が発生しにくい。IaC のコンセプトに従う。
- 軽量なので OS アップグレードも容易。nebraska など組み合わせると自動アップデートも可能。
上記の特徴から、本番環境でのコンテナワークロード運用に適した OS という立ち位置になっています。
Discussion