4. 私有镜像仓库认证:使用 imagePullSecrets 配置 Docker Registry、Harbor 等私有仓库认证

在生产环境中,镜像通常存储在私有仓库(如 Docker Registry、Harbor、Nexus 等)中,而非公共 Docker Hub。Kubernetes 在拉取私有镜像时,必须提供有效的认证凭据。本章将深入讲解 imagePullSecrets 的配置原理、创建方式及在 Deployment 中的挂载策略,确保灾备场景下镜像拉取不因认证失败而中断。

4.1 认证机制与核心概念

Kubernetes 通过 imagePullSecrets 资源将 Docker 仓库的认证凭据传递给 kubelet,kubelet 在拉取镜像时使用该凭据向私有仓库进行身份验证。其核心流程如下:

关键点: imagePullSecrets 本质是一个 kubernetes.io/dockerconfigjson 类型的 Secret,存储了 base64 编码的 Docker 认证信息(.dockerconfigjson)。
imagePullSecrets 私有仓库认证流程 Deployment spec.template.spec imagePullSecrets 引用 Secret 名称 Secret dockerconfigjson 私有仓库 Harbor / Registry kubelet 拉取镜像 流程说明 Deployment 通过 imagePullSecrets 引用 Secret → Secret 提供 dockerconfigjson → kubelet 使用凭据向私有仓库认证并拉取镜像

4.2 创建 imagePullSecrets 的三种方式

根据使用场景和自动化程度,可以选择以下三种方式创建 Secret:

创建方式 命令 / 工具 适用场景 优点
命令行直接创建 kubectl create secret docker-registry 快速测试、临时环境 简单直接,无需手动编码
手动 YAML 定义 编写 Secret YAML + base64 编码 GitOps、版本控制 可审计、可重复部署
自动注入工具 ImagePullSecret Controller / Kyverno 大规模集群、多命名空间 自动化注入,减少人工操作

4.2.1 方式一:kubectl 命令行创建(推荐)

这是最常用且最不易出错的方式,kubectl 会自动完成 base64 编码和 Secret 结构组装:

# 创建 Docker Registry 认证 Secret
kubectl create secret docker-registry my-registry-secret \
  --docker-server=https://harbor.example.com \
  --docker-username=admin \
  --docker-password=Harbor12345 \
  --docker-email=admin@example.com \
  --namespace=production

# 验证 Secret 是否创建成功
kubectl get secret my-registry-secret -n production -o yaml
最佳实践: 建议为每个私有仓库单独创建一个 Secret,并在 Secret 名称中体现仓库用途(如 harbor-prod-secret、registry-staging-secret),便于后期维护和审计。

4.2.2 方式二:手动 YAML 定义(GitOps 友好)

当需要将 Secret 纳入 Git 仓库管理时,可以手动编写 YAML。注意 .dockerconfigjson 字段需要预先进行 base64 编码:

# 1. 生成 Docker 认证 JSON
echo '{"auths":{"https://harbor.example.com":{"username":"admin","password":"Harbor12345","auth":"'$(echo -n "admin:Harbor12345" | base64)'"}}}' | base64

# 2. 编写 Secret YAML
apiVersion: v1
kind: Secret
metadata:
  name: harbor-prod-secret
  namespace: production
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: <base64-encoded-string>
安全警告: 切勿将明文密码提交到 Git 仓库。建议使用 SealedSecret、External Secrets Operator 或 Vault 等工具对 Secret 进行加密管理,或通过 CI/CD 流水线动态注入。

4.2.3 方式三:自动注入(大规模集群)

在拥有数十个命名空间的大规模集群中,手动为每个 Deployment 添加 imagePullSecrets 效率低下。可以使用准入控制器(如 Kyverno、OPA Gatekeeper)自动注入:

