時間があったので、前々から気になっていたPodmanをさわってみることにしました。
こちらに自分用のメモを残します。
Podmanの話をする前にコンテナがどういう動きをしているかを把握するため、コンテナランタイムについて調べていきます。
コンテナランタイム
わかりやすかったのは、こちらの方とこちらの方の記事です。
コンテナランタイムは、コンテナがホストOS上で動くためのあらゆる機能を提供するソフトウェアを指します。
コンテナランタイムには大きく分けて、高レベルランタイムと低レベルランタイムの2つがあり、
高レベルランタイムは、DockerやKubernetesからの命令を受け取り、低レベルランタイムに渡します。
低レベルランタイムは、高レベルランタイムからの命令を受け取り、コンテナの実行・停止などを行います。
コンテナといえばDockerですが、Dockerでは高レベルランタイムはcontainerd、低レベルランタイムはrunCで、ユーザからの入力をdockerdで受けてcontainerd→runcという流れで動いているようです。
(詳細は記事参照)
また、本筋と若干ずれますが、このDockerのコンテナランタイムには問題があり、Dockerの低レベルコンテナランタイムのrunCは、ホストのカーネル上で直接するアプリケーションを実行する仕組みのため、高速で動く代わりに、脆弱性があると危険という問題があります。
そのため、AWSのFirecrackerでは仮装OSをかませたり、GoogleのgVisorではゲストカーネルをかませたりして、直接ホストのカーネル上で実行しないようにしているようです。
なお、このrunCでの脆弱性の対策として、現在は非rootユーザでプロセスが実行されるようになったようです。
Podmanとは
やっとPodmanの話ですが、こちらの方の記事が非常にわかりやすかったです。
Podmanは、Dockerのdockeredやcontainerdのようなデーモンプロセスは無く、コンテナ度に独立したプロセスを立てるようで、あるコンテナでメモリリークなどの問題が起きても、他コンテナに影響が出にくいようになっています。
dockerコマンドをaliasでpodmanコマンドに変えて使うみたいなことも書いてある通り、立ち位置としては、Dockerと同じなのかなと思います。
使ってみる
まずはインストールから。Podman公式のinstallを参考に行います。
インストールとコンテナ起動
私の環境はMacなので、brewでインストールします。
$ brew install podman
Podmanをインストールしたのち、下記でPodmanを動かすための環境を作ります。
(PodmanはRedhat社が作っており、Macで動かすためにfedoraのVMを作っていました。docker machineコマンドとまんまいっしょですね。Linuxではこの操作はなさそうです。)
podman machine init
の時にオプションでCPUのコア数も指定できるようです。
$ podman machine init
$ podman machine start
上記のコマンドののち、下記のコマンドでインストールできたことを確認します。
$ podman info
host:
arch: amd64
buildahVersion: 1.23.1
cgroupControllers:
- memory
- pids
cgroupManager: systemd
cgroupVersion: v2
conmon:
package: conmon-2.0.30-2.fc35.x86_64
path: /usr/bin/conmon
version: 'conmon version 2.0.30, commit: '
cpus: 1
distribution:
distribution: fedora
variant: coreos
version: "35"
eventLogger: journald
hostname: localhost.localdomain
idMappings:
gidmap:
- container_id: 0
host_id: 1000
size: 1
- container_id: 1
host_id: 100000
size: 65536
uidmap:
- container_id: 0
host_id: 1000
size: 1
- container_id: 1
host_id: 100000
size: 65536
kernel: 5.15.7-200.fc35.x86_64
linkmode: dynamic
logDriver: journald
memFree: 1340944384
memTotal: 2061385728
ociRuntime:
name: crun
package: crun-1.3-1.fc35.x86_64
path: /usr/bin/crun
version: |-
crun version 1.3
commit: 8e5757a4e68590326dafe8a8b1b4a584b10a1370
spec: 1.0.0
+SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +CRIU +YAJL
os: linux
remoteSocket:
exists: true
path: /run/user/1000/podman/podman.sock
security:
apparmorEnabled: false
capabilities: CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID,CAP_SYS_CHROOT
rootless: true
seccompEnabled: true
seccompProfilePath: /usr/share/containers/seccomp.json
selinuxEnabled: true
serviceIsRemote: true
slirp4netns:
executable: /usr/bin/slirp4netns
package: slirp4netns-1.1.12-2.fc35.x86_64
version: |-
slirp4netns version 1.1.12
commit: 7a104a101aa3278a2152351a082a6df71f57c9a3
libslirp: 4.6.1
SLIRP_CONFIG_VERSION_MAX: 3
libseccomp: 2.5.3
swapFree: 0
swapTotal: 0
uptime: 9m 44.86s
plugins:
log:
- k8s-file
- none
- journald
network:
- bridge
- macvlan
volume:
- local
registries:
search:
- docker.io
store:
configFile: /var/home/core/.config/containers/storage.conf
containerStore:
number: 0
paused: 0
running: 0
stopped: 0
graphDriverName: overlay
graphOptions: {}
graphRoot: /var/home/core/.local/share/containers/storage
graphStatus:
Backing Filesystem: xfs
Native Overlay Diff: "true"
Supports d_type: "true"
Using metacopy: "false"
imageStore:
number: 0
runRoot: /run/user/1000/containers
volumePath: /var/home/core/.local/share/containers/storage/volumes
version:
APIVersion: 3.4.2
Built: 1636748737
BuiltTime: Fri Nov 12 20:25:37 2021
GitCommit: ""
GoVersion: go1.16.8
OsArch: linux/amd64
Version: 3.4.2
出力を見ると、fedora上で動いているっぽいです。
確認のため、さきほど作ったVMの稼働を見ます。コマンドはpodman machine --help
で確認できます。
$ podman machine list
NAME VM TYPE CREATED LAST UP CPUS MEMORY DISK SIZE
podman-machine-default* qemu 18 minutes ago Currently running 1 2.147GB 10.74GB
※VM TYPEのqemuは、仮想化ソフトウェアで、同じレイヤーの他のものではVirtualBoxなどがあります。
Podmanを使うためのVMは起動できていることが確認できたので次にコンテナを立てます。
# githubからalpine_nginxのDockerfileを取得
$ git clone http://github.com/baude/alpine_nginx && cd alpine_nginx
# ビルド
$ podman build -t alpine_nginx .
# コンテナを立ち上げる
$ podman run -dt -p 9999:80 alpine_nginx
# コンテナの稼働を確認
$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
931f3f56c318 localhost/alpine_nginx:latest nginx -g daemon o... 27 seconds ago Up 27 seconds ago 0.0.0.0:9999->80/tcp objective_murdock
# httpサーバにアクセス
$ curl http://localhost:9999
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
コンテナの起動が確認できました。
また、せっかくなので、conmonプロセス(コンテナごとの)が立ち上がっていることを確認します。
コンテナが動いているのはVM上なので、VMに入ってからプロセスを見ます。
# sshで接続
$ podman machine ssh podman-machine-default
$ ps aux | grep conmon
core 6933 0.0 0.1 82076 2440 ? Ssl 15:00 0:00 /usr/bin/conmon --api-version 1 -c 931f3f56c318ed41001fa92ebccb93aec82934f2308ce2face3ef9ce5878e876 -u 931f3f56c318ed41001fa92ebccb93aec82934f2308ce2face3ef9ce5878e876 -r /usr/bin/crun -b /var/home/core/.local/share/containers/storage/overlay-containers/931f3f56c318ed41001fa92ebccb93aec82934f2308ce2face3ef9ce5878e876/userdata -p /run/user/1000/containers/overlay-containers/931f3f56c318ed41001fa92ebccb93aec82934f2308ce2face3ef9ce5878e876/userdata/pidfile -n objective_murdock --exit-dir /run/user/1000/libpod/tmp/exits --full-attach -s -l journald --log-level info --runtime-arg --log-format=json --runtime-arg --log --runtime-arg=/run/user/1000/containers/overlay-containers/931f3f56c318ed41001fa92ebccb93aec82934f2308ce2face3ef9ce5878e876/userdata/oci-log -t --conmon-pidfile /run/user/1000/containers/overlay-containers/931f3f56c318ed41001fa92ebccb93aec82934f2308ce2face3ef9ce5878e876/userdata/conmon.pid --exit-command /usr/bin/podman --exit-command-arg --root --exit-command-arg /var/home/core/.local/share/containers/storage --exit-command-arg --runroot --exit-command-arg /run/user/1000/containers --exit-command-arg --log-level --exit-command-arg info --exit-command-arg --cgroup-manager --exit-command-arg systemd --exit-command-arg --tmpdir --exit-command-arg /run/user/1000/libpod/tmp --exit-command-arg --runtime --exit-command-arg crun --exit-command-arg --storage-driver --exit-command-arg overlay --exit-command-arg --events-backend --exit-command-arg journald --exit-command-arg container --exit-command-arg cleanup --exit-command-arg 931f3f56c318ed41001fa92ebccb93aec82934f2308ce2face3ef9ce5878e876
/usr/bin/conmonというコマンドが実行されていることが確認できました。
このconmonプロセスは、OCI container runtime monitorとあり、コンテナの管理をしているようです。
Podmanのコマンド一覧はこちらで見ることができ、dockerコマンドと同じような感じですね。
所感
Dockerとほぼ同じ使い勝手のようです。
参考にした記事を見ましたところ、Podmanの利点はデーモン無しというところより、どちらかというと改修のサイクルが早いというところらしいです。
本筋とずれますが、コンテナランタイムについて少し知れたのはよかったです。
参考
コンテナランタイムの仕組みと、Firecracker、gVisor、Unikernelが注目されている理由。 Container Runtime Meetup #2
DockerとPodmanの比較 [Container Runtime Meetup #3]
コンテナでプログラムをrootとして実行することがなぜ問題なのか KubernetsのCVE-2019-11245を例に考える