コンテナからコンテナを操作する


なぜコンテナからコンテナを操作するのか?

「コンテナからコンテナを操作したい!」なんて思ったことはないでしょうか?
以下は私が開発したブラウザでプログラムを実行できるアプリのアーキテクチャ図です。いわゆる、Paiza.IOのようなものです。

あれ?コンテナ(Golang)からコンテナ(Python)に矢印が向いていますよね。これはコンテナ(Golang)で外部コマンドを叩き、公式のPython Imageからコンテナを起動しPythonファイルを実行してもらい結果を取得しています。

そんなことしなくてもEC2にDockerをインストールしてホストからDocker起動する方が良くね?って思うかもしれません。ですが筆者はどうしてもECSにまるっと任せたかったのです。その方がEC2に1からインストールしなくていいしデプロイも簡単だと思ったからです。(興味本位でDockerからDockerを起動したいと思ったのもある)

コンテナからコンテナを操作する方法

DinD(Docker in Docker)とDooD(Docker outside of Docker)の2パターンがあります。詳しく見ていきましょう。

DinD(Docker in Docker)

Dockerがインストールされているコンテナを使用しコンテナ内でホストとは別にDockerデーモンを動かす方法です。

現在起動中のコンテナを確認してください。(最低1つあると今回の検証が理解できます)

$ docker ps

dockerがインストールされているコンテナをバックグラウンドで実行します。

$ docker run --privileged --name dind -d docker:dind

コンテナの中に入ります。

$ docker exec -it dind sh

起動中のコンテナを確認してください。何も表示されないはずです。

$ docker ps

DinDではホストのDockerとは別のDockerが利用することができます。

DooD(Docker outside of Docker)

コンテナ側からホストのdocker.sock (/var/run/docker.sock)をマウントすることでコンテナ上のDockerコマンドはホスト側のDocker環境で実行される。Dockerがインストールされているコンテナを使用するのはDinDと同じ

先程と同じように起動中のコンテナを確認します(最低1つあると今回の検証が理解できます)

$ docker ps

コンテナを起動して中に入ります。この時、ホストのdocker.sockをマウントする。

$ docker run -it -v /var/run/docker.sock:/var/run/docker.sock docker sh

起動中のコンテナを確認してください。ホストのコンテナ一覧が表示される。

$ docker ps

このようにDooDではホスト側のDocker環境を共用することができる。

マルチステージングビルド

じゃあコンテナ(Golang)にDockerをインストールしなければコンテナ(Python)を使用することができません。結論から言うと今回はマルチステージングビルドを用いました。

Dockerfile
FROM golang:latest AS builder

RUN mkdir /go/src/work

WORKDIR /go/src/work

COPY main.go .

RUN CGO_ENABLED=0 GOOS=linux go build main.go

FROM docker:latest

COPY --from=builder /go/src/work/main ./

EXPOSE 10000

おまけ(コンテナ間マウント)

このアプリを作成する上でコンテナ間マウントという技を使ったのでメモ代わりに --volumes-from <マウント元のコンテナ> とすることでコンテナ間マウントができる。サンプルは以下の通りです↓

$ docker run -it --volumes-from code python bash

しかしここで注意です、ECSのタスク定義にて決定したコンテナ名になっていないようでコンテナの名前をつけ変えるには以下のようにすることで名前を変更できます。

$ docker rename <Container ID> code

参考文献