GitLabのDependency Proxyを使ってDockerHubのRate Limitを回避する

GitLabの[Dependency Proxy](https://docs.gitlab.com/ee/user/packages/dependency_proxy/)を使ってみた時のメモ。
GitLab Japanの方の以下のブログを参考にした。

- [オンプレGitLabで依存関係プロキシ(Dependency Proxy)を設定してDockerHubのダウンロード制限を回避する(設定編)](https://qiita.com/ynott/items/fd03b0341b443e617bd5)
- [オンプレGitLabで依存関係プロキシ(Dependency Proxy)を利用する(docker pull利用編)](https://qiita.com/ynott/items/fbd1177940d49d1f014f)
  
上記の記事があるのでブログ化しようか迷ったが、上記の記事で古い点があったのでブログ化した。
検証にはGitLab Community Edition 15.8.3を利用した。
## Dependency Proxyとは
詳しくは[オンプレGitLabで依存関係プロキシ(Dependency Proxy)を設定してDockerHubのダウンロード制限を回避する(設定編)](https://qiita.com/ynott/items/fd03b0341b443e617bd5)で述べられているが、要はDockerHubを利用した際に`429 Too Many Requests`や`You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limits`が出てpullに失敗するのを避けるため、Proxyを設定してイメージをGitLab側にキャッシュさせるものである。

使い方としては、
```
docker pull <GitLabのDependency ProxyのURL>/<DockerHubのイメージ名>:<タグ>
```
で実行すると、初回はDockerHubからGitLabにPullされ、2回目以降はGitLabのものをpullする動きとなる。
なお、Dependency Proxyの単位はGroup単位もしくはホスト単位のようでProject単位では設定できない模様。
今回はGroup単位のもので確認している。ホスト単位で設定する場合は[こちらの公式ドキュメント](https://docs.gitlab.com/ee/administration/packages/dependency_proxy.html)を参考にするとよさそう。

## Dependency Proxyのインストール
こちらで確認したところ、docker-composeでGitLabをインストールする場合はデフォルトで有効化されており、helmでGitLabをインストールする場合は無効化されている模様。
自分はhelmでGitLabを使っているため、helmの`values.yaml`の`global.appConfig`に以下の設定を入れてデプロイした。
```
    dependencyProxy:
      enabled: true
      proxy_download: true
      bucket: gitlab-dependency-proxy
      connection: {}
```
デプロイのコマンドは以下。
```
helm upgrade -i -f ./values.yaml gitlab gitlab/gitlab -n gitlab
```
デプロイ後、GitLabにアクセスし、適当なGroupを作成してGroupの`Setings`->`Packages and registries`からDependency Proxyが見えたらOK。

![1677117486460.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/95a0a870-8537-772c-badd-be1be3895109.png)

## Dependency Proxyの利用

Proxy URLの取得方法はGitLab Japanのブログの方は古くなっており、現在は`Packages and registries`->`Dependency Proxy`から取得できる。

![1677117641696.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/116ee25a-7393-0673-2ed1-f6e22baf1aa9.png)

レジストリにログインする。注意点として、helmでインストールした場合、
- registry.domain
- gitlab.domain
のそれぞれのIngressリソースが作成され、通常コンテナイメージの管理はregistry.domainを利用するが、Dependency Proxyの場合はgitlab.domainの方を利用する。そのため、ログインコマンドは以下のようになる。
```
docker login gitlab.app.hogeeee.info
```
試しにnginxのイメージをpullしてみる。
```
docker pull gitlab.app.hogeeee.info/myapp/dependency_proxy/containers/nginx
```
pull前のDependency Proxyの表示は以下。

![1677119033816.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/a919d343-2d59-cb9b-33d0-da563c6ddb96.png)

GitLab上にはイメージは存在していないが、Proxyとして動くため、pullコマンドは問題なく動作する。
```
$ docker pull gitlab.app.hogeeee.info/myapp/dependency_proxy/containers/nginx
gitlab.app.hogeeee.info/myapp/dependency_proxy/containers/nginx:latest:           resolved       |++++++++++++++++++++++++++++++++++++++|
manifest-sha256:7f797701ded5055676d656f11071f84e2888548a2e7ed12a4977c28ef6114b17: done           |++++++++++++++++++++++++++++++++++++++|
config-sha256:3f8a00f137a0d2c8a2163a09901e28e2471999fde4efc2f9570b91f1c30acf94:   done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:7e9b29976cce358fbdd777b91ce2c52d18090dd1507d0616793e9ce8cc15979c:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:077b9569ff86b205b47334ce8fa1c4bcf55b124b2fe880f40b56f9932f856f68:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:a0bc35e7077319c74cd587e1c911894c0bc003e1783c0bc2e59e351d41cfa543:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:3082a16f3b619613a40d0b9056c6142493980314187ef6b6281909a40f6b7147:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:bb263680fed18eecdc67f885094df6f589bafc19004839d7fdf141df236a61aa:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:258f176fd22609802ed5def498ce4c7d1fa80a8ddba258b6e9eca0364df3ddb3:    done           |++++++++++++++++++++++++++++++++++++++|
elapsed: 103.7s                                                                   total:  24.3 M (240.0 KiB/s)
```

実行後、キャッシュされたことが分かる。
![1677119157125.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/376560d9-aa3f-80e4-7cab-8dd7da1b4551.png)

## CI/CDでの利用
利用は非常に簡単。[公式ドキュメント](https://docs.gitlab.com/ee/user/packages/dependency_proxy/#authenticate-within-cicd)にあるように、`CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX`をつけるだけ。
試しに以下のbusyboxイメージを使うジョブを持った`.gitlab-ci.yml`を作成してpushする。
```yaml
stages:
  - build

build-job:
  image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/busybox
  stage: build
  script:
    - echo "Compiling the code..."
    - echo "Compile complete."
```
すると実行されたジョブのログからDependency Proxyが使われたことが確認できる。
```
Running with gitlab-runner 15.8.2 (4d1ca121)
  on gitlab-runner-app-677f44dd67-m2f5h m6cNxfT2, system ID: r_ximVOH9cKkLk
Preparing the "kubernetes" executor
00:00
Using Kubernetes namespace: gitlab-demo
Using Kubernetes executor with image gitlab.app.hogeeee.info:443/myapp/dependency_proxy/containers/busybox ...
Using attach strategy to execute scripts...
```
Dependency Proxyの方にもbusyboxイメージが追加されていることが確認できる。
![1677123221854.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/dd7edf38-e47b-9f54-153d-38d533e9d74c.png)

なお、Privateなリポジトリから引っ張ってくる場合は`CI_DEPENDENCY_PROXY_USER`や`CI_DEPENDENCY_PROXY_PASSWORD`といった環境変数が用意されているので、こちらを設定して実行してやれば上手くいくと思う（未検証）。

## おわりに
Dependency Proxyの利用は非常に簡単なため、DockerHubのRate Limitに悩むチーム・組織などでは導入の検討の価値がありそうだ。
ただ、運用を考えた場合、イメージは[デフォルトでは自動で削除されない](https://docs.gitlab.com/ee/user/packages/dependency_proxy/reduce_dependency_proxy_storage.html)。
Dependency Proxyの設定から90日後にするなどの設定は可能だが、細かい削除ルールを適用したい場合はAPIの活用なども含めて検討する必要がある点は注意した方がいい。