正式なドキュメントは英語版であり、この日本語訳はAI支援翻訳により作成された参考用のものです。日本語訳の一部の内容は人間によるレビューがまだ行われていないため、翻訳のタイミングにより英語版との間に差異が生じることがあります。最新かつ正確な情報については、英語版をご参照ください。

Dockerを使用してDockerイメージをビルドする

  • プラン: Free、Premium、Ultimate
  • 提供形態: GitLab.com、GitLab Self-Managed、GitLab Dedicated

GitLab CI/CDとDockerを組み合わせてDockerイメージを作成できます。たとえば、アプリケーションのDockerイメージを作成し、それをテストして、コンテナレジストリにプッシュできます。

CI/CDジョブでDockerコマンドを実行するには、dockerコマンドをサポートするようにGitLab Runnerを設定する必要があります。この方法にはprivilegedモードが必要です。

Runnerでprivilegedモードを有効にせずにDockerイメージをビルドする場合は、Dockerの代替手段を使用できます。

CI/CDジョブでDockerコマンドを有効にする

CI/CDジョブでDockerコマンドを有効にするには、次のいずれかを使用できます:

Shell executorを使用する

CI/CDジョブにDockerコマンドを含めるには、shell executorを使用するようにRunnerを設定します。この設定では、gitlab-runnerユーザーがDockerコマンドを実行しますが、そのためには権限が必要です。

  1. GitLab Runnerをインストールします。

  2. Runnerを登録します。shell executorを選択します。次に例を示します:

    sudo gitlab-runner register -n \
      --url "https://gitlab.com/" \
      --registration-token REGISTRATION_TOKEN \
      --executor shell \
      --description "My Runner"
  3. GitLab Runnerがインストールされているサーバーに、Docker Engineをインストールします。サポートされているプラットフォームの一覧を確認してください。

  4. gitlab-runnerユーザーをdockerグループに追加します:

    sudo usermod -aG docker gitlab-runner
  5. gitlab-runnerにDockerへのアクセス権があることを確認します:

    sudo -u gitlab-runner -H docker info
  6. GitLabで、docker info.gitlab-ci.ymlに追加して、Dockerが動作していることを確認します:

    default:
      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-runnerdockerグループに追加すると、事実上gitlab-runnerに完全なroot権限を付与することになります。詳細については、dockerグループのセキュリティを参照してください。

Docker-in-Dockerを使用する

「Docker-in-Docker」(dind)を使用することは、以下を意味します:

Dockerイメージには、すべてのdockerツールが含まれており、イメージのコンテキストで、特権モードでジョブスクリプトを実行できます。

TLSを有効にしてDocker-in-Dockerを使用する必要があります。これは、GitLab.comインスタンスRunnerでサポートされています。

イメージの特定のバージョン(例: docker:24.0.5)を常に指定する必要があります。docker:latestのようなタグを使用する場合、どのバージョンが使用されるかを制御できません。これにより、新しいバージョンがリリースされたときに、互換性の問題が発生する可能性があります。

Docker executorでDocker-in-Dockerを使用する

Docker executorを使用して、Dockerコンテナでジョブを実行できます。

Docker executorでTLSが有効になっているDocker-in-Docker

Dockerデーモンは、TLS経由の接続をサポートしています。TLSは、Docker 19.03.12以降のデフォルトです。

このタスクでは--docker-privilegedを有効にします。これにより、コンテナのセキュリティメカニズムが事実上無効になり、ホストが特権エスカレーションのリスクにさらされます。このアクションにより、コンテナのブレイクアウトが発生する可能性があります。詳細については、Runtime privilege and Linux capabilities(ランタイム特権とLinux機能)を参照してください。

