kind で構成したクラスタから private registry へアクセスする(正常に動作しなかった)

趣旨

  • k8s(kind) から k8s(minikube) にデプロイした Docker Registry へアクセスしてみようとした
  • k8s(kind) の kubelet から利用する containerd自己署名証明書を許容しなかった
  • 設定で回避することもできず諦めた

やったこと

  1. TLS 通信のための自己署名証明書を作る
  2. ベーシック認証のための秘密情報ファイルを作る
  3. registry:2 をデプロイするためのマニフェストを作成する
  4. registry:2 をデプロイする
  5. docker を構成する
  6. kind を構成する
  7. kind でイメージを実行する

1. TLS 通信のための自己署名証明書を作る

外部から参照可能な名前を指定する。

ローカルネットワークだけで完結する場合は xip.io を利用すると便利。 myhost.<private ip address>.xip.io とすると <private ip address> に解決してくれる。

cn="registry.10.0.0.1.xip.io"
openssl req -newkey rsa:2048 -nodes -x509 -days 3650 \
    -subj "/C=JA/ST=Tokyo/L=Shinjuku/CN=${cn}" \
    -keyout ./certs/tls.key \
    -out ./certs/tls.crt

2. ベーシック認証のための秘密情報ファイルを作る

こちらのイメージを利用する。

hub.docker.com

docker run --rm -ti xmartlabs/htpasswd testuser pass01  > ./auth/htpasswd

3. registry:2 をデプロイするためのマニフェストを作成する

次のような注意点がある。

  • 環境変数で置換する部分がある ($cn の部分)
  • Nginx Ingress Controller の設定で proxy-body-size を大きくしてる
## registry.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: registry
  labels:
    app: registry
spec:
  replicas: 1
  selector:
    matchLabels:
      app: registry
  template:
    metadata:
      labels:
        app: registry
    spec:
      containers:
      - name: registry
        image: registry:2
        ports:
        - name: registry
          containerPort: 5000
        volumeMounts:
        - name: auth
          mountPath: "/auth"
        - name: data
          mountPath: "/var/lib/registry"
        env:
        - name: REGISTRY_AUTH_HTPASSWD_REALM
          value: "basic"
        - name: REGISTRY_AUTH_HTPASSWD_PATH
          value: "/auth/htpasswd"
      volumes:
      - name: auth
        secret:
          secretName: registry-auth
      - name: data
        emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: registry
  labels:
    app: registry
spec:
  selector:
    app: registry
  ports:
  - name: registry
    protocol: TCP
    port: 5000
    targetPort: 5000
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: registry
  annotations:
    kubernetes.io/ingress.class: "nginx"
    ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/proxy-body-size: "999m"
spec:
  tls:
  - hosts:
    - ${cn}
    secretName: registry-tls
  rules:
  - host: ${cn}
    http:
      paths:
      - path: /
        backend:
          serviceName: registry
          servicePort: 5000

4. registry:2 をデプロイする

名前空間を作る。

kubectl create ns registry

Ingress から参照する secret を作る。

kubectl -n registry create secret tls registry-tls --cert=./certs/tls.crt  --key=./certs/tls.key

マニフェストから参照する secret を作る。

kubectl -n registry create secret generic registry-auth --from-file=htpasswd=./auth/htpasswd

マニフェストをデプロイする。

$ cn="registry.10.0.0.1.xip.io" envsubst < ./manifest/registry.yaml | kubectl -n registry apply --dry-run -f -
deployment.apps/registry created (dry run)
service/registry created (dry run)
ingress.extensions/registry created (dry run)

$ cn="registry.10.0.0.1.xip.io" envsubst < ./manifest/registry.yaml | kubectl -n registry apply -f -
deployment.apps/registry created
service/registry created
ingress.extensions/registry created

https でアクセスしてみる。

$ curl -k https://${cn}/v2/_catalog
{"repositories":[]}

5. docker を構成する

  • docker host の設定
    • ./certs/tls.crt/etec/docker/certs.d/${cn}/ca.crt へ配置する。
    • docker daemon の再起動は不要。
  • docker client の設定
    • docker login ${cn} する

docker image push ${cn}/name:tag が成功すれば OK。

Z. minikube の場合に必要なこと

起動するときに minikube start --insecure-registry ${cn}:443 が必要。

  • insecure-registry オプションは dockerd に直接指定される
    • systemdunit ファイルで ExecStart に反映されてた
  • docekrdsystemddocker.service として実行されている

6. kind を構成する

こちらを参照。

minikube で kind を動かす - yujioramaの日記

7. kind でイメージを実行する

レジストリの認証情報を登録する。

kubectl --context=kind create secret docker-registry local-registry \
  --docker-server=${cn} \
  --docker-username=testuser \
  --docker-password=pass01 \
  --docker-email=testuser@registry

サービスアカウントに imagePullSecrets を追加。

kubectl --context=kind patch serviceaccount default -p '{"imagePullSecrets": [{"name":"local-registry"}]}'

前の手順で push したイメージを実行。

kubectl --context=kind run d --rm -it ${cn}/debian:buster-slim

ここから上手くいってない。

いろいろ確認した結果

原因は containerd自己署名証明書による TLS 通信に対応してないことだった。

github.com

中間証明局の証明書を OS の証明書チェインに追加するとかそういう方法はあるけど、設定ではどうにもならなそう。

TLS 通信をしない insecure registry なら設定でどうにかなるんだけど。

参考リンク