サービス
- プラン: Free、Premium、Ultimate
- 提供形態: GitLab.com、GitLab Self-Managed、GitLab Dedicated
CI/CDを設定する際、イメージを指定します。このイメージは、ジョブの実行場所となるコンテナの作成に使用されます。このイメージを指定するには、imageキーワードを使用します。
servicesキーワードを使用して、追加のイメージを指定できます。この追加のイメージは、別のコンテナを作成するために使用されますが、最初のコンテナでも使用できます。2つのコンテナは相互にアクセスでき、ジョブの実行時に通信できます。
サービスイメージは任意のアプリケーションを実行できますが、最も一般的なユースケースは、データベースコンテナの実行です。次に例を示します:
- MySQL
- PostgreSQL
- Redis
- JSON APIを提供するマイクロサービスの一例としてのGitLab
ストレージにデータベースを使用するコンテンツ管理システムを開発しているとします。アプリケーションのすべての機能をテストするには、データベースが必要です。このようなシナリオでは、サービスイメージとしてデータベースコンテナを実行するのが推奨されるユースケースです。
プロジェクトをビルドするたびにmysqlをインストールする代わりに、既存のイメージを使用して追加のコンテナとして実行します。
利用できるのはデータベースサービスだけではありません。必要な数のサービスを.gitlab-ci.ymlに追加したり、config.tomlを手動で変更したりできます。Docker Hubまたはプライベートコンテナレジストリにあるイメージは、サービスとして使用できます。
プライベートイメージの使用については、プライベートコンテナレジストリのイメージにアクセスするを参照してください。
サービスは、CIコンテナ自体と同じDNSサーバー、検索ドメイン、追加ホストを継承します。
サービスがジョブにリンクされる仕組み
コンテナのリンクの仕組みをより深く理解するには、コンテナのリンクに関するページをお読みください。
アプリケーションにmysqlをサービスとして追加すると、そのイメージを基にジョブコンテナにリンクされたコンテナが作成されます。
MySQLのサービスコンテナには、ホスト名mysqlでアクセスできます。データベースサービスにアクセスするには、ソケットやlocalhostではなく、mysqlというホストに接続します。詳細については、サービスにアクセスするを参照してください。
サービスのヘルスチェックの仕組み
サービスは、network accessible(ネットワーク経由でアクセスできる)追加機能を提供するようにデザインされています。MySQLやRedisのようなデータベース、またはDocker-in-Docker(DinD)を使用できるようにするdocker:dindなどがあります。実質的に、CI/CDジョブを進めるために必要で、ネットワーク経由でアクセスできるものであれば、なんでもサービスとして利用できます。
これが確実に機能するように、Runnerは以下を行います:
- デフォルトでコンテナから公開されているポートをチェックします。
- これらのポートにアクセスできるようになるまで待機する特別なコンテナを起動します。
チェックの第2段階が失敗した場合、次の警告が表示されます: *** WARNING: Service XYZ probably didn't start properly。この問題は、次の理由で発生する可能性があります:
- サービスで公開されているポートがない。
- サービスがタイムアウト前に正常に開始されず、ポートが応答していない。
ほとんどの場合、この警告はジョブに影響しますが、警告が表示されてもジョブが成功する場合があります。例:
- 警告が出た直後にサービスが開始され、リンクされたサービスをジョブが最初から使用していない場合。この場合、ジョブがサービスにアクセスする必要が生じた時点では、サービスはすでに開始され接続を待機していた可能性があります。
- サービスコンテナがネットワーキングサービスを何も提供しておらず、ジョブのディレクトリで何らかの処理を行っている場合(すべてのサービスには、
/buildsの下にジョブディレクトリがボリュームとしてマウントされています)。その場合、サービスが処理を担い、ジョブはサービスに接続しようとしないため、失敗しません。
サービスが正常に開始された場合、before_scriptが実行される前に開始されます。これは、サービスに対してクエリを実行するbefore_scriptを記述できることを意味します。
サービスはジョブの終了時に停止します。これは、ジョブが失敗した場合でも同様です。
サービスイメージによって提供されるソフトウェアを使用する
serviceを指定すると、network accessible(ネットワーク経由でアクセス可能な)サービスが提供されます。データベースは、そのようなサービスの最も単純な例です。
サービス機能は、定義されたservicesイメージからジョブのコンテナにソフトウェアを追加するわけではありません。
たとえば、ジョブで次のようにservicesを定義しても、php、node、goのコマンドはスクリプト内でnot(使用できず)、ジョブは失敗します:
job:
services:
- php:7
- node:latest
- golang:1.10
image: alpine:3.7
script:
- php -v
- node -v
- go versionスクリプトでphp、node、goを使用可能にする必要がある場合は、次のいずれかを行う必要があります:
- 必要なツールをすべて含む既存の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または、imageおよびservicesの拡張設定オプションを渡すこともできます:
default:
image:
name: ruby:2.6
entrypoint: ["/bin/bash"]
services:
- name: my-postgres:11.7
alias: db,postgres,pg
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-wordpresstutum__wordpress
アンダースコアの付いたホスト名はRFCに準拠していないため、サードパーティアプリケーションで問題が発生する可能性があります。
サービスホスト名のデフォルトエイリアスは、次のルールに従ってイメージ名から作成されます:
- コロン(
:)より後の部分はすべて削除されます。 - スラッシュ(
/)はダブルアンダースコア(__)に置き換えられ、プライマリエイリアスが作成されます。 - スラッシュ(
/)はシングルダッシュ(-)に置き換えられ、セカンダリエイリアスが作成されます。
デフォルトの動作をオーバーライドするには、1つ以上のサービスエイリアスを指定します。
サービスを接続する
外部APIが独自のデータベースと通信する必要があるE2Eテストなど、複雑なジョブでは相互依存するサービスを使用できます。
たとえば、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
- name: postgres:16.10
alias: db postgres db
variables:
FF_NETWORK_PER_BUILD: 1
POSTGRES_PASSWORD: supersecretpassword
BACKEND_POSTGRES_HOST: postgres
script:
- npm install
- npm testこのソリューションを機能させるには、ジョブごとに新しいネットワークを作成するネットワーキングモードを使用する必要があります。
CI/CD変数をサービスに渡す
カスタムCI/CD変数を渡して、Dockerのimagesとservicesを.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 specservicesで使用可能な設定
| 設定 | 必須 | GitLabバージョン | 説明 |
|---|---|---|---|
name | はい(他のオプションと組み合わせて使用する場合) | 9.4 | 使用するイメージのフルネーム。イメージのフルネームにレジストリホスト名が含まれる場合は、aliasオプションを使用して、短いサービスアクセス名を定義します。詳細については、サービスにアクセスするを参照してください。 |
entrypoint | いいえ | 9.4 | コンテナのエントリポイントとして実行するコマンドまたはスクリプト。コンテナの作成中に、Dockerの--entrypointオプションに変換されます。構文はDockerfileのENTRYPOINTディレクティブと同様で、各Shellトークンは配列内の個別の文字列です。 |
command | いいえ | 9.4 | コンテナのコマンドとして使用されるコマンドまたはスクリプト。イメージ名の後に続く引数として解釈され、Dockerに渡されます。構文はDockerfileのCMDディレクティブと同様で、各Shellトークンは配列内の個別の文字列です。 |
alias | いいえ | 9.4 | ジョブのコンテナからサービスにアクセスするための追加エイリアス。複数のエイリアスは、スペースまたはカンマで区切って指定できます。詳細については、サービスにアクセスするを参照してください。Kubernetes executorのコンテナ名としてエイリアスを使用する機能は、GitLab Runner 17.9で導入されました。詳細については、Kubernetes executorを使用してサービスコンテナ名を設定するを参照してください。 |
variables | いいえ | 14.5 | サービスのみに渡される追加の環境変数。構文はジョブ変数と同じです。サービス変数はそれ自体を参照できません。 |
pull_policy | いいえ | 15.1 | ジョブの実行時にRunnerがDockerイメージをどのようにプルするかを指定します。有効な値はalways、if-not-present、neverです。デフォルトはalwaysです。詳細については、services:pull_policyを参照してください。 |
同じイメージから複数のサービスを開始する
新しい拡張Docker設定オプションが導入される前は、次の設定は正しく動作しませんでした:
services:
- mysql:latest
- mysql:latestRunnerは2つのコンテナを起動し、それぞれがmysql:latestイメージを使用します。ただし、ホスト名のデフォルトの命名規則に基づき、両方のコンテナがmysqlエイリアスでジョブのコンテナに追加されます。そのため、サービスの1つにアクセスできなくなります。
新しい拡張Docker設定オプションの導入後は、前述の例は次のようになります:
services:
- name: mysql:latest
alias: mysql-1
- name: mysql:latest
alias: mysql-2Runnerは引き続きmysql:latestイメージを使用して2つのコンテナを起動しますが、それぞれのコンテナに.gitlab-ci.ymlファイルで設定されたエイリアスでアクセスできるようになります。
サービスにコマンドを設定する
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の構文は、DockerfileのCMDと同様です。
Kubernetes executorのサービスコンテナ名としてエイリアスを使用する
Kubernetes executorのサービスコンテナ名としてサービスエイリアスを使用できます。GitLab Runnerは、次の条件に基づいてコンテナに名前を付けます:
- サービスに複数のエイリアスが設定されている場合、次の条件を満たす最初のエイリアスがサービスコンテナ名として使用されます:
- 別のサービスコンテナですでに使用されていない。
- Kubernetesのラベル名の制約に従っている。
- サービスコンテナ名にエイリアスを使用できない場合、GitLab Runnerは
svc-iパターンにフォールバックします。
次の例は、Kubernetes executorにおいてサービスコンテナの名前付けにエイリアスがどのように使用されるかを示しています。
サービスにつき1つのエイリアス
次の.gitlab-ci.ymlファイルの場合:
job:
image: alpine:latest
script:
- sleep 10
services:
- name: alpine:latest
alias: alpine
- name: mysql:latest
alias: mysqlシステムは、標準のbuildコンテナとhelperコンテナに加えて、alpineおよびmysqlという名前のコンテナを持つジョブポッドを作成します。これらのエイリアスが使用される理由は次のとおりです:
- 他のサービスコンテナで使用されていない。
- Kubernetesのラベル名の制約に従っている。
一方、次の.gitlab-ci.ymlファイルの場合:
job:
image: alpine:latest
script:
- sleep 10
services:
- name: mysql:lts
alias: mysql
- name: mysql:latest
alias: mysqlシステムは、buildコンテナとhelperコンテナに加えて、mysqlおよびsvc-0という名前の2つのコンテナを作成します。mysqlコンテナはmysql:ltsイメージに対応し、svc-0コンテナはmysql:latestイメージに対応します。
サービスにつき複数のエイリアス
次の.gitlab-ci.ymlファイルの場合:
job:
image: alpine:latest
script:
- sleep 10
services:
- name: alpine:latest
alias: alpine,alpine-latest
- name: alpine:edge
alias: alpine,alpine-edge,alpine-latestシステムは、buildコンテナとhelperコンテナに加えて、4つのコンテナを作成します:
alpineは、alpine:latestイメージに基づくコンテナに対応。alpine-edgeは、alpine:edgeイメージに基づくコンテナに対応(alpineエイリアスは前のコンテナで使用済み)。
この例では、エイリアスalpine-latestは使用されていません。
一方、次の.gitlab-ci.ymlファイルの場合:
job:
image: alpine:latest
script:
- sleep 10
services:
- name: alpine:latest
alias: alpine,alpine-edge
- name: alpine:edge
alias: alpine,alpine-edge
- name: alpine:3.21
alias: alpine,alpine-edgebuildコンテナとhelperコンテナに加えて、さらに6つのコンテナが作成されます。
alpineは、alpine:latestイメージに基づくコンテナを指す。alpine-edgeは、alpine:edgeイメージに基づくコンテナを指す(alpineエイリアスは前のコンテナで使用済み)。svc-0は、alpine:3.21イメージに基づくコンテナを指す(alpineおよびalpine-edgeエイリアスは前のコンテナで使用済み)。svc-iパターンのiは、指定されたリストにおけるサービスの位置ではなく、使用可能なエイリアスが見つからなかった場合にサービスに付与される番号を表しています。無効なエイリアスが指定された場合(Kubernetesの制約を満たさない場合)、ジョブは次のエラーで失敗します(
alpine_edgeエイリアスの例)。この失敗は、ジョブポッドのローカルDNSエントリの作成時にもこのエイリアスが使用されるために発生します。ERROR: Job failed (system failure): prepare environment: setting up build pod: provided host alias alpine_edge for service alpine:edge is invalid DNS. a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*'). Check https://docs.gitlab.com/runner/shells/index.html#shell-profile-loading for more information.
docker run(Docker-in-Docker)と並行してservicesを使用する
docker runで起動したコンテナも、GitLabが提供するサービスに接続できます。
サービスの起動にコストや時間がかかる場合、テスト対象のサービスを1回だけ起動し、異なるクライアント環境からテストを実行できます。
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 executorを使用しないこと。使用する必要がある場合は、前述の例で、
hostの代わりにこのジョブ用に作成された動的ネットワーク名を使用します。
Dockerインテグレーションの仕組み
以下は、ジョブの実行中にDockerが実行するステップの概要です。
- サービスコンテナを作成します:
mysql、postgresql、mongodb、redis。 config.tomlや、ビルドイメージ(前述の例ではruby:2.6)のDockerfileで定義されたすべてのボリュームを格納するためのキャッシュコンテナを作成します。- ビルドコンテナを作成し、すべてのサービスコンテナをビルドコンテナにリンクします。
- ビルドコンテナを起動し、ジョブスクリプトをコンテナに送信します。
- ジョブスクリプトを実行します。
/builds/group-name/project-name/にコードをチェックアウトします。.gitlab-ci.ymlで定義されたステップを実行します。- ビルドスクリプトの終了ステータスを確認します。
- ビルドコンテナと作成されたすべてのサービスコンテナを削除します。
サービスコンテナログをキャプチャする
サービスコンテナで実行中のアプリケーションが生成したログをキャプチャし、後で調査やデバッグに利用できます。サービスコンテナが正常に起動しても、予期しない動作が原因でジョブが失敗した場合は、サービスコンテナのログを確認します。ログに、コンテナ内のサービス設定の不足や誤りが示される場合があります。
CI_DEBUG_SERVICESは、サービスコンテナをアクティブにデバッグしている場合にのみ有効にしてください。サービスコンテナのログをキャプチャすると、ストレージとパフォーマンスの両方に影響があるためです。
サービスログの生成を有効にするには、プロジェクトの.gitlab-ci.ymlファイルにCI_DEBUG_SERVICES変数を追加します:
variables:
CI_DEBUG_SERVICES: "true"指定できる値は次のとおりです:
- 有効:
TRUE、true、True - 無効:
FALSE、false、False
他の値を指定すると、エラーメッセージが表示され、実質的に機能が無効になります。
有効にすると、すべてのサービスコンテナのログがキャプチャされ、他のログと同時にジョブトレースログにストリーミングされます。各コンテナからのログには、コンテナのエイリアスがプレフィックスとして付加され、異なる色で表示されます。
ジョブの失敗を診断するには、ログをキャプチャするサービスコンテナのログの生成レベルを調整します。デフォルトのログの生成レベルでは、トラブルシューティングのために十分な情報が得られない場合があります。
CI_DEBUG_SERVICESを有効にすると、マスクされた変数が表示される可能性があります。CI_DEBUG_SERVICESが有効な場合、サービスコンテナのログとCIジョブのログは、ジョブのトレースログに同時にストリーミングされます。その結果、サービスコンテナのログが、ジョブのマスクされたログに挿入される可能性があります。これにより、変数のマスキングの仕組みが阻害され、マスクされた変数が露出してしまいます。
CI/CD変数をマスクするを参照してください。
ジョブをローカルでデバッグする
以下のコマンドは、ルート権限なしで実行します。ユーザーアカウントで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 runner-bin-host
EOFこの例では、Makefileを含むGitLab Runnerリポジトリを使用しているため、makeを実行すると、Makefileで定義されたターゲットが実行されます。make runner-bin-hostの代わりに、プロジェクトに固有のコマンドを実行することもできます。
次に、サービスコンテナを作成します:
docker run -d --name service-redis redis:latest前述のコマンドは、最新のRedisコンテナイメージを使用して、service-redisという名前のサービスコンテナを作成します。サービスコンテナはバックグラウンドで実行されます(-d)。
最後に、以前に作成したbuild_scriptファイルを実行して、ビルドコンテナを作成します:
docker run --name build -i --link=service-redis:redis golang:latest /bin/bash < build_script前述のコマンドは、golang:latestイメージから起動され、1つのサービスがリンクされたbuildという名前のコンテナを作成します。build_scriptはstdinを使用してbashインタープリターにパイプされ、bashインタープリターがbuildコンテナ内でbuild_scriptを実行します。
テストの完了後にコンテナを削除するには、次のコマンドを使用します:
docker rm -f -v build service-redisこのコマンドは強制的に(-f)、buildコンテナ、サービスコンテナ、およびコンテナの作成時に作成されたすべてのボリューム(-v)を削除します。
サービスコンテナ使用時のセキュリティ
Docker特権モードはサービスに適用されます。これは、サービスイメージコンテナがホストシステムにアクセスできることを意味します。信頼できるソースからのコンテナイメージのみを使用する必要があります。
共有/buildsディレクトリ
ビルドディレクトリは/buildsの下にボリュームとしてマウントされ、ジョブとサービスの間で共有されます。サービスが起動した後、ジョブはプロジェクトを/builds/$CI_PROJECT_PATHにチェックアウトします。サービスがプロジェクトファイルにアクセスしたり、アーティファクトを保存したりする必要がある場合は、そのディレクトリが存在し、$CI_COMMIT_SHAがチェックアウトされるまで待機しなくてはなりません。ジョブがチェックアウト処理を完了する前に行われた変更は、チェックアウト処理によって削除されます。
サービスは、ジョブディレクトリにデータが格納され、処理の準備が整っていることを検出する必要があります。たとえば、特定のファイルが利用可能になるまで待機します。
起動直後に処理を開始するサービスは、ジョブデータがまだ利用できないために失敗する可能性があります。たとえば、コンテナはdocker buildコマンドを使用して、DinDサービスへのネットワーク接続を確立します。サービスはそのAPIに対して、コンテナイメージのビルドを開始するよう指示します。Docker Engineは、Dockerfileで参照しているファイルにアクセスできなければなりません。したがって、そのサービスからCI_PROJECT_DIRにアクセスできる必要があります。ただし、Docker Engineは、ジョブでdocker buildコマンドが呼び出されるまでアクセスを試行しません。この時点で、/buildsディレクトリにはすでにデータが格納されています。開始直後にCI_PROJECT_DIRへの書き込みを試みるサービスは、No such file or directoryエラーで失敗する可能性があります。
ジョブデータとやり取りするサービスがジョブ自体によって制御されていないシナリオでは、Docker executorワークフローを検討してください。