次の手順で、TLSを有効にしてDocker-in-Dockerを使用できます:

  1. GitLab Runnerをインストールします。

  2. 次のように、コマンドラインからGitLab Runnerを登録します。dockerおよびprivilegedモードを使用します:

    sudo gitlab-runner register -n \
      --url "https://gitlab.com/" \
      --registration-token REGISTRATION_TOKEN \
      --executor docker \
      --description "My Docker Runner" \
      --tag-list "tls-docker-runner" \
      --docker-image "docker:24.0.5-cli" \
      --docker-privileged \
      --docker-volumes "/certs/client"
    • このコマンドは、(ジョブレベルで指定されていない場合)docker:24.0.5-cliイメージを使用するように新しいRunnerを登録します。ビルドコンテナとサービスコンテナを起動するには、privilegedモードを使用します。Docker-in-Dockerを使用する場合は、Dockerコンテナで常にprivileged = trueを使用する必要があります。
    • このコマンドは、/certs/clientをサービスコンテナとビルドコンテナにマウントします。これは、Dockerクライアントがそのディレクトリ内の証明書を使用するために必要です。詳細については、Dockerイメージのドキュメントを参照してください。

    前述のコマンドは、次の例のようなconfig.tomlエントリを作成します:

    [[runners]]
      url = "https://gitlab.com/"
      token = TOKEN
      executor = "docker"
      [runners.docker]
        tls_verify = false
        image = "docker:24.0.5-cli"
        privileged = true
        disable_cache = false
        volumes = ["/certs/client", "/cache"]
      [runners.cache]
        [runners.cache.s3]
        [runners.cache.gcs]
  3. これで、ジョブスクリプトでdockerを使用できるようになりました。次のように、docker:24.0.5-dindサービスを含める必要があります:

    default:
      image: docker:24.0.5-cli
      services:
        - docker:24.0.5-dind
      before_script:
        - docker info
    
    variables:
      # When you use the dind service, you must 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/services/#accessing-the-services.
      #
      # Specify to Docker where to create the certificates. Docker
      # creates them automatically on boot, and creates
      # `/certs/client` to share between the service and job
      # container, thanks to volume mount from config.toml
      DOCKER_TLS_CERTDIR: "/certs"
    
    build:
      stage: build
      tags:
        - tls-docker-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
Docker-in-Dockerとビルドコンテナ間で共有するボリューム上でUnixソケットを使用する

Docker executorでTLSを有効にしたDocker-in-Dockerのアプローチでは、volumes = ["/certs/client", "/cache"]で定義されたディレクトリは、ビルド間で永続します。Docker executor Runnerを使用する複数のCI/CDジョブでDocker-in-Dockerサービスが有効になっている場合、各ジョブが同じディレクトリパスに書き込みます。このアプローチでは、競合が発生する可能性があります。

この競合に対処するには、Docker-in-Dockerサービスとビルドコンテナの間で共有されるボリューム上でUnixソケットを使用します。このアプローチは、パフォーマンスを向上させ、サービスとクライアント間の安全な接続を確立します。

以下は、ビルドコンテナとサービスコンテナ間で共有される一時ボリュームを設定したconfig.tomlのサンプルです:

[[runners]]
  url = "https://gitlab.com/"
  token = TOKEN
  executor = "docker"
  [runners.docker]
    image = "docker:24.0.5-cli"
    privileged = true
    volumes = ["/runner/services/docker"] # Temporary volume shared between build and service containers.

Docker-in-Dockerサービスはdocker.sockを作成します。Dockerクライアントは、このDocker Unixソケットボリュームを介してdocker.sockに接続します。

job:
  variables:
    # This variable is shared by both the DinD service and Docker client.
    # For the service, it will instruct DinD to create `docker.sock` here.
    # For the client, it tells the Docker client which Docker Unix socket to connect to.
    DOCKER_HOST: "unix:///runner/services/docker/docker.sock"
  services:
    - docker:24.0.5-dind
  image: docker:24.0.5-cli
  script:
    - docker version
Docker executorでTLSが無効になっているDocker-in-Docker

