K8S 集群注入 Registry 方案

58 阅读3分钟

背景

在离线场景中,向 K8S 集群部署服务成为一项挑战,我们需要考虑如何将镜像导入到所有工作节点,这是一项复杂的工作,更好的做法是在离线环境中部署一套私有的镜像仓库,考虑到业务 Pod 可能出现各种漂移情况,私有镜像仓库最好还要具备高可用。

本文介绍了一种无需进入节点操作,在离线环境中向 K8S 集群注入高可用的私有镜像仓库的方法。

方案特点

  1. Registry 被部署在 K8S 集群内
  2. Registry 具备高可用
  3. 无需为 Registry 提供可信证书
  4. 无需为节点配置私有仓库 insecure-registries

前置条件

  • 一台内网互通的工作站
  • 通过 APIServer 访问 K8S 集群的权限
  • 集群支持 RWX 的持久化存储能力(如不考虑高可用,可以不用)

实施步骤

准备 registry 先锋实例

  1. 在工作站中导入 registry:2 镜像
docker load registry.tar.gz
  1. 在工作站中运行 registry 先锋实例
docker run --name registry -d -p 5000:5000 registry:2
  1. registry:2 镜像推送到 registry 先锋实例
docker tag registry:2 127.0.0.1:5000/registry:2
docker push 127.0.0.1:5000/registry:2
  1. 准备 registry-service.yaml 清单文件
apiVersion: v1
kind: Service
metadata:
  name: registry-service
spec:
  type: NodePort
  ports:
    - name: http
      protocol: TCP
      port: 5000
      targetPort: 5000
      NodePort: 32445

---

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: registry-service
  labels:
    kubernetes.io/service-name: registry-service
addressType: IPv4
ports:
  - name: http
    appProtocol: http
    protocol: TCP
    port: 5000
endpoints:
  - addresses:
      - "<工作站 IP地址>"
  1. 将清单文件应用到集群
kubectl apply -f registry-service.yaml

向集群部署高可用的 registry 服务

  1. 准备 cluster-registry.yaml 清单文件
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: cluster-registry
  labels:
    app: cluster-registry
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 10Gi

---

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: cluster-registry
  labels:
    app: cluster-registry
spec:
  selector:
    matchLabels:
      app: cluster-registry
  template:
    metadata:
      labels:
        app: cluster-registry
    spec:
      containers:
        - name: cluster-registry
          image: 127.0.0.1:32445/registry:2  # 此处是刻意使用 127.0.0.1 IP 地址,请勿删除
          resources:
            limits:
              memory: 200Mi
            requests:
              cpu: 100m
              memory: 200Mi
          ports:
            - containerPort: 5000
              name: http
          volumeMounts:
            - name: registry
              mountPath: /var/lib/registry
      volumes:
        - name: registry
          persistentVolumeClaim:
            claimName: cluster-registry
            
---

apiVersion: v1
kind: Service
metadata:
  name: cluster-registry
spec:
  selector:
    app: cluster-registry
  type: NodePort
  sessionAffinity: "ClientIP"
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800
  ports:
    - name: http
      protocol: TCP
      port: 5000
      targetPort: 5000
  1. 将清单文件应用到集群
kubectl create ns registry
kubectl apply -f cluster-registry.yaml -n registry
  1. 检查服务状态

检查 Pod 状态,确保 Pod 都已经 Running

kubectl get pod -n registry

清理 registry 先锋实例,服务反转

  1. 清理 ServiceEndpointSlice
kubectl delete -f registry-service.yaml
  1. 停止并删除工作站中的 registry 先锋实例
docker stop registry
docker rm registry
  1. 服务切换,将集群里的 registry 接管 32445 端口的流量
kubectl patch svc cluster-registry --type='json' -p='[{"op":"replace","path":"/spec/ports/0/nodePort","value":32445}]' -n registry
  1. 配置集群中 registry 的安全信任,打开 /etc/docker/daemon.json 文件,添加以下内容:
"insecure-registries": ["<任意节点IP>:32445"]
  1. 推送 registry:2 镜像到集群中的 registry 中
docker tag registry:2 <任意节点IP>:32445/registry:2
docker push <任意节点IP>:32445/registry:2

后续操作

在集群外访问 registry

可以通过 <任意节点 IP>:32445 进行访问

在集群内节点访问 registry

可以通过 127.0.0.1:32445 进行访问

部署服务时拉取镜像

可以通过 image: 127.0.0.1:32445/<镜像名称>:<版本号> 成功拉取到镜像