Podman in Docker を試してみた

7 min read読了の目安(約6400字

TL; DR

  • 以下の Dockerfile を使えばいい。Docker コンテナ内で rootless podman を利用できる。
  • 残念ながら --privileged オプションは必須。rootless ではない podman を使う場合でも同様。
    • そのため現状だと rootless の旨味がない。コンテナ内だけ rootless で動いても…
FROM alpine:edge

RUN echo -e "https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
    apk --no-cache add podman tzdata fuse-overlayfs && \
    echo -e "[storage]\n  driver = \"overlay\"\n  [storage.options]\n    mount_program = \"/usr/bin/fuse-overlayfs\"" > /etc/containers/storage.conf && \
    echo -e "[registries.search]\nregistries = ['docker.io', 'quay.io']" > /etc/containers/registries.conf && \
    adduser --disabled-password podman && \
    echo "podman:100000:65536" >> /etc/subuid && \
    echo "podman:100000:65536" >> /etc/subgid

USER podman
WORKDIR /home/podman
  • 以下は実行例:
$ docker build -t podman .
...
$ docker run --privileged --rm -it podman sh
~ $ podman run --rm -it ubuntu bash
Trying to pull docker.io/library/ubuntu...
Getting image source signatures
...
Writing manifest to image destination
Storing signatures
root@f1ababfdb4a9:/#

やったぜ。

Docker? Podman? なにそれおいしいの?

DockerPodman もコンテナランタイム[1]とかコンテナエンジンとか呼ばれるもの。Docker は現状のデファクトだが、root 権限が必要だったりデーモンとして動作させる必要があったりと、セキュリティや利便性に一部課題がある。Podman は後発のコンテナエンジンで、rootless(一般ユーザ)でも動き、またデーモン不要という特徴がある。両方とも OCI コンテナに対応しているため、動かせるコンテナイメージは同じ(はず)である。

最近はソフトウェアがコンテナイメージとして提供してあることも多い。ユーザーから見ると、Python 製だろうと Go 製だろうと docker pull, docker run, docker rmi などの統一的な方法でインストール・実行・アンインストールが可能(しかも各コンテナで完結しているので後腐れしない!)なので非常に便利。

一方で、単にコンテナ化するだけでは実質的に動かなくなるソフトウェアも存在する。例えばワークフロー管理システム (WfMS)、特に Scientific workflow を対象にする WfMS の場合、各ステップで動くツールも再現性の確保のためにコンテナ化されているため、コンテナ内でコンテナを動かす必要が出てくる[2]

Docker in Docker, Sibling Docker, Podman in Docker

現状でも Docker in DockerSibling Docker などを使えばコンテナ in コンテナっぽいことは可能だが、docker-compose の利用などの一手間が追加で必要になる。docker runpodman run だけでなんとかならないものか…

Docker がデーモンでしか動かないのが Docker in Docker が辛い理由(と理解している)なので、デーモン無しで動く podman を中に入れればホスト側は docker run のみでよくなるのでは?と考えていたところ、Alpine Linux のパッケージ一覧に podman があるのを見つけたため、Podman in Docker を試してみた。ついでに rootless podman in docker も試してみた。

できました。

以下は冒頭に貼った Dockerfile である。以下、雑に解説。

FROM alpine:edge

RUN echo -e "https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
    apk --no-cache add podman tzdata fuse-overlayfs && \
    echo -e "[storage]\n  driver = \"overlay\"\n  [storage.options]\n    mount_program = \"/usr/bin/fuse-overlayfs\"" > /etc/containers/storage.conf && \
    echo -e "[registries.search]\nregistries = ['docker.io', 'quay.io']" > /etc/containers/registries.conf && \
    adduser --disabled-password podman && \
    echo "podman:100000:65536" >> /etc/subuid && \
    echo "podman:100000:65536" >> /etc/subgid

USER podman
WORKDIR /home/podman

Podman in Docker のインストール

Podman in Docker は、基本的には Alpine Linux の testing リポジトリから podman パッケージをインストールすれば動く(おそらくホスト上の Alpine Linux で Podman を動かす場合も同様)。ただ、自分がやったときにはいくつか落とし穴があった。

  • echo -e "https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories

    • tagged repository を利用して podman とその依存パッケージのみを testing リポジトリからインストールする方法もある(そちらの方が一般的)が、そちらはうまくいかなかった。
  • apk --no-cache add podman tzdata (podman を動かすだけなら fuse-overlayfs は不要)

    • なぜか podman パッケージの依存関係に tzdata が入っていないが、tzdata を入れないと以下のエラーで動かないので注意。
      $ docker run --privileged --rm -it podman sh
      ~ $ podman run --rm -it ubuntu bash
      ERRO[0000]  error validating containers config: find timezone  in paths: /usr/share/zoneinfo, /etc/zoneinfo
      

Rootless Podman 用の各種設定

Rootless podman のために一般ユーザーの追加を行う必要がある。また Podman コンテナ(in Docker)内のユーザーと Docker コンテナ内のユーザーを対応付ける newuidmap と newgidmap の設定も合わせて追加する。

  • 一般ユーザー (今回は podman ユーザー) を追加
    • adduser --disabled-password podman
    • USER podman
    • WORKDIR /home/podman
  • newuidmap および newgidmap の設定を追加
    • echo "podman:100000:65536" >> /etc/subuid
    • echo "podman:100000:65536" >> /etc/subgid

vfs の代わりに fuse-overlayfs を利用する

これまでの設定だと Podman はレイヤー管理に vfs を用いるが、コンテナイメージをあまり賢く管理してくれないらしい。
fuse-overlayfs を入れることで、レイヤーの共有などを行ってくれるようになる。

  • apk --no-cache add fuse-overlayfs
  • echo -e "[storage]\n driver = \"overlay\"\n [storage.options]\n mount_program = \"/usr/bin/fuse-overlayfs\"" > /etc/containers/storage.conf

おまけ

これだけでも動作するが、このままだとイメージ名(e.g., alpine:3.12)をコンテナレジストリ名からフルで入力する(e.g., docker.io/library/alpine:3.12)必要があり、手間がかかる。/etc/containers/registries.conf にコンテナレジストリを列挙することで、レジストリ部分などを省略することができるようになる。

  • echo -e "[registries.search]\nregistries = ['docker.io', 'quay.io']" > /etc/containers/registries.conf

今後の課題

  • --privileged なんとかならない?
    • 試した範囲ではなんともならなかった。例えば --privileged ではないが、ほとんどフルオープンの --cap-add=ALL を使っても動かない(--cap-add=SYS_ADMIN だけあればよさそうだが、どちらにしても動かない)。
      $ docker run --cap-add=ALL --security-opt=seccomp=unconfined --device /dev/fuse --rm -it podman sh
      ~ $ podman run --rm -it ubuntu bash
      Trying to pull docker.io/library/ubuntu...
      Getting image source signatures
      ...
      Writing manifest to image destination
      Storing signatures
      Error: /usr/bin/slirp4netns failed: "WARNING: Support for seccomp is experimental\nopen(\"/dev/net/tun\"): No such file or directory\nchild failed(1)\n"
      
    • 識者による華麗な解決策を募集中です!
脚注
  1. Docker 社は Docker engine を container runtime と呼んでいるが、一方で例えばここを見ると、OCI 的には「コンテナランタイム」は containerd などの (Docker engine と比較すると)低レイヤーのものを指してるように見える。じゃあ Docker engine 相当はなんと呼べばいいのか… ↩︎

  2. ワークフロー管理システムは直接インストールすればいい?今更自分でインストールやら依存関係の解決とかしたくないでござる!!!それはそれとして、Sapporo-service など、CLI で動く WfMS (cwltoolなど)を Web サービス化するシステムのデプロイを考えると、コンテナ化されたステップ以外(Sapporo の場合は Sapporo 自体+Sapporo でサポートする WfMS 全部)をホストにインストールするのは手間がかかりすぎる、という問題がある。 ↩︎