- 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
をジョブで使用できるようにするには、3つの方法があります。
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のインストール方法については、サポートされているインストール方法を参照してください。
-
gitlab-runner
のユーザーをdocker
グループに追加します。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権限を与えることになります。より詳しい情報はDockerのセキュリティについてを参照してください。docker
グループは危険があると考えられています。Docker executorを使用したDocker-in-Dockerのワークフロー
2つ目のアプローチは、特別なDocker-in-Docker(dind)Dockerイメージをすべてのツール(docker
)がインストールされた状態で使用し、そのイメージのコンテキストでジョブスクリプトを特権モードで実行することです。
docker-compose
はDocker-in-Docker(dind)の一部ではありません。docker-compose
をCIビルドで使用するには、docker-compose
のインストール手順に従ってください。--docker-privilegedを
有効にすると、コンテナのすべてのセキュリティメカニズムを事実上無効にし、コンテナからの脱獄につながる権限昇格の危険性にホストをさらすことになります。詳細については、ランタイム権限とLinuxの機能に関するDockerの公式ドキュメントを参照してください。Docker-in-Dockerはうまく動作し推奨される構成ですが、独自の課題もあります。
- Docker-in-Dockerを使用する場合、各ジョブは過去の履歴のないクリーンな環境にあります。同時実行のジョブはビルドごとにDockerエンジンのインスタンスを取得するので問題なく動作しますが、レイヤーのキャッシュがないため、ジョブの処理速度が遅くなることがあります。
- デフォルトでは、Docker 17.09以降では推奨ストレージドライバである
--storage-driver overlay2
を使用しています。詳細はoverlayfsドライバの使用を参照してください。 -
docker:19.03.11-dind
コンテナとRunnerコンテナはルートファイルシステムを共有していないので、ジョブの作業ディレクトリを子コンテナのマウントポイントとして使えます。例えば、子コンテナと共有したいファイルがある場合、/builds/$CI_PROJECT_PATH
の下にサブディレクトリを作成し、それをマウントポイントとして使えます(より詳細な説明はissue #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:19.03.11の
ように特定のバージョンを指定してDocker imagesタグを使用しています。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を登録します。ビルドとサービスコンテナを起動するために特権
モードを使用していることに注意してください。Docker-in-Dockerモードを使用したい場合は、Dockerコンテナでprivileged = true
を使用しなければなりません。これは
Docker
クライアントがそのディレクトリ内の証明書を使うために必要なものです。TLSを使ったDockerの動作の詳細については、以下を参照してください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を無効にしたい正当な理由がある場合があります。
Runnerの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 = ["/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のビルドステップ
で既存のイメージをキャッシュとして使用でき、ビルドプロセスを大幅に高速化できます。
Dockerのキャッシングの仕組み
docker build
を実行すると、Dockerfile
の各コマンドはレイヤーになります。これらのレイヤーはキャッシュとして保存され、変更がなければ再利用できます。1つのレイヤーを変更すると、それ以降のすべてのレイヤーが再作成されます。
--cache-from
引数を使用することで、docker build
コマンドのキャッシュソースとして使用するタグ付きイメージを指定できます。複数のイメージをキャッシュソースとして指定するには、複数の --cache-from
引数を使用します。--cache-from
引数で使用するイメージは、キャッシュソースとして使用する前に(docker pull
を使用して)最初にプルされていなければならないことに注意してください。
Dockerキャッシングの使用
以下は、Dockerのキャッシングがどのように使えるかを示す.gitlab-ci.yml
ファイルです。
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
のようなを別のドライバを使用することで、これを回避できます。
要件
- 最新のカーネルが使用されていることを確認してください。
-
overlay
モジュールがロードされているかどうかを確認してください。sudo lsmod | grep overlay
結果が表示されない場合は、モジュールがロードされていないことを示しています。モジュールをロードするには、次のようにします。
sudo modprobe overlay
すべてがうまくいった場合は、再起動時にモジュールがUbuntuシステム上でロードされていることを確認する必要があります。これは
/etc/modules
を編集することによって行われます。以下の行を追加します。overlay
プロジェクトごとにOverlayFSドライバ使用
.gitlab-ci.yml
の DOCKER_DRIVER
環境変数を使用することで、プロジェクトごとに個別にドライバを有効にできます。
variables:
DOCKER_DRIVER: overlay2
すべてのプロジェクトでのOverlayFSドライバ使用
自身のGitLab Runnersを使用している場合は、config.toml
の[[runners]]
セクションにDOCKER_DRIVER
環境変数を設定することで、すべてのプロジェクトでドライバを有効にできます。
environment = ["DOCKER_DRIVER=overlay2"]
複数のRunnerを実行している場合は、すべての設定ファイルを修正する必要があります。
GitLabコンテナレジストリの使用
Dockerイメージをビルドしたら、そのイメージを組み込みのGitLab Container Registryにプッシュします。
トラブルシューティング
docker: tcp://docker:2375でDocker デーモンに接続できません。docker デーモンは起動していますか?
Dockerv19.03以上でDockerを使用している場合によくあるエラーです。
これは、Dockerが自動的にTLS上で起動するために発生します。
- 初めて設定する場合、Docker-in-Dockerのワークフローを熟読してください。
- v18.09以前のバージョンからアップグレードする場合は、アップグレードガイドをお読みください。