- Runnerの設定
- DockerレイヤーキャッシングでDocker-in-Dockerビルドを高速化する
- OverlayFS ドライバの使用
- GitLabコンテナレジストリの使用
- トラブルシューティング
GitLab CI/CDによるDockerイメージのビルド
GitLab CI/CDを使用することで、Docker Engineを使用した、Dockerベースプロジェクトのビルドおよびテストができます。
継続的インテグレーション/継続的デプロイにおける、この新しいトレンドを説明します。
- アプリケーションイメージを作成します。
- 作成したイメージに対してテストを実行します。
- イメージをリモートレジストリにプッシュします。
- プッシュしたイメージからサーバーにデプロイします。
また、画像を作成しテストするために使用できるDockerfile
をアプリケーションがすでに持っている場合にも便利です:
docker build -t my-image dockerfiles/
docker run my-image /script/to/run/tests
docker tag my-image my-registry:5000/my-image
docker push my-registry:5000/my-image
ジョブ中にdocker
サポートを有効にするには、GitLab Runnerの特別な設定が必要です。
Runnerの設定
ジョブ中にdocker build
、docker run
。それぞれトレードオフがあります。
docker build
、kanikoを使用する方法もあります。これにより、特権モードでRunnerを実行する必要がなくなります。
shell-executorの使用
最もシンプルな方法は、GitLab Runnerをshell
実行モードでインストールすることです。GitLab Runnerはgitlab-runner
ユーザーとしてジョブスクリプトを実行します。
-
GitLab Runnerをインストールします
-
GitLab Runnerのインストール中に、ジョブスクリプトの実行方法として
shell
を選択するか、コマンドを使用します:sudo gitlab-runner register -n \ --url https://gitlab.com/ \ --registration-token REGISTRATION_TOKEN \ --executor shell \ --description "My Runner"
-
Docker Engineをサーバーにインストールします。
異なるシステムへのDocker Engineのインストール方法については、サポートされているインストール方法を参照してください。
-
docker
グループにgitlab-runner
ユーザーを追加します:sudo usermod -aG docker gitlab-runner
-
gitlab-runner
が Docker にアクセスできることを確認します:sudo -u gitlab-runner -H docker info
.gitlab-ci.yml
にdocker info
を追加することで、すべてが機能することを確認できます:before_script: - docker info build_image: script: - docker build -t my-docker-image . - docker run my-docker-image /script/to/run/tests
-
これで
docker
コマンドが使えるようになります(必要であればdocker-compose
もインストールします)。
gitlab-runner
をdocker
グループに追加することで、事実上gitlab-runner
に完全な root 権限を与えることになります。詳しくはOn Dockersecurity:docker
group considered harmfulをお読みください。Docker executorを使用したDocker-in-Dockerのワークフロー
2つ目の方法は、すべてのツールがインストールされた特別なDocker-in-Docker(dind)Dockerイメージ(docker
)を使用し、特権モードでそのイメージのコンテキストでジョブスクリプトを実行する方法です。
docker-compose
Docker-in-Docker(dind)の一部ではありません。 docker-compose
CIビルドでdocker-compose
使用 docker-compose
するには、docker-compose
のインストール手順に従ってください。Docker-in-Dockerはうまく動作し推奨される構成ですが、独自の課題もあります。
- Docker-in-Dockerを使用する場合、各ジョブは過去の履歴のないクリーンな環境にあります。同時実行のジョブはビルドごとにDockerエンジンのインスタンスを取得するので問題なく動作しますが、レイヤーのキャッシュがないため、ジョブの処理速度が遅くなることがあります。
- デフォルトでは、Docker 17.09以降では推奨のストレージドライバである
--storage-driver overlay2
。 詳細はoverlayfsドライバの使用を参照してください。 -
docker:19.03.11-dind
コンテナと Runner コンテナはルートファイルシステムを共有しないので、ジョブの作業ディレクトリを子コンテナのマウントポイントとして使用することができます。 たとえば、子コンテナと共有したいファイルがある場合、/builds/$CI_PROJECT_PATH
の下にサブディレクトリを作成し、それをマウントポイントとして使用することができます(より詳細な説明については、イシュー#41227を参照してください):variables: MOUNT_POINT: /builds/$CI_PROJECT_PATH/mnt script: - mkdir -p "$MOUNT_POINT" - docker run -v "$MOUNT_POINT:/mnt" my-docker-image
このアプローチを使用したプロジェクトの例は、ここにありますhttps://gitlab.com/gitlab-examples/docker:
以下の例では、Docker imagesのタグを使用して、docker:19.03.11
のように特定のバージョンを指定しています。docker:stable
のようなタグを使用すると、どのバージョンが使用されるかを制御することができず、特に新しいバージョンがリリースされたときに、予測不可能な動作につながる可能性があります。
TLS有効化
DockerデーモンはTLS経由の接続をサポートしており、Docker 19.03.11以降ではデフォルトで使用されています。これは、推奨された方法です。Docker-in-DockerサービスとGitLab.com 共有 Runnersが対応しています。
-
GitLab Runnerをインストールします
-
コマンドラインからGitLab Runnerを登録し、
docker
、privileged
モードを使用します:sudo gitlab-runner register -n \ --url https://gitlab.com/ \ --registration-token REGISTRATION_TOKEN \ --executor docker \ --description "My Docker Runner" \ --docker-image "docker:19.03.11" \ --docker-privileged \ --docker-volumes "/certs/client"
上記のコマンドは、Dockerが提供する特別な
docker:19.03.11
イメージを使用する新しいRunnerを登録します。ビルドとサービスコンテナを起動するためにprivileged
モードを使用していることに注意してください。 Docker-in-Dockerモードを使用したい場合は、常にDockerコンテナでprivileged = true
。/certs/client
これは、Dockerクライアントがそのディレクトリ内部の証明書を使用するために必要です。 Docker with TLSがどのように機能するかについては、https://hub.docker.com/_/docker/#tlsを参照してください。上記のコマンドを実行すると、次のような
config.toml
のエントリーが作成されます:[[runners]] url = "https://gitlab.com/" token = TOKEN executor = "docker" [runners.docker] tls_verify = false image = "docker:19.03.11" privileged = true disable_cache = false volumes = ["/certs/client", "/cache"] [runners.cache] [runners.cache.s3] [runners.cache.gcs]
-
ビルドスクリプトで
docker
を使用できるようになりました(docker:19.03.11-dind
サービスが内部に含まれていることに注意してください):image: docker:19.03.11 variables: # When using dind service, we need to instruct docker, to talk with # the daemon started inside of the service. The daemon is available # with a network connection instead of the default # /var/run/docker.sock socket. Docker 19.03 does this automatically # by setting the DOCKER_HOST in # https://github.com/docker-library/docker/blob/d45051476babc297257df490d22cbd806f1b11e4/19.03/docker-entrypoint.sh#L23-L29 # # The 'docker' hostname is the alias of the service container as described at # https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#accessing-the-services. # # Note that if you're using GitLab Runner 12.7 or earlier with the Kubernetes executor and Kubernetes 1.6 or earlier, # the variable must be set to tcp://localhost:2376 because of how the # Kubernetes executor connects services to the job container # DOCKER_HOST: tcp://localhost:2376 # # Specify to Docker where to create the certificates, Docker will # create them automatically on boot, and will create # `/certs/client` that will be shared between the service and job # container, thanks to volume mount from config.toml DOCKER_TLS_CERTDIR: "/certs" services: - docker:19.03.11-dind before_script: - docker info build: stage: build script: - docker build -t my-docker-image . - docker run my-docker-image /script/to/run/tests
TLS無効化
例えば、使用しているGitLab Runnerの設定をコントロールできないなど、TLSを無効にしたい正当な理由がある場合があります。
Runnerconfig.toml
:
[[runners]]
url = "https://gitlab.com/"
token = TOKEN
executor = "docker"
[runners.docker]
tls_verify = false
image = "docker:19.03.11"
privileged = true
disable_cache = false
volumes = ["/cache"]
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
ビルドスクリプトでdocker
を使用できるようになりました(docker:19.03.11-dind
サービスが内部に含まれていることに注意してください):
image: docker:19.03.11
variables:
# When using dind service we need to instruct docker, to talk with the
# daemon started inside of the service. The daemon is available with
# a network connection instead of the default /var/run/docker.sock socket.
#
# The 'docker' hostname is the alias of the service container as described at
# https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#accessing-the-services
#
# Note that if you're using GitLab Runner 12.7 or earlier with the Kubernetes executor and Kubernetes 1.6 or earlier,
# the variable must be set to tcp://localhost:2375 because of how the
# Kubernetes executor connects services to the job container
# DOCKER_HOST: tcp://localhost:2375
#
DOCKER_HOST: tcp://docker:2375
#
# This will instruct Docker not to start over TLS.
DOCKER_TLS_CERTDIR: ""
services:
- docker:19.03.11-dind
before_script:
- docker info
build:
stage: build
script:
- docker build -t my-docker-image .
- docker run my-docker-image /script/to/run/tests
Dockerソケットバインディングの使用
3つ目の方法は、/var/run/docker.sock
をコンテナにバインドマウントして、Dockerがそのイメージのコンテキストで利用できるようにする方法です。
docker:19.03.11-dind
をサービスとして使用できなくなり、互換性がなくなります。そのためには、以下の手順に従ってください。
-
GitLab Runnerをインストールします
-
コマンドラインから GitLab Runner を登録して
docker
を使用し、/var/run/docker.sock
を共有します:sudo gitlab-runner register -n \ --url https://gitlab.com/ \ --registration-token REGISTRATION_TOKEN \ --executor docker \ --description "My Docker Runner" \ --docker-image "docker:19.03.11" \ --docker-volumes /var/run/docker.sock:/var/run/docker.sock
上記のコマンドは、Dockerによって提供される特別な
docker:19.03.11
イメージを使用する新しいRunnerを登録します。Runner自体のDockerデーモンを使用しており、Dockerコマンドによって生成されたコンテナはRunnerの子ではなくRunnerの兄弟になることに注意してください。これは、ワークフローに適さない複雑さや制限があるかもしれません。上記のコマンドを実行すると、次のような
config.toml
のエントリーが作成されます:[[runners]] url = "https://gitlab.com/" token = REGISTRATION_TOKEN executor = "docker" [runners.docker] tls_verify = false image = "docker:19.03.11" privileged = false disable_cache = false volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"] [runners.cache] Insecure = false
-
これでビルドスクリプトで
docker
(Docker in Docker executorを使用する場合のようにdocker:19.03.11-dind
サービスをインクルードする必要はないことに注意してください)を使用できるようになりました:image: docker:19.03.11 before_script: - docker info build: stage: build script: - docker build -t my-docker-image . - docker run my-docker-image /script/to/run/tests
上記の方法では特権モードでのDockerの使用を避けることができますが、以下のような意味合いがあることに注意してください。
- Dockerデーモンを共有することで、コンテナのすべてのセキュリティメカニズムを事実上無効にし、コンテナの脱走につながる特権の昇格にホストをさらすことになります。 例えば、プロジェクトが
docker rm -f $(docker ps -a -q)
、GitLab Runnerコンテナを削除します。 - 特定の名前を持つコンテナをテストで作成している場合、それらのコンテナは互いに競合する可能性があります。
-
ソースリポジトリからコンテナにファイルやディレクトリを共有しても、ボリュームマウントはビルドコンテナではなくホストマシンのコンテキストで行われるため、期待通りにはいかない場合があります。 例えば、以下のようになります。
docker run --rm -t -i -v $(pwd)/src:/home/app/src test-image:latest run_app_tests
DockerレイヤーキャッシングでDocker-in-Dockerビルドを高速化する
Docker-in-Dockerを使用する場合、Dockerはビルドを作成するたびにイメージの全レイヤーをダウンロードします。Dockerの最近のバージョン(Docker 1.13以上)では、docker build
ステップで既存のイメージをキャッシュとして使用することができ、ビルドプロセスを大幅に高速化できます。
Dockerのキャッシングの仕組み
docker build
を実行すると、Dockerfile
の各コマンドはレイヤーを生成します。これらのレイヤーはキャッシュとして保持され、変更がなければ再利用することができます。 1つのレイヤーを変更すると、それ以降のすべてのレイヤーが再作成されます。
docker build
コマンドのキャッシュソースとして使用するタグ付き画像は、--cache-from
引数で --cache-from
指定できます--cache-from
。複数の引数を使用することで、複数の画像をキャッシュソースとして指定 --cache-from
できます。--cache-from
引数で使用する画像は、キャッシュソースとして使用する前に、(docker pull
を使用して)最初にプルする必要があることに注意してください。
Dockerキャッシングの使用
.gitlab-ci.yml
、Dockerキャッシュの使い方を紹介します:
image: docker:19.03.11
services:
- docker:19.03.11-dind
variables:
# Use TLS https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#tls-enabled
DOCKER_HOST: tcp://docker:2376
DOCKER_TLS_CERTDIR: "/certs"
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
build:
stage: build
script:
- docker pull $CI_REGISTRY_IMAGE:latest || true
- docker build --cache-from $CI_REGISTRY_IMAGE:latest --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --tag $CI_REGISTRY_IMAGE:latest .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker push $CI_REGISTRY_IMAGE:latest
build
ステージのscript
セクションのステップをまとめると、次のようになります:
- 最初のコマンドは、
docker build
コマンドのキャッシュとして使用できるように、レジストリからイメージを取り出そうとします。 - 2番目のコマンドは、プルされたイメージが利用可能であれば、それをキャッシュとして使ってDockerイメージをビルドし(
--cache-from $CI_REGISTRY_IMAGE:latest
引数に注目)、タグ付けします。 - 最後の2つのコマンドは、タグ付けされたDockerイメージをコンテナレジストリにプッシュし、その後のビルドでもキャッシュとして使用できるようにします。
OverlayFS ドライバの使用
overlay2
ドライバを使用します。デフォルトでは、docker:dind
を使用する場合、Docker はvfs
ストレージドライバを使用し、実行毎にファイルシステムをコピーします。 これはディスクを大量に消費するオペレーションですが、別のドライバ、例えばoverlay2
を使用すれば回避できます。
要件
- 最近のカーネルが使われていることを確認してください。できれば
>= 4.2
。 -
overlay
モジュールがロードされているかチェックします:sudo lsmod | grep overlay
結果が表示されない場合は、モジュールがロードされていないことを示しています。モジュールをロードするには、次のようにします。
sudo modprobe overlay
すべてがうまくいった場合、再起動時にモジュールがロードされるようにする必要があります。 Ubuntuシステムでは、
/etc/modules
を編集して行います。 以下の行を追加するだけです:overlay
プロジェクトごとにOverlayFSドライバ使用
.gitlab-ci.yml
でDOCKER_DRIVER
環境変数を使用することで、プロジェクトごとにドライバを有効にすることができます:
variables:
DOCKER_DRIVER: overlay2
すべてのプロジェクトでのOverlayFSドライバ使用
独自の GitLabRunnerを使っている場合は、config.toml
](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section)の[[[runners]]
セクションでDOCKER_DRIVER
環境変数を設定することで、プロジェクトごとにドライバを有効にすることができます:
environment = ["DOCKER_DRIVER=overlay2"]
複数のRunnerを実行している場合は、すべての設定ファイルを修正する必要があります。
GitLabコンテナレジストリの使用
Dockerイメージをビルドしたら、そのイメージを組み込みのGitLab Container Registryにプッシュします。
トラブルシューティング
docker: Cannot connect to the Docker daemon at tcp://docker:2375. Is the docker daemon running?
Dockerv19.03以上でDockerを使用している場合によくあるエラーです。
これは、Dockerが自動的にTLS上で起動するために発生します。
- 初めて設定する場合、Docker-in-Dockerのワークフローを熟読してください。
- v18.09以前のバージョンからアップグレードする場合は、アップグレードガイドをお読みください。