Podman v3 で docker-composeを実行する

Red Hatでソリューションアーキテクトをしている田中司恩(@tnk4on)です。最近はPodmanOpenShiftの良さをより簡潔に伝えられないかと日々考えながら記事の寄稿などの活動も行っています。

前回の記事では RHEL 8.4 BetaとPodman v3について紹介しましたが、 ついにRHEL 8.4 がGAになりイメージの入手が可能になりました。有効なサブスクリプションをお持ちの場合や、Red Hat Developer Programのアカウントをお持ちの場合は今すぐに入手できます。なお、評価版についてはこの記事執筆時点ではRHEL 8.3のままのようです。

今回は前回記事でも触れたPodman v3でdocker-composeを実行する方法について紹介します。 前回記事はこちらです。 rheb.hatenablog.com

(追記)この記事の続きの記事を書きました。ルートレスモードでdocker-composeを使用する場合は下記記事を参照ください。 rheb.hatenablog.com


PodmanのREST APIを確認してみる

Podman v3におけるdocker-composのサポートはDocker互換のインターフェースとしてREST API *1がサポートされたことにより実現しています。

PodmanのREST API仕様はこちら。 docs.podman.io

RHEL 8.4上でPodmanのREST APIのテストをした結果はこちらです。なおPodman APIソケットを有効にするには、後ほど紹介するpodman.socketサービスを起動する必要があります。

podman version に相当するコマンド

# curl -s --unix-socket /run/podman/podman.sock http://d/v3.0.0/libpod/info | jq .version

出力結果を開く

{
  "APIVersion": "3.0.0",
  "Version": "3.0.2-dev",
  "GoVersion": "go1.15.7",
  "GitCommit": "",
  "BuiltTime": "Wed Apr  7 17:36:54 2021",
  "Built": 1617784614,
  "OsArch": "linux/amd64"
}

podman pull docker.io/library/hello-worldに相当するコマンド

curl -XPOST --unix-socket /run/podman/podman.sock -v 'http://d/v3.0.0/images/create?fromImage=docker.io%2Flibrary%2Fhello-world'

出力結果を開く