場合によっては、TLSを無効にする正当な理由があります。たとえば、使用しているGitLab Runnerの設定を制御できない場合などです。

  1. 次のように、コマンドラインからGitLab Runnerを登録します。dockerおよびprivilegedモードを使用します:

    sudo gitlab-runner register -n \
      --url "https://gitlab.com/" \
      --registration-token REGISTRATION_TOKEN \
      --executor docker \
      --description "My Docker Runner" \
      --tag-list "no-tls-docker-runner" \
      --docker-image "docker:24.0.5-cli" \
      --docker-privileged

    前述のコマンドは、次の例のようなconfig.tomlエントリを作成します:

    [[runners]]
      url = "https://gitlab.com/"
      token = TOKEN
      executor = "docker"
      [runners.docker]
        tls_verify = false
        image = "docker:24.0.5-cli"
        privileged = true
        disable_cache = false
        volumes = ["/cache"]
      [runners.cache]
        [runners.cache.s3]
        [runners.cache.gcs]
  2. ジョブスクリプトにdocker:24.0.5-dindサービスを含めます:

    default:
      image: docker:24.0.5-cli
      services:
        - docker:24.0.5-dind
      before_script:
        - docker info
    
    variables:
      # When using dind service, you must 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
      #
      DOCKER_HOST: tcp://docker:2375
      #
      # This instructs Docker not to start over TLS.
      DOCKER_TLS_CERTDIR: ""
    
    build:
      stage: build
      tags:
        - no-tls-docker-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
Docker executorでプロキシが有効になっているDocker-in-Docker

docker pushコマンドを使用するには、プロキシの設定が必要になる場合があります。

詳細については、dindサービスの使用時のプロキシ設定を参照してください。

Kubernetes executorでDocker-in-Dockerを使用する

Kubernetes executorを使用して、Dockerコンテナでジョブを実行できます。

KubernetesでTLSが有効になっているDocker-in-Docker

次の手順で、KubernetesでTLSを有効にしてDocker-in-Dockerを使用できます:

  1. Helmチャートを使用して、values.ymlファイルを更新し、ボリュームマウントを指定します。

    runners:
      tags: "tls-dind-kubernetes-runner"
      config: |
        [[runners]]
          [runners.kubernetes]
            image = "ubuntu:20.04"
            privileged = true
          [[runners.kubernetes.volumes.empty_dir]]
            name = "docker-certs"
            mount_path = "/certs/client"
            medium = "Memory"
  2. ジョブにdocker:24.0.5-dindサービスを含めます:

    default:
      image: docker:24.0.5-cli
      services:
        - name: docker:24.0.5-dind
          variables:
            HEALTHCHECK_TCP_PORT: "2376"
      before_script:
        - docker info
    
    variables:
      # When using dind service, you must 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_HOST: tcp://docker:2376
      #
      # The 'docker' hostname is the alias of the service container as described at
      # https://docs.gitlab.com/ee/ci/services/#accessing-the-services.
      #
      # Specify to Docker where to create the certificates. Docker
      # creates them automatically on boot, and creates
      # `/certs/client` to share between the service and job
      # container, thanks to volume mount from config.toml
      DOCKER_TLS_CERTDIR: "/certs"
      # These are usually specified by the entrypoint, however the
      # Kubernetes executor doesn't run entrypoints
      # https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4125
      DOCKER_TLS_VERIFY: 1
      DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client"
    
    build:
      stage: build
      tags:
        - tls-dind-kubernetes-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
KubernetesでTLSが無効になっているDocker-in-Docker

KubernetesでTLSを無効にしてDocker-in-Dockerを使用するには、前述の例を次のように変更する必要があります:

  • values.ymlファイルから[[runners.kubernetes.volumes.empty_dir]]セクションを削除する。
  • DOCKER_HOST: tcp://docker:2375を指定し、ポートを2376から2375に変更する。
  • DOCKER_TLS_CERTDIR: ""を指定し、TLSを無効にしてDockerを起動するように指示する。

次に例を示します:

  1. Helmチャートを使用して、values.ymlファイルを更新します:

    runners:
      tags: "no-tls-dind-kubernetes-runner"
      config: |
        [[runners]]
          [runners.kubernetes]
            image = "ubuntu:20.04"
            privileged = true
  2. これで、ジョブスクリプトでdockerを使用できるようになりました。次のように、docker:24.0.5-dindサービスを含める必要があります:

    default:
      image: docker:24.0.5-cli
      services:
        - name: docker:24.0.5-dind
          variables:
            HEALTHCHECK_TCP_PORT: "2375"
      before_script:
        - docker info
    
    variables:
      # When using dind service, you must 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_HOST: tcp://docker:2375
      #
      # The 'docker' hostname is the alias of the service container as described at
      # https://docs.gitlab.com/ee/ci/services/#accessing-the-services.
      #
      # This instructs Docker not to start over TLS.
      DOCKER_TLS_CERTDIR: ""
    build:
      stage: build
      tags:
        - no-tls-dind-kubernetes-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests

