はじめに
コンテナ経由でコンテナを作成するのに大きく2パターンある。
- ホストのDockerプロセスを使う場合
- Dockerプロセス内でさらにコンテナを作成 (DinD)
以下では、それぞれがどのように動作するかと、CIサーバを作成することで実際の利用シーンを確認していく。
CIでよくあるパターンで説明
GitlabCIやJenkinsなど、自分で実行環境を容易する場合、上の2パターンを併用するので違いがわかりやすい。構成としては↓のようになる。
1. ホストのDockerプロセスを使う
これは socket 経由でDockerデーモンに命令する。
以下のようにsocketファイルをマウントすれば、socket経由でDockerファイルを起動できる。
docker run -v /var/run/docker.sock:/var/run/docker.sock container
2. DinDの場合
Dockerコンテナ内で新たなDockerコマンドを呼び出せる。
ファイルシステムにアクセスするため、privilegedモードで実行する必要がある。
ただ、内部で実際にやってることは、1と大きく変わっていない。socket経由でDinDコンテナのDockerデーモンにアクセスしている。
実際にGitlabCIをコンテナだけで動かす
GCPのContainer-Optimized OSを利用して、GitlabCIをコンテナだけでGitlabRunner(CIを実行するサーバ)を動かすことで理解する。
Container-Optimized OSとは、Dockerコンテナの実行に最適化されたOSのことで、最近はこれを多用している。
サーバ作成
Compute Engine > VM instancesからインスタンスを作成
Container image : gitlab/gitlab-runner:latest
Directory mount:
Mount path | Host path | Mode |
---|---|---|
/var/run/docker.sock | /var/run/docker.sock | Read/write |
/etc/gitlab-runner | /var/gitlab-runner/config | Read/write |
このgitlab-runnerコンテナでは、privilegedである必要はないので、Run as privilegedはfalseでいい。
gitlab-runnerサーバの登録
サーバ作成時に指定したconfigファイルのパスをVolume mountして設定ファイルを保存する。
$ sudo docker run --rm -t -i -v /var/gitlab-runner/config:/etc/gitlab-runner gitlab/gitlab-runner register
ここで、gitlabサーバがホストされているドメインや、プロジェクト設定画面に表示されるトークンなどを入力していく。
入力が完了すると、/var/gitlab/runner/config 内にtomlファイルが作成される。このままだとDinDができないので、出力されたファイルを編集する必要がある。
[[runners]]
name = "sample"
url = "<url>"
token = "<token>"
executor = "docker"
[runners.docker]
tls_verify = false
image = "alpine:latest"
privileged = true // ここをtrueに変更
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = true // ここをtrueに変更
disable_cache=false
だとコンテナ作成時のデータがキャッシュされて、大量にゴミデータが残ってしまう。
.gitlab-ci.ymlを定義
たとえばコンテナ内でDockerビルドする場合は以下のように行う。
image: docker:stable
stages:
- deploy
variables:
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
services:
- docker:dind
deploy:
stage: deploy
script:
- docker build . -t sampleregistry.com/container:latest
- docker push sampleregistry.com/container:latest
以上で完了。
最後に
今回は、Dockerコマンドを、コンテナ内から呼ぶ方法を書いた。
Dockerコマンドが内部で何をやってるか、イメージがどのように構成されてるか、というのも最近調べたのでいずれ書きたい。