依存プロキシ

  • 13.6でGitLab PremiumからGitLab Freeに移動しました。
  • GitLab 13.7で非公開グループをサポート。
  • GitLab 13.7から公開グループのイメージへの匿名アクセスは利用できなくなりました。
  • GitLab 13.10でpull-by-digestとDockerバージョン20.xのサポートを導入しました。

GitLab 依存プロキシは、頻繁にアクセスするアップストリームイメージに使用できるローカルプロキシです。

CI/CD の場合、依存プロキシはリクエストを受けてレジストリからアップストリームイメージを返し、プルスルーキャッシュとして機能します。

前提条件

依存プロキシを使うには、GitLabインスタンスで有効になっている必要があります。デフォルトでは有効になっていますが、管理者はオフにすることができます。

サポートされているイメージとパッケージ

以下のイメージとパッケージがサポートされています。

イメージ/パッケージGitLabバージョン
Docker11.11+

今後の追加予定については、ディレクションページをご覧ください。

グループの依存プロキシの有効化または無効化

GitLab 15.0 で必須ロールが開発者からメンテナーに変更されました。

グループの依存プロキシを有効または無効にするには:

  1. 左のサイドバーで、Search(検索)を選択するか、Go to(移動)を選択してグループを探します。
  2. 設定 > パッケージとレジストリを選択します。
  3. 依存プロキシ]セクションを展開します。
  4. プロキシを有効にするには、[プロキシを有効にする] をオンにします。オフにするには、トグルをオフにします。

この設定はグループの依存プロキシにのみ影響します。GitLab インスタンス全体の依存プロキシのオン/オフを切り替えることができるのは管理者のみです。

依存プロキシを見る

依存プロキシを表示します:

  1. 左のサイドバーで、Search(検索)を選択するか、Go to(移動)を選択してグループを探します。
  2. オペレーション]→[依存プロキシ]を選択します。

依存プロキシはプロジェクトでは使用できません。

Dockerイメージには依存プロキシを使用します。

DockerイメージのソースとしてGitLabを使うことができます。

前提条件:

  • イメージはDocker Hubに保存する必要があります。

依存プロキシによる認証

  • GitLab 13.7 でdependency_proxy_for_private_groupsというフラグで導入されました。デフォルトで有効です。
  • GitLab 15.0で機能フラグdependency_proxy_for_private_groups削除
  • GitLab 16.3で導入されたグループアクセストークンをサポート。

依存プロキシはあなたのグループに関連付けられたスペースにDockerイメージを保存するため、依存プロキシに対して認証を行う必要があります。

非公開レジストリからイメージを使用する手順に従ってください。ただし、registry.example.com:5000 を使用する代わりに、ポートgitlab.example.comを使用せずに GitLab ドメインを使用してください。

例えば、手動でサインインする場合:

docker login gitlab.example.com --username my_username --password my_password

を使用して認証できます:

個人アクセストークンまたはユーザ名とパスワードを使用して依存プロキシにアクセスするユーザは、イメージをプルするグループのゲストロール以上を持っている必要があります。

依存プロキシはDocker v2のトークン認証フローに従い、プルリクエストに使用するJWTをクライアントに発行します。認証の結果発行されたJWTは、しばらくすると失効します。トークンの有効期限が切れると、ほとんどのDockerクライアントは認証情報を保存し、それ以上アクションを起こさなくても自動的に新しいトークンを要求します。

トークンの有効期限は設定可能です。GitLab.comでは、有効期限は15分です。

SAML SSO

SSO が有効になっている場合、ユーザーは依存プロキシ経由でイメージをプルする前に、SSO でサインインする必要があります。

CI/CD 内での認証

  • GitLab 13.7 で導入されました
  • GitLab 13.9で、依存プロキシを使ってジョブのイメージを取得する際の自動ランナー認証が追加されました。
  • GitLab 13.10で大文字を含むグループ名のプレフィックスが修正されました。

ランナーは自動的に依存プロキシにサインインします。依存プロキシを経由するには、定義済みの変数のいずれかを使用します:

  • CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX を使用します。
  • CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX は、プロジェクトが存在するサブグループ、または直接のグループを通してプルします。

例:最新のアルペン画像をプル

# .gitlab-ci.yml
image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/alpine:latest

他にも、定義済みのCI/CD変数があります:

  • CI_DEPENDENCY_PROXY_USER:依存プロキシにログインするための CI/CD ユーザー。
  • CI_DEPENDENCY_PROXY_PASSWORD:依存プロキシにログインするための CI/CD パスワード。
  • CI_DEPENDENCY_PROXY_SERVER:依存プロキシにログインするためのサーバ。
  • CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX: トップレベルグループから依存プロキシを通してイメージを引き出すためのイメージプレフィックス。
  • CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX: プロジェクトが属する直接のグループまたはサブグループから、依存プロキシを通して画像を引き出すための画像接頭辞。

