Podman in Docker を試してみた
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? なにそれおいしいの?
Docker も Podman もコンテナランタイム[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 Docker や Sibling Docker などを使えばコンテナ in コンテナっぽいことは可能だが、docker-compose の利用などの一手間が追加で必要になる。docker run
や podman 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
- なぜか podman パッケージの依存関係に tzdata が入っていないが、tzdata を入れないと以下のエラーで動かないので注意。
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"
- 識者による華麗な解決策を募集中です!
- 試した範囲ではなんともならなかった。例えば
-
Docker 社は Docker engine を container runtime と呼んでいるが、一方で例えばここを見ると、OCI 的には「コンテナランタイム」は containerd などの (Docker engine と比較すると)低レイヤーのものを指してるように見える。じゃあ Docker engine 相当はなんと呼べばいいのか… ↩︎
-
ワークフロー管理システムは直接インストールすればいい?今更自分でインストールやら依存関係の解決とかしたくないでござる!!!それはそれとして、Sapporo-service など、CLI で動く WfMS (cwltoolなど)を Web サービス化するシステムのデプロイを考えると、コンテナ化されたステップ以外(Sapporo の場合は Sapporo 自体+Sapporo でサポートする WfMS 全部)をホストにインストールするのは手間がかかりすぎる、という問題がある。 ↩︎
Discussion