Docker のプライベートレジストリを構築し Kubernetes から利用する

# 1. はじめに

Docker で作成したイメージを個人でのみ利用したい場合 Docker Hub などのプライベートレジストリが利用できますがオンプレミスの Kubernetes 環境に Docker Registry を作成しプライベートリポジトリとして使用することもできます。本文章では Docker Registry を Kubernetes 上に作成し Dockerfile から NGINX が動作するコンテナイメージを登録しそのコンテナイメージを元に Pod を Kubernetes 上に作成する方法を記します。

尚、私の Kubernetes 環境はこんな感じなのでこれをベースとした説明となります。また認証はせず HTTP での通信となります。

```
$ kubectl get node -o wide
NAME   STATUS   ROLES                  AGE   VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME
k60h   Ready    control-plane,master   20h   v1.23.1   10.185.1.60   <none>        Ubuntu 20.04.3 LTS   5.4.0-91-generic   docker://20.10.7
k61h   Ready    <none>                 20h   v1.23.1   10.185.1.61   <none>        Ubuntu 20.04.3 LTS   5.4.0-91-generic   docker://20.10.7
k62h   Ready    <none>                 20h   v1.23.1   10.185.1.62   <none>        Ubuntu 20.04.3 LTS   5.4.0-91-generic   docker://20.10.7
k63h   Ready    <none>                 20h   v1.23.1   10.185.1.63   <none>        Ubuntu 20.04.3 LTS   5.4.0-91-generic   docker://20.10.7
```

全ての node で /etc/hosts を用いて k60h.local の名前解決ができるようにしています。本記事でホストと記されているのは k60h.local を指しています。

```
$ egrep k60h /etc/hosts
10.185.1.60     k60h.local      k60h
```

# 2. Docker Registry を Kubernetes にデプロイする

まず Docker Registry が push されたコンテナイメージを保存するディレクトリをホスト上に作成します。Docker Registry のコンテナ上から見ると /var/lib/registry を使用するのでホストも同様に /var/lib/registry を作成しても良いです。

```
$ sudo mkdir /var/local/registry
```

以下の yaml ファイルを作成します。kubernetes.io/hostname で該当の Pod が動作するホストを指定しています。私の環境では master に Docker Registry を兼用させることにしました。

```
$ cat 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: k60h
      containers:
      - name: docker-registry
        image: registry:2
        ports:
        - containerPort: 5000
        volumeMounts:
        - name: registry
          mountPath: /var/lib/registry
      volumes:
      - name: registry
        hostPath:
          type: Directory
          path: /var/local/registry
```

上記 yaml を apply し http://localhost:5000/ から HTTP の応答があることを確認します。

```
$ kubectl apply -f ./docker-registry.yaml
deployment.apps/docker-registry created
$ kubectl get pods
NAME                              READY   STATUS    RESTARTS      AGE
docker-registry-87b77c57c-d8kfz   1/1     Running   1 (87m ago)   88m
$ curl -I http://localhost:5000/
HTTP/1.1 200 OK
Cache-Control: no-cache
Date: Mon, 20 Dec 2021 01:49:31 GMT
```

# 3. コンテナイメージを作成し Docker Registry に Push する

自分が使用する Docker コンテナイメージ用の Dockerfile を作成します。今回は以下のような Dockerfile を使用します。html ディレクトリには適当な html ファイルを作成します。

```
$ mkdir my-nginx
$ cd my-nginx
~/my-nginx$ vi Dockerfile
~/my-nginx$ cat Dockerfile
FROM ubuntu:20.04

RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y nginx

COPY ./html /var/www/html

EXPOSE 80
STOPSIGNAL SIGQUIT
CMD ["nginx", "-g", "daemon off;"]
~/my-nginx$ mkdir html
~/my-nginx$ vi html/index.html
~/my-nginx$ cat html/index.html
<html><body>Hello World!</body></html>
```

上記 Dockerfile を元にコンテナイメージを作成します。コンテナイメージは自動的に Docker に追加されます。

```
~/my-nginx$ docker build -t my-nginx .
Sending build context to Docker daemon  5.632kB
Step 1/8 : FROM ubuntu:20.04
 ---> ba6acccedd29
Step 2/8 : RUN apt-get update
 ---> Running in 076fc7382a2e
Get:1 http://archive.ubuntu.com/ubuntu focal InRelease [265 kB]
<snip>
Successfully tagged my-nginx:latest
~/my-nginx$ docker images | grep my-nginx
my-nginx                                         latest    ccc3acacf1ce   22 seconds ago   177MB
```