Docker-in-Dockerに関する既知の問題

Docker-in-Dockerは推奨される設定ですが、次の問題に注意してください:

  • The docker-compose command(コマンド): この設定において、デフォルトではこのコマンドは使用できません。ジョブスクリプトでdocker-composeを使用するには、Docker Composeのインストール手順に従ってください。

  • Cache(キャッシュ): 各ジョブは新しい環境で実行されます。各ビルドが独自のDockerエンジンインスタンスを取得するため、同時ジョブが競合を引き起こすことはありません。ただし、レイヤーがキャッシュされないため、ジョブが遅くなる可能性があります。Dockerレイヤーキャッシュを参照してください。

  • Storage drivers(ストレージドライバー): デフォルトでは、以前のバージョンのDockerではvfsストレージドライバーを使用し、ジョブごとにファイルシステムをコピーします。Docker 17.09以降では--storage-driver overlay2を使用し、これが推奨されるストレージドライバーです。詳細については、OverlayFSドライバーを使用するを参照してください。

  • Root file system(ルートファイルシステム): docker:24.0.5-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

Dockerソケットバインディングを使用する

CI/CDジョブでDockerコマンドを使用するには、/var/run/docker.sockをビルドコンテナにバインドマウントします。これにより、イメージのコンテキストでDockerを使用できるようになります。

Dockerソケットをバインドすると、docker:24.0.5-dindをサービスとして使用できません。ボリュームバインディングはサービスにも影響し、互換性が失われます。

Docker executorでDockerソケットバインディングを使用する

Docker executorでDockerソケットをマウントするには、[runners.docker]セクションのボリューム"/var/run/docker.sock:/var/run/docker.sock"を追加します。

  1. Runnerの登録時に/var/run/docker.sockをマウントするには、次のオプションを含めます:

    sudo gitlab-runner register \
      --non-interactive \
      --url "https://gitlab.com/" \
      --registration-token REGISTRATION_TOKEN \
      --executor "docker" \
      --description "docker-runner" \
      --tag-list "socket-binding-docker-runner" \
      --docker-image "docker:24.0.5-cli" \
      --docker-volumes "/var/run/docker.sock:/var/run/docker.sock"

    前述のコマンドは、次の例のようなconfig.tomlエントリを作成します:

    [[runners]]
      url = "https://gitlab.com/"
      token = RUNNER_TOKEN
      executor = "docker"
      [runners.docker]
        tls_verify = false
        image = "docker:24.0.5-cli"
        privileged = false
        disable_cache = false
        volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
      [runners.cache]
        Insecure = false
  2. ジョブスクリプトでDockerを使用します:

    default:
      image: docker:24.0.5-cli
      before_script:
        - docker info
    
    build:
      stage: build
      tags:
        - socket-binding-docker-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests

Kubernetes executorでDockerソケットバインディングを使用する

Kubernetes executorでDockerソケットをマウントするには、[[runners.kubernetes.volumes.host_path]]セクションのボリューム"/var/run/docker.sock"を追加します。

  1. ボリュームマウントを指定するには、Helmチャートを使用してvalues.ymlファイルを更新します。

    runners:
      tags: "socket-binding-kubernetes-runner"
      config: |
        [[runners]]
          [runners.kubernetes]
            image = "ubuntu:20.04"
            privileged = false
          [runners.kubernetes]
            [[runners.kubernetes.volumes.host_path]]
              host_path = '/var/run/docker.sock'
              mount_path = '/var/run/docker.sock'
              name = 'docker-sock'
              read_only = true
  2. ジョブスクリプトでDockerを使用します:

    default:
      image: docker:24.0.5-cli
      before_script:
        - docker info
    build:
      stage: build
      tags:
        - socket-binding-kubernetes-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests

