docker-composeからの脱却。podman-composeからのPod化までの道

# はじめに
<!-- 発端や概要を記載 -->
Docker有償化で小規模コンテナ環境の代用をPodmanで運用できないか？という相談を受けたついでに色々さわったのでまとめました。
RHEL8以降、Dockerが非推奨になっており代わりにPodmanを使ってね！という話だったのですが、運用できないかといわれるとちょっと自信がなかったわけです。特にdocker-composeしたものってどうやったらPodmanで動くんだっけ？と今更ながら。。。
PodmanがM1に対応したのかなども踏まえて実際にdocker-composeから'play kube'でPod実行までを自分の環境でやってみました。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [準備](#Chapter1)
1. [podman-composeの実行](#Chapter2)
1. [Pod化と実行](#Chapter3)
1. [まとめ](#Chapter4)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# 準備
最初に必要なものを集めます。まず適当なdocker-compose用のymlを探します。最初に参考にした赤帽ブログのwordpress用のファイルを[こちら](https://rheb.hatenablog.com/entry/podman3_docker_compose)から拝借しました。
```docker-compose.yml
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)の対応強化されているそうです。実際得に引っかかることはなくインストール完了。
```bash
% brew install podman
% podman -v
podman version 4.1.1
```
次にmacOSで動かすためのLinux環境をPodman machineで準備します。
```bash
% podman machine init
```
つつがなく完了。fedoraは36になるようです。
```bash
%  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を起動して準備完了です。
```bash
% podman machine start
・・・
Machine "podman-machine-default" started successfully
```
これでPodmanが動かせる様になりました。
（※podmanコマンドが通らない場合はzshにexportでPATHを追加するのがいいですが今回は略）


<a id="#Chapter2"></a>
# podman-composeの実行
さて準備できたけど、まずはどうしようというところで、[こちら](https://qiita.com/thirdpenguin/items/c9e58c27e96f02b0a96d)参考にさせていただきました。なるほどPodman3.xからdocker-composeも動かせるのね。。けど今回やりたいのはdocker-composeからの脱却でPodmanでdocker-compose用定義をコントロールしたいのです。というわけで[podman-compose](https://github.com/containers/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になってこういうところはまだ不便をかんじます。マルチアーキテクチャ対応も快適にならないかな。

```docker-compose.yml
  db:
    image: arm64v8/mysql
```
書き換えて再実行。今度はうまく行った様なのでcontainerを確認します。

```bash
% 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
```
コンテナが２つ立ち上がりました。
ついでにPod化されていればいいのですが、Podとしては動かせない模様。
まずはpodman-composeがちゃんと動くのかを調べるためにブラウザで`http://localhost:8080`へアクセス。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2608370/c15304cb-b7be-84ad-c084-25fa2fad8438.png)
ちゃんとDBまで疎通とれていい感じです。元のファイルをほぼ変えないままでよかった。
podmanとpodman-composeでほぼdocker-composeと同じ事ができました。

<a id="#Chapter3"></a>
# Pod化と実行
Podmanを使うメリットの１つとしてkubernetesへの対応があり、kubernetes用のyamlファイルが生成できます。いずれkubernetesへの移行も想定したいのでこの機能を利用してyaml生成しておこうというのが今回のゴールです。
Podmanで実行しているPod(orコンテナ)を対象として生成する機能になるので、先のpodman-composeで実行した際に２つのコンテナが同一のPodに入っていれば通信関係も問題なくPod化できるはず！と踏んでいました。実際は別々のコンテナとして動いています（どうやってDB見つけてるんだろ。。）

ここで対応できそうな方法をいくつか考えました。

1. 事前にPodを作成し、podman-composeでpodを指定する
1. それぞれ別Podとして生成し、Podman networkを使って接続させる
1. それぞれ別Podとして生成し、yamlを手でマージさせる

結論からいくと３番目の方法が一番簡単でした。

### 案1
--podman-run-argsに--podでpod指定してみる。
```bash
% 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'
```
オプションが死んでいるのかうまくいかず。（上手くいけた方いたら教えてください）


### 案２
[こちら](https://www.zu-min.com/archives/878)が参考になりました。
dnsを設定するためにプラグインを入れて、podを指名してあげる事でPodmanでもPod間通信ができるようになるそうです。ただ、これは少し手順が多く、ここまでやるならkubernetes上に持って行った方がいい印象です。
もともとの挙動に近しくするためにあくまでもPodで動かしたいので今回はパスしました。

### 案３
案３はまずwordpressとmysqlのPodを作成し、手マージしてしまいます。
まずはコンテナをそれぞれPod用yamlに生成します
```
% podman generate kube wordpress_wordpress_1 > kubernetes-wp.yml
```

```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
```

```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 `して単体で動くのを確認します。
問題なく動作したら以下のように合体させます。

```kubernetes-hybrid.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: 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に変えています。）
あとは行の並べ替えのみです。
```yml
    - name: WORDPRESS_DB_HOST
      value: 127.0.0.1
```
Pod化が完了しているので`podman play kube`で実行します。
```bash
% podman play kube kubernetes-hybrid.yml
```
動作確認
```bash
% 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
```
１Podで３つのコンテナがはいってます。infraは自動ではいるのかな。
PORTSも若干怪しい。。。Webでアクセスしてみます。ブラウザで`http://localhost:8081`へアクセス。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2608370/08339be9-8c7b-7e93-ce25-cf5ea7357862.png)

無事に表示してDB疎通もできていました。



<a id="#Chapter4"></a>
# まとめ
Dockerで比較的単純な運用できているレベルの話であればPodmanを利用しても同じことができます。
kubernetesへの移行を検討している場合にはpodman-composeを利用して変換すれば、kubernetes/Openshiftへの移行がしやすくなるのではないかと思いました。

・podman-composeを使えば、docker-composeからPodmanへの移行は簡単
・podman-composeでマルチコンテナPodを作る時は一部編集が必要
・podmanはPodを管理することができるが、いきすぎた場合kubernetesで管理したほうがよさそう

podman-composeもoptionをうまく利用すればもう少し色々できそうなのでまた触ってみたいと思います。

<a id="#reference"></a>
# 参考文献
- [赤帽エンジニアブログ　Podman v3 で docker-composeを実行する](https://rheb.hatenablog.com/entry/podman3_docker_compose)
- [豆蔵デベロッパーサイト　macOS 上で Podman を動かす](https://developer.mamezou-tech.com/blogs/2022/02/23/podman-machine/)
- [Podman で Compose したかったらどうするの？](https://qiita.com/thirdpenguin/items/c9e58c27e96f02b0a96d)
- [ZU-MIN.COM podman のコンテナ名で通信する](https://www.zu-min.com/archives/878)