CIパイプラインの一般的なユースケースは、アプリケーションをデプロイするためのDockerイメージを構築することです。GitLab CIは、統合されたプルプロキシサービスをサポートしているため、優れたオプションです。これは、より高速なパイプラインと、ビルドイメージを保存するための組み込みレジストリを意味します。
このガイドでは、上記の両方の機能を使用するDockerビルドをセットアップする方法を示します。実行する必要のある手順は、パイプラインに使用するGitLabRunnerエグゼキューターのタイプによってわずかに異なります。以下では、ShellおよびDockerエグゼキュータについて説明します。
ShellExecutorでビルドする
シェルエグゼキュータを使用している場合は、ランナーをホストしているマシンにDockerがインストールされていることを確認してください。Docker executorは、Runnerホストでバイナリを使用して通常のシェルコマンドを実行することで機能します。
イメージをビルドするプロジェクトのGitリポジトリに移動します。リポジトリのルートに.gitlab-ci.ymlファイルを作成します。このファイルは、変更がプロジェクトにプッシュされたときに実行されるGitLabCIパイプラインを定義します。
ファイルに以下を追加します。
stages:
- build
docker_build:
stage: build
script:
- docker build -t example.com/example-image:latest .
- docker push example.com/example-image:latest
この単純な構成は、パイプライン駆動型のイメージ構築の基本を示すのに十分です。GitLabはGitリポジトリをビルド環境に自動的に複製するため、docker buildを実行すると、プロジェクトのDockerfileが使用され、リポジトリのコンテンツがビルドコンテキストとして利用できるようになります。
ビルドが完了したら、Dockerプッシュしてイメージをレジストリに追加できます。それ以外の場合は、ビルドを実行しているローカルのDockerインストールでのみ使用できます。プライベートレジストリを使用している場合は、最初にdocker loginを実行して、正しい認証の詳細を提供します。
script:
- docker login -u $DOCKER_REGISTRY_USER -p $DOCKER_REGISTRY_PASSWORD
GitLabWebUIで[設定]>[CI/ CD]> [変数]に移動して、2つのクレデンシャル変数の値を定義します。青い[変数の追加]ボタンをクリックして、新しい変数を作成し、値を割り当てます。GitLabは、これらの変数を、ジョブの実行に使用されるシェル環境で使用できるようにします。
Dockerエグゼキュータでビルドする
GitLab RunnerのDockerエグゼキューターは通常、各ジョブに完全にクリーンな環境を提供するために使用されます。ジョブは分離されたコンテナで実行されるため、dockerRunnerホストのバイナリにはアクセスできません。
Docker executorは、イメージをビルドするための2つの可能な戦略を提供します。Docker-in-Dockerを使用するか、ホストのDockerソケットをRunnerのビルド環境にバインドします。次に、公式のDockerコンテナイメージをジョブイメージとして使用して、DockerコマンドをCIスクリプトで使用できるようにします。
Docker-in-Docker
Docker-in-Docker(DinD)を使用してイメージを構築すると、ジョブごとに完全に分離された環境が提供されます。ビルドを実行するDockerプロセスは、CIジョブを実行するためにGitLabRunnerがホスト上に作成するコンテナーの子になります。
DinDを使用するには、GitLab Runner Dockerエグゼキューターを登録し、特権モードを有効にする必要があります。ランナーを登録するときにフラグを追加します--docker-privileged:
sudo gitlab-runner register -n \
--url https://example.com \
--registration-token $GITLAB_REGISTRATION_TOKEN \
--executor docker \
--description "Docker Runner" \
--docker-image "docker:20.10" \
--docker-volumes "/certs/client" \
--docker-privileged
CIパイプラインで、docker:dindイメージをサービスとして追加します。これにより、Dockerはジョブイメージにリンクされた個別のイメージとして使用できるようになります。dockerコマンドを使用して、docker:dindコンテナー内のDockerインスタンスを使用してイメージをビルドできます。
services:
- docker:dind
docker_build:
stage: build
image: docker:latest
script:
- docker build -t example-image:latest .
DinDを使用すると、相互にまたはホストに影響を与えない完全に分離されたビルドが得られます。主な欠点は、より複雑なキャッシュ動作です。各ジョブには新しい環境があり、以前に構築されたレイヤーにはアクセスできません。これを部分的に回避するには、ビルドする前に以前のバージョンのイメージをプルしてから、-cache-fromビルドフラグを使用して、プルしたイメージのレイヤーをキャッシュソースとして使用できるようにします。
docker_build:
stage: build
image: docker:latest
script:
- docker pull $CI_REGISTRY_IMAGE:latest || true
- docker build --cache-from $CI_REGISTRY_IMAGE:latest -t $CI_REGISTRY_IMAGE:latest .
Docker executorを使用する場合は、ホストのDockerソケットをジョブ環境にマウントすることもできます。これにより、シームレスなキャッシュが可能になり、docker:dindサービスをCI構成に追加する必要がなくなります。
docker-volumesこれを設定するには、ホストのDockerソケットを/var/run/docker.sock内部ジョブコンテナーにバインドするフラグをランナーに登録します。
sudo gitlab-runner register -n \
--url https://example.com \
--registration-token $GITLAB_REGISTRATION_TOKEN \
--executor docker \
--description "Docker Runner" \
--docker-image "docker:20.10" \
--docker-volumes /var/run/docker.sock:/var/run/docker.sock
これで、イメージを使用して実行されたジョブDockerは、バイナリを通常どおりに使用できるようになります。アクションは実際にはホスト上で実行され、サブコンテナではなくジョブコンテナの兄弟になります。
これは、実際には、ホストのDockerインストールでシェルエグゼキュータを使用するのと似ています。イメージはホストマシンに常駐し、通常のDockerビルドレイヤーキャッシングをシームレスに使用します。
このアプローチにより、パフォーマンスが向上し、構成が少なくなり、DinDの制限がなくなりますが、独自の問題もあります。これらの中で最も顕著なのはセキュリティへの影響です。ジョブはRunnerホスト上で任意のDockerコマンドを実行できるため、GitLabインスタンス内の悪意のあるプロジェクトがdocker run-it悪意のあるイメージ:latestまたはdocker rm -f $(docker ps -a )壊滅的な結果をもたらします。
GitLabは、ジョブが同時に実行されている場合、ソケットバインディングが問題を引き起こす可能性があることも警告しています。これは、特定の名前で作成されたコンテナに依存している場合に発生します。ジョブの2つのインスタンスが並行して実行される場合、コンテナー名がホストに既に存在するため、2番目のインスタンスは失敗します。
これらの問題のいずれかが厄介であると予想される場合は、DinDを検討する必要があります。DinDは一般的に推奨されなくなりましたが、同時CIジョブを実行する公開されているGitLabインスタンスの方が理にかなっています。
画像をGitLabのレジストリにプッシュする
GitLabプロジェクトでは、オプションでレジストリを統合できます。レジストリは、画像の保存に使用できます。プロジェクトのサイドバーで[パッケージとレジストリ]>[コンテナレジストリ]に移動すると、レジストリの内容を表示できます。このリンクが表示されない場合は、[設定]>[一般]>[表示、プロジェクト、機能、アクセス許可]に移動し、[コンテナーレジストリ]トグルをアクティブにして、レジストリを有効にします。
GitLabはCIジョブに環境変数を自動的に設定し、プロジェクトのコンテナーレジストリを参照できるようにします。スクリプトセクションを調整してレジストリにログインし、イメージをプッシュします。
script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker build -t $CI_REGISTRY_IMAGE:latest .
- docker push $CI_REGISTRY_IMAGE:latest
GitLabは、CIジョブごとに安全なクレデンシャルのセットを生成します。環境変数には、ジョブがユーザーCIJOBTOKENとしてレジストリgitlab − ci −トークンに接続するために使用できるアクセストークンが含まれます。登録サーバーのURLは、CI_JOB_TOKENとしてレジストリgitlab-ci-tokenに接続します。登録サーバーのURLはで始まりますC IJO BTOKENアイデンティティがレジストリに接続されていますgit l a b _−c i−to ken。_ _ _ _ _ レジストリサーバーのURLはCI_REGISTRYで始まります。
最後の変数CIREGISTRYIMAGEは、プロジェクトコンテナレジストリへのフルパスを提供します。これは、画像タグに適したベースです。この変数を展開してサブリポジトリを作成できます。たとえば、CI_REGISTRY_IMAGEはプロジェクトコンテナレジストリへのフルパスを提供します。これは、画像タグに適したベースです。この変数を展開して、サブリポジトリを作成できます。C IRE G I S T R Y私はM A G Eは、プロジェクトコンテナレジストリへのフルパスを提供します。これは、画像タグに適したベースです。この変数を展開して、 CI_REGISTRY_IMAGE / product / api:latestなどのサブリポジトリを作成できます。
他のDockerクライアントは、アクセストークンで認証することにより、レジストリからイメージをプルできます。これらは、プロジェクトの[設定]>[アクセストークン]画面で生成できます。read_registryスコープを追加し、表示された資格情報をDockerログインプロジェクトのレジストリに使用します。
GitLabの依存関係プロキシを使用する
GitLabのDependencyProxyは、DockerHubからプルするアップストリームイメージのキャッシュレイヤーを提供します。画像が実際に変更されたときにのみ画像コンテンツをフェッチするため、DockerHubのレート制限内にとどまることができます。これにより、ビルドのパフォーマンスも向上します。
[設定]>[パッケージとレジストリ]>[依存関係プロキシ]に移動して、GitLabグループレベルで依存関係プロキシをアクティブ化します。.gitlab-ci.ymlを有効にしたら、プレフィックスイメージ参照$CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIXをファイルに追加してプロキシ経由でプルします。
docker_build:
stage: build
image: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/docker:latest
services:
- name: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/docker:dind
alias: docker
ここですべてです!GitLab Runnerは依存関係プロキシレジストリに自動的にログインするため、手動で資格情報を提供する必要はありません。
GitLabは画像をキャッシュし、ネットワークの停止に対するパフォーマンスと回復力を向上させます。サービス定義も調整する必要があることに注意してください。環境変数は以前に使用したインライン形式では機能しないため、nameで画像全体を指定してから、部分エイリアスでコマンドを参照する必要があります。脚本
作業段階で直接使用されるイメージのプロキシを設定しましたが、Dockerfileビルドでベースイメージのサポートを追加するには、さらに多くの作業を行う必要があります。このような通常のディレクティブはプロキシを通過しません。
FROM ubuntu:latest
最後の部分を追加するには、Dockerのビルドパラメーターを使用して、Dockerfileをステップスルーするときに依存関係プロキシURLを使用できるようにします。
ARG GITLAB_DEPENDENCY_PROXY
FROM ${GITLAB_DEPENDENCY_PROXY}/ubuntu:latest
次に、docker buildコマンドを変更して、変数の値を定義します。
script:
>
- docker build \
--build-arg GITLAB_DEPENDENCY_PROXY=${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX} \
-t example-image:latest .
これで、ベースイメージも依存関係プロキシを介してプルされます。
一般化する
Dockerイメージの構築は、GitLabCIパイプラインに簡単に統合できます。Runnerの初期構成後、Dockerプッシュのジョブスクリプトセクションにあるdocker buildコマンドを使用するだけで、リポジトリのDockerfileにイメージを作成できます。GitLabの組み込みコンテナレジストリは、プロジェクトの画像のプライベートストレージを提供します。
基本的なビルドに加えて、GitLabの依存関係プロキシを統合して、パフォーマンスを向上させ、DockerHubのレート制限に達しないようにする価値があります。また、選択した方法で信頼できないプロジェクトがRunnerホストでコマンドを実行できるかどうかを評価して、インストールのセキュリティを確認する必要があります。独自の問題がありますが、Docker-in-Dockerは、GitLabインスタンスが一般にアクセス可能であるか、大規模なユーザーベースからアクセスできる場合に最も安全なアプローチです。