Dockerソケットバインディングに関する既知の問題

Dockerソケットバインディングを使用すると、特権モードでDockerを実行することを回避できます。ただし、この方法には次の注意点があります:

  • Dockerデーモンを共有すると、コンテナのセキュリティメカニズムが事実上無効になり、ホストが特権エスカレーションのリスクにさらされます。これにより、コンテナのブレイクアウトが発生する可能性があります。たとえば、プロジェクトでdocker rm -f $(docker ps -a -q)を実行すると、GitLab Runnerコンテナが削除されます。

  • 同時ジョブが機能しない可能性があります。テストで特定の名前のコンテナを作成する場合、それらが相互に競合する可能性があります。

  • Dockerコマンドによって作成されたコンテナは、Runnerの子ではなく、Runnerの兄弟になります。これにより、ワークフローが複雑になる可能性があります。

  • ソースリポジトリからコンテナへのファイルとディレクトリの共有が、期待どおりに動作しない可能性があります。ボリュームのマウントは、ビルドコンテナではなく、ホストマシンのコンテキストで実行されるためです。次に例を示します:

    docker run --rm -t -i -v $(pwd)/src:/home/app/src test-image:latest run_app_tests

docker:24.0.5-dindサービスを含める必要はありません。Docker-in-Docker executorを使用する場合は、このサービスが必要になります:

default:
  image: docker:24.0.5-cli
  before_script:
    - docker info

build:
  stage: build
  script:
    - docker build -t my-docker-image .
    - docker run my-docker-image /script/to/run/tests

CodeClimateを使用したコード品質スキャンなど、複雑なDocker-in-Dockerセットアップでは、適切に実行するためにホストとコンテナのパスを一致させる必要があります。詳細については、CodeClimateベースのスキャンにプライベートRunnerを使用するを参照してください。

Dockerパイプバインディングを使用する

Windowsコンテナは、Windows Serverカーネルとユーザーランド向けにコンパイルされたWindows実行可能ファイル(windowsservercoreまたはnanoserver)を実行します。Windowsコンテナをビルドして実行するには、コンテナをサポートするWindowsシステムが必要です。詳細については、Windowsコンテナを参照してください。

Dockerパイプバインディングを使用するには、ホストのWindows ServerオペレーティングシステムにDocker Engineをインストールして実行する必要があります。詳細については、Windows ServerへのDocker Community Edition(CE)のインストールに関するページを参照してください。

WindowsベースのコンテナCI/CDジョブでDockerコマンドを使用するには、起動されたexecutorコンテナに\\.\pipe\docker_engineをバインドマウントします。これにより、イメージのコンテキストでDockerを使用できるようになります。

WindowsにおけるDockerパイプバインディングは、LinuxにおけるDockerソケットバインディングに似ており、Dockerソケットバインディングに関する既知の問題と同様の既知の問題があります。

Dockerパイプバインディングを使用するための必須前提要件は、ホストのWindows ServerオペレーティングシステムにDocker Engineがインストールされ、実行されていることです。参照: Windows ServerへのDocker Community Edition(CE)のインストール

Docker executorでDockerパイプバインディングを使用する

Docker executorを使用して、Windowsベースのコンテナでジョブを実行できます。

Docker executorでDockerパイプをマウントするには、[runners.docker]セクションのボリューム"\\.\pipe\docker_engine:\\.\pipe\docker_engine"を追加します。

  1. Runnerの登録時に"\\.\pipe\docker_engineをマウントするには、次のオプションを含めます:

    .\gitlab-runner.exe register \
      --non-interactive \
      --url "https://gitlab.com/" \
      --registration-token REGISTRATION_TOKEN \
      --executor "docker-windows" \
      --description "docker-windows-runner"
      --tag-list "docker-windows-runner" \
      --docker-image "docker:25-windowsservercore-ltsc2022" \
      --docker-volumes "\\.\pipe\docker_engine:\\.\pipe\docker_engine"

    前述のコマンドは、次の例のようなconfig.tomlエントリを作成します:

    [[runners]]
      url = "https://gitlab.com/"
      token = RUNNER_TOKEN
      executor = "docker-windows"
      [runners.docker]
        tls_verify = false
        image = "docker:25-windowsservercore-ltsc2022"
        privileged = false
        disable_cache = false
        volumes = ["\\.\pipe\docker_engine:\\.\pipe\docker_engine"]
      [runners.cache]
        Insecure = false
  2. ジョブスクリプトでDockerを使用します:

    default:
      image: docker:25-windowsservercore-ltsc2022
      before_script:
        - docker version
        - docker info
    
    build:
      stage: build
      tags:
        - docker-windows-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests

