CIパイプラインの一般的なユースケースの1つは、アプリケーションのデプロイに使用するDockerイメージを構築することです。 GitLab CIは、統合されたプルプロキシサービスをサポートしているため、これに最適です。つまり、より高速なパイプラインと、ビルドされたイメージを保存するための組み込みのレジストリがサポートされています。
このガイドでは、上記の両方の機能を使用するDockerビルドを設定する方法を説明します。実行する必要のある手順は、パイプラインに使用するGitLabRunnerエグゼキューターのタイプによってわずかに異なります。以下では、ShellとDockerのエグゼキュータについて説明します。
Shell executorを使用している場合は、ランナーをホストするマシンにDockerがインストールされていることを確認してください。エグゼキュータは、docker
を使用して通常のシェルコマンドを実行することで機能します ランナーのホスト上のバイナリ。
イメージをビルドするプロジェクトの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 push
を実行できます レジストリへの画像。それ以外の場合は、ビルドを実行したローカルのDockerインストールでのみ使用できます。プライベートレジストリを使用している場合は、docker login
を実行します 最初に適切な認証の詳細を提供します:
script: - docker login -u $DOCKER_REGISTRY_USER -p $DOCKER_REGISTRY_PASSWORD
GitLabWebUIで[設定]>[CI/ CD]> [変数]に移動して、2つのクレデンシャル変数の値を定義します。青い[変数の追加]ボタンをクリックして、新しい変数を作成し、値を割り当てます。 GitLabは、これらの変数を、ジョブの実行に使用されるシェル環境で使用できるようにします。
DockerExecutorを使用したビルド
GitLab RunnerのDockerエグゼキューターは、通常、各ジョブに完全にクリーンな環境を提供するために使用されます。ジョブは分離されたコンテナで実行されるため、docker
Runnerホストのバイナリにアクセスできなくなります。
Docker executorは、イメージをビルドするための2つの可能な戦略を提供します。Docker-in-Dockerを使用するか、ホストのDockerソケットをRunnerのビルド環境にバインドします。次に、公式のDockerコンテナイメージをジョブのイメージとして使用して、docker
を作成します。 CIスクリプトで使用可能なコマンド。
Docker-in-Docker
Docker-in-Docker(DinD)を使用してイメージを構築すると、ジョブごとに完全に分離された環境が得られます。ビルドを実行するDockerプロセスは、GitLabRunnerがCIジョブを実行するためにホスト上に作成するコンテナーの子になります。
DinDを使用するには、特権モードを有効にしてGitLabRunnerDockerエグゼキューターを登録する必要があります。 --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インストールでシェルエグゼキュータを使用するのと実質的に同じです。イメージはホスト上に存在し、通常のdocker build
のシームレスな使用を容易にします レイヤーキャッシング。
このアプローチは、パフォーマンスの向上、構成の削減、およびDinDの制限のいずれにもつながる可能性がありますが、独自の問題があります。これらの中で最も顕著なのはセキュリティへの影響です。ジョブはRunnerホスト上で任意のDockerコマンドを実行する可能性があるため、GitLabインスタンス内の悪意のあるプロジェクトがdocker run -it malicious-image:latest
を実行する可能性があります またはdocker rm -f $(docker ps -a)
壊滅的な結果をもたらします。
GitLabは、ジョブが同時に実行されるときにソケットバインディングが問題を引き起こす可能性があることにも注意しています。これは、特定の名前で作成されているコンテナに依存している場合に発生します。ジョブの2つのインスタンスが並行して実行される場合、コンテナ名はホストにすでに存在するため、2番目のインスタンスは失敗します。
これらの問題のいずれかが厄介になると予想される場合は、代わりにDinDの使用を検討する必要があります。 DinDは一般的には推奨されなくなりましたが、同時CIジョブを実行する公開されているGitLabインスタンスの方が理にかなっています。
GitLabプロジェクトには、画像の保存に使用できる統合レジストリのオプションがあります。プロジェクトのサイドバーで[パッケージとレジストリ]>[コンテナレジストリ]に移動すると、レジストリのコンテンツを表示できます。このリンクが表示されない場合は、[設定]>[一般]>[可視性、プロジェクト、機能、権限]に移動し、[コンテナレジストリ]トグルを有効にしてレジストリを有効にします。
GitLabは、CIジョブに環境変数を自動的に設定し、プロジェクトのコンテナーレジストリを参照できるようにします。 script
を調整します レジストリにログインして画像をプッシュするセクション:
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ジョブごとに安全なクレデンシャルのセットを生成します。 $CI_JOB_TOKEN
環境変数には、ジョブがgitlab-ci-token
としてレジストリに接続するために使用できるアクセストークンが含まれます。 ユーザー。レジストリサーバーのURLは、$CI_REGISTRY
として利用できます。 。
最後の変数、$CI_REGISTRY_IMAGE
、プロジェクトのコンテナレジストリへの完全なパスを提供します。これは、画像タグに適したベースです。この変数を拡張して、$CI_REGISTRY_IMAGE/production/api:latest
などのサブリポジトリを作成できます。 。
他のDockerクライアントは、アクセストークンを使用して認証することにより、レジストリからイメージをプルできます。これらは、プロジェクトの[設定]>[アクセストークン]画面で生成できます。 read_registry
を追加します スコープを設定し、表示されたクレデンシャルを使用してdocker login
プロジェクトのレジストリに追加します。
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は画像をキャッシュするようになり、パフォーマンスが向上し、ネットワークの停止に対する回復力が向上します。 services
に注意してください 定義も調整する必要がありました。環境変数は以前に使用したインラインフォームでは機能しないため、画像全体のname
指定する必要があり、次にコマンドalias
script
で参照する セクション。
これで、ジョブステージで直接使用されるイメージのプロキシが設定されましたが、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パイプラインに簡単に統合できます。ランナーの初期構成後、docker build
およびdocker push
ジョブのscript
のコマンド Dockerfile
を使用して画像を作成するために必要なのはセクションだけです。 リポジトリ内。 GitLabの組み込みコンテナレジストリは、プロジェクトの画像用のプライベートストレージを提供します。
基本的なビルドに加えて、GitLabの依存関係プロキシを統合して、パフォーマンスを加速し、DockerHubのレート制限に達しないようにする価値があります。また、選択した方法で信頼できないプロジェクトがRunnerホストでコマンドを実行できるかどうかを評価して、インストールのセキュリティを確認する必要があります。独自の問題がありますが、Docker-in-Dockerは、GitLabインスタンスが一般にアクセス可能であるか、大規模なユーザーベースからアクセスできる場合に最も安全なアプローチです。