Docker与Kubernetes实战:2026年容器编排最佳实践
·
Docker与Kubernetes实战:2026年容器编排最佳实践
引言
如果说前几年云原生还是"先进技术"的代表,那现在基本已经是行业标配了。2026年,新启动的项目大部分都会考虑用容器、微服务这些技术栈。Kubernetes在企业生产容器编排workload中市场占比高达92%。
本文将从环境搭建到生产部署,系统性地拆解Docker与Kubernetes的核心实战技能,帮助开发者和运维人员建立起从单机到集群的完整操作闭环。
一、Docker核心实战
1.1 Docker解决了什么问题
Docker的核心是容器化。你可以把它想象成一个超级轻量级的"虚拟机"。但与虚拟机需要模拟完整的操作系统不同,容器直接共享宿主机的操作系统内核,只打包应用及其运行所需的库和依赖。这使得容器具有启动快、资源消耗小、部署一致性好等巨大优势。
它主要解决了以下痛点:
- 环境一致性:“在我机器上能跑,为什么到你那就报错?” Docker通过镜像保证了从开发、测试到生产环境的高度一致。
- 资源高效:容器共享宿主机内核,无需为每个应用加载完整的操作系统。
- 快速部署与扩展:镜像一旦构建完成,可以在任何安装了Docker的平台上秒级启动。
1.2 编写高质量Dockerfile
# 多阶段构建 - 减小最终镜像体积
# 阶段1: 构建阶段
FROM node:20-alpine AS builder
WORKDIR /app
# 先复制依赖文件,利用Docker缓存层
COPY package.json package-lock.json ./
RUN npm ci --only=production
# 复制源码并构建
COPY . .
RUN npm run build
# 阶段2: 运行阶段
FROM node:20-alpine
# 安全加固:使用非root用户
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup
WORKDIR /app
# 只复制生产依赖和构建产物
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./
# 设置环境变量
ENV NODE_ENV=production
ENV PORT=3000
EXPOSE 3000
USER appuser
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
CMD ["node", "dist/main.js"]
1.3 Docker Compose多服务编排
version: '3.8'
services:
# 应用服务
api:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DB_HOST=postgres
- REDIS_HOST=redis
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
networks:
- app-network
# PostgreSQL数据库
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: appuser
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser -d myapp"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
# Redis缓存
redis:
image: redis:7-alpine
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
# Nginx反向代理
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- api
networks:
- app-network
volumes:
postgres-data:
redis-data:
networks:
app-network:
driver: bridge
1.4 Docker安全最佳实践
# 安全Dockerfile示例
FROM alpine:3.19
# 1. 使用特定版本标签,不用latest
# 2. 最小化安装
RUN apk add --no-cache ca-certificates tzdata
# 3. 创建非root用户
RUN addgroup -S app && adduser -S app -G app
# 4. 复制文件并设置权限
COPY --chown=app:app ./app /app
# 5. 使用USER切换用户
USER app
# 6. 不使用root运行
WORKDIR /app
CMD ["./app"]
二、Kubernetes核心实战
2.1 基础概念速览
| 概念 | 说明 | 类比 |
|---|---|---|
| Pod | 最小部署单元,包含一个或多个容器 | 一个"逻辑主机" |
| Deployment | 管理Pod的副本数和更新策略 | 应用的"部署描述" |
| Service | 为Pod提供稳定的网络访问入口 | 负载均衡器 |
| ConfigMap | 存储非敏感配置 | 配置文件 |
| Secret | 存储敏感信息 | 加密的配置文件 |
| Ingress | 管理外部访问路由 | 反向代理规则 |
2.2 完整部署示例
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
labels:
app: api
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: myapp/api:v1.2.3
ports:
- containerPort: 3000
name: http
env:
- name: NODE_ENV
value: "production"
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: api-config
key: db_host
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: api-secrets
key: db_password
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health/live
port: 3000
initialDelaySeconds: 15
periodSeconds: 20
readinessProbe:
httpGet:
path: /health/ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
volumeMounts:
- name: config
mountPath: /app/config
readOnly: true
volumes:
- name: config
configMap:
name: api-config
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: api-service
spec:
type: ClusterIP
selector:
app: api
ports:
- port: 80
targetPort: 3000
protocol: TCP
name: http
---
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: api-config
data:
db_host: "postgres-service"
redis_host: "redis-service"
log_level: "info"
app.yaml: |
server:
port: 3000
timeout: 30s
database:
max_connections: 20
idle_timeout: 60s
---
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: api-tls
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
2.3 HPA自动扩缩容
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-deployment
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "1000"
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 50
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
- type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
三、CI/CD流水线
3.1 GitHub Actions + Kubernetes
# .github/workflows/deploy.yml
name: Build and Deploy
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Deploy to Kubernetes
uses: azure/k8s-deploy@v4
with:
manifests: |
k8s/deployment.yaml
k8s/service.yaml
k8s/ingress.yaml
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
四、监控与日志
4.1 Prometheus + Grafana
# prometheus-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
data:
prometheus.yml: |
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
4.2 应用指标暴露
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
httpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
[]string{"method", "endpoint", "status"},
)
httpRequestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "HTTP request duration in seconds",
Buckets: prometheus.DefBuckets,
},
[]string{"method", "endpoint"},
)
)
func init() {
prometheus.MustRegister(httpRequestsTotal, httpRequestDuration)
}
// 中间件
func MetricsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// 包装ResponseWriter以获取状态码
wrapped := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}
next.ServeHTTP(wrapped, r)
duration := time.Since(start).Seconds()
httpRequestsTotal.WithLabelValues(r.Method, r.URL.Path, strconv.Itoa(wrapped.statusCode)).Inc()
httpRequestDuration.WithLabelValues(r.Method, r.URL.Path).Observe(duration)
})
}
五、生产环境最佳实践
5.1 资源管理
# LimitRange - 设置默认资源限制
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
spec:
limits:
- default:
memory: "512Mi"
cpu: "500m"
defaultRequest:
memory: "256Mi"
cpu: "250m"
type: Container
---
# ResourceQuota - 命名空间资源配额
apiVersion: v1
kind: ResourceQuota
metadata:
name: namespace-quota
spec:
hard:
requests.cpu: "10"
requests.memory: "20Gi"
limits.cpu: "20"
limits.memory: "40Gi"
persistentvolumeclaims: "10"
pods: "50"
5.2 PodDisruptionBudget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: api
5.3 NetworkPolicy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-network-policy
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 3000
egress:
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
- to:
- podSelector:
matchLabels:
app: redis
ports:
- protocol: TCP
port: 6379
六、总结
本文从Docker基础到Kubernetes生产部署,系统性地覆盖了容器化全流程:
- Docker核心:多阶段构建、安全加固、Compose编排
- Kubernetes部署:Deployment、Service、Ingress、HPA
- CI/CD:GitHub Actions自动化构建部署
- 监控:Prometheus + Grafana可观测性
- 生产实践:资源管理、PDB、网络策略
掌握这些技能,你将能够独立完成从代码到生产环境的完整容器化部署流程。
更多推荐
所有评论(0)