おうちk8sクラスタを作る: Dockerレジストリ編

![DSC_1728.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58479/4971e1d1-8a75-2c58-a1a9-fe74f1b4b0cb.jpeg)
![DSC_1727.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58479/990f68af-9c76-4b55-6a6f-7d1b32952756.jpeg)
写真: 2020年3月7日時点のおうちk8sクラスタ

## 1. 概要

　本記事は、学習用に構築しているRaspberry Piによるk8sクラスタ、いわゆる「おうちk8sクラスタ」の製作記の「Dockerレジストリ編」です。

　k8sクラスタでDockerコンテナを起動する場合、ノードにDockerイメージを配布するために、Dockerイメージを格納した「Dockerレジストリ」が必要です。（話を簡単にするために、Docker前提で話を進めます）
今回は、Docker Inc.が提供しているDockerイメージ「[registry](https://hub.docker.com/_/registry)」を使い、k8sのマスターノードにDockerレジストリを構築しました。

　なお、今回のk8sクラスタは限定された環境下でのみアクセスされるため、Dockerレジストリの認証は行っていません。
認証が必要な場合は[Harbor](https://goharbor.io/)、[Portus](http://port.us.org/)などのソフトウェアを使ってDockerレジストリを構築するのが良いかと思います。

## 2. 環境

　今回の環境は以下の通りです。詳しい環境、構築方法については別記事『[Raspberry Pi 4に64ビット版UbuntuでKubernetes環境を構築する](https://qiita.com/yuyakato/items/6aeb42868cd521237e75)』をご参照ください。

* ハードウェア: Raspberry Pi 4 4GB 4台
* OS: Ubuntu Server 19.10 ARM64（AArch64）版
* ノード構成:
    * マスターノード: 1台
    * ワーカーノード: 3台

```text
ubuntu@k8s-m1:~$ cat /etc/os-release
NAME="Ubuntu"
VERSION="19.10 (Eoan Ermine)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 19.10"
VERSION_ID="19.10"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=eoan
UBUNTU_CODENAME=eoan

ubuntu@k8s-m1:~$ uname -a
Linux ubuntu 5.3.0-1014-raspi2 #16-Ubuntu SMP Tue Nov 26 11:18:23 UTC 2019 aarch64 aarch64 aarch64 GNU/Linux

ubuntu@k8s-m1:~$ cat /proc/cpuinfo
...
Hardware    : BCM2835
Revision    : c03112
Serial      : 10000000794dd63d
Model       : Raspberry Pi 4 Model B Rev 1.2

ubuntu@k8s-m1:~$ cat /proc/meminfo
MemTotal:        3882408 kB
MemFree:         1965400 kB
MemAvailable:    3563220 kB
...

ubuntu@k8s-m1:~$ kubectl get nodes --output wide
NAME     STATUS   ROLES    AGE     VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE       KERNEL-VERSION      CONTAINER-RUNTIME
k8s-m1   Ready    master   26m     v1.17.3   192.168.1.211   <none>        Ubuntu 19.10   5.3.0-1017-raspi2   docker://19.3.6
k8s-n1   Ready    <none>   17m     v1.17.3   192.168.1.212   <none>        Ubuntu 19.10   5.3.0-1017-raspi2   docker://19.3.6
k8s-n2   Ready    <none>   2m44s   v1.17.3   192.168.1.213   <none>        Ubuntu 19.10   5.3.0-1017-raspi2   docker://19.3.6
k8s-n3   Ready    <none>   2m39s   v1.17.3   192.168.1.214   <none>        Ubuntu 19.10   5.3.0-1017-raspi2   docker://19.3.6

ubuntu@k8s-m1:~$ kubectl get pods --all-namespaces --output wide
NAMESPACE     NAME                             READY   STATUS    RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
kube-system   coredns-6955765f44-jz5pv         1/1     Running   0          26m     10.244.0.3      k8s-m1   <none>           <none>
kube-system   coredns-6955765f44-whxsx         1/1     Running   0          26m     10.244.0.2      k8s-m1   <none>           <none>
kube-system   etcd-k8s-m1                      1/1     Running   0          26m     192.168.1.211   k8s-m1   <none>           <none>
kube-system   kube-apiserver-k8s-m1            1/1     Running   0          26m     192.168.1.211   k8s-m1   <none>           <none>
kube-system   kube-controller-manager-k8s-m1   1/1     Running   0          26m     192.168.1.211   k8s-m1   <none>           <none>
kube-system   kube-flannel-ds-arm64-58rgk      1/1     Running   0          21m     192.168.1.211   k8s-m1   <none>           <none>
kube-system   kube-flannel-ds-arm64-7gcj5      1/1     Running   0          17m     192.168.1.212   k8s-n1   <none>           <none>
kube-system   kube-flannel-ds-arm64-b4lc9      1/1     Running   0          3m4s    192.168.1.213   k8s-n2   <none>           <none>
kube-system   kube-flannel-ds-arm64-skgjw      1/1     Running   0          2m59s   192.168.1.214   k8s-n3   <none>           <none>
kube-system   kube-proxy-bh8c5                 1/1     Running   0          2m59s   192.168.1.214   k8s-n3   <none>           <none>
kube-system   kube-proxy-shjkv                 1/1     Running   0          17m     192.168.1.212   k8s-n1   <none>           <none>
kube-system   kube-proxy-tngmj                 1/1     Running   0          26m     192.168.1.211   k8s-m1   <none>           <none>
kube-system   kube-proxy-ttx28                 1/1     Running   0          3m4s    192.168.1.213   k8s-n2   <none>           <none>
kube-system   kube-scheduler-k8s-m1            1/1     Running   0          26m     192.168.1.211   k8s-m1   <none>           <none>
```

## 3. 構築

　今回利用する`registry`は単一のDockerイメージで構成されており、とても簡単にデプロイすることができます。今回は以下の設定でデプロイしました。

* Dockerレジストリはマスターノード`k8s-m1`に配置する。
* 永続化が必要なファイルは、マスターノードのストレージに格納する。
* Dockerイメージは`registry:2.7`を使用する。
* ホストネットワークを利用し、`5000/tcp`で待ち受けする。

使用した定義ファイルは以下の通りです。

```docker-registry.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: docker-registry
  labels:
    app: docker-registry
spec:
  replicas: 1
  selector:
    matchLabels:
      app: docker-registry
  template:
    metadata:
      labels:
        app: docker-registry
    spec:
      hostNetwork: true
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      nodeSelector:
        kubernetes.io/hostname: k8s-m1
      containers:
      - name: docker-registry
        image: registry:2.7
        ports:
        - containerPort: 5000
        volumeMounts:
        - name: registry
          mountPath: /var/lib/registry
      volumes:
      - name: registry
        hostPath:
          type: Directory
          path: /var/lib/registry
```

　定義ファイルの適用、`curl`による簡易的な動作確認の手順は以下の通りです。

```text
ubuntu@k8s-m1:~$ kubectl apply -f docker-registry.yaml
ubuntu@k8s-m1:~$ kubectl get pods -o wide
NAME                              READY   STATUS    RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
docker-registry-5c5cb844f-h7mzb   1/1     Running   0          4m34s   192.168.1.211   k8s-m1   <none>           <none>
nginx-munin-7kvf8                 1/1     Running   12         23d     10.244.3.14     k8s-n3   <none>           <none>
nginx-munin-8f88x                 1/1     Running   7          23d     10.244.1.9      k8s-n1   <none>           <none>
nginx-munin-jw4jd                 1/1     Running   5          23d     10.244.0.18     k8s-m1   <none>           <none>
nginx-munin-m8flt                 1/1     Running   5          23d     10.244.2.8      k8s-n2   <none>           <none>

ubuntu@k8s-m1:~$ curl -v http://localhost:5000/
*   Trying 127.0.0.1:5000...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5000 (#0)
> GET / HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.65.3
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Cache-Control: no-cache
< Date: Mon, 09 Mar 2020 07:45:47 GMT
< Content-Length: 0
<
* Connection #0 to host localhost left intact
```

## 4. 動作確認

　Dockerデーモンは、デフォルトではTLS接続（暗号化あり）のDockerレジストリのみ使用できます。
今回構築したDockerレジストリは非TLS接続（暗号化なし）を用いるため、Dockerデーモンの設定を変更する必要があります。
具体的には、設定ファイル`/etc/docker/daemon.json`の`insecure-registries`キーにホスト名、ポート番号を記載する必要があります。
設定ファイルを変更し、Dockerデーモンの再読み込み（再起動は不要）を行うことで、非TLS接続のDockerレジストリに接続できるようになります。なお、この設定はすべてのノードで行う必要があります。

```text
ubuntu@k8s-m1:~$ sudo vim /etc/docker/daemon.json
ubuntu@k8s-m1:~$ cat /etc/docker/daemon.json
{
  "insecure-registries": ["k8s-m1.local:5000"]
}

ubuntu@k8s-m1:~$ sudo systemctl reload docker
```

　動作確認の第1ステップとして、マスターノード（`k8s-m1`）にてDocker Hubから[hello-world](https://hub.docker.com/_/hello-world)イメージを取得（`docker pull`）し、構築したDockerレジストリに転送（`docker push`）してみました。
マスターノードの`/var/lib/registry`以下に、転送されたDockerイメージが格納されているのが確認できます。

```text
ubuntu@k8s-m1:~$ docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
256ab8fe8778: Pull complete
Digest: sha256:fc6a51919cfeb2e6763f62b6d9e8815acbf7cd2e476ea353743570610737b752
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest

ubuntu@k8s-m1:~$ docker tag hello-world k8s-m1.local:5000/hello-world
ubuntu@k8s-m1:~$ docker push k8s-m1.local:5000/hello-world
The push refers to repository [k8s-m1.local:5000/hello-world]
167d9097a0a0: Pushed
latest: digest: sha256:963612c5503f3f1674f315c67089dee577d8cc6afc18565e0b4183ae355fb343 size: 525

ubuntu@k8s-m1:~$ ls -l /var/lib/registry/
total 4
drwxr-xr-x 3 root root 4096 Mar  9 16:53 docker
```

　続いて、ワーカーノードの1つ（`k8s-n1`）で、構築したDockerレジストリからDockerイメージを取得してみました。

```text
ubuntu@k8s-n1:~$ sudo vim /etc/docker/daemon.json
ubuntu@k8s-n1:~$ sudo systemctl reload docker
ubuntu@k8s-n1:~$ docker pull k8s-m1.local:5000/hello-world
Using default tag: latest
latest: Pulling from hello-world
256ab8fe8778: Pull complete
Digest: sha256:963612c5503f3f1674f315c67089dee577d8cc6afc18565e0b4183ae355fb343
Status: Downloaded newer image for k8s-m1.local:5000/hello-world:latest
k8s-m1.local:5000/hello-world:latest
```

　`docker push`、`docker pull`ともに正常に動作することが確認できました。なお、認証は行っていないので`docker login`は不要です。

　以上、Dockerレジストリ編でした。
また余裕があれば、他の記事（電源編、ファン編、ケース編）なども書きたいと思います。