Docker 上でコンテナイメージが正しく動作するか確認します。http://localhost:8080 から idnex.html の内容が返ってくれば正常に動作しています。

```
~/my-nginx$ docker run --name mytest -p 8080:80 -d my-nginx
0ca08080c313ac9757a1c5f05cf2e4183a932cc39e20fcdb605a4595fe9c2f18
~/my-nginx$ docker ps | grep my-nginx
0ca08080c313   my-nginx               "nginx -g 'daemon of…"   56 seconds ago   Up 55 seconds   0.0.0.0:8080->80/tcp, :::8080->80/tcp   mytest
~/my-nginx$ curl http://localhost:8080
<html><body>Hello World!</body></html>
```

コンテナイメージに Tag 付をし Docker Registry にコンテナイメージを Push します。k60h.local は適時自分の環境に合わせ読み替えてください。Docker Registry から正しく /var/local/registry が mount されていた場合ホスト上に docker ディレクトリが作成されホストが再起動された場合などにもイメージが残ります。

```
$ docker tag my-nginx k60h.local:5000/my-nginx
$ docker push k60h.local:5000/my-nginx
Using default tag: latest
The push refers to repository [k60h.local:5000/my-nginx]
92d1830d3944: Pushed
a23d7252aa4b: Pushed
2bfe651cb586: Pushed
51b1fda25509: Pushed
9f54eef41275: Mounted from ubuntu-nginx
latest: digest: sha256:74e4ee005fb6a23423eb0e32cefc0172eee267c80e661ac4ff9a815a9cfdeec8 size: 1371
$ ls -l /var/local/registry/
total 4
drwxr-sr-x 3 root staff 4096 Dec 20 00:19 docker
```

ホスト上で動作しているコンテナやコンテナイメージを削除します。

```
$ docker container stop mytest
$ docker container rm mytest
$ docker rmi k60h.local:5000/my-nginx
$ docker rmi my-nginx
```

# 4. Docker Registry からコンテナイメージを Pull できるか試す

Docker から HTTP でコンテナイメージを PULL するには以下のような記述を各 node の /etc/docker/daemon.json に追加する必要があります。

```
{
  "insecure-registries" : ["k60h.local:5000"]
}
```

私の環境では /etc/docker/daemon.json は以下のようになっています。

```
$ cat /etc/docker/daemon.json
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2",
  "insecure-registries" : ["k60h.local:5000"]
}
```

Docker の設定ファイルを再読み込みします。

```
$ sudo systemctl reload docker
```

以下は k61h での実行結果となります。他の node からも k60h で動作する Docker Registry からコンテナイメージを pull できることが確認できます。pull したイメージは削除します。

```
$ sudo docker pull k60h.local:5000/my-nginx
Using default tag: latest
latest: Pulling from ubuntu-nginx
7b1a6ab2e44d: Pull complete
544fed566923: Pull complete
7db40321f9e0: Pull complete
b74505b5a888: Pull complete
b3c005019179: Pull complete
Digest: sha256:9da756d1a9e50198d75bb669de126bd8a17858336dde70d1f093661111448225
Status: Downloaded newer image for k60h.local:5000/ubuntu-nginx:latest
k60h.local:5000/ubuntu-nginx:latest
$ sudo docker rmi k60h.local:5000/ubuntu-nginx
```

# 5. Kubernetes 上に Docker Registry のコンテナイメージを使用し Pod を作成する

kubectl run を使うと以下のように確認することができます。テスト実施後作成した Pod を削除しています。

```
$ kubectl run mytest --image=k60h.local:5000/my-nginx
pod/mytest created
$ kubectl get pod -o wide | grep mytest
mytest                            1/1     Running   0          7s    10.244.3.27   k63h   <none>           <none>
$ curl 10.244.3.27
<html><body>Hello World!</body></html>
$ kubectl delete pod mytest
pod "mytest" deleted
```

yaml を利用して Deployment として利用することも可能です。テスト実施後 Deployment も削除しています。

```
$ cat my-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      app: ubuntu-nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: ubuntu-nginx
    spec:
      containers:
      - name: ubuntu-nginx
        image: k60h.local:5000/ubuntu-nginx
        ports:
        - containerPort: 80
$ kubectl get pods -o wide | grep my-nginx
my-nginx-6b48b4d4f9-4p888         1/1     Running   0          19s   10.244.3.28   k63h   <none>           <none>
$ curl 10.244.3.28
<html><body>Hello World!</body></html>
$ kubectl delete -f ./my-nginx.yaml
deployment.apps "my-nginx" deleted
```