サービス内容

CI/CDを設定する際、ジョブが実行されるコンテナを作成するためのイメージを指定します。このイメージを指定するには、image キーワードを使用します。

services キーワードを使用すると、追加のイメージを指定できます。この追加イメージは、最初のコンテナで使用可能な別のコンテナを作成するために使用されます。2 つのコンテナは互いにアクセスでき、ジョブを実行するときに通信できます。

サービスイメージは任意のアプリケーションを実行できますが、最も一般的な使用例は、データベースコンテナなどを実行することです:

プロジェクトがビルドされるたびにmysql などをインストールするよりも、既存のイメージを使用して追加のコンテナとして実行するほうが簡単で高速です。

データベース・サービスだけに限定されるわけではありません。.gitlab-ci.yml に必要なサービスをいくつでも追加したり、手動でconfig.toml を変更することができます。Docker Hubや非公開のコンテナレジストリにあるイメージなら、どんなものでもサービスとして使用できます。

サービスは、CIコンテナ自体と同じDNSサーバー、検索ドメイン、および追加ホストを継承します。

サービスをジョブに連携するには

コンテナのリンクがどのように機能するかをよりよく理解するには、コンテナをリンクするを参照してください。

アプリケーションにmysql をサービスとして追加した場合、イメージはジョブコンテナにリンクされたコンテナを作成するために使用されます。

MySQL のサービスコンテナは、ホスト名mysqlでアクセスできます。データベースサービスにアクセスするには、ソケットやlocalhost ではなく、mysql という名前のホストに接続します。詳しくはサービスへのアクセスを参照してください。

サービスのヘルスチェックの仕組み

サービスは、ネットワークからアクセス可能な追加機能を提供するために設計されています。MySQLのようなデータベースやRedis、Docker-in-Dockerを使えるようにするdocker:dind 。CI/CDジョブの進行に必要で、ネットワークからアクセスできるものであれば何でも構いません。

これが動作することを確認するために、Runner:

  1. デフォルトでコンテナから公開されているポートをチェックします。
  2. これらのポートがアクセス可能になるのを待つ特別なコンテナを起動します。

チェックの第2ステージが失敗すると、警告が表示されます:*** WARNING: Service XYZ probably didn't start properly 。このイシューは、以下の理由で発生する可能性があります:

  • サービスに開かれているポートがありません。
  • タイムアウト前にサービスが正しく開始されておらず、ポートが応答していません。

ほとんどの場合、この警告はジョブに影響しますが、警告が表示されてもジョブが成功する場合もあります。例えば

  • 警告が表示された直後にサービスが開始され、ジョブが最初からリンクされたサービスを使用していない場合。この場合、ジョブがサービスにアクセスする必要があったとき、すでに接続待ちの状態になっている可能性があります。
  • サービスコンテナはネットワークサービスを提供していませんが、ジョブのディレクトリに対して何かを行っています(すべてのサービスはジョブディレクトリを/builds の下にボリュームとしてマウントしています)。この場合、サービスはそのジョブを実行し、ジョブが接続を試みていないため、失敗することはありません。

サービスが正常に開始された場合、before_script が実行される前に開始されます。つまり、サービスをクエリするbefore_script を書くことができます。

ジョブが失敗しても、ジョブの終了時にサービスは停止します。

どのようなサービスがあるか

前述したように、この機能はネットワークからアクセス可能なサービスを提供するために設計されています。データベースはそのようなサービスの最も単純な例です。

サービス機能は、定義されたservices イメージからジョブのコンテナにソフトウェアを追加するようには設計されていません。

例えば、ジョブ内に以下のservices が定義されている場合、phpnodego コマンドはスクリプトで利用できず、ジョブは失敗します:

job:
  services:
    - php:7
    - node:latest
    - golang:1.10
  image: alpine:3.7
  script:
    - php -v
    - node -v
    - go version

phpnodegoをスクリプトで利用できるようにする必要がある場合は、どちらかを選択する必要があります。

  • 必要なツールをすべて含む既存のDockerイメージを選択します。
  • 必要なツールがすべて含まれた独自のDockerイメージを作成し、ジョブで使用します。

.gitlab-ci.yml ファイルでservices を定義します。

ジョブごとに異なる画像とサービスを定義することも可能です:

default:
  before_script:
    - bundle install

test:2.6:
  image: ruby:2.6
  services:
    - postgres:11.7
  script:
    - bundle exec rake spec

