Private Docker Registryを構築しよう！(NginxでのBasic認証付き)

本記事は[東京学芸大学 櫨山研究室 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/hazelab)の八日目の記事になります．

# はじめに

みなさんはDockerを利用していますか？

Dockerではイメージを共有し，イメージからコンテナを生成することが簡単にできます．
作ったアプリケーションをちょっと公開したいと思えば，サーバ上でイメージからコンテナを立ち上げるだけで実行することができ非常に便利ですね．

一方でDockerイメージをそのように管理する方法は少し悩ましい問題だと思います．

本記事では自前のサーバにDocker Registryを立ててイメージを管理する方法を扱います．

# 構成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225901/ac973992-008d-ad34-119e-f30c69048c46.png)

NginxをリバースプロキシにおいてDocker RegistryとGUIのクライアントソフトにアクセスできるようにします．
またNginxのBasic認証を有効にして簡易的に認証機能を持たせます．

前提として

- サーバのドメインは取得済み
- サーバにDocker，Nginxは導入済み
- NginxのSSLは設定済み
- 動作環境はCent OS 7を想定

として進めます🙇‍♂️

# Docker Registryの導入

Docker RegistryはDocker Imageを保管するアプリケーションです．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225901/afdcaeb0-a601-4c99-5d9d-de9792d3f751.png)


Docker Registryを自前のサーバで動かすことで`docker push`コマンドでローカルやCI環境で構築したDockerイメージを保存し`Docker pull`コマンドでイメージの取得が行えます．