Kubernetes executorでDockerパイプバインディングを使用する

Kubernetes executorを使用して、Windowsベースのコンテナでジョブを実行できます。

WindowsベースのコンテナにKubernetes executorを使用するには、KubernetesクラスターにWindowsノードを含める必要があります。詳細については、Windows containers in Kubernetes(KubernetesにおけるWindowsコンテナ)を参照してください。

Linux環境で動作し、WindowsノードをターゲットにするRunnerを使用できます。

Kubernetes executorでDockerパイプをマウントするには、[[runners.kubernetes.volumes.host_path]]セクションのボリューム"\\.\pipe\docker_engine"を追加します。

  1. ボリュームマウントを指定するには、Helmチャートを使用してvalues.ymlファイルを更新します。

    runners:
      tags: "kubernetes-windows-runner"
      config: |
        [[runners]]
          executor = "kubernetes"
    
          # The FF_USE_POWERSHELL_PATH_RESOLVER feature flag has to be enabled for PowerShell
          # to resolve paths for Windows correctly when Runner is operating in a Linux environment
          # but targeting Windows nodes.
          [runners.feature_flags]
            FF_USE_POWERSHELL_PATH_RESOLVER = true
    
          [runners.kubernetes]
            [[runners.kubernetes.volumes.host_path]]
              host_path = '\\.\pipe\docker_engine'
              mount_path = '\\.\pipe\docker_engine'
              name = 'docker-pipe'
              read_only = true
    
            [runners.kubernetes.node_selector]
              "kubernetes.io/arch" = "amd64"
              "kubernetes.io/os" = "windows"
              "node.kubernetes.io/windows-build" = "10.0.20348"
  2. ジョブスクリプトでDockerを使用します:

    default:
      image: docker:25-windowsservercore-ltsc2022
      before_script:
        - docker version
        - docker info
    
    build:
      stage: build
      tags:
        - kubernetes-windows-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
AWS EKS Kubernetesクラスターに関する既知の問題

dockerdからcontainerdに移行する際、AWS EKSブートストラップスクリプトStart-EKSBootstrap.ps1はDockerサービスを停止して無効にします。この問題を回避するには、Windows ServerにDocker Community Edition(CE)をインストールした後、次のスクリプトを使用してDockerサービスの名前を変更します:

Write-Output "Rename the just installed Docker Engine Service from docker to dockerd"
Write-Output "because the Start-EKSBootstrap.ps1 stops and disables the docker Service as part of migration from dockerd to containerd"
Stop-Service -Name docker
dockerd --register-service --service-name dockerd
Start-Service -Name dockerd
Write-Output "Ready to do Docker pipe binding on Windows EKS Node! :-)"

Dockerパイプバインディングに関する既知の問題

Dockerパイプバインディングには、Dockerソケットバインディングに関する既知の問題と同じ一連のセキュリティおよび分離の問題があります。

docker:dindサービスのレジストリミラーを有効にする

サービスコンテナ内でDockerデーモンが起動すると、デフォルト設定が使用されます。パフォーマンスを向上させるため、またDocker Hubのレート制限を超えないようにするため、レジストリミラーを設定することをおすすめします。

.gitlab-ci.ymlファイル内のサービス

dindサービスに追加のCLIフラグを追加して、レジストリミラーを設定できます:

services:
  - name: docker:24.0.5-dind
    command: ["--registry-mirror", "https://registry-mirror.example.com"]  # Specify the registry mirror to use

GitLab Runner設定ファイル内のサービス

