Zenn
🐳

Docker outside of Docker (DooD)の実践ガイド

に公開
1

目次

  1. はじめに
  2. DooD vs DinD
  3. DooD実装手順
  4. セキュリティ上の考慮事項
  5. トラブルシューティング
  6. ユースケース
  7. まとめ
  8. 参考資料

はじめに

本記事では、Dockerコンテナの中からホストマシンのDocker Daemonにアクセスし、他のコンテナを操作するための「Docker outside of Docker (DooD)」について説明します。

なぜ調べたか

Dockerコンテナの中からホストマシンのDocker Daemonで管理されているコンテナを利用したいという要件がありました。また、Docker in Docker(DinD)の情報に対し、DooDの情報が少ないと感じたため、記事としてまとめました。

DooD vs DinD

Dockerコンテナ内でDockerを扱う方法には主に2つのアプローチがあります

  1. Docker in Docker (DinD)

    • コンテナ内に完全なDockerエンジンをインストール
    • コンテナ内で独立したDockerデーモンが動作
    • 特権モード(--privileged)が必要
    • イメージやコンテナはホストと分離される
  2. 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ユーザーでの実行は推奨されません。

一般ユーザーでの実行(推奨)

一般ユーザーでコンテナを実行する場合は以下の手順を踏みます

  1. ホストマシンの/var/run/docker.sockをコンテナ内にマウント
  2. コンテナ内のユーザーをホストマシンの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グループに属していない場合に発生します。以下を確認してください。

  1. コンテナ起動時に--group-addオプションまたは適切なGID設定が行われているか
  2. マウントされたdocker.sockの権限が適切か(660)
  3. コンテナ内でユーザーの所属グループを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が正しくマウントされていない場合に発生します。以下を確認してください。

  1. -v /var/run/docker.sock:/var/run/docker.sockオプションが指定されているか
  2. ホストマシンでDockerデーモンが実行されているか
  3. ソケットファイルの存在確認:ls -l /var/run/docker.sock

まとめ

本記事では、Dockerコンテナ内からホストマシンのDocker Daemonを操作する「Docker outside of Docker (DooD)」の実装方法について解説しました。しかし、ホストのdocker.sockをマウントすることで、実質的に特権モードと同じリスクが生じるため、rootユーザーでの利用は控えるなど、適切なセキュリティ対策が必須です。

頻繁に用いる技術ではないと思いましたが、知っていればいつか役に立つかも、とも思った技術でした。

参考資料

  1. Docker Engine インストールガイド (Ubuntu)
  2. Docker outside of Docker vs Docker in Docker
  3. Docker セキュリティベストプラクティス
  4. Rootless Docker
1

Discussion

ログインするとコメントできます