Docker HubでDocker Registryの[公式イメージ](https://hub.docker.com/_/registry)が公開されています．

動かすだけなら以下のコマンドで5000番ポートで動作します．

```bash:bash
docker run -p 5000:5000 registry:latest
```

今回は以下のような形で起動します．

|項目|内容|
|:--|:--|
|コンテナ名|registry|
|ポートマッピング|5000:5000|
|restart|always|
|ネットワーク|registry|
|ボリューム|registry-volume:/var/lib/registry|
|環境変数|REGISTRY_STORAGE_DELETE_ENABLED=true|

環境変数`REGISTRY_STORAGE_DELETE_ENABLED`をtrueにすることでRegistry上に保管されたDockerイメージを削除することが可能です．

```bash:bash
# dockerネットワークの作成
docker network create registry

# dockerボリュームの作成
docker volume create --name registry-volume

# コンテナの起動
docker container run -d \\
--name registry \\
-p 5000:5000 \\
--restart always \\
--net registry \\
-v docker-registry:/var/lib/registry \\
-e REGISTRY_STORAGE_DELETE_ENABLED=true \\
registry:latest
```

これで5000番ポートでDocker Registryが動作します．

# Docker Registry UIの導入

Docker Registryにどのようなイメージが保管されているのかGUIで確認できた方が何かと便利なのでGUIツールを導入します．

今回は，[Docker Registry UI](https://github.com/Joxit/docker-registry-ui)というツールを使います．

![registre-ui](https://camo.githubusercontent.com/daa08da8dda8bacb90181a0130673ae70af6ee0f2430666b883e85bbae701d33/68747470733a2f2f7261772e6769746875622e636f6d2f4a6f7869742f646f636b65722d72656769737472792d75692f6d61737465722f646f636b65722d72656769737472792d75692e676966)

> [画像引用元] Docker Registry UI, https://github.com/Joxit/docker-registry-ui

Docker Hubでイメージが公開されているのでDocker環境があれば簡単に動かすことができます．

以下のような形で起動します．

|項目|内容|
|:--|:--|
|コンテナ名|registry_ui|
|ポートマッピング|4000:80|
|restart|always|
|ネットワーク|registry|
|環境変数|REGISTRY_URL=http://registry <br> DELETE_IMAGES=true|

```bash:bash
docker container run -d \\
--name registry_ui \\
-p 4000:80 \\
--restart always \\
--net registry \\
-e REGISTRY_URL=http://registry \\
-e DELETE_IMAGES=true \\
joxit/docker-registry-ui:latest
```

これで4000番ポートでDocker Registry UIが動作します．

# NginxでリバースプロキシとBasic認証をつける

はじめにBasic認証をかけるためにパスワードファイルを作成します．
次にNginxの設定ファイルを記述してパスに応じてリクエストをdocker registryとdocker registry uiに流します．

## パスワードファイルの作成

作成するパスワードファイルは`/etc/nginx/.htpasswd`とします．

```bash:bash
# htpasswdのインストール(必要に応じて)
sudo yum install httpd-tools

# パスワードファイルの作成
htpasswd -c  /etc/nginx/.htpasswd test-user
```

## リバースプロキシの設定

リバースプロキシの設定ファイルを`/etc/nginx/conf.d/registry.conf`に作成します．

- パスが`/v2/`から始まる場合はdocker registryにアクセス
- パスが`/registry-ui/`から始まる場合はdocker registry uiにアクセス

とします．

設定ファイルの内容は以下です．
なおここではNginxの設定で`/etc/nginx/conf.d`配下の`.conf`ファイルを読み込むようになっているものとしています．

```conf:/etc/nginx/conf.d/registry.conf
# docker registryの設定
location /v2/ {
  # Do not allow connections from docker 1.5 and earlier
  # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
  if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
    return 404;
  }

  # To add basic authentication to v2 use auth_basic setting.
  auth_basic "Enter password";
  auth_basic_user_file /etc/nginx/.htpasswd;

  proxy_pass http://localhost:5000;

  proxy_set_header  Host              $http_host;   # required for docker client's sake
  proxy_set_header  X-Real-IP         $remote_addr; # pass on real client's IP
  proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
  proxy_set_header  X-Forwarded-Proto $scheme;
  proxy_read_timeout                  900;
}

# docker registry uiの設定
location /registry-ui/ {
  auth_basic "Enter password";
  auth_basic_user_file /etc/nginx/.htpasswd;

  proxy_pass http://localhost:4000/;

  proxy_set_header        HOST                $http_host;
  proxy_set_header        X-Forwarded-Host    $host;
  proxy_set_header        X-Forwarded-Port    $server_port;
  proxy_set_header        X-Real-IP           $remote_addr;
  proxy_set_header        X-Forwarded-For     $proxy_add_x_forwarded_for;
  proxy_set_header        X-Forwarded-Proto   $scheme;
  proxy_read_timeout      900;
}
```

## Nginxの再起動

ここまでの設定を反映するためにNginxを再起動します．

```bash:bash
sudo systemctl restart nginx
```

# 動作確認

ローカルのマシンからサーバ上のDocker Registryにアクセスを試みます．

```bash:bash
docker login ${サーバのドメイン名}
```

ここでユーザー名とパスワードを聞かれるので先ほど作成した`test-user`とそのパスワードを入力します．

認証が完了したら`docker push`コマンドでイメージをpushしたり登録されている`docker pull`コマンドでイメージをpullすることができます．

次にdocker registry uiにアクセスしてみましょう．

ブラウザで`https://{ドメイン名}/registry-ui`にアクセスします．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225901/54029dc6-d338-c52b-8d13-dccc7836d41e.png)

ユーザー名とパスワードを入力して，以下のような画面が見れれば成功ですね．

![registre-ui](https://camo.githubusercontent.com/daa08da8dda8bacb90181a0130673ae70af6ee0f2430666b883e85bbae701d33/68747470733a2f2f7261772e6769746875622e636f6d2f4a6f7869742f646f636b65722d72656769737472792d75692f6d61737465722f646f636b65722d72656769737472792d75692e676966)


# おわりに

本記事では自前のサーバにDocker Registryを構築する方法を扱いました．

PraivateなDocker Registryを構築したい！という方に参考になれば幸いです．


# 参考

Authenticate proxy with nginx, https://docs.docker.com/registry/recipes/nginx/