はじめに
Docker有償化で小規模コンテナ環境の代用をPodmanで運用できないか?という相談を受けたついでに色々さわったのでまとめました。
RHEL8以降、Dockerが非推奨になっており代わりにPodmanを使ってね!という話だったのですが、運用できないかといわれるとちょっと自信がなかったわけです。特にdocker-composeしたものってどうやったらPodmanで動くんだっけ?と今更ながら。。。
PodmanがM1に対応したのかなども踏まえて実際にdocker-composeから'play kube'でPod実行までを自分の環境でやってみました。
目次
準備
最初に必要なものを集めます。まず適当なdocker-compose用のymlを探します。最初に参考にした赤帽ブログのwordpress用のファイルをこちらから拝借しました。
version: '3.1'
services:
wordpress:
image: wordpress
restart: always
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- wordpress:/var/www/html
db:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- db:/var/lib/mysql
volumes:
wordpress:
db:
続いてPodmanのインストール。3.xのころはM1ではpodman machineが動かなかったり、設定追加が必要だったそうですが4.xからMac/Win(WSL)の対応強化されているそうです。実際得に引っかかることはなくインストール完了。
% brew install podman
% podman -v
podman version 4.1.1
次にmacOSで動かすためのLinux環境をPodman machineで準備します。
% podman machine init
つつがなく完了。fedoraは36になるようです。
% ls -lh ~/.local/share/containers/podman/machine/qemu
total 8197592
-rw-r--r-- 1 toomori staff 604M 8 4 14:35 fedora-coreos-36.20220723.2.2-qemu.aarch64.qcow2.xz
-rw------- 1 toomori staff 3.2G 8 9 23:31 podman-machine-default_fedora-coreos-36.20220723.2.2-qemu.aarch64.qcow2
-rw-r--r-- 1 toomori staff 64M 8 4 14:58 podman-machine-default_ovmf_vars.fd
最後にPodman machineを起動して準備完了です。
% podman machine start
・・・
Machine "podman-machine-default" started successfully
これでPodmanが動かせる様になりました。
(※podmanコマンドが通らない場合はzshにexportでPATHを追加するのがいいですが今回は略)
podman-composeの実行
さて準備できたけど、まずはどうしようというところで、こちら参考にさせていただきました。なるほどPodman3.xからdocker-composeも動かせるのね。。けど今回やりたいのはdocker-composeからの脱却でPodmanでdocker-compose用定義をコントロールしたいのです。というわけでpodman-composeに辿り着きます。
早速これもいれちゃいましょ。
今度はpipです。サードパーティ製なのは気になるがまぁよしとしよう。
pip3 install podman-compose
ここは問題なくインストール。先人達に感謝しつつ実行。
podman-compose -f docker-compose.yml up -d
docker-compose.ymlに記載されてるサービス毎にpodman run
にコンバートされて実行されている的なログがでます。
...
Trying to pull docker.io/library/mysql:5.7...
Error: choosing an image from manifest list docker://mysql:5.7: no image found in manifest list for architecture arm64, variant "v8", OS linux
exit code: 125
podman start wordpress_db_1
Error: no container with name or ID "wordpress_db_1" found: no such container
exit code: 125
なんか出た。MySQLのほうがARMに対応していないらしい。M1っぽい問題でしたが、v8とヒントをもらってるのでおきかえます。仕方がないけどM1になってこういうところはまだ不便をかんじます。マルチアーキテクチャ対応も快適にならないかな。
db:
image: arm64v8/mysql
書き換えて再実行。今度はうまく行った様なのでcontainerを確認します。
% podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c431db05b0cb docker.io/library/wordpress:latest apache2-foregroun... 3 days ago Up 3 days ago 0.0.0.0:8080->80/tcp wordpress_wordpress_1
f24872732c1f docker.io/arm64v8/mysql:latest mysqld 3 days ago Up 3 days ago wordpress_db_1
% podman pod ps
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
コンテナが2つ立ち上がりました。
ついでにPod化されていればいいのですが、Podとしては動かせない模様。
まずはpodman-composeがちゃんと動くのかを調べるためにブラウザでhttp://localhost:8080
へアクセス。
ちゃんとDBまで疎通とれていい感じです。元のファイルをほぼ変えないままでよかった。
podmanとpodman-composeでほぼdocker-composeと同じ事ができました。
Pod化と実行
Podmanを使うメリットの1つとしてkubernetesへの対応があり、kubernetes用のyamlファイルが生成できます。いずれkubernetesへの移行も想定したいのでこの機能を利用してyaml生成しておこうというのが今回のゴールです。
Podmanで実行しているPod(orコンテナ)を対象として生成する機能になるので、先のpodman-composeで実行した際に2つのコンテナが同一のPodに入っていれば通信関係も問題なくPod化できるはず!と踏んでいました。実際は別々のコンテナとして動いています(どうやってDB見つけてるんだろ。。)
ここで対応できそうな方法をいくつか考えました。
- 事前にPodを作成し、podman-composeでpodを指定する
- それぞれ別Podとして生成し、Podman networkを使って接続させる
- それぞれ別Podとして生成し、yamlを手でマージさせる
結論からいくと3番目の方法が一番簡単でした。
案1
--podman-run-argsに--podでpod指定してみる。
% podman pod create --name wp-pod
56977b21b4ce8062bbbc3eac4c013feb39d98bb10d4ed9f61fc50a93d44a9ee0
% podman pod ps
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
56977b21b4ce wp-pod Created 3 days ago 7b8bf8e908ee 1
% podman-compose -f docker-compose.yml up -d --podman-run-args="--pod='wp-pod'"
...
podman-compose: error: unrecognized arguments: --podman-run-args=--pod='wp-pod'
オプションが死んでいるのかうまくいかず。(上手くいけた方いたら教えてください)
案2
こちらが参考になりました。
dnsを設定するためにプラグインを入れて、podを指名してあげる事でPodmanでもPod間通信ができるようになるそうです。ただ、これは少し手順が多く、ここまでやるならkubernetes上に持って行った方がいい印象です。
もともとの挙動に近しくするためにあくまでもPodで動かしたいので今回はパスしました。
案3
案3はまずwordpressとmysqlのPodを作成し、手マージしてしまいます。
まずはコンテナをそれぞれPod用yamlに生成します
% podman generate kube wordpress_wordpress_1 > kubernetes-wp.yml
# Save the output of this file and use kubectl create -f to import
# it into Kubernetes.
#
# Created with podman-4.1.1
# NOTE: If you generated this yaml from an unprivileged and rootless podman container on an SELinux
# enabled system, check the podman generate kube man page for steps to follow to ensure that your pod/container
# has the right permissions to access the volumes added.
---
apiVersion: v1
kind: Pod
metadata:
annotations:
io.kubernetes.cri-o.TTY/wordpresswordpress1: "false"
io.podman.annotations.autoremove/wordpresswordpress1: "FALSE"
io.podman.annotations.init/wordpresswordpress1: "FALSE"
io.podman.annotations.privileged/wordpresswordpress1: "FALSE"
io.podman.annotations.publish-all/wordpresswordpress1: "FALSE"
creationTimestamp: "2022-08-05T13:46:41Z"
labels:
app: wordpresswordpress1-pod
name: wordpresswordpress1-pod
spec:
containers:
- args:
- apache2-foreground
env:
- name: WORDPRESS_DB_USER
value: exampleuser
- name: WORDPRESS_DB_PASSWORD
value: examplepass
- name: WORDPRESS_DB_NAME
value: exampledb
- name: WORDPRESS_DB_HOST
value: wordpressdb1-pod
image: docker.io/library/wordpress:latest
name: wordpresswordpress1
ports:
- containerPort: 80
hostPort: 8081
securityContext:
capabilities:
drop:
- CAP_MKNOD
- CAP_NET_RAW
- CAP_AUDIT_WRITE
volumeMounts:
- mountPath: /var/www/html
name: wordpress_wordpress-pvc
volumes:
- name: wordpress_wordpress-pvc
persistentVolumeClaim:
claimName: wordpress_wordpress
% podman generate kube wordpress_db_1 > kubernetes-mysql.yml
# Created with podman-4.1.1
# NOTE: If you generated this yaml from an unprivileged and rootless podman container on an SELinux
# enabled system, check the podman generate kube man page for steps to follow to ensure that your pod/container
# has the right permissions to access the volumes added.
---
apiVersion: v1
kind: Pod
metadata:
annotations:
io.kubernetes.cri-o.TTY/wordpressdb1: "false"
io.podman.annotations.autoremove/wordpressdb1: "FALSE"
io.podman.annotations.init/wordpressdb1: "FALSE"
io.podman.annotations.privileged/wordpressdb1: "FALSE"
io.podman.annotations.publish-all/wordpressdb1: "FALSE"
creationTimestamp: "2022-08-05T09:32:54Z"
labels:
app: wordpressdb1-pod
name: wordpressdb1-pod
spec:
containers:
- args:
- mysqld
env:
- name: MYSQL_PASSWORD
value: examplepass
- name: MYSQL_RANDOM_ROOT_PASSWORD
value: "1"
- name: MYSQL_USER
value: exampleuser
- name: MYSQL_DATABASE
value: exampledb
image: docker.io/arm64v8/mysql:latest
name: wordpressdb1
securityContext:
capabilities:
drop:
- CAP_MKNOD
- CAP_NET_RAW
- CAP_AUDIT_WRITE
volumeMounts:
- mountPath: /var/lib/mysql
name: wordpress_db-pvc
volumes:
- name: wordpress_db-pvc
persistentVolumeClaim:
claimName: wordpress_db
それぞれのyamlをpodman play kube
して単体で動くのを確認します。
問題なく動作したら以下のように合体させます。
# Save the output of this file and use kubectl create -f to import
# it into Kubernetes.
#
# Created with podman-4.1.1
# NOTE: If you generated this yaml from an unprivileged and rootless podman container on an SELinux
# enabled system, check the podman generate kube man page for steps to follow to ensure that your pod/container
# has the right permissions to access the volumes added.
---
apiVersion: v1
kind: Pod
metadata:
annotations:
io.kubernetes.cri-o.TTY/wordpresswordpress1: "false"
io.podman.annotations.autoremove/wordpresswordpress1: "FALSE"
io.podman.annotations.init/wordpresswordpress1: "FALSE"
io.podman.annotations.privileged/wordpresswordpress1: "FALSE"
io.podman.annotations.publish-all/wordpresswordpress1: "FALSE"
creationTimestamp: "2022-08-05T13:46:41Z"
labels:
app: wordpresswordpress1-pod
name: wordpresswordpress1-pod
spec:
containers:
- args:
- apache2-foreground
env:
- name: WORDPRESS_DB_USER
value: exampleuser
- name: WORDPRESS_DB_PASSWORD
value: examplepass
- name: WORDPRESS_DB_NAME
value: exampledb
- name: WORDPRESS_DB_HOST
value: 127.0.0.1
image: docker.io/library/wordpress:latest
name: wordpresswordpress1
ports:
- containerPort: 80
hostPort: 8081
securityContext:
capabilities:
drop:
- CAP_MKNOD
- CAP_NET_RAW
- CAP_AUDIT_WRITE
volumeMounts:
- mountPath: /var/www/html
name: wordpress_wordpress-pvc
- args:
- mysqld
env:
- name: MYSQL_PASSWORD
value: examplepass
- name: MYSQL_RANDOM_ROOT_PASSWORD
value: "1"
- name: MYSQL_USER
value: exampleuser
- name: MYSQL_DATABASE
- value: exampledb
image: docker.io/arm64v8/mysql:latest
name: wordpressdb1
securityContext:
capabilities:
drop:
- CAP_MKNOD
- CAP_NET_RAW
- CAP_AUDIT_WRITE
volumeMounts:
- mountPath: /var/lib/mysql
name: wordpress_db-pvc
volumes:
- name: wordpress_wordpress-pvc
persistentVolumeClaim:
claimName: wordpress_wordpress
- name: wordpress_db-pvc
persistentVolumeClaim:
claimName: wordpress_db
変えたのはWORDPRESS_DB_HOST
の値のみ。127.0.0.1
で指す様に編集。
(※便宜上8080を8081に変えています。)
あとは行の並べ替えのみです。
- name: WORDPRESS_DB_HOST
value: 127.0.0.1
Pod化が完了しているのでpodman play kube
で実行します。
% podman play kube kubernetes-hybrid.yml
動作確認
% podman pod ps
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
f6ee088f1f1f wordpresswordpress1-pod Running 3 days ago 6ff1c5d2686a 3
% podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6ff1c5d2686a localhost/podman-pause:4.1.1-1655914710 3 days ago Up 3 days ago 0.0.0.0:8081->80/tcp f6ee088f1f1f-infra
72e336da5e7b docker.io/library/wordpress:latest apache2-foregroun... 3 days ago Up 3 days ago 0.0.0.0:8081->80/tcp wordpresswordpress1-pod-wordpresswordpress1
1d36ae3682ed docker.io/arm64v8/mysql:latest mysqld 3 days ago Up 3 days ago 0.0.0.0:8081->80/tcp wordpresswordpress1-pod-wordpressdb1
1Podで3つのコンテナがはいってます。infraは自動ではいるのかな。
PORTSも若干怪しい。。。Webでアクセスしてみます。ブラウザでhttp://localhost:8081
へアクセス。
無事に表示してDB疎通もできていました。
まとめ
Dockerで比較的単純な運用できているレベルの話であればPodmanを利用しても同じことができます。
kubernetesへの移行を検討している場合にはpodman-composeを利用して変換すれば、kubernetes/Openshiftへの移行がしやすくなるのではないかと思いました。
・podman-composeを使えば、docker-composeからPodmanへの移行は簡単
・podman-composeでマルチコンテナPodを作る時は一部編集が必要
・podmanはPodを管理することができるが、いきすぎた場合kubernetesで管理したほうがよさそう
podman-composeもoptionをうまく利用すればもう少し色々できそうなのでまた触ってみたいと思います。