DockerプライベートレジストリをRaspberryPi上に作成

- [はじめに](#org02646e1)
  - [作業環境](#org45dd38a)
  - [レジストリの選択](#orgdfdcaf3)
  - [作業ステップ概要](#org2c3628e)
- [作業ステップ](#org6d90705)
  - [設計する](#org3321f13)
  - [ローカル接続](#org5f1ec36)
  - [リモート接続](#org960d182)
  - [各ノードの設定](#org6b4b55b)
- [参考情報](#org18d76ba)


<a id="org02646e1"></a>

# はじめに

Kubernatesクラスタを構成する場合には、どこのノードからも同一のDocker イメージの参照が できるように、Docker イメージの照会及び登録するレジストリが必要になります。 (KubernatesのPodは、原則どこのノードでも動作する可能性があるため)

一般的には、利用するクラウドサービス(Google/AWS/IBM..)が提供しているレジストリサービ スを利用することが普通であると思いますが、学習のために自前でレジストリサービスを構築 することにチャレンジします。


<a id="org45dd38a"></a>

## 作業環境

-   ハードウエア Raspberry Pi 3B x 3台、4B x 2台
-   Kubernates version 1.18.2


<a id="orgdfdcaf3"></a>

## レジストリの選択

Dockerイメージのレジストリとしては、クラスタ内外を含めたの様々な構成ができますが、以 下の3パターンが一般的な構成になります。

1.  パブリックレジストリを利用(Docker Hub)
2.  クラウドサービスの提供するプライベートレジストリを利用(Google/IBM/AWSのContainer Registory等)
3.  自前でプライベートレジストリを構築

可用性、運用・保守性、移行性等々を考慮すれば、1. または 2. から選択することが望ましい ですが、Kubernatesの構築を通じて、Kubernatesを理解することが目的であるので、ここでは、 「3. 自前でプライベートレジストリを構築」 を選択します。


<a id="org2c3628e"></a>

## 作業ステップ概要

作業が間違っていないことを確認して進めるために、以下の作業手順でレジストリサービスを構築していきます。

1.  設計する
2.  レジストリをDockerコマンドで実行し、ローカル接続ができることを確認
3.  レジストリをDockerコマンドで実行し、リモート接続ができることを確認


<a id="org6d90705"></a>

# 作業ステップ


<a id="org3321f13"></a>

## 設計する

作成するレジストリに対して、想定している設定内容を以下で記述する。

| 設定   | 内容       | 補足                  |
|------ |---------- |--------------------- |
| 通信方式 | TLS 1.2    | HTTPのみではノード間での通信ができない |
| サーバー認証 | 自己証明書 | 無料で済ませるため    |
| サーバー名 | レジストのサーバー名 | 実行例は rasp-registry |
| ポート番号 | レジストのポート番号 | 実行例は 5000         |

TLS <sup><a id="fnr.1" class="footref" href="#fn.1">1</a></sup>

通信をTLSと自己証明書で構築する理由は、それしか選択肢がないからです。


<a id="org5f1ec36"></a>

## ローカル接続

Dockerの機能のみを利用して、ローカル接続ができるレジストリの構築ができることを確認します。

```shell
$ sudo mkdir -p /var/local/volume
$ docker run -d -p 5000:5000 --name registry --hostname registry --restart on-failure:10 -v /var/local/volume:/var/lib/registry registry:2
```

/var/local/volume を Docker イメージを登録するレジストリのディレクトリになります。 docker ps として、registry:2 イメージが稼働していれば、完了です。

```shell

# パブリックリポジトリからイメージを入手
$ docker pull hello-world

# タグを追加する
$ docker tag hello-world localhost:5000/hello-world

# プライベートリポジトリにイメージを登録
$ docker push localhost:5000/hello-world

# プライベートリポジトリにからイメージが入手
$ docker pull localhost:5000/hello-world
```

docker image でイメージが入手できたことを確認することができます。 ノード内で利用可能なレジストリであるため、localhost を利用してイメージを参照します。

    $ docker images 
    REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
    hello-world                          latest              851163c78e4a        6 months ago        4.85kB
    localhost:5000/hello-world           latest              851163c78e4a        6 months ago        4.85kB

ノード内で実行できることが確認できたので、コンテナーを削除しておきます。

```shell

# CONTAINER ID を確認する
$ docker ps | grep registry

# コンテナを停止させ、削除します。 
$ docker stop [CONTAINER ID]
$ docker rm [CONTAINER ID]

```


<a id="org960d182"></a>

## リモート接続

Dockerの機能のみを利用して、リモート接続ができるレジストリの構築ができることを確認し ます。

TLS通信で利用するための証明書を生成します。今回は外部に公開せず、Kubernatesのテスト環 境であるため自己証明書を利用します。

以下のコマンドでは、x509自己署名証明書を4096ビットのRSA秘密鍵を生成しています。

自己署名証明書作成時に、Common Nameを聞いてくるので、このサーバーにアクセスする際の 名前と一致させて置く必要があります。

domain.key が秘密鍵ファイル、domain.crtが証明書ファイルになります。

```shell
mkdir -p ~/tmp/certs
cd ~/tmp/certs
openssl req -newkey rsa:4096 -nodes -keyout domain.key -x509 -days 365 -out domain.crt
```

自己証明書を利用して、レジストリの実行を確認します。秘密鍵と証明書ファイルとは先ほど 作成したファイルパスを指定します。以下では、ホスト側のファイルパス ~/tmp/certs を コ ンテナ側の /ファイルパス certs で参照できるようにして、起動をしています。

REGISTRY_HTTP_TLS_CERTIFICATE、REGISTRY_HTTP_TLS_KEY の環境変数には、それぞれ、証明書 ファイル、秘密鍵ファイルの指定をします。コンテナ側のプロセスが参照するために、コンテナ側のファイルパスで指定をします。

```shell
docker run -d -p 5000:5000 \
 -v ~/tmp/certs:/certs \
 -v /var/local/volume:/var/lib/registry \
 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
 -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
 --restart=always --name registory registry:2
```


<a id="org6b4b55b"></a>

## 各ノードの設定

各ノードからレジストリに接続するためには、レジストリの証明書を各ノード上のDockerサーバーに登 録する必要があります。そのためには、以下の作業をする必要があります。

1.  Docker サーバーが管理する証明書のディレクトリ(/etc/docker/certs.d/レジストリのホ スト名:ポート番号)を作成する。
2.  作成した証明書のディレクトリに、証明書ファイルを ca.crt の名称で複写する
3.  Docker サーバーの再起動をします。

```shell

# Docker サーバーの証明書のディレクトリを作成する
$ sudo mkdir -p /etc/docker/certs.d/rasp-registry:5000
$ cd /etc/docker/certs.d/rasp-registry:5000

# 証明書のコピーとサーバーの再起動
$ sudo scp pi@証明書を作成したホスト:証明書の生成パス/domain.crt ca.crt
$ sudo service docker restart

```

レジストリが各ノードからアクセスできることを確認しています。 お馴染みの hello-world が pull できることを確認します。 (hello-worldは、事前に push しなくても登録されている様でした)

```shell
$ docker pull rasp-registry:5000/hello-world
Using default tag: latest
latest: Pulling from hello-world
4ee5c797bcd7: Pull complete 
Digest: sha256:50b8560ad574c779908da71f7ce370c0a2471c098d44d1c8f6b513c5a55eeeb1
Status: Downloaded newer image for rasp-registry:5000/hello-world:latest

$ docker run rasp-registry:5000/hello-world
```

確かに実行をすることもできました。


<a id="org18d76ba"></a>

# 参考情報

-   Dockerの日本語サイト

[Dokcerの日本語サイト](http://docs.docker.jp/registry/toc.html)

-   Dockerの英語サイト

[Dockerの英語サイト](https://docs.docker.com/registry/)

-   privateなdockerレジストリを構築する - Qiita

<https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwj2nNirzuzqAhWlL6YKHW_bAioQFjABegQIAxAB&url=https%3A%2F%2Fqiita.com%2Fzknzfz%2Fitems%2F13d5d07ab5bb0feb1fd1&usg=AOvVaw2xeT2eTFSePsBvtmU2LcPS>

Docker Private Registryの構築 on Kubernetes <https://qiita.com/khk-h/items/c4bf26d771f5a4a78ae6>

Test an insecure registry <https://docs.docker.com/registry/insecure/>

## Footnotes

<sup><a id="fn.1" class="footnum" href="#fnr.1">1</a></sup> Transport Layer Securit