test:2.7:
  image: ruby:2.7
  services:
    - postgres:12.2
  script:
    - bundle exec rake spec

または、imageservices拡張設定オプションを渡すこともできます:

default:
  image:
    name: ruby:2.6
    entrypoint: ["/bin/bash"]
  services:
    - name: my-postgres:11.7
      alias: db-postgres
      entrypoint: ["/usr/local/bin/db-postgres"]
      command: ["start"]
  before_script:
    - bundle install

test:
  script:
    - bundle exec rake spec

サービスへのアクセス

アプリケーションとAPIのインテグレーションをテストするためにWordpressのインスタンスが必要だとします。その場合、例えば.gitlab-ci.yml ファイルでtutum/wordpress イメージを使用することができます:

services:
  - tutum/wordpress:latest

サービスエイリアスを指定しない場合、ジョブが実行されるとtutum/wordpress が起動します。ビルドコンテナから2つのホスト名でアクセスできます:

  • tutum-wordpress
  • tutum__wordpress

アンダースコアを含むホスト名は RFC 上有効ではなく、サードパーティのアプリケーションで問題が発生する可能性があります。

サービスのホスト名のデフォルトのエイリアスは、これらのルールに従って、そのイメージ名から作成されます。

  • コロン (:) 以降はすべて取り除かれます。
  • スラッシュ (/) はダブルアンダースコア (__) に置き換えられ、メインのエイリアスが作成されます。
  • スラッシュ (/) はシングルダッシュ (-) に置き換えられ、セカンダリーエイリアスが作成されます (GitLab Runner v1.1.0 以降が必要です)。

デフォルトの動作を上書きするために、サービスのエイリアスを指定できます。

サービスの接続

外部 API が独自のデータベースと通信する必要があるエンドツーエンドテストのような複雑なジョブでは、相互に依存するサービスを使用できます。

たとえば、API を使用するフロントエンドアプリケーションのエンドツーエンドテストで、API がデータベースを必要とします:

end-to-end-tests:
  image: node:latest
  services:
    - name: selenium/standalone-firefox:${FIREFOX_VERSION}
      alias: firefox
    - name: registry.gitlab.com/organization/private-api:latest
      alias: backend-api
    - postgres:14.3
  variables:
    FF_NETWORK_PER_BUILD: 1
    POSTGRES_PASSWORD: supersecretpassword
    BACKEND_POSTGRES_HOST: postgres
  script:
    - npm install
    - npm test

このソリューションを動作させるには、ジョブごとに新しいネットワークを作成するネットワーキング・モードを使用する必要があります。

CI/CD変数をサービスに渡す

Dockerimagesservices を微調整するためのカスタムCI/CD変数を .gitlab-ci.yml ファイルで直接渡すこともできます。詳しくは.gitlab-ci.yml 定義変数をお読みください。

# The following variables are automatically passed down to the Postgres container
# as well as the Ruby container and available within each.
variables:
  HTTPS_PROXY: "https://10.1.1.1:8090"
  HTTP_PROXY: "https://10.1.1.1:8090"
  POSTGRES_DB: "my_custom_db"
  POSTGRES_USER: "postgres"
  POSTGRES_PASSWORD: "example"
  PGDATA: "/var/lib/postgresql/data"
  POSTGRES_INITDB_ARGS: "--encoding=UTF8 --data-checksums"

default:
  services:
    - name: postgres:11.7
      alias: db
      entrypoint: ["docker-entrypoint.sh"]
      command: ["postgres"]
  image:
    name: ruby:2.6
    entrypoint: ["/bin/bash"]
  before_script:
    - bundle install

test:
  script:
    - bundle exec rake spec

利用可能な設定services

GitLabとGitLab Runner 9.4で導入されました。

設定必須GitLabバージョン説明
name他のオプションと併用する場合は必須9.4使用す る イ メ ージ の完全名。完全なイメージ名にレジストリホスト名が含まれている場合は、alias オプションを使用して、より短いサービスアクセス名を定義します。詳細については、サービスへのアクセスを参照してください。
entrypointいいえ9.4コンテナのエントリポイントとして実行するコマンドまたはスクリプト。コンテナの作成時に Docker--entrypoint オプションに変換されます。構文はDockerfileENTRYPOINT ディレクティブに似ており、各シェルトークンは配列内の個別の文字列です。
commandいいえ9.4コンテナのコマンドとして使用するコマンドまたはスクリプト。イメージ名の後に Docker に渡される引数に変換されます。構文はDockerfileCMD ディレクティブに似ており、各 Shell トークンは配列内の個別の文字列となります。
alias (1)いいえ9.4ジョブのコンテナからサービスにアクセスするために使用できる追加のエイリアスです。詳細については、サービスへのアクセスを参照してください。
variables (2)いいえ14.5サービスにのみ渡される追加の環境変数。構文はジョブ変数と同じです。サービス変数は自分自身を参照することはできません。

