時折、ある Docker コンテナの中から別の Docker 関連の何かに命令したい時があります。Docker コンテナ・ネットワークを経由して命令できれば楽のですが、そうもいかない時があります(完了したら exit する前提のイメージの使用など)。そういった時は Docker コンテナ内で新たに Docker を立ち上げるか、Docker コンテナ内から外の Docker デーモンに命令するかの二択になります。この記事では Docker コンテナ内から外の Docker デーモンに命令する方法を紹介します。ちなみに Docker outside of Docker でググるとこの方式について色々出てきます。
Docker コンテナ・ネットワークの理解 — Docker-docs-ja 17.06 ドキュメント
大筋はシンプルです。外側の Docker デーモンとやり取りする docker.sock を内側であるコンテナにマウント。コンテナ内から Docker Client を使ってマウントした docker.sock 経由で外側の Docker デーモンとやり取りします。例えば、次のコードでこれは実現できます。
# docker-compose.yml version: "3" services: app: build: context: ./docker/php volumes: - ./:/work # ここで docker.sock をマウントすると定義 - /var/run/docker.sock:/var/run/docker.sock
# docker-compose.yml に書いた ./docker/php 直下の Dockerfile FROM php:7.4-fpm-buster # 省略( PHP を構築する色々) # Docker Client をインストール ENV DOCKER_CLIENT_VERSION=latest # API_VERSION と Docker 自身のバージョン対応は次のリンクを参照 # @see https://docs.docker.com/engine/api/ # とりあえず外の Docker Client と合わせておけば動きます。 ENV DOCKER_API_VERSION=1.39 # Docker Client になるバイナリを入手. ドキュメントが古いのでもっといいやり方があるかもしれません。 # バイナリから Docker CE のインストール — Docker-docs-ja 17.06 ドキュメント # @see http://docs.docker.jp/engine/installation/linux/docker-ce/binaries.html RUN curl -fsSL https://get.docker.com/builds/Linux/x86_64/docker-${DOCKER_CLIENT_VERSION}.tgz \ | tar -xzC /usr/local/bin --strip=1 docker/docker
これでコンテナ内部から外の Docker デーモンを操作できます。具体的には内部のシェルで docker hoge とコマンドを打って外の Docker を操作できるわけです。例えば PHP 上からは exec 系統で次の様に動かせます。
// docker ps | grep java | awk '{print $1}' でコンテナ名 java のコンテナのコンテナIDを取得 // ここでは docker exec ですが、もちろん docker run も使えます echo shell_exec("docker exec $(docker ps | grep java | awk '{print $1}') java --version"); // openjdk 16-ea 2021-03-16 // OpenJDK Runtime Environment (build 16-ea+13-521) // OpenJDK 64-Bit Server VM (build 16-ea+13-521, mixed mode, sharing)
この様に Docker 間で直接命令するやり取りができる様になります。