Docker & Kubernetes 完全指南 第9篇:ConfigMap、Secret、Ingress 的使用
Docker & Kubernetes Complete Guide Part 9: ConfigMap, Secret, and Ingress
前言:配置管理与外部访问的重要性
在运营容器化应用程序时,最重要的课题之一是配置的分离。将应用程序代码与配置分离后,可以在开发、预发布、生产环境中重用同一镜像。Kubernetes 为此提供了 ConfigMap 和 Secret 这两种资源。
此外,从集群外部访问内部服务需要适当的路由机制。Ingress 作为 L7 负载均衡器,将 HTTP/HTTPS 流量路由到集群内部的服务。本篇将详细介绍这三个核心资源。
1. 配置管理的重要性
1.1 为什么要分离配置?
正如 12-Factor App 方法论所强调的,配置应该与代码分离:
- 环境部署:可以将同一镜像部署到各种环境(开发、测试、生产)
- 安全增强:敏感信息无需包含在代码仓库中
- 灵活变更:更改配置时无需重新构建镜像即可应用
- 团队协作:开发人员和运维人员可以独立管理各自的领域
1.2 Kubernetes 的配置管理方式
Kubernetes 通过两种资源来管理配置:
| 资源 | 用途 | 存储方式 |
|---|---|---|
| ConfigMap | 一般配置数据 | 明文(Plain text) |
| Secret | 敏感信息 | Base64 编码 |
2. ConfigMap 的创建和使用
2.1 什么是 ConfigMap?
ConfigMap 是用于存储键值对配置数据的 Kubernetes 资源。可以存储应用程序的环境变量、配置文件、命令行参数等。
2.2 ConfigMap 创建方法
方法1:使用字面值创建
# 单个键值对
kubectl create configmap app-config --from-literal=APP_ENV=production
# 多个键值对
kubectl create configmap app-config \
--from-literal=APP_ENV=production \
--from-literal=LOG_LEVEL=info \
--from-literal=MAX_CONNECTIONS=100
方法2:从文件创建
# 单个文件
kubectl create configmap nginx-config --from-file=nginx.conf
# 整个目录
kubectl create configmap app-configs --from-file=./configs/
方法3:使用 YAML 清单创建
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: default
data:
# 简单键值对
APP_ENV: "production"
LOG_LEVEL: "info"
MAX_CONNECTIONS: "100"
# 多行配置文件
application.properties: |
server.port=8080
spring.datasource.url=jdbc:mysql://mysql:3306/mydb
spring.jpa.hibernate.ddl-auto=update
logging.level.root=INFO
# JSON 格式配置
config.json: |
{
"apiEndpoint": "https://api.example.com",
"timeout": 30,
"retryCount": 3
}
kubectl apply -f configmap.yaml
2.3 ConfigMap 使用:环境变量
将单个键作为环境变量使用
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:latest
env:
# 仅注入特定键作为环境变量
- name: APPLICATION_ENV
valueFrom:
configMapKeyRef:
name: app-config
key: APP_ENV
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
将所有键作为环境变量使用
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:latest
envFrom:
- configMapRef:
name: app-config
# 可以添加前缀
- configMapRef:
name: app-config
prefix: CONFIG_
2.4 ConfigMap 使用:卷挂载
如果需要配置文件,可以将其作为卷挂载:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/conf.d
readOnly: true
volumes:
- name: config-volume
configMap:
name: nginx-config
# 仅挂载特定键时
items:
- key: nginx.conf
path: default.conf
使用 subPath 挂载特定文件
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: config-volume
mountPath: /app/config/application.properties
subPath: application.properties
volumes:
- name: config-volume
configMap:
name: app-config
3. Secret 的创建和使用
3.1 什么是 Secret?
Secret 是用于存储密码、OAuth 令牌、SSH 密钥等敏感信息的资源。与 ConfigMap 类似,但数据以 Base64 编码方式存储。
3.2 Secret 类型
| 类型 | 说明 | 使用示例 |
|---|---|---|
| Opaque | 任意用户自定义数据 | 密码、API 密钥 |
| kubernetes.io/tls | TLS 证书 | HTTPS 证书 |
| kubernetes.io/dockerconfigjson | Docker 仓库认证 | 私有仓库访问 |
| kubernetes.io/basic-auth | 基本认证信息 | 用户名/密码 |
| kubernetes.io/ssh-auth | SSH 认证 | SSH 私钥 |
3.3 Opaque Secret 创建
方法1:通过命令行创建
# 使用字面值创建
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password=s3cr3tP@ssw0rd
# 从文件创建
kubectl create secret generic ssh-key \
--from-file=ssh-privatekey=/path/to/id_rsa
方法2:使用 YAML 清单创建
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data:
# Base64 编码的值
# echo -n 'admin' | base64 -> YWRtaW4=
username: YWRtaW4=
# echo -n 's3cr3tP@ssw0rd' | base64 -> czNjcjN0UEBzc3cwcmQ=
password: czNjcjN0UEBzc3cwcmQ=
---
# 使用 stringData(自动 Base64 编码)
apiVersion: v1
kind: Secret
metadata:
name: api-credentials
type: Opaque
stringData:
api-key: my-super-secret-api-key
api-secret: another-secret-value
3.4 TLS Secret 创建
# 创建 TLS 证书 Secret
kubectl create secret tls tls-secret \
--cert=path/to/tls.crt \
--key=path/to/tls.key
# tls-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: tls-secret
type: kubernetes.io/tls
data:
tls.crt: |
LS0tLS1CRUdJTi... (Base64 编码的证书)
tls.key: |
LS0tLS1CRUdJTi... (Base64 编码的密钥)
3.5 使用 Secret
作为环境变量注入
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:latest
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
作为卷挂载
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: db-credentials
# 文件权限设置
defaultMode: 0400
3.6 Secret 安全注意事项
Secret 默认只进行 Base64 编码,并未加密。需要考虑以下安全措施:
- etcd 加密:对存储在 etcd 中的 Secret 进行加密
# EncryptionConfiguration apiVersion: apiserver.config.k8s.io/v1 kind: EncryptionConfiguration resources: - resources: - secrets providers: - aescbc: keys: - name: key1 secret: base64-encoded-32-byte-key - identity: {} - RBAC 限制:最小化对 Secret 的访问权限
- 使用外部 Secret 管理工具:HashiCorp Vault、AWS Secrets Manager、Azure Key Vault 等
- Secret 轮换:定期更改 Secret 值
- 审计日志:启用 Secret 访问的审计日志
4. 什么是 Ingress?
4.1 Ingress 概念
Ingress 是管理从集群外部到内部服务的 HTTP/HTTPS 流量的 API 对象。作为 L7(应用层)负载均衡器,提供以下功能:
- 基于主机的路由:根据域名路由到不同的服务
- 基于路径的路由:根据 URL 路径路由到不同的服务
- TLS/SSL 终止:处理 HTTPS 流量
- 负载均衡:将流量分发到多个 Pod
4.2 Ingress vs Service(NodePort/LoadBalancer)
| 特性 | NodePort | LoadBalancer | Ingress |
|---|---|---|---|
| 层级 | L4 | L4 | L7 |
| 协议 | TCP/UDP | TCP/UDP | HTTP/HTTPS |
| URL 路由 | 不可能 | 不可能 | 可能 |
| TLS 终止 | 不可能 | 不可能 | 可能 |
| 成本 | 免费 | 产生云费用 | 单个 LB 服务多个服务 |
5. Ingress Controller
5.1 什么是 Ingress Controller?
Ingress 资源只是声明性的路由规则,实际运行需要 Ingress Controller。Ingress Controller 监视 Ingress 资源并据此配置负载均衡器。
5.2 主要 Ingress Controller
Nginx Ingress Controller
# Nginx Ingress Controller 安装(Helm)
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install nginx-ingress ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace
# 或使用 manifest 安装
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml
Traefik Ingress Controller
# Traefik 安装(Helm)
helm repo add traefik https://helm.traefik.io/traefik
helm repo update
helm install traefik traefik/traefik \
--namespace traefik \
--create-namespace
其他 Ingress Controller
- HAProxy Ingress:高性能负载均衡
- Contour:基于 Envoy
- AWS ALB Ingress Controller:集成 AWS Application Load Balancer
- GKE Ingress Controller:集成 Google Cloud Load Balancer
6. Ingress YAML 编写
6.1 基本 Ingress 结构
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
# Ingress Controller 特定设置
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx # 指定使用的 Ingress Controller
rules:
- host: example.com # 基于主机的路由
http:
paths:
- path: / # 基于路径的路由
pathType: Prefix
backend:
service:
name: my-service
port:
number: 80
6.2 pathType 选项
- Exact:仅匹配完全一致的路径
- Prefix:匹配以指定路径开头的所有请求
- ImplementationSpecific:根据 Ingress Controller 行为
7. 基于主机/路径的路由
7.1 基于主机的路由
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: host-based-ingress
spec:
ingressClassName: nginx
rules:
# api.example.com -> api-service
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
# web.example.com -> web-service
- host: web.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
# admin.example.com -> admin-service
- host: admin.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 3000
7.2 基于路径的路由
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-based-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- host: example.com
http:
paths:
# example.com/api/* -> api-service
- path: /api(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: api-service
port:
number: 8080
# example.com/web/* -> web-service
- path: /web(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: web-service
port:
number: 80
# example.com/* (默认) -> frontend-service
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
7.3 复合路由(主机 + 路径)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: combined-ingress
spec:
ingressClassName: nginx
rules:
- host: shop.example.com
http:
paths:
- path: /products
pathType: Prefix
backend:
service:
name: product-service
port:
number: 8080
- path: /orders
pathType: Prefix
backend:
service:
name: order-service
port:
number: 8080
- path: /users
pathType: Prefix
backend:
service:
name: user-service
port:
number: 8080
8. TLS 配置
8.1 TLS Secret 创建
# 创建自签名证书(测试用)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key \
-out tls.crt \
-subj "/CN=example.com"
# 创建 TLS Secret
kubectl create secret tls example-tls \
--cert=tls.crt \
--key=tls.key
8.2 在 Ingress 中应用 TLS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com
- www.example.com
secretName: example-tls
- hosts:
- api.example.com
secretName: api-tls
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
8.3 使用 cert-manager 自动管理证书
# 安装 cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
# Let's Encrypt ClusterIssuer 配置
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: your-email@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx
---
# 自动证书签发 Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: auto-tls-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com
secretName: example-tls-auto # cert-manager 自动生成
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
9. 实战示例:微服务路由
# 完整的微服务 Ingress 配置
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: microservices-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls
rules:
- host: myapp.example.com
http:
paths:
# API Gateway
- path: /api/v1/users
pathType: Prefix
backend:
service:
name: user-service
port:
number: 8080
- path: /api/v1/products
pathType: Prefix
backend:
service:
name: product-service
port:
number: 8080
- path: /api/v1/orders
pathType: Prefix
backend:
service:
name: order-service
port:
number: 8080
# WebSocket
- path: /ws
pathType: Prefix
backend:
service:
name: websocket-service
port:
number: 8081
# 前端(默认)
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
10. 结论
本篇我们详细了解了 Kubernetes 的核心配置管理资源 ConfigMap 和 Secret,以及管理外部流量的 Ingress:
- ConfigMap:管理一般配置数据,可以作为环境变量或卷注入到 Pod
- Secret:安全存储敏感信息,需要额外的安全措施
- Ingress:作为 L7 负载均衡器,提供基于主机/路径的路由和 TLS 终止
- Ingress Controller:实际实现 Ingress 资源的组件
在下一篇第10篇中,我们将介绍 Kubernetes 包管理器 Helm 和 CI/CD 流水线 的构建。将涵盖使用 Helm Chart 进行应用程序部署和基于 GitOps 的自动化部署策略。