はじめに
Dockerのコンテナイメージを、自分で作ったコンテナレジストリにpushしてDockerやKubernetesからpullして運用する方法について本記事にまとめます。Docker Hubやクラウドのコンテナレジストリを使う手もあると思いますが、多くの場合はそれなりの費用が掛かります。なので既存のコンテナレジストリサービスを使わず、自分でコンテナレジストリを作ってコストを節約したい方などの参考になれば幸いです。
本記事に記載する内容は以下です。
- Dockerを使ってコンテナレジストリを作成する方法
- 作成したコンテナレジストリにDockerからpushおよびpullする方法
- KubernetesのPodに自作コンテナレジストリのイメージをpullしてデプロイする方法
前提条件
- OS : Linux
- 動作確認したのはUbuntuとDebian
- インストールが必要なツール
- Docker
- Kubernetesクラスター
- 筆者が作成したものですが、k8s-setup等を使って構築可能です
- 尚、K8sクラスターが使うコンテナランタイムはcontainerdであることを想定しています
コンテナレジストリの作成
コンテナイメージを格納するためのコンテナレジストリを作成します。
docker run -d --name docker-registry -p 5000:5000 registry
コンテナが起動しているのを確認します。
$ docker ps -f "name=registry"
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cadcd49f9a3a registry "/entrypoint.sh /etc…" 7 minutes ago Up 7 minutes 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp docker-registry
また、HTTPでコンテナレジストリのサービスが提供されているのを確認します。
※[hostname]
の部分は実際には、コンテナレジストリを起動したマシンのホスト名やIPアドレスを記入します。
$ curl -k http://[hostname]:5000/v2/_catalog
{"repositories":[]}
コンテナレジストリにpushできる状態にする
docker pushが"できない"ことを確認
まずは「作成したコンテナレジストリにpushできない」ことを、busyboxのコンテナイメージで確認してみます。
以下のコマンドで、Docker Hubからbusyboxのコンテナイメージを取得後、自分で作ったコンテナレジストリにpushするために別名をつけます。
docker pull busybox:1.36.1
docker tag busybox:1.36.1 [hostname]:5000/busybox:1.36.1
このままコンテナレジストリにpushしようとすると、敢えなく失敗します。
$ docker push [hostname]:5000/busybox:1.36.1
The push refers to repository [[hostname]:5000/busybox]
Get "https://[hostname]:5000/v2/": http: server gave HTTP response to HTTPS client
ログより、DockerはレジストリのデフォルトのプロトコルはHTTPSを想定しているようです。今回pushしたいレジストリはHTTPなので、HTTPのレジストリにpushできるようにDockerの設定を変更する必要があります。
docker pushとpullを可能にするための設定
/etc/docker/daemon.json
を編集して、insecure-registries
にコンテナレジストリのホスト名とポートを追記します。
{
"insecure-registries": ["[hostname]:5000"]
}
Dockerサービスを再起動します。
sudo systemctl restart docker
サービス再起動によりコンテナレジストリも止まってしまった場合は、以下のコマンドでコンテナレジストリを再起動させる必要があります。
docker start docker-registry
docker pushできる事を確認
再びコンテナイメージのpushを試みると、問題なくpushできるはずです!
$ docker push [hostname]:5000/busybox:1.36.1
The push refers to repository [[hostname]:5000/busybox]
95c4a60383f7: Pushed
1.36.1: digest: sha256:db16cd196b8a37ba5f08414e6f6e71003d76665a5eac160cb75ad3759d8b3e29 size: 527
コンテナレジストリのHTTPサービスにアクセスして、busyboxのイメージが追加されていることも確認できます。
$ curl -k http://[hostname]:5000/v2/_catalog
{"repositories":["busybox"]}
一旦ローカルのコンテナイメージを消して、pushしたコンテナイメージがpullできることも確認してみましょう。
docker rmi [hostname]:5000/busybox:1.36.1
docker rmi busybox:1.36.1
問題なくpullできました!
$ docker pull [hostname]:5000/busybox:1.36.1
1.36.1: Pulling from busybox
3a2e9cc4b126: Pull complete
Digest: sha256:db16cd196b8a37ba5f08414e6f6e71003d76665a5eac160cb75ad3759d8b3e29
Status: Downloaded newer image for [hostname]:5000/busybox:1.36.1
[hostname]:5000/busybox:1.36.1
KubernetesのPodをデプロイしてみる
続いて、自作のコンテナレジストリにpushしたbusyboxのコンテナイメージを使って、KubernetesのPodを立ち上げるための設定を行なっていきます。
コンテナイメージがpullできないことの確認
まずは何も設定せずにbusyboxのコンテナイメージでPodをデプロイしてみましょう。
kubectl run busybox-tmp -n default \
--image=[hostname]:5000/busybox:1.36.1 \
--command -- tail -f /dev/null
現状だと上手くpullできません。
$ kubectl get pod -n default
NAME READY STATUS RESTARTS AGE
busybox-tmp 0/1 ErrImagePull 0 8s
詳細を見ると、「https://[hostname]:5000
にアクセスできない」とメッセージが出ていることを確認できます。
$ kubectl describe pod -n default busybox-tmp | grep -A 32 ^Event
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 85s default-scheduler Successfully assigned default/busybox-tmp to livaz
Normal Pulling 45s (x3 over 84s) kubelet Pulling image "[hostname]:5000/busybox:1.36.1"
Warning Failed 45s (x3 over 84s) kubelet Failed to pull image "[hostname]:5000/busybox:1.36.1": failed to pull and unpack image "[hostname]:5000/busybox:1.36.1": failed to resolve reference "[hostname]:5000/busybox:1.36.1": failed to do request: Head "https://[hostname]:5000/v2/busybox/manifests/1.36.1": http: server gave HTTP response to HTTPS client
Warning Failed 45s (x3 over 84s) kubelet Error: ErrImagePull
Normal BackOff 15s (x4 over 83s) kubelet Back-off pulling image "[hostname]:5000/busybox:1.36.1"
Warning Failed 15s (x4 over 83s) kubelet Error: ImagePullBackOff
pull可能にするための設定
上記の問題を解消して、自作コンテナレジストリのイメージをKubernetesで使えるための設定をしていきます。
本記事では、K8sのコンテナランタイムにcontainerdを使っていることが前提となります。dockerdやcri-o等の他のコンテナランタイムを使っている場合は、各コンテナランタイムに応じた設定を行なってください。
/etc/containerd/config.toml
に以下を追記します。
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d"
次のように、[hostname]:5000
という名前のディレクトリを作成します。
sudo mkdir -p /etc/containerd/certs.d/[hostname]:5000
作成したディレクトリ内に、hosts.toml
というファイルを作成します。
sudo touch /etc/containerd/certs.d/[hostname]:5000/hosts.toml
hosts.toml
は次のような内容になるように編集します。
server = "http://[hostname]:5000"
[host."http://[hostname]:5000"]
capabilities = ["pull", "resolve"]
skip_verify = true
設定を反映させるために、containerdを再起動します。
sudo systemctl restart containerd
一旦Podを消して、再び同じPodを作ります。
(本当は消さなくてもいいかもしれないですが、なるべく早くpullできることを確認するためにそうしました。)
kubectl delete po -n default busybox-tmp
kubectl run busybox-tmp -n default \
--image=[hostname]:5000/busybox:1.36.1 \
--command -- tail -f /dev/null
今度は問題なくPodを起動できました!
$ kubectl get pod -n default
NAME READY STATUS RESTARTS AGE
busybox-tmp 1/1 Running 0 14s
$ kubectl describe pod -n default busybox-tmp | grep -A 32 ^Event
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 34s default-scheduler Successfully assigned default/busybox-tmp to livaz
Normal Pulling 33s kubelet Pulling image "[hostname]:5000/busybox:1.36.1"
Normal Pulled 32s kubelet Successfully pulled image "[hostname]:5000/busybox:1.36.1" in 873ms (873ms including waiting)
Normal Created 32s kubelet Created container busybox-tmp
Normal Started 32s kubelet Started container busybox-tmp
おわりに
今回書いた内容は、約一年半前に筆者が書いた以下の記事にも実は出てきます。
この記事は「KubernetesのOperator作成を自分で作ったコンテナレジストリで実現する」ために書いたものですが、当時一番やりたかったのはKubernetesのOperator作成で、自作レジストリに関する設定はそれを実現するために必要になってしまったから仕方なくやったという位置づけでした。
そして最近になって自作レジストリ周りの設定をやり直す機会があったのですが、過去に上の記事に書いてまとめたのをすっかり忘れている自分がいました。「確かどこかにその記録をしていたはず」と思い、自分のメモやQiitaの記事を時間をかけて探してもなかなか見つからず。。。自分のメモの中に「KubernetesのOperator作成の記事に前に書いた」みたいな一言が書かれていたおかげて、ようやく設定ができたという顛末でした。
「自分が書いたものでも見つからないんだから、他の人が見つけるのはなおさら困難だろうなあ」と思い、自作コンテナレジストリの部分だけ切り出して改めて本記事にまとめてみました。お役に立てれば幸いです。
参考にしたサイト
- Dockerで自作レジストリにpush可能にするための設定
- containerdで自作レジストリからpull可能にするための設定