プライベートDocker Registryの構築方法

プライベートDocker Registryを構築する方法を記載します。
この記事では、Docker Registryへの通信をhttpsで行っています。
社内で運用する目的で構築するので、http通信でも問題ありませんが、Docker Registryの通信方法は、デフォルトではhttpsになっており、httpよりもhttpsの方が簡単に構築できました。自己証明書でも運用には問題がないので、自己証明書で構築するようにしています。
最終的に構築したDocker Registryにローカル（Docker Registryが置かれたサーバー）からイメージのpush/pullを行えるようになります。

***記事の中で<>で囲っているものは、名前が任意のものであることを示しています。***

# 環境
ubuntu 18.04
docker-ce 19.03.4
OpenSSL 1.1.0g

# 構築方法
### イメージのダウンロード
Docker Resistryは、Docker hubに[公式のイメージ](https://hub.docker.com/_/registry)があるので、それをダウンロードします。

```
$ docker pull registry
```

### 自己証明書の作成
https通信用の証明書を作成します。


####秘密鍵の作成
秘密鍵の名前をserver.keyとします。

```
$ openssl genrsa -aes256 -out <server.key> 2048  
Generating RSA private key, 2048 bit long modulus
....................+++++
...........................+++++
e is 65537 (0x010001)
Enter pass phrase for <server.key>:（任意のパスフレーズ）
Verifying - Enter pass phrase for <server.key>:
```
***※注意***
秘密鍵にパスワードが設定されていると、エラーによりDocker Registryコンテナが起動しません。
しかし、秘密鍵作成時に以下のように必ずパスワードを要求してくるので、適当なパスワードを設定し、後から削除します。
`You must type in 4 to 1023 characters`


####秘密鍵のパスワードを削除
```
$ openssl rsa -in <server.key> -out <server.key> -passin pass:（秘密鍵のパスワード）
```

####証明書発行要求の作成
証明書発行要求の名前をserver.csrとします。

```
$ openssl req -new -key <server.key> -out <server.csr>

You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]: （未入力）
State or Province Name (full name) [Some-State]:（未入力）
Locality Name (eg, city) []:（未入力）
Organization Name (eg, company) [Internet Widgits Pty Ltd]:（未入力）
Organizational Unit Name (eg, section) []:（未入力）
Common Name (e.g. server FQDN or YOUR name) []:<myregistry>（Docker Resistryがあるノードのドメインを入力）
Email Address []:（未入力）
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:（未入力）
An optional company name []:（未入力）
```

####自己証明書作成
証明書の名前をserver.crtとします。

```
$ openssl x509 -days 3650 -in <server.csr> -req -signkey <server.key> -out <server.crt>
Signature ok
subject=C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = <myregistry>
Getting Private key
```

###Docker Registryの起動
証明書を`<registry-certs>`ディレクトリに置きます。

```
$ mkdir -p /<registry-certs>
$ mv <server.key> <server.csr> <server.crt> /<registry-certs>
```

コンテナを起動します。
なお、今回はホスト側のポートを5000番にマッピングしてますが、ホスト側のポートは、任意です。コンテナ側のポートは、公式イメージで5000番がエクスポートされているので、固定です。


```
$ docker run \
  -d \
  -p 5000:5000 \
  -v /<registry-certs>:/<certs> \
  -v /<registry-data>:/var/lib/registry \
  -e REGISTRY_HTTP_TLS_CERTIFICATE="/<certs>/<server.crt>" \
  -e REGISTRY_HTTP_TLS_KEY="/<certs>/<server.key>" \
  -e REGISTRY_HTTP_TLS_ADDR="0.0.0.0:5000" \
  registry
```

**オプションの説明**

```
 -d：コンテナをバックグラウンドで起動します。
 -p：ホスト側のポートとコンテナ側のポートをマッピングします。<host_port>:<container_port>
 -v：コンテナのボリュームをホストにマウントします。<host_volume>:<container_volume>
 -e：コンテナに環境変数を設定します。
```

###動作確認
####イメージをpushする
確認用のイメージをpullします。

```
$ docker pull hello-world
```

Registryにイメージをpushするときは、以下の形式で書きます。


`<repositry>:<registry_port>/<project>/<image_name>:<tag>`

`<repositry>`の箇所は、docker hub上のリポジトリを指しています。
今回は、プライベートレジストリなのでリポジトリは、ありません。
このような場合、`<repository>`は、Docker Registryのあるノード名に置き換えられます。
`<tag>`はデフォルトでは、latestとなります。

```
$ docker tag hello-world localhost:5000/<hello-project>/<hello-world>
```

イメージをpushします。

```
$ docker push localhost:5000/<hello-project>/<hello-world>
```

イメージがpushされます。/registry-data以下にイメージが置かれていることが確認できます。
また、pushをpullに変えれば、pullも行えます。


# 参考文献
1．「レジストリ・サーバのデプロイ」, 
　　http://docs.docker.jp/registry/deploying.html#running-a-domain-registry , 
　　2019年11月17日アクセス
2．「オレだよオレオレ認証局で証明書つくる」, 
　　https://qiita.com/ll_kuma_ll/items/13c962a6a74874af39c6 , 
　　2019年11月17日アクセス