はじめに
注意:今回作る環境は,初心者が学習用に作成したものです.
決して本番環境等,外部に公開するような重要な環境ではそのままの手順通りで行わないで下さい.
また,insecureな設定やベストプラクティスから外れた運用をしている箇所があります.
学習用Kubernetes環境を作るの第3回です.
Part 2 学習用Kubernetes環境を作る2 動的PVが使えない環境でKubernetes管理WebUIのPortainer環境を作る/データ永続化/NodePortについて
KubernetesでDockerコンテナを利用出来るようにローカルにプライベートDockerレジストリーを作成します.
Kubernetesの環境は,第1回,第2回で構築した環境を前提としています.
Harbor用PVを作成
HarborをHelmでインストールする前に,Harborが利用するPVを作成します.
今回は,個人的に管理しやすいという都合上,全てのPVC毎にSCを作成します.
PVを作る前に,PVの実際の保存先を作成します.
cd /mnt/kubernetes
sudo mkdir harbor
cd harbor
sudo mkdir chartmuseum database jobservice redis registry trivy
chmod 777 chartmuseum database jobservice redis registry trivy
PVを作成するymlをharbor-vol.ymlという名前で作成します.
内容は以下の通りです.
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: harbor-registry
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: harbor-registry-pv
spec:
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: harbor-registry
local:
path: /mnt/kubernetes/harbor/registry
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- ノード名
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: harbor-chartmuseum
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: harbor-chartmuseum-pv
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: harbor-chartmuseum
local:
path: /mnt/kubernetes/harbor/chartmuseum
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- ノード名
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: harbor-jobservice
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: harbor-jobservice-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: harbor-jobservice
local:
path: /mnt/kubernetes/harbor/jobservice
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- ノード名
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: harbor-database
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: harbor-database-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: harbor-database
local:
path: /mnt/kubernetes/harbor/database
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- ノード名
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: harbor-redis
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: harbor-redis-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: harbor-redis
local:
path: /mnt/kubernetes/harbor/redis
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- ノード名
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: harbor-trivy
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: harbor-trivy-pv
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: harbor-trivy
local:
path: /mnt/kubernetes/harbor/trivy
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- ノード名
レジストリのPVは,PVCデフォルトの5GBだと少ない気がしたので,20GBに増やしています.
レジストリのPV以外は,PVCに指定されていた容量を指定しています.
このymlをapplyします.
kubectl apply -f harbor-vol.yml
次に,HarborのHelmリポジトリを追加します.
helm repo add harbor https://helm.goharbor.io
実際に,Harborをインストールします.
helm install --create-namespace -n harbor-system harbor harbor/harbor \
--set expose.type=nodePort --set expose.tls.enabled=false \
--set persistence.persistentVolumeClaim.registry.storageClass=harbor-registry --set persistence.persistentVolumeClaim.registry.size=20Gi \
--set persistence.persistentVolumeClaim.chartmuseum.storageClass=harbor-chartmuseum \
--set persistence.persistentVolumeClaim.jobservice.storageClass=harbor-jobservice \
--set persistence.persistentVolumeClaim.database.storageClass=harbor-database \
--set persistence.persistentVolumeClaim.redis.storageClass=harbor-redis \
--set persistence.persistentVolumeClaim.trivy.storageClass=harbor-trivy \
--set externalURL=http://tailscaleのmagicDNS(小文字):30002 --set harborAdminPassword=パスワード
namespaceは,harbor-systemです.
Portainerと同じくデフォルトSCを使用する場合は,persistence.persistentVolumeClaimをセットする必要はありません.
また,レジストリのサイズをデフォルトの5GBにした場合,persistence.persistentVolumeClaim.registry.sizeの指定は不要です.
ブラウザで,
http://tailscaleのmagicDNS(小文字):30002
を開けば,ユーザー名adminと設定したパスワードでログインできます.
テスト用プロジェクトを作成します
ログイン後,+NEW PROJECTから動作テスト用のプロジェクトを作成します.
今回は,認証のテストをしたいので,Privateなレジストリをtestという名前で作成します.
DockerでプライベートDockerレジストリを使えるようにする
今回,NodePortのhttpでデプロイしましたが,Dockerはデフォルトでは,httpsでないとLoginしたり,Pullしたり出来ません.
なので,今回作ったレジストリを使用できるように設定する必要があります.
Linux上のDockerであれば以下の通りです.
/etc/docker/daemon.jsonを以下のように編集し,Dockerデーモンの設定を変更します.
既に設定がある場合,前の要素の末尾に『,』を追加して次の行に"insecure-registries"の要素を記述して下さい.
{
"insecure-registries": [
"tailscaleのmagicDNS(小文字):30002"
]
}
Dockerデーモンをリスタートします.
sudo systemctl restart docker
Docker Desktopの場合,歯車マーク->Docker Engineと移動して,同じように既にあるinsecure-registriesに対して"tailscaleのmagicDNS(小文字):30002"を設定し,Apply&Restartを選択すれば良い.
Windows Server等の場合は,C:\ProgramData\docker\config\に,上記と同内容のdaemon.jsonを作成して下さい(動作未確認).
Dockerでログイン
Dockerでログインし,認証が必要なプロジェクトのレジストリにPush出来るようにします.
以下のようなコマンドでログインします.
docker login -u admin -p Helmでインストール時に設定したパスワード http://tailscaleのmagicDNS(小文字):30002
Login Successとなれば,成功です.
テスト用イメージをPush
適当にnginxのイメージをPullします.
docker pull nginx
Pushする先のtagをつけます(自分のコンテナイメージを使う時は,ビルド時に指定すれば良い).
先程,作成したtestプロジェクトのタグを付けます.
docker tag nginx tailscaleのmagicDNS(小文字):30002/test/nginx
Pushします.
docker push tailscaleのmagicDNS(小文字):30002/test/nginx
Kubernetes(containerd)でもプライベートDockerレジストリを使えるようにする
KubernetesのCRIとして採用したcontainerdも,デフォルトではhttpsでないとPull出来ないので,今回作ったレジストリを使用できるようにcontainerdを,設定する必要があります.
以下の様に,/etc/containerd/config.tomlを編集して下さい.
追加部分は,tailscaleのmagicDNSを用いている部分のみです.
(前略)
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://registry-1.docker.io"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."tailscaleのmagicDNS(小文字):30002"]
endpoint = ["http:/tailscaleのmagicDNS(小文字):30002"]
(後略)
設定を変更したら,containerdをリスタートさせます.
sudo systemctl restart containerd
containerdで,プライベートレジストリが使用できるか確認します.
sudo ctr image pull -u admin:パスワード tailscaleのmagicDNS(小文字):30002/test/nginx
問題なく,Pull出来れば,Pullしたイメージを削除します.
sudo ctr image rm tailscaleのmagicDNS(小文字):30002/test/nginx
Kubernetesでレジストリの認証情報を持ったsecretを作成
HarborはPullに認証が必要なPrivateと不要なPublicレジストリがありますが,認証が必要な場合は以下のようにして,secretを作る必要があります.
また,secretは使用するnamespace毎に,作成する必要があります.
Dockerの認証情報を用いる場合は,以下の通りです.
デフォルトnamespaceに作成する場合,『-n namespace名』の部分は不要です(以降).
kubectl -n namespace名 create secret generic secret名 \
--from-file=.dockerconfigjson=$HOME/.docker/config.json \
--type=kubernetes.io/dockerconfigjson
他のレジストリの認証情報を含んだ複数の認証情報を持つsecretを作成するには,最適な方法です.
Docker環境で,サーバーのkubectlが使えない場合や,secretの認証情報を単一にしたい場合は,以下の通りです.
kubectl -n namespace名 create secret docker-registry secret名 \
--docker-server=http://tailscaleのmagicDNS(小文字):30002 \
--docker-username=admin \
--docker-password=パスワード
プライベートレジストリのイメージを使用したアプリケーションを実際にデプロイ
テスト用のアプリケーションとして,以下のようなymlをtest.ymlという名前で作成します.
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
spec:
replicas: 1
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
containers:
- name: nginx
image: tailscaleのmagicDNS(小文字):30002/test/nginx
imagePullSecrets:
- name: secret名
---
apiVersion: v1
kind: Service
metadata:
name: test-service
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 32767
protocol: TCP
selector:
app: test
前回のymlのイメージ取得先を変更しています.
kubectl apply -f test.yml
前回と同じ様に確認して問題なければ成功です.
Podのステータスが,ErrImagePullや,ImagePullBackOffになっていないことが重要です.
余談:DockerでマルチCPUアーキテクチャ対応のイメージをPushする
Harborは,マルチCPUアーキテクチャ対応のDockerレジストリですが,上記のDockerデーモンの設定変更は,マルチCPUアーキテクチャ対応のイメージについては無意味です.
push時にregistry.insecure=trueオプションを設定して上げる必要があります.
docker buildx build --platform linux/amd64,linux/arm64 -t tailscaleのmagicDNS(小文字):30002/プロジェクト名/イメージ名 --output=type=image,push=true,registry.insecure=true .