GitLab Runnerの管理者は、commandを指定して、Dockerデーモンのレジストリミラーを設定できます。DockerまたはKubernetes executorに対してdindサービスを定義する必要があります。

Docker:

[[runners]]
  ...
  executor = "docker"
  [runners.docker]
    ...
    privileged = true
    [[runners.docker.services]]
      name = "docker:24.0.5-dind"
      command = ["--registry-mirror", "https://registry-mirror.example.com"]

Kubernetes:

[[runners]]
  ...
  name = "kubernetes"
  [runners.kubernetes]
    ...
    privileged = true
    [[runners.kubernetes.services]]
      name = "docker:24.0.5-dind"
      command = ["--registry-mirror", "https://registry-mirror.example.com"]

GitLab Runner設定ファイル内のDocker executor

GitLab Runnerの管理者は、すべてのdindサービスに対してミラーを使用できます。設定を更新して、ボリュームマウントを指定します。

たとえば、次の内容の/opt/docker/daemon.jsonファイルがあるとします:

{
  "registry-mirrors": [
    "https://registry-mirror.example.com"
  ]
}

上記のファイルを/etc/docker/daemon.jsonにマウントするためにconfig.tomlファイルを更新します。これにより、GitLab Runnerが作成するevery(すべて)のコンテナにこのファイルがマウントされます。dindサービスがこの設定を検出します。

[[runners]]
  ...
  executor = "docker"
  [runners.docker]
    image = "alpine:3.12"
    privileged = true
    volumes = ["/opt/docker/daemon.json:/etc/docker/daemon.json:ro"]

GitLab Runner設定ファイル内のKubernetes executor

GitLab Runnerの管理者は、すべてのdindサービスに対してミラーを使用できます。設定を更新して、ConfigMapボリュームマウントを指定します。

たとえば、次の内容の/tmp/daemon.jsonファイルがあるとします:

{
  "registry-mirrors": [
    "https://registry-mirror.example.com"
  ]
}

このファイルの内容でConfigMapを作成します。そのためには、次のようなコマンドを実行します:

kubectl create configmap docker-daemon --namespace gitlab-runner --from-file /tmp/daemon.json

GitLab RunnerのKubernetes executorがジョブポッドの作成に使用するネームスペースを使用する必要があります。

ConfigMapが作成されたら、そのファイルを/etc/docker/daemon.jsonにマウントするためにconfig.tomlファイルを更新します。この更新により、GitLab Runnerが作成するevery(すべて)のコンテナにこのファイルがマウントされます。dindサービスがこの設定を検出します。

[[runners]]
  ...
  executor = "kubernetes"
  [runners.kubernetes]
    image = "alpine:3.12"
    privileged = true
    [[runners.kubernetes.volumes.config_map]]
      name = "docker-daemon"
      mount_path = "/etc/docker/daemon.json"
      sub_path = "daemon.json"

Docker-in-Dockerでレジストリに対して認証する

Docker-in-Dockerを使用する場合、サービスによって新しいDockerデーモンが起動されるため、標準の認証方法は機能しません。レジストリに対して認証する必要があります。

Dockerレイヤーのキャッシュを使用してDocker-in-Dockerのビルドを高速化する

Docker-in-Dockerを使用する場合、ビルドを実行するたびに、Dockerはイメージのすべてのレイヤーをダウンロードします。Dockerレイヤーのキャッシュを使用して、ビルドを高速化できます。

OverlayFSドライバーを使用する

GitLab.comのインスタンスRunnerは、デフォルトでoverlay2ドライバーを使用します。

デフォルトでは、docker:dindを使用する場合、Dockerはvfsストレージドライバーを使用します。これにより、実行のたびにファイルシステムをコピーします。別のドライバー(たとえば、overlay2)を使用すると、ディスクに高い負荷がかかるこの処理を回避できます。