CI_DEPENDENCY_PROXY_SERVER CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX およびCI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX にはサーバーポートが含まれます。依存プロキシのパスを明示的に含める場合は、ポートを含めずに手動で依存プロキシにログインした場合を除き、ポートを含める必要があります:

docker pull gitlab.example.com:443/my-group/dependency_proxy/containers/alpine:latest

依存プロキシを使用してイメージをビルドする場合の例:

# Dockerfile
FROM gitlab.example.com:443/my-group/dependency_proxy/containers/alpine:latest
# .gitlab-ci.yml
image: docker:20.10.16

variables:
  DOCKER_HOST: tcp://docker:2375
  DOCKER_TLS_CERTDIR: ""

services:
  - docker:20.10.16-dind

build:
  image: docker:20.10.16
  before_script:
    - docker login -u $CI_DEPENDENCY_PROXY_USER -p $CI_DEPENDENCY_PROXY_PASSWORD $CI_DEPENDENCY_PROXY_SERVER
  script:
    -  docker build -t test .

カスタム CI/CD 変数を使用して、個人のアクセストークンやデプロイトークンを保存したりアクセスしたりすることもできます。

依存プロキシキャッシュへのDockerイメージの保存

Docker イメージを依存プロキシストレージに保存します:

  1. 左のサイドバーで、Search(検索)を選択するか、Go to(移動)を選択してグループを探します。
  2. オペレーション]→[依存プロキシ]を選択します。
  3. 依存プロキシ画像のプレフィックスをコピーします。
  4. 以下のコマンドのいずれかを使用します。これらの例では、イメージはalpine:latest です。
  5. 画像をダイジェストで取り出すこともでき、取り出す画像のバージョンを正確に指定することができます。

    • .gitlab-ci.yml ファイルに画像を追加して、タグを指定して画像を取り出します:

       image: gitlab.example.com/groupname/dependency_proxy/containers/alpine:latest
      
    • .gitlab-ci.yml ファイルに画像を追加して、ダイジェストで画像を取り出します:

       image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/alpine@sha256:c9375e662992791e3f39e919b26f510e5254b42792519c180aad254e6b38f4dc
      
    • 手動でDockerイメージをプルします:

       docker pull gitlab.example.com/groupname/dependency_proxy/containers/alpine:latest
      
    • Dockerfile にURLを追加します:

       FROM gitlab.example.com/groupname/dependency_proxy/containers/alpine:latest
      

GitLabはDocker HubからDockerイメージをプルし、GitLabサーバにblobをキャッシュします。次に同じイメージをプルするとき、GitLabはDocker Hubからイメージの最新情報を取得しますが、GitLabサーバから既存のblobを提供します。

ストレージ使用量の削減

依存プロキシで使用するストレージを削減する方法については、「依存プロキシのストレージ使用量を削減する」を参照してください。

Docker Hubのレート制限と依存プロキシ

GitLab 13.7 で導入されました

Docker Hubのレート制限を回避するための依存プロキシの使い方をご覧ください。

2020年11月、DockerはDocker Hubからのプルリクエストにレート制限を導入しました。GitLabCI/CD設定でDocker Hubからのイメージを使用している場合、ジョブが実行されるたびにプルリクエストとしてカウントされる可能性があります。この制限を回避するために、代わりに依存プロキシキャッシュからイメージをプルすることができます。

イメージをプルすると(docker pull や、.gitlab-ci.yml ファイルではimage: foo:latest のようなコマンドを使用します)、Docker クライアントはリクエストのコレクションを作成します:

  1. イメージマニフェストが要求されます。マニフェストには、イメージのビルド方法に関する情報が含まれています。
  2. マニフェストを使用して、Dockerクライアントはブロブとも呼ばれるレイヤーのコレクションを1つずつ要求します。

Docker Hubのレート制限は、マニフェストに対するGETリクエスト数に基づいています。依存プロキシは指定されたイメージのマニフェストとブロブの両方をキャッシュするため、再度要求する際にDocker Hubに連絡する必要はありません。

GitLabは、キャッシュされたタグ付きイメージが古いかどうかをどのように知るのですか?

alpine:latest のような画像タグを使っている場合、画像は時間とともに変化します。変更されるたびに、マニフェストにはリクエストするブロブに関する異なる情報が含まれます。依存プロキシは、マニフェストが変更されるたびに新しいイメージをプルするのではなく、マニフェストが古くなったときにのみチェックします。

Dockerはイメージマニフェストに対するHEADリクエストをレート制限にカウントしません。alpine:latest に対して HEAD リクエストを行い、ヘッダで返されるダイジェスト(チェックサム)値を表示して、マニフェストが変更されたかどうかを判断できます。

