GitLab Runner: Dockerイメージのビルド

StackheroランナーとDocker-in-Dockerを使って、GitLab CI/CDパイプラインからDockerイメージをビルドおよびプッシュする方法

👋 Stackhero ドキュメントへようこそ!

Stackhero では、GitLab Runner cloud を簡単にご利用いただけるソリューションとしてご提供しています。GitLab CI/CD ジョブを効率的に処理できるよう設計されています。主な特長は以下の通りです:

  • 無制限の CI/CD 分数:分単位の課金はありませんので、必要なときにいつでもパイプラインを実行できます。
  • 複数ジョブの同時実行:複数のジョブを同時に実行し、パイプライン全体の処理速度を向上させます。
  • Docker executorDocker-in-Docker サポート:コンテナイメージのビルドやプッシュを効率化します。
  • GitLab.com およびあらゆる セルフホスト型 GitLab インスタンスに対応。
  • 高速な NVMe/SSD ディスクを搭載した プライベート専用 VM で、安定したビルド環境を提供します。
  • 🇪🇺 ヨーロッパ および 🇺🇸 USA リージョンでご利用可能です。

時間を節約:最初の GitLab Runner を接続し、数分でパイプラインの実行を開始できます!

Stackhero GitLab Runnerを利用すると、ジョブはDocker executorで実行されます。つまり、各ジョブは指定したimageをベースにした新しいコンテナ内で開始されます。パイプラインの一部として独自のDockerイメージをビルドしたい場合は、Docker-in-Docker(DinD)を活用できます。この構成では、ジョブと並行してDockerデーモンが起動し、docker builddocker pushなどのコマンドをパイプライン内で直接実行できます。

大きなメリットの一つは、ランナーには無制限のCI/CD分数が付与されていることです。イメージは好きなだけ何度でもビルドできます。さらに、ビルドキャッシュがランナー専用ディスク上に保存されるため、繰り返しのビルドでは以前のレイヤーを再利用でき、パイプラインの完了が大幅に高速化されます。

以下は、リポジトリに追加できるサンプルの.gitlab-ci.ymlです。この設定では、プロジェクトのルートにあるDockerfileをビルドします。

build-image:
  stage: build
  image: docker:27
  services:
    - docker:27-dind
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
  before_script:
    - docker info
  script:
    # "my-image"を任意のイメージ名に置き換えてください:
    - docker build -t my-image .
    # 必要に応じて、ビルドしたイメージで簡単なスモークテストを実行できます:
    # - docker run --rm my-image /path/to/tests

この構成では、docker:27-dindサービスがDockerデーモンを起動します。変数DOCKER_TLS_CERTDIR: "/certs"は、ジョブとDockerデーモン間の安全なTLS接続を有効にします。

GitLabは、パイプラインが追加のシークレットなしでプロジェクトのコンテナレジストリにログインし、イメージをプッシュできるように、いくつかの事前定義変数(CI_REGISTRY, CI_REGISTRY_USER, CI_REGISTRY_PASSWORD, CI_REGISTRY_IMAGE)を提供しています。

以下は、イメージをビルドしてプッシュするジョブの例です。

build-and-push:
  stage: build
  image: docker:27
  services:
    - docker:27-dind
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
  script:
    - docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" .
    - docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA"
    # デフォルトブランチの場合は"latest"タグでもプッシュできます:
    - |
      if [ "$CI_COMMIT_BRANCH" = "$CI_DEFAULT_BRANCH" ]; then
        docker tag "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" "$CI_REGISTRY_IMAGE:latest"
        docker push "$CI_REGISTRY_IMAGE:latest"
      fi

もしDocker Hubやプライベートレジストリなど、他のレジストリにイメージをプッシュしたい場合は、CI/CD変数として認証情報を保存し、同様にdocker loginで利用できます。

ランナーのディスクはパイプライン間で永続化されるため、以前のイメージレイヤーをキャッシュとして再利用することでビルドを高速化できます。以下のように設定します。

build-cached:
  stage: build
  image: docker:27
  services:
    - docker:27-dind
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
  script:
    # キャッシュ用に最新イメージをpull(まだ存在しなくても問題ありません):
    - docker pull "$CI_REGISTRY_IMAGE:latest" || true
    - docker build --cache-from "$CI_REGISTRY_IMAGE:latest" -t "$CI_REGISTRY_IMAGE:latest" .
    - docker push "$CI_REGISTRY_IMAGE:latest"

この方法により、Dockerのレイヤーキャッシュを最大限活用し、パイプラインの処理速度が時間とともに向上します。

ご契約プランによって、同時に実行できるジョブ数(並列度)が決まります。同じステージ内のジョブは、並列度の上限まで同時に開始されます。つまり、複数の独立したジョブがある場合、最も遅いジョブが完了した時点でそのステージが終了し、すべてのジョブを順番に実行する必要はありません。

以下はシンプルな例です。

stages:
  - test

unit:
  stage: test
  image: node:22
  script: npm run test:unit

integration:
  stage: test
  image: node:22
  script: npm run test:integration

e2e:
  stage: test
  image: node:22
  script: npm run test:e2e

並列度を3以上に設定すれば、unitintegratione2eの各ジョブはすべて同時に実行されます。

CIでのDockerイメージビルドについてさらに詳しく知りたい場合は、公式GitLabドキュメントもご参照ください。