4. 私有镜像仓库认证:使用 imagePullSecrets 配置 Docker Registry、Harbor 等私有仓库认证
在生产环境中,镜像通常存储在私有仓库(如 Docker Registry、Harbor、Nexus 等)中,而非公共 Docker Hub。Kubernetes 在拉取私有镜像时,必须提供有效的认证凭据。本章将深入讲解 imagePullSecrets 的配置原理、创建方式及在 Deployment 中的挂载策略,确保灾备场景下镜像拉取不因认证失败而中断。
4.1 认证机制与核心概念
Kubernetes 通过 imagePullSecrets 资源将 Docker 仓库的认证凭据传递给 kubelet,kubelet 在拉取镜像时使用该凭据向私有仓库进行身份验证。其核心流程如下:
kubernetes.io/dockerconfigjson 类型的 Secret,存储了 base64 编码的 Docker 认证信息(.dockerconfigjson)。
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
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>
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 进行认证,直到成功拉取镜像或所有凭据尝试失败。
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 的创建、更新和删除操作。