依存プロキシはすべてのリクエストを HEAD リクエストで開始します。マニフェストが古くなった場合、そのときだけ新しいイメージがプルされます。

例えば、パイプラインがnode:latest 5分ごとに node:latestプルする場合node:latest 、依存プロキシはイメージ全体をキャッシュし、 node:latest変更がnode:latest あった場合のみ更新 node:latestします。そのため、6時間に360回のイメージのプルリクエストがある(Docker Hubのレート制限を超える)代わりに、その間にマニフェストが変更されない限り、プルリクエストは1回で済みます。

Docker Hubのレート制限を確認してください。

Docker Hubへのリクエスト数と残数が気になる場合は、Runnerから、あるいはCI/CDスクリプトでこれらのコマンドを実行することができます:

# Note, you must have jq installed to run this command
TOKEN=$(curl "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq --raw-output .token) && curl --head --header "Authorization: Bearer $TOKEN" "https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest" 2>&1 | grep --ignore-case RateLimit
...

出力はこんな感じです:

RateLimit-Limit: 100;w=21600
RateLimit-Remaining: 98;w=21600

この例では、6時間以内に100回のプルを行い、残り98回が限界であることを示しています。

CI/CD ジョブのレート制限を確認します。

この例では、jqcurl がインストールされたイメージを使用する GitLab CI/CD ジョブを示しています:

hub_docker_quota_check:
    stage: build
    image: alpine:latest
    tags:
        - <optional_runner_tag>
    before_script: apk add curl jq
    script:
      - |
        TOKEN=$(curl "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq --raw-output .token) && curl --head --header "Authorization: Bearer $TOKEN" "https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest" 2>&1

トラブルシューティング

認証エラー:「HTTP Basic: アクセス拒否”

依存プロキシに対する認証時にHTTP Basic: Access denied エラーが発生する場合は、2要素認証のトラブルシューティングガイドを参照してください。

依存プロキシ接続の失敗

サービスエイリアスが設定されていない場合、docker:20.10.16 イメージはdind サービスを見つけることができず、以下のようなエラーが発生します:

error during connect: Get http://docker:2376/v1.39/info: dial tcp: lookup docker on 192.168.0.1:53: no such host

これはDockerサービスのサービスエイリアスを設定することで解決できます:

services:
    - name: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/docker:18.09.7-dind
      alias: docker

CI/CDジョブから依存プロキシへの認証時のイシュー

GitLab Runnerは依存プロキシに対して自動的に認証を行います。しかし、基盤となるDockerエンジンはまだその作成者の認証解決プロセスに従います。

認証メカニズムの設定を誤ると、HTTP Basic: Access denied403: Access forbidden エラーが発生する可能性があります。

ジョブログを使用して、依存プロキシに対する認証に使用された認証メカニズムを表示できます:

Authenticating with credentials from $DOCKER_AUTH_CONFIG
Authenticating with credentials from /root/.docker/config.json
Authenticating with credentials from job payload (GitLab Registry)

期待される認証メカニズムを使用していることを確認してください。

Not Found または、404 画像を引き出す際にエラーが発生します。

このようなエラーは、ジョブを実行しているユーザーが依存プロキシグループに最低限Guestロールを持っていないことを示している可能性があります:

  • ```plaintext ERROR: gitlab.example.com:443/group1/dependency_proxy/containers/alpine:latest: not found

failed to solve with frontend dockerfile.v0: failed to create LLB definition: gitlab.example.com:443/group1/dependency_proxy/containers/alpine:latest: not found ```

  •    ERROR: Job failed: failed to pull image "gitlab.example.com:443/group1/dependency_proxy/containers/alpine:latest" with specified policies [always]:
       Error response from daemon: error parsing HTTP 404 response body: unexpected end of JSON input: "" (manager.go:237:1s)
    

Access denied と同様のケースのエラーメッセージを改善する作業の詳細については、イシュー354826 を参照してください。

exec format error 依存プロキシからイメージを実行するとき

note
このイシューはGitLab 16.3で解決されました。16.2以前のセルフマネージドインスタンスについては、インスタンスを16.3にアップデートするか、以下に記載する回避策をご利用ください。

このエラーは、GitLab 16.2以前のARMベースのDockerインストールで依存プロキシを使用しようとすると発生します。依存プロキシは、特定のタグを持つイメージをプルする際に x86_64 アーキテクチャのみをサポートします。

回避策として、依存プロキシに異なるアーキテクチャをプルさせるためにイメージの SHA256 を指定することができます:

docker pull ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/library/docker:20.10.3@sha256:bc9dcf5c8e5908845acc6d34ab8824bca496d6d47d1b08af3baf4b3adb1bd8fe

この例では、bc9dcf5c8e5908845acc6d34ab8824bca496d6d47d1b08af3baf4b3adb1bd8fe が ARM ベースのイメージの SHA256 です。