使用 image-operator 自动替换 k8s 集群 Dockerhub 镜像

309 阅读2分钟

最近由于 Dockerhub 仓库被封导致常用的镜像无法拉取,好在网上已经有搭建镜像仓库的教程,比如使用 cloudflare-docker-proxy 基于 Cloudflare Workers 搭建镜像代理服务。虽然解决了镜像拉取的问题,但对于部署在 k8s 集群上的应用,管理员需要手动修改 YAML 文件中的镜像地址,如果集群上部署的应用较多这个工作量就会很大。更麻烦的是一些使用 Operator 管理的应用,甚至无法直接修改镜像地址。

image-operator 是基于 Admission Webhook 实现的一个 Operator,工作原理是在 Pod 创建时根据规则重写镜像地址,这个过程对使用者来说是透明的,无需手动修改 YAML 中的镜像地址。

安装 image-operator

image-operator 提供了 Helm Chart 方便安装,首先添加 Helm 仓库:


$ helm repo add image-operator https://yxwuxuanl.github.io/k8s-image-operator/

接着安装 image-operator


$ helm install image-operator image-operator/image-operator -n image-operator --create-namespace

稍等片刻后查看 image-operator 的状态:


$ kubectl get pods -n image-operator

NAME READY STATUS RESTARTS AGE

image-operator-b8c8d5ddb-zkv6l 1/1 Running 0 2m

到这里 image-operator 就安装完成了。

重写镜像地址

image-operator 使用 Rule CRD 来配置重写规则,下面来看一个例子:


apiVersion: image.lin2ur.cn/v1

kind: Rule

metadata:

name: dockerhub

spec:

rewrite: # <- 重写规则,可以配置多个

- registry: docker.io # <- 需要重写的镜像仓库

replacement: docker.mymirror.com # <- 重写目标镜像仓库

# 使用正则表达式重写,等效于上面的配置

- regex: ^docker\.io/(.*)$

replacement: docker.mymirror.com/$1

将上面的配置保存为 rule.yaml 并应用,然后使用 Dockerhub 仓库的镜像创建一个应用:


$ kubectl apply -f rule.yaml

rule/dockerhub created

  


$ kubectl run image-operator-test --image=nginx # <- 使用 Dockerhub 仓库的镜像

pod/image-operator-test created

  


$ kubectl get pod image-operator-test '-o=jsonpath={.spec.containers[0].image}'

docker.mymirror.com/library/nginx:latest # <- 镜像地址已被重写

此外 image-operator 还支持对特定的 Pod 进行重写:


apiVersion: image.lin2ur.cn/v1

kind: Rule

metadata:

name: dockerhub

spec:

namespaceSelector: # <- 选择需要重写的 Namespace

matchExpressions:

- key: kubernetes.io/metadata.name # <- 排除 kube-system 命名空间下的 Pods

operator: NotIn

values:

- kube-system

podSelector: # <- 选择需要重写的 Pod

matchLabels: # <- 仅对包含 rewrite=true 标签的 Pod 进行重写

rewrite: 'true'

同步镜像

如果只是用到少量 Dockerhub 镜像并且不想大费周章搭建镜像仓库,可以使用 Mirror CRD 将 Dockerhub 上的镜像同步到自己的镜像仓库:


apiVersion: image.lin2ur.cn/v1

kind: Mirror

metadata:

generateName: nginx-

spec:

images:

- source: nginx # <- 源镜像

target: myregistry.com/nginx # <- 目标镜像

tags: # <- 镜像标签

- '1.27'

platforms: # <- (可选) 镜像架构,默认为全部架构

- linux/amd64

dockerConfig: # <- (可选) Docker 配置,用于私有仓库的拉取和推送

secretName: '' # <- 必须是 `kubernetes.io/dockerconfigjson` 类型的 Secret

httpProxy: '' # <- (可选) 拉取镜像时使用 HTTP 代理

parallelism: 1 # <- (可选) 并发数,默认为 1

sizeLimit: 1Gi # <- (可选) 任务 Pod 的临时存储大小

activeDeadlineSeconds: 300 # <- (可选) 任务 Pod 的超时时间

将上面的配置保存为 mirror.yaml 并应用:


$ kubectl create -f mirror.yaml

mirror.image.lin2ur.cn/nginx-pq9dg created

image-operator 会创建一个 Job 来同步镜像,稍等片刻后查看任务状态:


$ kubectl get mirror nginx-pq9dg

NAME IMAGES RUNNING FAILED SUCCEEDED

nginx-pq9dg 0 0 2

同步完成后就可以使用 myregistry.com/nginx:1.27 这个镜像了。