Podmanでの複数コンテナの連携方法

# はじめに

最近の仕事では新規にサーバーを立てるとき、CentOS 8が多いのだが、Docker から Podman を使う、という風に置き換えられている。 もちろん、Docker もまだ使えるのだが、今後のサポートを考えると、できればRHELが主力とする Podman に置き換えたい。

今後、知識が必要になってきそうなので、ここらでどれぐらい互換性があるのか、自分なりに調べてみる事にした。 ~~Podman自体には思うところはないのですが、互換性を謳っているとはいえ、完全互換がないのに強制置き換えという方針を取るコミュニティは正直何を考えてるんだとは思わなくはないですが。~~ 

## TL; DR

- Dockerコマンドを置き換えると言っているが、異なる概念を持つツールなので別物と考えた方が変にハマったりしない
- podmanのpodは、複数のコンテナをあたかも１つの仮想マシンのようにして動かすための単位
- 1つのpodでは同一のポートを expose しているコンテナを同時に動かせない
- rootless なコンテナ同士の通信はホスト側のIPが参照できるのでこれを使って通信する
- rootful なコンテナ同士の通信は内部ネットワークに割り振られたIPを使う
- 内部ネットワークのIPを振る方法として固定IP方式やDNSなどの方法があるが、固定IP方式の場合の方法を説明する


# Hello, Podman

## Podman とは

![SnapCrab_NoName_2020-7-9_15-56-54_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502582/3406d2ff-5aab-9ddc-2dbb-b19ae2a518fe.png)

> Podman is a daemonless container engine for developing, managing, and running OCI Containers on your Linux System. Containers can either be run as root or in rootless mode. Simply put: `alias docker=podman`.

（画像・文言は https://podman.io/ からの引用)

- Linux上で動作するデーモンレスなコンテナエンジン
- root / rootless の両方のモードで動作する
- docker コマンドのエイリアスとして動作する
- ~~このアイコン見ると多くの人はダグ〇リオを思い浮かべるような気がする~~

ということで、**中身を見ないのであれば** Docker と同じ機能を提供してくれるもの、という理解で良いかと思います。ただ、実際には仕組みが異なっているので、**Dockerをそのまま置き換えてくれるものではありません**。 


## 検証環境