要件

  1. 最新のカーネルを使用していることを確認してください(>= 4.2を推奨)。

  2. overlayモジュールが読み込まれているかどうかを確認します:

    sudo lsmod | grep overlay

    結果が表示されない場合は、モジュールが読み込まれていません。モジュールを読み込むには、次を使用します:

    sudo modprobe overlay

    モジュールが読み込まれたら、再起動時にもモジュールが読み込まれるようにする必要があります。そのためには、Ubuntuシステムでは/etc/modulesに次の行を追加します:

    overlay

OverlayFSドライバーをプロジェクトごとに使用する

.gitlab-ci.ymlCI/CD変数DOCKER_DRIVERを使用して、プロジェクトごとに個別にドライバーを有効にすることができます:

variables:
  DOCKER_DRIVER: overlay2

OverlayFSドライバーをすべてのプロジェクトに使用する

独自のRunnerを使用している場合は、config.tomlファイルの[[runners]]セクションDOCKER_DRIVER環境変数を設定することにより、すべてのプロジェクトでドライバーを有効にできます:

environment = ["DOCKER_DRIVER=overlay2"]

複数のRunnerを実行している場合は、すべての設定ファイルを変更する必要があります。

Runnerの設定OverlayFSストレージドライバーの使用の詳細を参照してください。

Dockerの代替手段

Runnerで特権モードを有効にしなくても、コンテナイメージをビルドできます:

  • BuildKit: Dockerデーモンの依存関係をなくすルートレスBuildKitオプションが含まれています。
  • Buildah: Dockerデーモンを必要とせず、OCI準拠のイメージをビルドします。

Buildahの例

BuildahをGitLab CI/CDで使用するには、次のいずれかのexecutorを備えたRunnerが必要です:

この例では、Buildahを使用して以下を行います:

  1. Dockerイメージをビルドする。
  2. それをGitLabコンテナレジストリにプッシュする。

最後のステップで、BuildahはプロジェクトのルートディレクトリにあるDockerfileを使用してDockerイメージをビルドします。最後に、そのイメージをプロジェクトのコンテナレジストリにプッシュします:

build:
  stage: build
  image: quay.io/buildah/stable
  variables:
    # Use vfs with buildah. Docker offers overlayfs as a default, but Buildah
    # cannot stack overlayfs on top of another overlayfs filesystem.
    STORAGE_DRIVER: vfs
    # Write all image metadata in the docker format, not the standard OCI format.
    # Newer versions of docker can handle the OCI format, but older versions, like
    # the one shipped with Fedora 30, cannot handle the format.
    BUILDAH_FORMAT: docker
    FQ_IMAGE_NAME: "$CI_REGISTRY_IMAGE/test"
  before_script:
    # GitLab container registry credentials taken from the
    # [predefined CI/CD variables](../variables/_index.md#predefined-cicd-variables)
    # to authenticate to the registry.
    - echo "$CI_REGISTRY_PASSWORD" | buildah login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
  script:
    - buildah images
    - buildah build -t $FQ_IMAGE_NAME
    - buildah images
    - buildah push $FQ_IMAGE_NAME

OpenShiftクラスターにデプロイされたGitLab Runner Operatorを使用している場合は、ルートレスコンテナでBuildahを使用してイメージをビルドするチュートリアルを試してください。

GitLabコンテナレジストリを使用する

Dockerイメージをビルドしたら、それをGitLabコンテナレジストリにプッシュできます。

トラブルシューティング

open //./pipe/docker_engine: The system cannot find the file specified

マウントされたDockerパイプにアクセスするためにPowerShellスクリプトでdockerコマンドを実行すると、次のエラーが表示される場合があります:

PS C:\> docker version
Client:
 Version:           25.0.5
 API version:       1.44
 Go version:        go1.21.8
 Git commit:        5dc9bcc
 Built:             Tue Mar 19 15:06:12 2024
 OS/Arch:           windows/amd64
 Context:           default
error during connect: this error may indicate that the docker daemon is not running: Get "http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.44/version": open //./pipe/docker_engine: The system cannot find the file specified.

このエラーは、Windows Amazon EKSノードでDocker Engineが実行されていないため、WindowsベースのexecutorコンテナでDockerパイプバインディングを使用できなかったことを示しています。

この問題を解決するには、Kubernetes executorでDockerパイプバインディングを使用するで説明されている回避策を使用します。