*   Trying /run/podman/podman.sock...
* Connected to d (/run/podman/podman.sock) port 80 (#0)
> POST /v3.0.0/images/create?fromImage=docker.io%2Flibrary%2Fhello-world HTTP/1.1
> Host: d
> User-Agent: curl/7.61.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Api-Version: 1.40
< Content-Type: application/json
< Libpod-Api-Version: 3.0.0
< Server: Libpod/3.0.0 (linux)
< Date: Tue, 18 May 2021 19:42:35 GMT
< Content-Length: 198
<
{"status":"pulling image () from docker.io/library/hello-world:latest (Download complete)","progress":"","progressDetail":{},"id":"d1165f2212346b2bab48cb01c1e39ee8ad1be46b87873d9ca7a4e434980a7726"}
* Connection #0 to host d left intact

podman list imagesに相当するコマンド

# curl --unix-socket /run/podman/podman.sock -v 'http://d/v3.0.0/libpod/images/json' | jq

出力結果を開く

*   Trying /run/podman/podman.sock...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to d (/run/podman/podman.sock) port 80 (#0)
> GET /v3.0.0/libpod/images/json HTTP/1.1
> Host: d
> User-Agent: curl/7.61.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Api-Version: 1.40
< Content-Type: application/json
< Libpod-Api-Version: 3.0.0
< Server: Libpod/3.0.0 (linux)
< Date: Tue, 18 May 2021 19:44:59 GMT
< Content-Length: 596
<
{ [596 bytes data]
100   596  100   596    0     0   8514      0 --:--:-- --:--:-- --:--:--  8637
* Connection #0 to host d left intact
[
  {
    "Id": "d1165f2212346b2bab48cb01c1e39ee8ad1be46b87873d9ca7a4e434980a7726",
    "ParentId": "",
    "RepoTags": [
      "docker.io/library/hello-world:latest"
    ],
    "RepoDigests": [
      "docker.io/library/hello-world@sha256:1b26826f602946860c279fce658f31050cff2c596583af237d971f4629b57792",
      "docker.io/library/hello-world@sha256:5122f6204b6a3596e048758cabba3c46b1c937a46b5be6225b835d091b90e46c"
    ],
    "Created": 1614986725,
    "Size": 19981,
    "SharedSize": 0,
    "VirtualSize": 19981,
    "Labels": null,
    "Containers": 0,
    "Names": [
      "docker.io/library/hello-world:latest"
    ],
    "Digest": "sha256:5122f6204b6a3596e048758cabba3c46b1c937a46b5be6225b835d091b90e46c"
  }
]

Podman v2でREST APIがサポートされた時の紹介記事も参考にしてください。 www.redhat.com

Podmanでdocker-composeを実行する

ここからはPodmanでdocker-composeを実行する手順を紹介します。

なお、RHEL 8.4に搭載されているPodman(v3.0.2-dev)ではルートモードによる実行しかサポートされていません。ルートレスで実行した場合にはエラーになります。ルートレスでdocker-composeを実行するには、現在開発中のPodman v3.2.0以降が必要です(2021/5/19、時点)。

docker-composeのインストール

docker-composeはpipで簡単にインストールできます。docker-composeのドキュメントでは配布バイナリを使用する方法も紹介されています。

# dnf install python3-pip
# pip3 install -U pip
# pip3 install docker-compose

podman-pluginsのインストール

docker-composeを使ったアプリケーションでは複数のコンテナ間の通信をコンテナ名で行うように指定されていることが多くありますが、Podmanはデフォルトでコンテナ名での通信はできません。Podmanではdnsnameプラグインを使用することでローカルDNSレコードをコンテナに割り当ててコンテナ間で通信することができます。dnsnameプラグインはpodman-pluginsという名前のパッケージでdnfコマンドで追加できます。また同時にdnsmasqも追加されます。

# dnf install podman-plugins

podman.socketサービスの起動

Podmanのインストール初期状態ではREST APIの待ち受けサービス(Podman APIソケット)が起動していませんので、下記の手順でサービスを起動します。

# systemctl enable podman.socket
Created symlink /etc/systemd/system/sockets.target.wants/podman.socket → /usr/lib/systemd/system/podman.socket.
# systemctl start podman.socket
# systemctl status podman.socket
● podman.socket - Podman API Socket
   Loaded: loaded (/usr/lib/systemd/system/podman.socket; enabled; vendor preset: disabled)
   Active: active (listening) since Wed 2021-05-19 04:35:50 JST; 17s ago
     Docs: man:podman-system-service(1)
   Listen: /run/podman/podman.sock (Stream)
   CGroup: /system.slice/podman.socket

 5月 19 04:35:50 rhel84 systemd[1]: Listening on Podman API Socket.

サービスの正常起動後、先に紹介したREST APIの確認手順で応答があれば準備完了です。

docker-compose.ymlの作成

docker-composeの実行サンプルアプリとしてWordPressを使用します。docker-composeの実行に必要なdocker-compose.ymlファイルは、Docker Hubに載っているものを流用します。

https://hub.docker.com/_/wordpress

適当なディレクトリを作成して、docker-compose.ymlファイルを配置してください。

# mkdir wordpress && cd wordpress
# vi docker-compose.yml

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:

DOCKER_HOST環境変数の設定

通常、docker-composeはdockerコマンドを介して実行されるため、DOCKER_HOST環境変数にはdockerデーモンのURLが指定されます。Podmanでdocker-composeを実行する場合は、podman.socketサービスで起動したPodman APIソケットを指定します。

# export DOCKER_HOST=unix:///run/podman/podman.sock

docker-composeの実行

docker-compose.ymlファイルがあるディレクトリでdocker-compose upを実行します。-dオプションをつけることでデタッチモードでの実行になります。

# docker-compose up -d
Starting wordpress_db_1        ... done
Starting wordpress_wordpress_1 ... done

正常にコンテナが実行されているか確認します。

# docker-compose ps
        Name                       Command               State       Ports
------------------------------------------------------------------------------
wordpress_db_1          docker-entrypoint.sh mysqld      Up
wordpress_wordpress_1   docker-entrypoint.sh apach ...   Up      :8080->80/tcp
# podman ps -a
CONTAINER ID  IMAGE                               COMMAND               CREATED         STATUS             PORTS                 NAMES
bd63862f4042  docker.io/library/wordpress:latest  apache2-foregroun...  12 minutes ago  Up 13 seconds ago  0.0.0.0:8080->80/tcp  wordpress_wordpress_1
bf023e2b9b71  docker.io/library/mysql:5.7         mysqld                12 minutes ago  Up 13 seconds ago                        wordpress_db_1

ブラウザでhttp://<ホストのIPアドレス>:8080へアクセスしてWordPressのインストール画面が表示されたらOKです。

WordPressのインストール画面
WordPressのインストール画面

(参考)podman network

docker-composeの実行時に自動的に専用のネットワーク(今回はwordpress_default)が作成されます。

# podman network ls
NAME               VERSION  PLUGINS
podman             0.4.0    bridge,portmap,firewall,tuning
wordpress_default  0.4.0    bridge,portmap,firewall,tuning,dnsname

作成されたネットワークの設定ファイルは/etc/cni/net.d/配下にあり、中身を確認することもできます。

# cat /etc/cni/net.d/wordpress_default.conflist

出力結果を開く

# cat /etc/cni/net.d/wordpress_default.conflist
{
   "args": {
      "podman_labels": {
         "com.docker.compose.network": "default",
         "com.docker.compose.project": "wordpress",
         "com.docker.compose.version": "1.29.2"
      }
   },
   "cniVersion": "0.4.0",
   "name": "wordpress_default",
   "plugins": [
      {
         "type": "bridge",
         "bridge": "cni-podman1",
         "isGateway": true,
         "ipMasq": true,
         "hairpinMode": true,
         "ipam": {
            "type": "host-local",
            "routes": [
               {
                  "dst": "0.0.0.0/0"
               }
            ],
            "ranges": [
               [
                  {
                     "subnet": "10.89.0.0/24",
                     "gateway": "10.89.0.1"
                  }
               ]
            ]
         }
      },
      {
         "type": "portmap",
         "capabilities": {
            "portMappings": true
         }
      },
      {
         "type": "firewall",
         "backend": ""
      },
      {
         "type": "tuning"
      },
      {
         "type": "dnsname",
         "domainName": "dns.podman",
         "capabilities": {
            "aliases": true
         }
      }
   ]
}

まとめ

RHEL 8.4から導入されたPodman v3を使ってdocker-composeを実行する方法をご紹介しました。RHEL 8.4に搭載されているPodman v3.0.1ではルートモードのみしかdocker-composeが実行できませんが、現在開発版として公開されているv3.2.0-RC1ではルートレスでdocker-composeが実行できることを確認しています。 RHEL 8.4でv3.2.0以降が使用できるようになった時は、ルートレスモードの実行方法についてもご紹介します。楽しみにしておいてください。

*1:本記事ではREST APIで統一して記載。REST APIはRESTful APIとも言います。REST APIに関するRed Hatの紹介ページはこちら。 https://www.redhat.com/ja/topics/api/what-is-a-rest-api

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。