Kubernetes通过containerd访问registry的30443端口

问题描述 由于Kubernetes默认情况下只开放30000-32767这些端口,但是docker-registry在部署在Kubernetes中的时候conrainerd访问就会出现端口不匹配的问题,主要原因是containerd默认情况下HTTPS方式的访问端口为443,但是按照Kubernetes默认的设置,docker-registry在部署的时候对外暴露的端口在30000-32767之间,因此要么修改Kubernetes默认的端口开启443端口,要么让containerd在访问HTTPS的默认端口为30000-32767之间。
解决方案 一. 修改Kubernetes默认端口范围

#解决方法为修改apiserver的启动参数 vim /etc/kubernetes/manifests/kube-apiserver.yaml # 添加如下配置 - --service-node-port-range=1-65535

上述配置为将默认端口都开放,但是这种解决方案存在安全性问题,因此不推荐使用。
二. 修改containerd源码使得HTTPS默认端口为指定值
1. 在Kubernetes中部署docker registry的时候向外暴露的端口设置为30443(也可以设置其他值) 部署过程看我另外一篇文章:https://blog.csdn.net/weixin_...
docker-registry.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: docker-registry namespace: default spec: selector: matchLabels: app: docker-registry spec: nodeSelector: kubernetes.io/hostname: master1 containers: - name: docker-registry image: docker.io/library/registry:2.7.1 imagePullPolicy: IfNotPresent ports: - containerPort: 8443 env: - name: REGISTRY_HTTP_ADDR value: "0.0.0.0:8443" - name: REGISTRY_HTTP_TLS_CERTIFICATE value: "/certs/Yuan.crt" - name: REGISTRY_HTTP_TLS_KEY value: "/certs/Yuan.key" - name: REGISTRY_AUTH value: "htpasswd" - name: REGISTRY_AUTH_HTPASSWD_PATH value: "/auth/htpasswd" - name: REGISTRY_AUTH_HTPASSWD_REALM value: "Registry Realm" volumeMounts: - name: reg-data mountPath: /vat/lib/registry - name: reg-auth mountPath: /auth - name: reg-certs mountPath: /certs volumes: - name: reg-data hostPath: path: /home/docker-registry/images - name: reg-auth hostPath: path: /home/docker-registry/auth - name: reg-certs hostPath: path: /home/docker-registry/certs --- apiVersion: v1 kind: Service metadata: name: docker-registry namespace: default spec: type: NodePort ports: - port: 8443 targetPort: 8443 nodePort: 30443 protocol: TCP selector: app: docker-registry

# 部署 $ kubectl apply -f docker-registry.yaml # 查看Pod $ kubectl get po # 查看svc,这里就可以看到docker registry对外暴露的端口号为30443 $ kubectl get svc

2. 尝试拉取镜像 通过命令:
# 修改containerd的配置文件中的端口号 $ vim /etc/containerd/config.toml endpoint = ["https://10.131.82.53:30443"] # 可以拉取到镜像的命令 ctictl pull Yuan.com/nginx:v1 --creds Yuan:Abcd123456 ctr i pull Yuan.com:30443/nginx:v1 --user Yuan:Abcd123456 # 不能拉取镜像的命令 ctictl pull Yuan.com:30443/nginx:v1 --creds Yuan:Abcd123456 ctr i pull Yuan.com/nginx:v1 --user Yuan:Abcd123456

通过yaml部署文件
pod-pull-test.yaml
apiVersion: v1 kind: Pod metadata: name: pod-pull-test spec: nodeSelector: kubernetes.io/hostname: master1 containers: - name: pod-pull-test image: Yuan.com/nginx:v1 imagePullPolicy: Always

部署测试
$ kubectl apply -f pod-pull-test.yaml $ kubectl describe po pull-pod failed to do request: Head "https://Yuan.com:443/v2/nginx:v1" # 通过以上输出信息可以看出containerd在拉取镜像的时候还是走的443端口,因此拉取镜像失败 # 同时可以推断出来Kubernetes在拉取镜像的时候的命令与`ctr i pull Yuan.com/nginx:v1 --user Yuan:Abcd123456`效果类似

修改yaml文件再次拉取
pod-pull-test.yaml
apiVersion: v1 kind: Pod metadata: name: pod-pull-test spec: nodeSelector: kubernetes.io/hostname: master1 containers: - name: pod-pull-test image: Yuan.com:30443/nginx:v1 imagePullPolicy: Always

部署测试
$ kubectl apply -f pod-pull-test.yaml $ kubectl describe po pull-pod failed to do request: Head "https://Yuan.com:443/v2/nginx:v1" x509: certificate signed by unknown authority # 通过以上输出信息可以看出containerd在拉取镜像的时候走的还是443端口 # 同时还报了证书签名的问题导致镜像拉取失败

3.修改containerd源码HTTPS默认端口号
# 在containerd源码目录下面执行如下命令 $ grep -rwnI "443" # 找到于Kubernetes的相关的代码,路径如下 containerd/vendor/k8s.io/apimachinery/third_party/forked/golang/netutil/adr.go:16:https: 443 # 将这一行修改为30443后编译部署containerd

4.修改证书信息
cd certs # 生成2048位的私钥,也可以生成4096位的,看自己需求 openssl genrsa -out Yuan.key 2048 # 生成证书请求文件 openssl req -new -key Yuan.key -subj "/CN=Yuan.com" -out Yuan.csr # 将DNS地址写入一个文件,为了解决上述所说的那个问题 echo subjectAltName = DNS:Yuan.com>extfile.cnf # 将IP地址写入一个文件,为了解决上述所说的那个问题 echo subjectAltName = IP:10.131.82.54>>extfile.cnf # 这里的ca我就使用了集群自带的,在/etc/kubernetes/pki/下 openssl x509 -req-in Yuan.csr -CA ca.crt -CAkey ca.key -CAcreateserial -extfile extfile.cnf -out Yuan.crt -days 5000 # 查看证书信息 openssl x509 -in Yuan.crt -noout -text # 将生存的证书信息追加到系统的证书管理文件后 cat Yuan.crt >> /etc/pki/tls/certs/ca-bundle.crt

上述IP地址修改为你部署docker registry机器的IP地址
修改yaml文件再次拉取
pod-pull-test.yaml
apiVersion: v1 kind: Pod metadata: name: pod-pull-test spec: nodeSelector: kubernetes.io/hostname: master1 containers: - name: pod-pull-test image: Yuan.com/nginx:v1 imagePullPolicy: Always

部署测试
$ kubectl apply -f pod-pull-test.yaml $ kubectl get po # 通过上面的命令就可以看到pod成功拉起了

总结 【Kubernetes通过containerd访问registry的30443端口】为了符合Kubernetes的端口要求并且可以通过containerd成功部署业务镜像就必须要修改containerd的HTTPS默认端口号,在生成docker reigstry证书的时候需要将IP信息和DNS信息写入才能成功拉取到镜像,这样修改完的好处是不用修改Kubernetes的相关默认配置,在私有仓库拉取镜像的时候不用指定docker registry服务的端口号。

    推荐阅读