(1) Kubernetes ExecutorのエイリアスサポートはGitLab Runner 12.8で導入され、Kubernetesバージョン1.7以降でのみ利用可能です。

(2) DockerとKubernetes Executorのサービス変数サポートはGitLab Runner 14.8で導入れました。

同じイメージから複数のサービスを起動する

GitLabとGitLab Runnerの9.4で導入されました。詳細は拡張設定オプションを参照してください。

新しい拡張Docker設定オプションが導入される前には、以下の設定が正しく動作しませんでした。

services:
  - mysql:latest
  - mysql:latest

Runnerは2つのコンテナを起動し、それぞれがmysql:latest 。ランナーは、mysql イメージを使用する2つのコンテナを起動しますが、デフォルトのホスト名命名に基づき、 エイリアスでジョブのコンテナに追加されます。この場合、サービスの1つにアクセスできなくなります。

新しい拡張Docker設定オプションの導入後は、上記の例は以下のように動作が変更されます。

services:
  - name: mysql:latest
    alias: mysql-1
  - name: mysql:latest
    alias: mysql-2

Runnerはmysql:latest イメージを使って2つのコンテナを起動しますが、それぞれのコンテナには.gitlab-ci.yml ファイルで設定したエイリアスでもアクセスできるようになります。

サービスのコマンド設定

GitLabとGitLab Runnerの9.4で導入されました。詳細は拡張設定オプションを参照してください。

SQLデータベースを内部に持つsuper/sql:latest 。これをジョブのサービスとして使用したいとします。また、このイメージはコンテナの起動時にデータベースプロセスを開始しないとします。ユーザーは手動で/usr/bin/super-sql run をコマンドとして使用してデータベースを起動する必要があります。

新しい拡張Docker設定オプションの前は、以下のことが必要でした:

  • super/sql:latest イメージをベースに独自のイメージを作成します。
  • デフォルトのコマンドを追加します。
  • ジョブの設定で画像を使用します。

    • my-super-sql:latest イメージのDockerfileを使います:

       FROM super/sql:latest
       CMD ["/usr/bin/super-sql", "run"]
      
    • .gitlab-ci.yml 内のジョブで:

       services:
         - my-super-sql:latest
      

新しい拡張Docker設定オプションの後は、代わりに.gitlab-ci.yml ファイルでcommand

services:
  - name: super/sql:latest
    command: ["/usr/bin/super-sql", "run"]

command の構文はDockerfileCMD と似ています。

servicesdocker run (Docker-in-Docker)を並行して使用します。

docker run で起動したコンテナは GitLab が提供するサービスにも接続できます。

サービスを起動するのにコストがかかったり時間がかかったりする場合は、このテクニックを使ってさまざまなクライアント環境からテストを実行し、テスト対象のサービスは一度だけ起動するようにしましょう。

access-service:
  stage: build
  image: docker:20.10.16
  services:
    - docker:dind                    # necessary for docker run
    - tutum/wordpress:latest
  variables:
    FF_NETWORK_PER_BUILD: "true"     # activate container-to-container networking
  script: |
    docker run --rm --name curl \
      --volume  "$(pwd)":"$(pwd)"    \
      --workdir "$(pwd)"             \
      --network=host                 \
      curlimages/curl:7.74.0 curl "http://tutum-wordpress"

この解決策を実行するには

Dockerインテグレーションの仕組み

以下、ジョブの実行中にDockerで実行されるステップを高レベルでまとめてみました。

  1. 任意のサービスコンテナを作成:mysql,postgresql,mongodb,redis.
  2. ビルドイメージのconfig.tomlDockerfile で定義されているすべてのボリュームを格納するキャッシュコンテナを作成します ( 上記の例ではruby:2.6 )。
  3. ビルド・コンテナを作成し、任意のサービス・コンテナをビルド・コンテナにリンクします。
  4. ビルド・コンテナを起動し、コンテナにジョブ・スクリプトを送信します。
  5. ジョブ・スクリプトを実行します。
  6. /builds/group-name/project-name/ にコードをチェックアウトします。
  7. .gitlab-ci.ymlで定義されたステップを実行します。
  8. ビルドスクリプトの終了ステータスをチェックします。
  9. ビルド・コンテナと作成されたすべてのサービス・コンテナを削除します。