AWS上の Centos 8.2.2004 で検証。 [別のブログ](http://cream-worker.blog.jp/archives/1077468886.html)で知ったが、[CentOS Wiki でオフィシャル提供のAMI IDが公開されている](https://wiki.centos.org/Cloud/AWS)。 Marketplace にあるわけではないようだ。
ちなみに、このAMIの初期ログインユーザーは（他のCentOS AMIと同様） `centos` である。

## セットアップとインストール

普通に `dnf` (今までの `yum` )で各種セットアップしていきます。 なお、以下のコマンドは全て `centos` (sudo権限あり) ユーザーで実施しています。

```bash
$ sudo dnf -y update
# -- 以下2件はオプションで
$ sudo dnf install -y langpacks-ja # 日本語環境
$ sudo timedatectl set-timezone Asia/Tokyo # 時刻をJSTに
# -- podman のインストール
$ sudo dnf install -y podman
```

RHELのオフィシャルサポートということで、dnf で簡単にインストールできますね。 ただ、これでインストールするとちょっと古かったです(執筆時点で1.6.4)。


## コンテナを立ててみる

Docker の場合、systemctl などで docker のデーモンを立てておかないと docker コマンドが利用できません。 しかし、podman はデーモンレスと謳っている通り、こういったサービスプロセスを動作させなくても各種コマンドを動かすことができます。

```bash
# nginx コンテナを起動
$ sudo podman run -d -p 80:80 nginx
Trying to pull registry.access.redhat.com/nginx...
  unsupported: This repo requires terms acceptance and is only available on registry.redhat.io
Trying to pull registry.redhat.io/nginx...
  unable to retrieve auth token: invalid username/password: unauthorized: Please login to the Red Hat Registry using your Customer Portal credentials. Further instructions can be found here: https://access.redhat.com/RegistryAuthentication
Trying to pull docker.io/library/nginx...
Getting image source signatures
Copying blob 8d69e59170f7 done
Copying blob 1e22bfa8652e done
Copying blob d1f5ff4f210d done
Copying blob 3f9f1ec1d262 done
Copying blob 8559a31e96f4 done
Copying config 2622e6cca7 done
Writing manifest to image destination
Storing signatures
7fddd586d2fa5d5e408b06cd01d002aa29a08d0d9b8b97d5dbbc1105360f08e2

# nginx が正常に稼働
$ curl -I http://localhost
HTTP/1.1 200 OK
Server: nginx/1.19.0
Date: Thu, 09 Jul 2020 07:28:07 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 May 2020 15:00:20 GMT
Connection: keep-alive
ETag: "5ecd2f04-264"
Accept-Ranges: bytes
```

このように動きましたが、CentOS 8 で podman を入れるとデフォルトのレジストリとして `registry.access.redhat.com` , `registry.redhat.io` も登録されており、これを利用するためには認証情報が必要なようです。 DockerHubだけで良いのであれば [` /etc/containers/registries.conf` からレジストリ情報を削除しておきます](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/building_running_and_managing_containers/working-with-container-images_building-running-and-managing-containers)

```bash
# podman search でレジストリを DockerHub のみにした後の search の結果
$ sudo podman search httpd
INDEX       NAME                                              DESCRIPTION                                       STARS   OFFICIAL   AUTOMATED
docker.io   docker.io/library/httpd                           The Apache HTTP Server Project                    3093    [OK]       
docker.io   docker.io/centos/httpd-24-centos7                 Platform for running Apache httpd 2.4 or bui...   34                 
docker.io   docker.io/manageiq/httpd                          Container with httpd, built on CentOS for Ma...   0                  [OK]
docker.io   docker.io/publici/httpd                           httpd:latest                                      1                  [OK]
docker.io   docker.io/centos/httpd                                                                              29                 [OK]
docker.io   docker.io/itsziget/httpd24                        Extended HTTPD Docker image based on the off...   0                  [OK]
docker.io   docker.io/solsson/httpd-openidc                   mod_auth_openidc on official httpd image, ve...   1                  [OK]
docker.io   docker.io/manageiq/httpd_configmap_generator      Httpd Configmap Generator                         0                  [OK]
docker.io   docker.io/clearlinux/httpd                        httpd HyperText Transfer Protocol (HTTP) ser...   1                  
docker.io   docker.io/hypoport/httpd-cgi                      httpd-cgi                                         0                  [OK]
docker.io   docker.io/dariko/httpd-rproxy-ldap                Apache httpd reverse proxy with LDAP authent...   1                  [OK]
docker.io   docker.io/e2eteam/httpd                                                                             0                  
docker.io   docker.io/dockerpinata/httpd                                                                        0                  
docker.io   docker.io/lead4good/httpd-fpm                     httpd server which connects via fcgi proxy h...   1                  [OK]
docker.io   docker.io/interlutions/httpd                      httpd docker image with debian-based config ...   0                  [OK]
docker.io   docker.io/appertly/httpd                          Customized Apache HTTPD that uses a PHP-FPM ...   0                  [OK]
docker.io   docker.io/izdock/httpd                            Production ready Apache HTTPD Web Server + m...   0                  
docker.io   docker.io/manasip/httpd                                                                             0                  
docker.io   docker.io/amd64/httpd                             The Apache HTTP Server Project                    0                  
docker.io   docker.io/trollin/httpd                                                                             0                  
docker.io   docker.io/jonathanheilmann/httpd-alpine-rewrite   httpd:alpine with enabled mod_rewrite             1                  [OK]
docker.io   docker.io/salim1983hoop/httpd24                   Dockerfile running apache config                  2                  [OK]
docker.io   docker.io/ppc64le/httpd                           The Apache HTTP Server Project                    0                  
docker.io   docker.io/alvistack/httpd                         Docker Image Packaging for Apache                 0                  [OK]
docker.io   docker.io/arm32v7/httpd                           The Apache HTTP Server Project                    9   

# 参考: docker search の結果
$ docker search httpd
NAME                                    DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
httpd                                   The Apache HTTP Server Project                  3093                [OK]                
centos/httpd-24-centos7                 Platform for running Apache httpd 2.4 or bui…   34                                      
centos/httpd                                                                            29                                      [OK]
arm32v7/httpd                           The Apache HTTP Server Project                  9                                       
salim1983hoop/httpd24                   Dockerfile running apache config                2                                       [OK]
lead4good/httpd-fpm                     httpd server which connects via fcgi proxy h…   1                                       [OK]
solsson/httpd-openidc                   mod_auth_openidc on official httpd image, ve…   1                                       [OK]
jonathanheilmann/httpd-alpine-rewrite   httpd:alpine with enabled mod_rewrite           1                                       [OK]
clearlinux/httpd                        httpd HyperText Transfer Protocol (HTTP) ser…   1                                       
publici/httpd                           httpd:latest                                    1                                       [OK]
dariko/httpd-rproxy-ldap                Apache httpd reverse proxy with LDAP authent…   1                                       [OK]
interlutions/httpd                      httpd docker image with debian-based config …   0                                       [OK]
manageiq/httpd                          Container with httpd, built on CentOS for Ma…   0                                       [OK]
e2eteam/httpd                                                                           0                                       
hypoport/httpd-cgi                      httpd-cgi                                       0                                       [OK]
appertly/httpd                          Customized Apache HTTPD that uses a PHP-FPM …   0                                       [OK]
izdock/httpd                            Production ready Apache HTTPD Web Server + m…   0                                       
manasip/httpd                                                                           0                                       
amd64/httpd                             The Apache HTTP Server Project                  0                                       
trollin/httpd                                                                           0                                       
manageiq/httpd_configmap_generator      Httpd Configmap Generator                       0                                       [OK]
itsziget/httpd24                        Extended HTTPD Docker image based on the off…   0                                       [OK]
ppc64le/httpd                           The Apache HTTP Server Project                  0                                       
alvistack/httpd                         Docker Image Packaging for Apache               0                                       [OK]
```

レジストリを DockerHub だけにすれば、認証エラーは起こらずに済みます。

```bash
$ sudo podman run -d -p 8080:80 httpd
Trying to pull docker.io/library/httpd...
Getting image source signatures
Copying blob 8559a31e96f4 skipped: already exists
Copying blob f67007e59c3c done
Copying blob f3cbcb88690d done
Copying blob bd517d441028 done
Copying blob 83c578481926 done
Copying config ccbcea8a67 done
Writing manifest to image destination
Storing signatures
0a6efcb3da1fcd4a5b065984386ae11b88e3117a35baa14231fd6b1a17fe83aa
```

## コンテナ間通信

さて、ここからが調査したかった事の本筋です。 具体的には、コンテナ間の通信はどのように実現するのでしょうか？ 例えば、httpd -> db といった通信は必須になってきます。
docker -> podman への置き換えで私が一番懸念したのがここでした。 というのも調べた段階でこんな文言が飛び込んできたからです。

> podman が対応していない dockerコマンドのオプションには、network、node、plugin (podman はプラグインをサポートしません)、rename (rm および create を使用して podman でコンテナーの名前を変更します)、secret、service、stack、swarm (podman は Docker Swarm をサポートしません) が含まれます。
> 引用 - https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/building_running_and_managing_containers/container-command-line-reference_building-running-and-managing-containers

普段は docker-compose で書いて 別コンテナへとアクセス可能な network を自動生成しているので、これがサポートされない…ということは、（流石に機能としては絶対あるだろうけれど）使い方が変わるのか…、と真っ先に考えました。
調べてみれば docker-compose を置き換えるための [podman-compose](https://github.com/containers/podman-compose) もあるようですが、[他の方の記事を見るとまだ発展途上っぽい挙動](https://qiita.com/rururu_kenken/items/115f426c81496fc27eb7) で、現時点ではdocker-composeを単に置き換えられるようには見えなかったので。 そのため、どういう動きをするのかを調査することにして、この記事を書くに至ったのですが。

...と、ここまで考えて実際に podman を使ってみると、 **`podman network` が存在するという事実に気づく**。どうやら、先の引用ページに書かれていたのは **`docker`コマンドと同様に利用可能な、互換性のあるコマンドのみの一覧** であり、その機能が無いというわけではないらしい。 ~~`alias docker = podman` と謳ってるのにこのあたりが分かりづらいのはどうかと思うので、やっぱり別物と考えた方が良いと思います。~~

## Podman Network

というわけで Get Started に戻ってきました。 以下のような記述があります。

> By definition, all containers in the same Podman pod share the same network namespace. Therefore, the containers will share the IP Address, MAC Addresses and port mappings. You can always communicate between containers in the same pod, using localhost.
> 引用 - https://podman.io/getting-started/network

Podという単位があり、その中で複数のコンテナが動作する。 そして、それらのコンテナは全て同じ（仮想）ネットワークの中にあり、IP/MACアドレスやポートマッピングを共有する。 これらの(同じPodの中にある)コンテナは、localhost を使って互いに通信できる。

という事で、ここに書いてある通り複数のコンテナ間で通信を行うための方針は以下の通りです。

- 通信したいコンテナを1つの Pod 内に定義する
- あるコンテナから `localhost:[pod内に公開しているポート]` で別のコンテナにアクセスする

podman の名前の一部でもある Pod だが、元は Kubernetes (ざっと説明すると、複数のコンテナをうまく動かすための仕組み・ツール) 用語であり、(Kubernetesの) 実行の最小単位になる。 公式ページの説明は以下の通り。

> Pod は（クジラの小群やエンドウ豆のさやのように）、共有のストレージ/ネットワークを持つ1つ以上のコンテナ（例えばDockerコンテナ）、およびコンテナを実行する方法についての仕様です。Pod内のコンテナ群は常に同じ場所に配置され、協調してスケジューリングされ、共通のコンテキストで実行されます。
> (中略)
> Pod内のコンテナはIPアドレスとポートの空間を共有し、 localhost を通じてお互いを見つけることができます 。
> 引用 - https://kubernetes.io/ja/docs/concepts/workloads/pods/pod/

pod を使うために、まずはチュートリアルに基づいてネットワークを理解していく。

### ルートレスモードのネットワークアクセス

まずは rootless モードでのコンテナを用意します。

```bash
$ podman ps
CONTAINER ID  IMAGE                           COMMAND               CREATED        STATUS            PORTS                 NAMES
cdd022ca1e71  docker.io/library/nginx:1.17    nginx -g daemon o...  5 seconds ago  Up 5 seconds ago  0.0.0.0:8081->80/tcp  hopeful_chandrasekhar
2ec3835911f7  docker.io/library/nginx:latest  nginx -g daemon o...  9 minutes ago  Up 9 minutes ago  0.0.0.0:8080->80/tcp  wizardly_brown

$ ps aux | grep nginx
centos     28490  0.0  0.6  10624  5124 ?        Ss   21:53   0:00 nginx: master process nginx -g daemon off;
100100     28524  0.0  0.2  11020  2440 ?        S    21:53   0:00 nginx: worker process
centos     28810  1.0  0.6  10632  5108 ?        Ss   22:02   0:00 nginx: master process nginx -g daemon off;
100100     28821  0.0  0.3  11088  2588 ?        S    22:02   0:00 nginx: worker process
centos     28834  0.0  0.1 221900   976 pts/2    R+   22:03   0:00 grep --color=auto nginx
```

ちゃんと nginx の実行ユーザーが `centos` になっており、root で実行されていない rootless であることが分かります。 では、こういった場合どのようにコンテナから別のコンテナにアクセスするかですが、こうあります。

> Communicating between two rootless containers can be achieved in mutiple ways. The easiest and most convenient way is to communicate via published ports and the underlying host.
> 引用 - https://podman.io/getting-started/network

ルートレスモードのコンテナには権限の関係でIPアドレスは割り当てられません。 しかし、**コンテナ内からコンテナを動作されているホストに対してIPアドレスによってアクセスをすることができます。** 今回はAWSのVPC上に立てたEC2インスタンスで、`172.31.12.231` というプライベートアドレスがあるので、これを使って、コンテナ間での相互の通信を行ってみます。

```bash
$ podman exec -it wizardly_brown curl -IL http://172.31.12.231:8081
HTTP/1.1 200 OK
Server: nginx/1.17.10
Date: Thu, 09 Jul 2020 13:05:22 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 14 Apr 2020 14:19:26 GMT
Connection: keep-alive
ETag: "5e95c66e-264"
Accept-Ranges: bytes

$ podman exec -it wizardly_brown curl -IL http://172.31.12.231:8080
HTTP/1.1 200 OK
Server: nginx/1.19.0
Date: Thu, 09 Jul 2020 13:05:24 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 May 2020 15:00:20 GMT
Connection: keep-alive
ETag: "5ecd2f04-264"
Accept-Ranges: bytes
```

異なる Nginx Version が表示されているため、一方のコンテナから、自分自身、および、自分以外のコンテナへとアクセスできていることが確認できる。
一度自分を動かしているホストを経由することで、ホスト上で動作していて port が公開されているそれ以外のサービスにもアクセス可能である。

ホストのIPを知る必要こそあるが、非常に分かりやすい。 ただ、おそらく "コンテナA -> ホスト -> コンテナB" というネットワークを辿っており、"コンテナA -> コンテナB" のような直通にはなっていないので若干（と言っても、取るに足らない量だとは思うが）オーバーヘッドは生じているようには見える。


### ルートフルモードのネットワークアクセス

ルートレスモードと同じ方法の場合、どうなるのかを実験。

```bash:実行環境
# rootless(8082) と rootful (8080, 8081)を定義
$ podman ps -a
CONTAINER ID  IMAGE                           COMMAND               CREATED         STATUS             PORTS                 NAMES
f3f0f8f5b703  docker.io/library/nginx:latest  nginx -g daemon o...  18 seconds ago  Up 18 seconds ago  0.0.0.0:8082->80/tcp  peaceful_easley

$ sudo podman ps
CONTAINER ID  IMAGE                           COMMAND               CREATED        STATUS            PORTS                 NAMES
3a694ec05d05  docker.io/library/nginx:1.17    nginx -g daemon o...  3 minutes ago  Up 3 minutes ago  0.0.0.0:8081->80/tcp  quizzical_gagarin
667b73260168  docker.io/library/nginx:latest  nginx -g daemon o...  4 minutes ago  Up 4 minutes ago  0.0.0.0:8080->80/tcp  festive_goldwasser
```

```bash:rootless->rootfulは全部OK
$ podman exec -it f3f curl -I http://172.31.12.231:8080
HTTP/1.1 200 OK
Server: nginx/1.19.0
Date: Thu, 09 Jul 2020 13:14:33 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 May 2020 15:00:20 GMT
Connection: keep-alive
ETag: "5ecd2f04-264"
Accept-Ranges: bytes

$ podman exec -it f3f curl -I http://172.31.12.231:8081
HTTP/1.1 200 OK
Server: nginx/1.17.10
Date: Thu, 09 Jul 2020 13:14:34 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 14 Apr 2020 14:19:26 GMT
Connection: keep-alive
ETag: "5e95c66e-264"
Accept-Ranges: bytes

$ podman exec -it f3f curl -I http://172.31.12.231:8082
HTTP/1.1 200 OK
Server: nginx/1.19.0
Date: Thu, 09 Jul 2020 13:14:36 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 May 2020 15:00:20 GMT
Connection: keep-alive
ETag: "5ecd2f04-264"
Accept-Ranges: bytes
```

```bash:rootful->rootfulで一部ダメなケースがある
# -- OK: rootful -> rootful (自分自身)
$ sudo podman exec -it 667 curl -I http://172.31.12.231:8080
HTTP/1.1 200 OK
Server: nginx/1.19.0
Date: Thu, 09 Jul 2020 13:16:09 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 May 2020 15:00:20 GMT
Connection: keep-alive
ETag: "5ecd2f04-264"
Accept-Ranges: bytes

# -- NG: rootful -> rootful (別のコンテナ)
$ sudo podman exec -it 667 curl -I http://172.31.12.231:8081
^CError: non zero exit code: 130: OCI runtime error

# -- OK: rootful -> rootless
$ sudo podman exec -it 667 curl -I http://172.31.12.231:8082
HTTP/1.1 200 OK
Server: nginx/1.19.0
Date: Thu, 09 Jul 2020 13:16:16 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 May 2020 15:00:20 GMT
Connection: keep-alive
ETag: "5ecd2f04-264"
Accept-Ranges: bytes
```

というわけで、別の方法が必要。

チュートリアルを引き続き見てみると、ルートフルモードの場合、内部にネットワークが作られ、コンテナ個別に内部ネットワークのIPアドレスが割り振られている。

```bash:コンテナに振られるIPアドレス
# rootful の場合 IPAddress が割り振られる
$ sudo podman inspect 667 | grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "10.88.0.6",
$ sudo podman inspect 3a6 | grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "10.88.0.7",

# 一方、rootless の場合 IPAddress は割り振られない
$ podman inspect f3f | grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "",
```

このIPアドレスを使うことで別のコンテナに直接アクセスできる。 ただし、これは内部ネットワークであり、**`-p` でマッピングしているのはホスト:コンテナのポートマッピング** なので、内部ネットワークでアクセスする場合はコンテナが直接 EXPOSE しているポートを指定する。

```bash:プライベートIPであれば別のルートフルコンテナにアクセス可能
$ sudo podman exec -it 667 curl -I http://10.88.0.6
HTTP/1.1 200 OK
Server: nginx/1.19.0
Date: Thu, 09 Jul 2020 13:27:03 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 May 2020 15:00:20 GMT
Connection: keep-alive
ETag: "5ecd2f04-264"
Accept-Ranges: bytes
$ sudo podman exec -it 667 curl -I http://10.88.0.7
HTTP/1.1 200 OK
Server: nginx/1.17.10
Date: Thu, 09 Jul 2020 13:27:21 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 14 Apr 2020 14:19:26 GMT
Connection: keep-alive
ETag: "5e95c66e-264"
Accept-Ranges: bytes

# ホストにマッピングしたポートはこの場合は使えない
$ sudo podman exec -it 667 curl -I http://10.88.0.6:8080
curl: (7) Failed to connect to 10.88.0.6 port 8080: Connection refused
Error: non zero exit code: 7: OCI runtime error
[centos@ip-172-31-12-231 ~]$ sudo podman exec -it 667 curl -I http://10.88.0.7:8080
curl: (7) Failed to connect to 10.88.0.7 port 8080: Connection refused
Error: non zero exit code: 7: OCI runtime error
```

**が、違う。 欲しいのは起動時に指定した名前で別のコンテナにアクセスしたいだけ** であって、この方法では都度IPアドレスを調べないといけないから、実際に動かすときに複雑になる上、IPが変わったら逐次そこを変えないといけない。
Get Started にはさらにDNSサービスを立てて別のサービスのディスカバリに使おうって言ってる。 **が、高々2個 (httpd - db) ぐらいの構成のためにそこまでやりたくない** 。

何かいい方法はないものか…。

## pod の利用

ここで最初を思い出す。

> By definition, all containers in the same Podman pod share the same network namespace. Therefore, the containers will share the IP Address, MAC Addresses and port mappings. You can always communicate between containers in the same pod, using localhost.
> 引用 - https://podman.io/getting-started/network

記述を信じれば、podを使えば複数のコンテナを１つのサーバーのように動かせるはず。 
ここでは、wordpress と mysql のコンテナを1つのpod内で動かすことを考えてみる。

先に説明しておくが、podman の pod は **複数のコンテナをまとめた、１つのサーバーのような振る舞いをする** 。 そのため、動作ホストからpodにアクセスする場合、pod を作成する段階でポートを publish しておく必要がある (見てみたが、後から追加で publish する方法が分からなかったので、作るタイミングで publish する)。
また、コンテナを特定pod内で稼働させるオプションは `--pod [pod名]` なのですが、これが[コマンドの公式ドキュメントの中に見つからない……](http://docs.podman.io/en/latest/markdown/podman-run.1.html)。 と思ったら、新しいバージョンの `--help` には出てきたので、どうも公式ドキュメントは更新が遅いらしいですね…。

```podを作成
# wp-pod という名前の pod を作成。 外部公開用ポートのマッピングは 8080:80 
$ sudo podman pod create -p 8080:80 --name wp-pod 

# run --pod オプションで特定の pod 内にコンテナを追加
$ sudo podman run -d --pod wp-pod -e MYSQL_ROOT_PASSWORD=sample mysql
$ sudo podman run -d --pod wp-pod wordpress

# pod と containers の情報
$ sudo podman pod ps 
POD ID        NAME    STATUS   CREATED             # OF CONTAINERS  INFRA ID
b764b7ec91a9  wp-pod  Running  About a minute ago  3                6ab3502eb8be

$ sudo podman ps --pod
$ sudo podman ps --pod
CONTAINER ID  IMAGE                               COMMAND               CREATED             STATUS                 PORTS                 NAMES               POD ID        PODNAME
6ab3502eb8be  k8s.gcr.io/pause:3.2                                      7 minutes ago       Up 6 minutes ago       0.0.0.0:8080->80/tcp  b764b7ec91a9-infra  b764b7ec91a9  wp-pod
ccb20a20e891  docker.io/library/wordpress:latest  apache2-foregroun...  6 minutes ago       Up 6 minutes ago       0.0.0.0:8080->80/tcp  ecstatic_hellman    b764b7ec91a9  wp-pod
cefb3bc1c40b  docker.io/library/mysql:latest      mysqld                About a minute ago  Up About a minute ago  0.0.0.0:8080->80/tcp  zealous_franklin    b764b7ec91a9  wp-pod
```

WordPress の簡単インストールによって、 `localhost:3306` に MySQL がインストールされて利用可能であることを確認します。 rootパスワードは今回の例では `sample` ですが、必要によって `mysql_secure_installation` を実行するなどでパスワードを適時変更してください。

```bash:Databaseを作成する
# 必要に応じて、rootパスワードを正常に変えること
# $ sudo podman exec -it cefb mysql_secure_installation
$ sudo podman exec -it cefb mysqladmin -u root -p create wordpress
Enter password: 
```

この状態で WordPress のセットアップ画面でDB情報を入力します。

![SnapCrab_NoName_2020-7-10_1-1-41_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502582/9a3ad543-a51d-eff5-2695-86c04564a2b5.png)

注意点ですが、(MySQL) データベースのホスト名は **localhostではなく、127.0.0.1を指定してください** 。 というのも、MySQL クライアントは `localhost` を入れると同じサーバー上の `/var/lib/mysql/mysql.sock` を見に行くようになっているみたいなので、これを見るのではなく、ちゃんと `127.0.0.1:3306` を参照するためです。

![SnapCrab_NoName_2020-7-10_1-1-53_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502582/bc98a5f5-b235-7956-5ab0-80e1457a6388.png)

これで同一 pod 内に存在するコンテナ間の通信が localhost (127.0.0.1) 経由で実施可能であることが分かりました。

なお、実用化する場合はホストとのボリューム共有などでデータを永続化することをちゃんと考えて下さい。 これはあくまで検証用の設定です。

~~ここまで調べて、podとnetworkは全く関係がなかったことに気づきました。~~

## pod の仕様と限界

普通であればこれで良いのですが、ちょっと発展的な使い方をする場合、こんなことを実施したいことがあります。

1. httpd (2.4.41) と mysql が動いている
2. 新しい httpd のバージョン (2.4.43) が出たので、こちらに切り替えたい
3. 一時的に２つのバージョンを並列稼働させ、ダウンタイムなしでミドルウェアをアップデートする

この場合、podの仕様として問題なのが the containers will share the IP Address, MAC Addresses and port mappings とあり、**ポートを共有してしまう** ことです。 言い換えると、**１つのコンテナが同じポートを expose している場合、それらを同じpodの中で同時に動かすことができません**。 こういったケース以外にも、例えば httpd コンテナと phpmyadmin コンテナ (両方とも Expose 80) を併用することはできません。

なので、こういったケースを考える場合は pod だけでは完結できず、別の方法を考える必要があります。

## Podman Network 再び

先にルートフルなコンテナの場合、動的に割り振られる動的IPアドレスを指定すれば同一ネットワーク内のコンテナ同士が通信できることが分かっています。 また、この時は同じポートを Expose していても、それらを同時に動かすことができます。
そして、この時問題視していたのはどんなIPアドレスが割り当てられるか分からないので「DNSを使うなどの解決策がある」ということでした。 ただ、十分に小さい(10個未満)ぐらいであれば、**ホスト上でどのようなIPアドレスを割り当てるかを固定して、それぞれに名前を与える** ことで、各コンテナから別のコンテナを参照できるようになります。

### Podman のバージョン更新

CentOS 8 の dnf で入ってくるバージョンは 1.6.4 でした (記事執筆時現在)。 しかし、[どうもデフォルト以外のネットワークにIPを固定する機能にバグがあり](https://github.com/containers/podman/issues/4500)、うまくいかなかったので、[podmanのセットアップページ](https://podman.io/getting-started/installation.html)を元にして執筆時点で最新の podman 2.0.2 をインストールし、利用しています。

```bash:CentOS8での最新版podmanインストール
# see - https://podman.io/getting-started/installation.html
sudo dnf -y module disable container-tools
sudo dnf -y install 'dnf-command(copr)'
sudo dnf -y copr enable rhcontainerbot/container-selinux
sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo
sudo dnf -y install podman
```

### Podman Network の作成と固定IPのコンテナ作成

今回は新しいネットワークに subnet: `10.100.0.0/24` を割り振ります。 現在のネッ
トワーク設定は `cat /etc/cni/net.d` 以下のファイルに書き出されています。 ネットワークレンジは重複しないようにしてください。

```bash:wp-networkを作成して、その上にwordpressとmysqlコンテナを固定IPで作成
$ sudo podman network create --subnet 10.100.0.0/24 wp-network
/etc/cni/net.d/wp-network.conflist

$ sudo podman run -d --network wp-network --ip 10.100.0.10 -e MYSQL_ROOT_PASSWORD=sample mysql
$ sudo podman run -d --network wp-network --ip 10.100.0.20 --add-host mysql-server:10.100.0.10 -p 8080:80 wordpress

# コンテナの確認
$ sudo podman ps 
CONTAINER ID  IMAGE                               COMMAND               CREATED         STATUS             PORTS                 NAMES
6d1ff5c8b9ee  docker.io/library/wordpress:latest  apache2-foregroun...  21 seconds ago  Up 21 seconds ago  0.0.0.0:8080->80/tcp  elegant_williamson
a04bac92be8e  docker.io/library/mysql:latest      mysqld                2 minutes ago   Up 2 minutes ago                         cool_bartik

# 例によって空のDBは作っておく
$ sudo podman exec -it a04 mysqladmin -u root -p create wordpress
```

ポイントは `--network` , `--ip` , `--add-host` です。 それぞれ、作成済のネットワークに、特定の固定IPアドレスで、コンテナの `/etc/hosts` に追加する内容を、それぞれ与えます。 `--add-host` は複数あってもOKです。

これで、WordPressコンテナからmysqlコンテナに対して、サーバー名 `mysql-server` によってアクセスできることが分かります。

![SnapCrab_NoName_2020-7-10_1-39-4_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502582/6403a532-e74c-7ad7-aed5-6b26d5d90a7e.png)

この方法であれば、ホストのポートを個別に publish できるので、同じポートを expose している複数のコンテナを同一のネットワーク内で動かせます。 先ほど例に挙げた無停止更新をしたい場合はいくつか方法があり、

- サーバー到達までの間に nginx を挟み、upstrem でどちらのコンテナに到達させるかを切り替える
- DNSのサービスディスカバリをちゃんと導入して、内部DNSレベルで切り替える

といった方法がありますが、今回は触れません。 
大分回り道をしましたが、名前 - 固定IPマッピングをしておくことで、１台のホスト上での名前解決は可能になったように思います。 ただし、destination側 (今回の場合のmysql) のIPが変わるような複雑なネットワーク構成の場合、DNSを導入した方が良いでしょう。


# 終わりに

今回調べてみて、ドキュメントも読みやすいし、デーモンレスにあるメリットは納得できるので podmanというアプリケーション **そのものには** いい印象を持ってます。
が、ツールをDockerの完全互換に見えるような形で説明しているように見えることや、RHEL周りによる導入の進め方(docker = podman と言い切って、完全な互換性は無けれどもサポートを podman only にする）とかのあたりが個人的には逆に分かりづらかったり、これでいいのか…？ と思ったりしました。
正直、今まで Docker を使っていて、それで Docker の完璧な互換がないものしかサポートしないと言われると、クラウドのこのご時世であれば Linux OS を Docker をサポートしている別のディストリビューションに乗り換えることも検討する気がするんだけれどなぁ…

`alias docker = podman` と説明されているせいなのか、あまり詳しい説明がなかった気がするので、誰かの助けになれば幸いです。

# 参考

- [Dockerの置き換えを目指す ルートレス&デーモンレスの Podman 入門](https://qiita.com/MahoTakara/items/65ff8c2810ca820bc0b3)
- [[随時更新]Podmanを使ってみて気になったところ](https://qiita.com/rururu_kenken/items/115f426c81496fc27eb7)
- [Podman: Managing pods and containers in a local container runtime](https://developers.redhat.com/blog/2019/01/15/podman-managing-containers-pods/)
- [株式会社デージーネット - podとは](https://www.designet.co.jp/faq/term/?id=UG9k)