# Kyverno 策略示例:自动注入 imagePullSecrets
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: inject-imagepullsecrets
spec:
  rules:
  - name: inject-registry-secret
    match:
      resources:
        kinds:
        - Pod
    mutate:
      patchStrategicMerge:
        spec:
          imagePullSecrets:
          - name: harbor-prod-secret  # 自动注入

4.3 在 Deployment 中引用 imagePullSecrets

创建好 Secret 后,需要在 Deployment 的 Pod 模板中通过 imagePullSecrets 字段引用。支持两种作用域:

  • Pod 级别(推荐): 在 spec.template.spec.imagePullSecrets 中定义,该 Pod 内的所有容器共享此凭据。
  • ServiceAccount 级别: 将 Secret 绑定到 ServiceAccount,该 SA 创建的所有 Pod 自动继承凭据。

4.3.1 Pod 级别引用

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      imagePullSecrets:                     # 在此处引用
      - name: harbor-prod-secret
      containers:
      - name: app-container
        image: harbor.example.com/my-app:v1.0.0
        ports:
        - containerPort: 8080

4.3.2 ServiceAccount 级别引用(全局生效)

当同一命名空间下多个 Deployment 使用相同仓库时,绑定到 ServiceAccount 可避免重复配置:

# 1. 创建 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-sa
  namespace: production
imagePullSecrets:
- name: harbor-prod-secret

# 2. Deployment 引用 ServiceAccount
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: production
spec:
  template:
    spec:
      serviceAccountName: app-sa          # 自动继承 imagePullSecrets
      containers:
      - name: app-container
        image: harbor.example.com/my-app:v1.0.0

4.4 多仓库认证与灾备场景

在灾备场景中,可能需要从多个私有仓库拉取镜像(如主仓库故障时切换到备用仓库)。Kubernetes 支持在 imagePullSecrets 中配置多个 Secret:

spec:
  imagePullSecrets:
  - name: harbor-primary-secret    # 主仓库
  - name: harbor-dr-secret         # 灾备仓库
  containers:
  - name: app
    image: primary-registry.com/my-app:v1.0.0   # 优先从主仓库拉取

当主仓库不可用时,kubelet 会依次尝试使用后续 Secret 进行认证,直到成功拉取镜像或所有凭据尝试失败。

多仓库灾备认证架构 Deployment imagePullSecrets: [secret1, secret2] kubelet 重试机制 顺序尝试每个 Secret 主仓库(Harbor) primary-registry.com 灾备仓库(Registry) dr-registry.com 拉取失败 所有凭据尝试完毕 灾备策略:主仓库认证失败 → 自动切换到灾备仓库 Secret → 保障镜像拉取不中断

4.5 常见问题与排错

问题现象 可能原因 排查命令 / 解决方案
Pod 状态 ImagePullBackOff Secret 不存在、凭据错误或过期 kubectl describe pod <pod-name> 查看事件;kubectl get secret 确认 Secret 存在
认证失败 401 Unauthorized 密码变更、仓库地址不匹配 重新创建 Secret;检查 --docker-server 是否包含协议头(https://)
镜像拉取超时 网络不通或仓库不可达 在节点上手动 docker login 测试;检查防火墙和 DNS 解析
Secret 未生效 Deployment 未引用或引用名称错误 检查 spec.template.spec.imagePullSecrets 字段;确认 Secret 与 Pod 在同一命名空间
快速排错命令:
kubectl get events --field-selector involvedObject.name=<pod-name> — 查看 Pod 相关事件
kubectl get secret <secret-name> -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d — 解码查看 Secret 内容

4.6 安全加固建议

  • 定期轮换凭据: 使用 External Secrets Operator 或 Vault 自动轮换仓库密码,避免凭据长期有效。
  • 最小权限原则: 为每个仓库创建只读账号(pull-only),避免使用管理员账号。
  • 命名空间隔离: 不同环境(dev/staging/prod)使用不同的 Secret,避免凭据泄露影响生产。
  • 审计与监控: 开启 Kubernetes 审计日志,记录 Secret 的创建、更新和删除操作。