こんにちは、ナナオです。
自宅にk8sを構築してからいろいろやりたいことが増えました。
ということで今回はk8sを使って自宅内で使えるプライベートレジストリの構築に挑戦してみました。
どうやって構築するか
うちには以前ジャンクで買ったNASがあるので、このNASをストレージにしてDockerイメージを放り込めるようにしたいです。
NASにはNFSで接続できます。
一度NAS側にDockerイメージを放り込むためのディレクトリを作成しておきます。
次に先ほど作成したディレクトリを参照するPVとPVCを作っていきます。
apiVersion: v1
kind: PersistentVolume
metadata:
name: registry-pv
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteMany # 複数ノードから同時に読み書き可能
persistentVolumeReclaimPolicy: Retain
storageClassName: nas
nfs:
server: 192.168.0.xx # NASのIPアドレス
path: /docker-registry # NASの共有パス
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: registry-pvc
namespace: kube-system
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 100Gi
storageClassName: nas
作成したところ、エラーになりました。
│ Warning FailedScheduling 15m default-scheduler 0/3 nodes are available: persistentv │
│ olumeclaim "registry-pvc" not found. not found │
│ Warning FailedScheduling 15m default-scheduler running PreFilter plugin "VolumeBind │
│ ing": error getting PVC "kube-system/registry-pvc": could not find v1.PersistentVolumeClaim "kube-system │
│ /registry-pvc" │
│ Normal Scheduled 15m default-scheduler Successfully assigned kube-system/do │
│ cker-registry-85dbb54f6c-zmrkl to nanaonuc6caysserver │
│ Warning FailedMount 58s (x15 over 15m) kubelet MountVolume.SetUp failed for volume │
│ "registry-pv" : mount failed: exit status 32 │
│ Mounting command: mount │
│ Mounting arguments: -t nfs 192.168.0.94:/docker-registry /var/lib/kubelet/pods/1f2e1d4d-447c-4bcf-9987-c │
│ 930a2576654/volumes/kubernetes.io~nfs/registry-pv │
│ Output: mount: /var/lib/kubelet/pods/1f2e1d4d-447c-4bcf-9987-c930a2576654/volumes/kubernetes.io~nfs/regi │
│ stry-pv: bad option; for several filesystems (e.g. nfs, cifs) you might need a /sbin/mount.<type> helper │
│ program. │
│ dmesg(1) may have more information after failed mount system call.
エラーのbad option; for several filesystems (e.g. nfs, cifs) you might need a /sbin/mount.<type> helperから、NFSを扱うためのツールセット各ノードにがインストールされていないことが原因だとわかりました。
各ノード上でsudo apt install -y nfs-commonを実行すればいいんですが、ノードが増えた時のことを考えるとsshでログインして各ノードでその作業を実施するのが面倒です。
ということでAnsibleを使ってこの問題を解決します。
hosts.yamlには以下のように各ノードの情報を登録しておきます。
---
all:
vars:
ansible_user: username
ansible_password: password
children:
control-plane:
hosts:
thinkcentle1:
ansible_host: 192.168.0.14
nuc1:
ansible_host: 192.168.0.15
mouse1:
ansible_host: 192.168.0.16
playbookは以下のように定義します。
- hosts: all
become: yes
tasks:
- name: nfs-commonのインストール
apt:
name: nfs-common
state: present
update_cache: yes
これを実行します。
ansible-playbook -i hosts.yaml playbook.yaml
成功したら先ほどのPVとPVCを再度適用しましょう。
kubectl apply -f docker-registry-storage.yaml
今度は成功しました!
つづけて作成したPVCにDockerイメージを格納するregistryをDeploymentで作成します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: docker-registry
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: docker-registry
template:
metadata:
labels:
app: docker-registry
spec:
containers:
- name: registry
image: registry:3
ports:
- containerPort: 5000
volumeMounts:
- name: registry-data
mountPath: /var/lib/registry
# 先ほど作成したPVCを割り当てる
volumes:
- name: registry-data
persistentVolumeClaim:
claimName: registry-pvc
---
apiVersion: v1
kind: Service
metadata:
name: docker-registry
namespace: kube-system
spec:
type: NodePort
selector:
app: docker-registry
ports:
- port: 5000
targetPort: 5000
nodePort: 30500 # ★外部(操作PC)から 192.168.0.14:30500 でアクセス可能
これを適用します。
kubectl apply -f docker-registry-deploy.yaml
これでレジストリの構築はできました。
次にDocker desktopの設定にinsecure-registriesを追加します。
{
"builder": {
"gc": {
"defaultKeepStorage": "20GB",
"enabled": true
}
},
"experimental": false,
"insecure-registries": ["192.168.0.14:30500"]
}
以下のコマンドでプッシュしてみます。
docker tag library-checker:0.1.0 192.168.0.14:30500/library-checker:0.1.0
docker push 192.168.0.14:30500/library-checker:0.1.0
プッシュに成功しました!
実際にこのイメージを使用したDeploymentを作成しましょう。
以前この記事でデプロイしたDockerイメージの宛先を今回プッシュしたDockerイメージに変更します。
# ...イメージの宛先を構築したプライベートレジストリのイメージURLにする
image: 192.168.0.14:30500/library-checker:0.1.0
ただ、結果はErrImagePullになってしまいます。
kubectl apply -fした結果は以下の通りです。
# ...中略...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 33s default-scheduler Successfully assigned default/library-checker-689fb88597-8s2gj to mouse1
Normal Pulled 33s kubelet Container image "selenium/standalone-chrome:4.39.0-20251212" already present on machine
Normal Created 33s kubelet Created container: chrome
Normal Started 33s kubelet Started container chrome
Normal Pulling 17s (x2 over 33s) kubelet Pulling image "192.168.0.14:30500/library-checker:0.1.0"
Warning Failed 17s (x2 over 33s) kubelet Failed to pull image "192.168.0.14:30500/library-checker:0.1.0": failed to pull and unpack image "192.168.0.14:30500/library-checker:0.1.0": failed to resolve reference "192.168.0.14:30500/library-checker:0.1.0": failed to do request: Head "https://192.168.0.14:30500/v2/library-checker/manifests/0.1.0": http: server gave HTTP response to HTTPS client
Warning Failed 17s (x2 over 33s) kubelet Error: ErrImagePull
Normal BackOff 3s (x2 over 32s) kubelet Back-off pulling image "192.168.0.14:30500/library-checker:0.1.0"
Warning Failed 3s (x2 over 32s) kubelet Error: ImagePullBackOff
failed to resolve reference "192.168.0.14:30500/library-checker:0.1.0": failed to do request: Head "https://192.168.0.14:30500/v2/library-checker/manifests/0.1.0": http: server gave HTTP response to HTTPS clientとなっており、イメージのプルに失敗していることがわかります。
各ノードに追加で設定が必要だということがわかりました。
以下の公式ドキュメントを参考にして、各ノードに設定を反映していきます。
https://docs.k3s.io/ja/installation/private-registry
以下のようにregistries.yamlを定義します。
mirrors:
"mydocker.io": # レジストリへのアクセス先
endpoint:
- "http://192.168.0.14:30500"
このファイルをAnsibleを使って各ノードに配布します。
- hosts: all
become: yes
tasks:
- name: nfs-commonのインストール
apt:
name: nfs-common
state: present
update_cache: yes
- name: /etc/rancher/k3s ディレクトリの作成
file:
path: /etc/rancher/k3s
state: directory
mode: '0755'
- name: registries.yaml の配置
copy:
src: ./registries.yaml
dest: /etc/rancher/k3s/registries.yaml
owner: root
group: root
mode: '0644'
notify:
- restart_k3s
handlers:
- name: restart_k3s
systemd:
name: k3s
state: restarted
ignore_errors: yes
実行します。
❯ ansible-playbook -i update-node-ansible/hosts.yaml update-node-ansible/playbook.yaml -K
BECOME password:
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
PLAY [all] *************************************************************************************************
TASK [Gathering Facts] *************************************************************************************
[WARNING]: Host 'thinkcentle1' is using the discovered Python interpreter at '/usr/bin/python3.12', but future installation of another Python interpreter could cause a different interpreter to be discovered. See https://docs.ansible.com/ansible-core/2.20/reference_appendices/interpreter_discovery.html for more information.
ok: [thinkcentle1]
[WARNING]: Host 'mouse1' is using the discovered Python interpreter at '/usr/bin/python3.12', but future installation of another Python interpreter could cause a different interpreter to be discovered. See https://docs.ansible.com/ansible-core/2.20/reference_appendices/interpreter_discovery.html for more information.
ok: [mouse1]
[WARNING]: Host 'nuc1' is using the discovered Python interpreter at '/usr/bin/python3.12', but future installation of another Python interpreter could cause a different interpreter to be discovered. See https://docs.ansible.com/ansible-core/2.20/reference_appendices/interpreter_discovery.html for more information.
ok: [nuc1]
TASK [nfs-commonのインストール] ****************************************************************************
ok: [thinkcentle1]
ok: [mouse1]
ok: [nuc1]
TASK [/etc/rancher/k3s ディレクトリの作成] *****************************************************************
ok: [thinkcentle1]
ok: [mouse1]
ok: [nuc1]
TASK [registries.yaml の配置] ******************************************************************************
changed: [thinkcentle1]
changed: [mouse1]
changed: [nuc1]
RUNNING HANDLER [restart_k3s] ******************************************************************************
changed: [thinkcentle1]
changed: [nuc1]
changed: [mouse1]
PLAY RECAP *************************************************************************************************
mouse1 : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
nuc1 : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
thinkcentle1 : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
実行に成功しました。
レジストリのアクセス先を変更します。
image: mydocker.io/library-checker:0.1.0
これで再度kubectl apply -fを実行すると…
今度はちゃんと動いています!
感想
意外とプライベートレジストリの構築が簡単にできて拍子抜けしちゃいました。
しかしk8s、おもしろっ(デスノートリューク風)
今後ももっと活用していきたいです。