Docker outside of Docker (DooD)の実践ガイド
目次
はじめに
本記事では、Dockerコンテナの中からホストマシンのDocker Daemonにアクセスし、他のコンテナを操作するための「Docker outside of Docker (DooD)」について説明します。
なぜ調べたか
Dockerコンテナの中からホストマシンのDocker Daemonで管理されているコンテナを利用したいという要件がありました。また、Docker in Docker(DinD)の情報に対し、DooDの情報が少ないと感じたため、記事としてまとめました。
DooD vs DinD
Dockerコンテナ内でDockerを扱う方法には主に2つのアプローチがあります
-
Docker in Docker (DinD):
- コンテナ内に完全なDockerエンジンをインストール
- コンテナ内で独立したDockerデーモンが動作
- 特権モード(
--privileged
)が必要 - イメージやコンテナはホストと分離される
-
Docker outside of Docker (DooD):
- コンテナ内にDocker CLIのみをインストール
- ホストマシンのDocker socketをマウントして利用
- 特権モードは不要だが、ホストのDockerデーモンを制御できるため、実質的に特権モードと同じリスクがある
- ホストマシンのイメージやコンテナを直接操作できる
今回は後者のDooDアプローチを解説します。
DooD実装手順
Dockerコンテナ内のOS確認
コンテナのOSによってdocker-ce-cliのインストール方法が異なるため、確認します。Linuxであれば以下のコマンドで確認可能です。なお、以降の記事ではLinuxをベースとしたコンテナを前提とします。
cat /etc/*-release
docker-ce-cliのインストール
DooDの実現にはDockerエンジン全体ではなく、CLIツールだけをインストールすれば十分です。docker-ce-cli
のみをインストールし、Docker DaemonやContainer Runtimeなどはホストマシンのものを利用します。
OS | インストールコマンド |
---|---|
Ubuntu(Debian) | apt-get install docker-ce-cli |
Alpine | apk add docker-cli |
CentOS/RHEL | yum install docker-ce-cli |
Ubuntu/DebianではaptライブラリにDockerの公式リポジトリを追加する必要があります。以下はUbuntu 22.04の例です
FROM ubuntu:22.04
# Docker公式のGPGキーを追加
RUN apt-get update \
&& apt-get install -y ca-certificates curl gnupg \
&& install -m 0755 -d /etc/apt/keyrings \
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc \
&& chmod a+r /etc/apt/keyrings/docker.asc
# リポジトリを apt sources に追加
RUN echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null \
&& apt-get update \
&& apt-get install -y --no-install-recommends docker-ce-cli \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
Dockerイメージのビルド
作成したDockerfileからイメージをビルドします
docker build -f Dockerfile -t dood-example .
Dockerコンテナの実行
Dockerコンテナを実行する際、ログインユーザーがrootか一般ユーザーかで対応が異なります。この違いは、ホストマシンにおけるdocker.sock
ファイルの権限が660になっているため生じます。
# ホストマシンのdocker.sockの権限確認
$ ls -l /var/run/docker.sock
srw-rw---- 1 root docker 0 Mar 25 2024 /var/run/docker.sock
rootユーザーでの実行(非推奨)
rootユーザーでコンテナを実行する場合、ホストのdocker.sock
をマウントするだけで動作します
docker run -it -v /var/run/docker.sock:/var/run/docker.sock dood-example
ただし、セキュリティ上の理由からrootユーザーでの実行は推奨されません。
一般ユーザーでの実行(推奨)
一般ユーザーでコンテナを実行する場合は以下の手順を踏みます
- ホストマシンの
/var/run/docker.sock
をコンテナ内にマウント - コンテナ内のユーザーをホストマシンの
docker
グループに追加
docker run -it \
-v /var/run/docker.sock:/var/run/docker.sock \
-u $(id -u $USER):$(id -g $USER) \
--group-add $(grep docker /etc/group | cut -d: -f3) \
dood-example
動作確認
コンテナに入ったら、docker images
コマンドを実行してみます。正しく設定できていれば、ホストマシンに保存されているDockerイメージ一覧が表示されます。
docker images
さらに、簡単なコンテナを起動して、DooD機能が正しく動作していることを確認できます。
docker run --rm hello-world
セキュリティ上の考慮事項
DooD方式には以下のセキュリティリスクがあることを認識しておく必要があります。
1. 実質的な特権モードのリスク
DooDでは --privileged
を指定しなくてもホストのDocker Daemonを利用できるため、コンテナがホストを完全に制御可能 になります。
例えば、コンテナ内から以下のコマンドを実行すると、ホスト上に特権コンテナを作成できます。
docker run --privileged -it --pid=host --network=host -v /:/host alpine sh
このコンテナ内から /host
にアクセスすれば、ホストのファイルシステム全体にアクセスできます。このため、コンテナが侵害されるとホストごと乗っ取られる可能性があります。
2. 権限設定の問題と対策
最小権限の原則を適用する
- Docker APIへのアクセスを制限する
- SELinux や AppArmor を利用してコンテナの制御を制限する
- rootless Docker の活用を検討する
3. コンテナ隔離のためのテクニック
セキュリティリスクを低減するための追加対策としてコンテナのルートファイルシステムを読み取り専用にする方法が挙げられます。
-
読み取り専用ファイルシステム:
docker run --read-only ...
トラブルシューティング
「permission denied」エラーが発生する場合
Got permission denied while trying to connect to the Docker daemon socket
このエラーは一般ユーザーがdockerグループに属していない場合に発生します。以下を確認してください。
- コンテナ起動時に
--group-add
オプションまたは適切なGID設定が行われているか - マウントされた
docker.sock
の権限が適切か(660) - コンテナ内でユーザーの所属グループを
id
で表示、dockerグループが含まれているか確認
「Cannot connect to the Docker daemon」エラーが発生する場合
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
このエラーはDocker socketが正しくマウントされていない場合に発生します。以下を確認してください。
-
-v /var/run/docker.sock:/var/run/docker.sock
オプションが指定されているか - ホストマシンでDockerデーモンが実行されているか
- ソケットファイルの存在確認:
ls -l /var/run/docker.sock
まとめ
本記事では、Dockerコンテナ内からホストマシンのDocker Daemonを操作する「Docker outside of Docker (DooD)」の実装方法について解説しました。しかし、ホストのdocker.sock
をマウントすることで、実質的に特権モードと同じリスクが生じるため、rootユーザーでの利用は控えるなど、適切なセキュリティ対策が必須です。
頻繁に用いる技術ではないと思いましたが、知っていればいつか役に立つかも、とも思った技術でした。
Discussion