サービス・コンテナ・ログの取得

GitLab Runner 15.6で導入されました

サービスコンテナ内で実行されているアプリケーションによって生成されたログは、その後の調査やデバッグのためにキャプチャすることができます。サービスコンテナのログを見たいのは、サービスコンテナが正常に起動したものの、期待通りの動作をしておらず、ジョブの失敗につながっている場合でしょう。ログは、コンテナ内のサービスの設定漏れや不正確さを示している可能性があります。

CI_DEBUG_SERVICES サービスコンテナのログをキャプチャすると、ストレージとパフォーマンスの両方に影響があるため、サービスコンテナがアクティブにデバッグされている場合にのみ有効にしてください。

サービスロギングを有効にするには、プロジェクトの.gitlab-ci.yml ファイルにCI_DEBUG_SERVICES 変数を追加します:

variables:
  CI_DEBUG_SERVICES: "true"

受け入れられる値は以下のとおりです:

  • 有効です:TRUE trueTrue
  • 無効FALSE falseFalse

これ以外の値を指定するとエラーメッセージが表示され、実質的に機能が無効になります。

有効にすると、_すべての_サービスコンテナのログがキャプチャされ、他のログと同時にジョブトレースログにストリーミングされます。各コンテナからのログは、コンテナのエイリアスが先頭に付き、異なる色で表示されます。

note
デフォルトのログレベルでは、ジョブの障害を診断するのに十分な詳細が得られない場合があるため、ログをキャプチャするサービスコンテナのログレベルを調整するとよいでしょう。
caution
有効にすると、CI_DEBUG_SERVICES マスクされた変数が明らかに CI_DEBUG_SERVICESなるCI_DEBUG_SERVICES ことがあります CI_DEBUG_SERVICES。有効にCI_DEBUG_SERVICES すると CI_DEBUG_SERVICES、サービスコンテナのログと CI ジョブのログが_同時に_ジョブのトレースログにストリームされるため、ジョブのマスクされたログの_中に_サービスコンテナのログが挿入される可能性があります。これにより、変数のマスキングメカニズムが妨害され、マスキングされた変数が明らかになります。

CI/CD 変数のマスクを参照してください。

ジョブのローカルデバッグ

以下のコマンドはroot権限なしで実行します。ユーザーアカウントでDockerを実行できるはずです。

まず、build_scriptというファイルを作成します:

cat <<EOF > build_script
git clone https://gitlab.com/gitlab-org/gitlab-runner.git /builds/gitlab-org/gitlab-runner
cd /builds/gitlab-org/gitlab-runner
make
EOF

ここでは、Makefileを含むGitLab Runnerリポジトリを例にしているので、実行make するとMakefileで定義されたコマンドが make実行されます。のmake 代わりに make、プロジェクト固有のコマンドを実行することもできます。

次に、いくつかのサービスコンテナを作成します。

docker run -d --name service-mysql mysql:latest
docker run -d --name service-postgres postgres:latest

それぞれ最新のMySQLイメージとPostgreSQLイメージを使用するservice-mysqlservice-postgres という名前の2つのサービスコンテナを作成します。どちらもバックグラウンドで実行されます (-d)。

最後に、先ほど作成したbuild_script ファイルを実行してビルドコンテナを作成します:

docker run --name build -i --link=service-mysql:mysql --link=service-postgres:postgres ruby:2.6 /bin/bash < build_script

build このコンテナはruby:2.6 イメージから生成され、2 つのサービスがリンクされています。build_scriptstdin を使って Bash インタープリターにパイプされ、Bash インタープリターはbuild コンテナでbuild_script を実行します。

テストが終了しコンテナが不要になったら、コンテナを削除します。

docker rm -f -v build service-mysql service-postgres

これにより、build コンテナ、2 つのサービスコンテナ、およびコンテナ作成時に作成されたすべてのボリューム (-v) が強制的に (-f) 削除されます。

サービスコンテナ使用時のセキュリティ

Docker特権モードはサービスに適用されます。これは、サービスイメージコンテナがホストシステムにアクセスできることを意味します。信頼できるソースからのコンテナイメージのみを使用する必要があります。

共有/buildsディレクトリ

すべてのサービスは、ジョブディレクトリを/builds 以下のボリュームとしてマウントしているため、ビルドからファイルにアクセスできます。