KubernetesのPodでDockerコンテナを実行する
KubernetesのPodでDockerコンテナを実行する方法を紹介します。
Dockerコンテナ内でコンテナを起動する方法のことをDinD (Docker inside Docker)などと言われていますが、同じことをKubernetesのPodで実行するには少し工夫する必要があります。
アプローチとして2種類のやり方があり、双方にメリットとデメリットがあるため状況に合わせて適切なものを選択する必要があります。
アプローチ
1つめのやり方はPodが動いているホストマシンのDockerデーモンを共有する方法で、DooD (Docker outside of Docker)とよばれるものをPodに適応させたパターンです。
2つめのやり方はPod内でDockerデーモンを動かす、DinD (Docker inside Docker)と呼ばれるものを適応させたパターンです。
それぞれの方法のやり方とメリット・デメリットについて紹介します。
DooDパターン
DooDパターンをk8sに適応させるのは簡単で、ホストの /var/run
を共有してDockerデーモンにアクセスできるようにするだけです。
apiVersion: v1 kind: Pod metadata: name: dood spec: containers: - name: docker image: docker:19.03 command: ["docker", "run", "nginx:latest"] volumeMounts: - mountPath: /var/run name: docker-sock volumes: - name: docker-sock hostPath: path: /var/run
DooDパターンの場合、コンテナ内で作成されたコンテナはホストが管理するその他のコンテナと同列の扱いになることに注意する必要があります。
つまり、コンテナを作成したPodと同列の扱いのコンテナとなります。
しかしながらPod内で作成したコンテナはk8sの管理下にはありません。
また、もし他にもコンテナを作成するPodが存在した場合は、コンテナ名などのリソースが競合する可能性があるので注意しなければいけません。
偶然発生する可能性は低いですが、k8sのリソースと競合する可能性もあります。
コンテナのポートをマッピングする場合も注意が必要で、デーモンが動いているのはホストマシンになるためポートマッピングされるのもホストになります。
そのためコンテナを作成したPodのIPで作成したコンテナにはアクセスできません。ホストのIPでアクセスする必要があります。
また、k8sの管理から外れるため、Podに指定したリソース制限が適用されません。
さらに -d
としてコンテナを起動した場合はPodの削除時に作成したコンテナが削除されません。
このように様々な落とし穴があるため、k8sのPodの場合はDooDパターンはオススメしません。次に解説するDinDパターンを使うべきです。
メリット
- 特別な権限を与える必要がない
- コンテナを動かしたいイメージにDockerコマンドをインストールするだけで動かすことができる
デメリット
- Podの中ではなくホストマシンの中にコンテナが作成される
- k8sの管理下からはずれたところにコンテナが作成される
- ホストでリソースの競合が発生する可能性がある
DinDパターン
DinDパターンはDooDパターンと比べると少しだけ複雑です。
dockerコマンドを実行するコンテナのサイドカーとしてDockerデーモンを動かし、dockerコマンドがサイドカーに対してアクセスするように設定します。
以下がその設定をしたマニフェストファイルです。
apiVersion: v1 kind: Pod metadata: name: dind spec: containers: - name: docker image: docker:18.09 command: ["docker", "run", "nginx:latest"] env: - name: DOCKER_HOST value: tcp://localhost:2375 - name: dind-daemon image: docker:18.09-dind resources: requests: cpu: 20m memory: 512Mi securityContext: privileged: true
Dockerデーモンを動かすコンテナは公式のイメージがあるのでそれを使います。この公式イメージは2375ポートでDockerのREST APIを公開しています。
そこに対してDocker CLIがアクセスするように環境変数 DOCKER_HOST
を設定します。
DinDパターンでは作成したコンテナはDockerデーモンが動くサイドカーコンテナの中に作成されるため、Podに設定したCPUやメモリなどのリソースの制限を受けた状態でコンテナを作成できます。
また、このPodを削除したときに作成したコンテナも同時に削除されます。
ポートマッピングを使用したときもDockerデーモンが動いているネットワーク、つまりはPodのネットワークに対して行われるため、ホストのリソースを汚すことなくPodのIPでアクセスできます。
同様にコンテナ名などのリソース競合もPod内でしかおこりません。
ただし一つだけ意識しなければならないことがあり、Dockerデーモンが動くコンテナは privileged
権限で実行しなければいけません。ここが障害にならない限りDinDパターンを選択することをオススメします。
メリット
- Pod内にコンテナを作成できる
- ホストに影響を与えることなくPod内で完結する
- Podの設定(リソースやネットワーク)を引き継ぐことができる
デメリット
- サイドカーコンテナが1つ増える
- privilegedでコンテナを動かす必要がある
まとめ
privilegedで動かしても問題ない環境であればDinDパターンがオススメです。
DooDを使う場合はリソース競合など、ホスト側でコンテナが動いていることを忘れずに使う必要があります。