云原生架构入门:容器化与K8s部署实战指南
·
云原生架构入门:容器化与K8s部署实战指南
本文摘要:云原生(Cloud Native)已成为现代应用架构的标准范式。本文从 Docker 容器化基础到 Kubernetes 集群部署实战,系统讲解云原生核心概念、Dockerfile 最佳实践、K8s 核心资源对象、CI/CD 流水线搭建,助你快速上手云原生开发。
一、云原生是什么?
1.1 云原生的四大支柱
┌──────────────────────────────────────────────┐
│ 云原生应用 │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ 容器化 │ │ 微服务 │ │
│ │ Docker │ │ 微服务架构 │ │
│ └──────────┘ └──────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ 动态编排 │ │ 持续交付 │ │
│ │ K8s │ │ CI/CD │ │
│ └──────────┘ └──────────┘ │
└──────────────────────────────────────────────┘
1.2 传统部署 vs 云原生部署
| 维度 | 传统部署 | 云原生部署 |
|---|---|---|
| 部署方式 | 物理机/虚拟机 | 容器 |
| 扩缩容 | 手动,分钟级 | 自动,秒级 |
| 资源利用率 | 低(预留资源) | 高(按需分配) |
| 故障恢复 | 人工介入 | 自动重启/迁移 |
| 发布频率 | 周/月 | 每天多次 |
| 环境一致性 | 经常不一致 | 容器保证一致 |
二、Docker 容器化
2.1 Dockerfile 最佳实践
# ===== 多阶段构建:减小镜像体积 =====
# 阶段1:构建阶段
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /build
# 先复制pom.xml,利用Docker缓存层
COPY pom.xml .
RUN mvn dependency:go-offline
# 复制源码并构建
COPY src ./src
RUN mvn clean package -DskipTests
# 阶段2:运行阶段(使用精简基础镜像)
FROM eclipse-temurin:17-jre-alpine
# 安装必要工具
RUN apk add --no-cache curl tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
# 创建非root用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
# 从构建阶段复制jar包
COPY --from=builder /build/target/*.jar app.jar
# 设置JVM参数
ENV JAVA_OPTS="-Xms512m -Xmx512m -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
ENV SPRING_PROFILES_ACTIVE=prod
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
CMD curl -f http://localhost:8080/actuator/health || exit 1
# 切换非root用户
USER appuser
EXPOSE 8080
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
2.2 Dockerfile 优化要点
| 优化项 | 说明 | 效果 |
|---|---|---|
| 多阶段构建 | 构建和运行分离 | 镜像从800MB→150MB |
| 使用Alpine基础镜像 | 精简OS | 减少安全风险 |
| 合并RUN命令 | 减少层数 | 加快构建速度 |
| 利用缓存层 | pom.xml先复制 | 依赖不变时跳过下载 |
| 非root运行 | 安全加固 | 防止提权攻击 |
2.3 docker-compose 本地开发
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=dev
- MYSQL_HOST=mysql
- REDIS_HOST=redis
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
networks:
- app-network
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: myapp
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
redis:
image: redis:7-alpine
ports:
- "6379:6379"
command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
networks:
- app-network
volumes:
mysql-data:
networks:
app-network:
driver: bridge
三、Kubernetes 核心概念
3.1 K8s 架构总览
┌─────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ │
│ ┌────────────────────────────────────────────┐ │
│ │ Control Plane (Master) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ API Server│ │Scheduler │ │ etcd │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ │ ┌──────────────────────────────────────┐ │ │
│ │ │ Controller Manager │ │ │
│ │ └──────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ Node 1 │ │ Node 2 │ │ Node 3 │ │
│ │ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌────────┐ │ │
│ │ │kubelet │ │ │ │kubelet │ │ │ │kubelet │ │ │
│ │ ├──────────┤ │ │ ├──────────┤ │ │ ├────────┤ │ │
│ │ │kube-proxy│ │ │ │kube-proxy│ │ │ │kube- │ │ │
│ │ ├──────────┤ │ │ ├──────────┤ │ │ │proxy │ │ │
│ │ │ Pods │ │ │ │ Pods │ │ │ ├────────┤ │ │
│ │ │┌───────┐ │ │ │ │┌───────┐ │ │ │ │ Pods │ │ │
│ │ ││容器1 │ │ │ │ ││容器1 │ │ │ │ │ │ │ │
│ │ ││容器2 │ │ │ │ ││容器2 │ │ │ │ │ │ │ │
│ │ │└───────┘ │ │ │ │└───────┘ │ │ │ │ │ │ │
│ │ └──────────┘ │ │ └──────────┘ │ │ └────────┘ │ │
│ └──────────────┘ └──────────────┘ └────────────┘ │
└─────────────────────────────────────────────────────┘
3.2 核心资源对象速查
| 对象 | 作用 | 类比 |
|---|---|---|
| Pod | 最小部署单元,包含1+容器 | 一个进程 |
| Deployment | 管理Pod副本和滚动更新 | 进程管理器 |
| Service | 提供稳定的网络访问 | 负载均衡器 |
| Ingress | HTTP层路由 | Nginx反向代理 |
| ConfigMap | 配置管理 | 配置文件 |
| Secret | 敏感配置 | 加密配置 |
| PersistentVolume | 持久化存储 | 磁盘 |
四、K8s 部署实战
4.1 Deployment
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
namespace: production
labels:
app: order-service
version: v1
spec:
replicas: 3 # 3个副本
strategy:
type: RollingUpdate # 滚动更新
rollingUpdate:
maxSurge: 1 # 滚动更新时最多多出1个
maxUnavailable: 0 # 滚动更新时不允许减少
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
version: v1
spec:
containers:
- name: order-service
image: registry.cn-hangzhou.aliyuncs.com/myapp/order-service:v1.0.0
ports:
- containerPort: 8080
name: http
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
- name: MYSQL_HOST
valueFrom:
configMapKeyRef:
name: db-config
key: mysql-host
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: mysql-password
resources:
requests: # 资源请求(调度依据)
cpu: "250m" # 0.25核
memory: "512Mi"
limits: # 资源上限(硬限制)
cpu: "500m"
memory: "1Gi"
livenessProbe: # 存活探针:失败则重启
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
failureThreshold: 3
readinessProbe: # 就绪探针:失败则从负载均衡移除
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 5
failureThreshold: 3
lifecycle:
preStop: # 优雅停机
exec:
command: ["sh", "-c", "sleep 10"]
terminationGracePeriodSeconds: 60
4.2 Service
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: order-service
namespace: production
spec:
type: ClusterIP # 集群内部访问
selector:
app: order-service
ports:
- port: 80 # Service端口
targetPort: 8080 # Pod端口
protocol: TCP
name: http
4.3 Ingress
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
namespace: production
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/rate-limit: "100"
nginx.ingress.kubernetes.io/rate-limit-window: "1m"
spec:
tls:
- hosts:
- api.example.com
secretName: tls-secret
rules:
- host: api.example.com
http:
paths:
- path: /api/user
pathType: Prefix
backend:
service:
name: user-service
port:
number: 80
- path: /api/order
pathType: Prefix
backend:
service:
name: order-service
port:
number: 80
- path: /api/product
pathType: Prefix
backend:
service:
name: product-service
port:
number: 80
4.4 ConfigMap 与 Secret
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: db-config
namespace: production
data:
mysql-host: "mysql.production.svc.cluster.local"
mysql-port: "3306"
redis-host: "redis.production.svc.cluster.local"
application.yml: |
spring:
datasource:
url: jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/orders
hikari:
maximum-pool-size: 20
redis:
host: ${REDIS_HOST}
port: 6379
---
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: db-secret
namespace: production
type: Opaque
data:
mysql-password: cGFzc3dvcmQxMjM= # base64编码
redis-password: cmVkaXMxMjM=
4.5 HPA(自动扩缩容)
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: order-service-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: order-service
minReplicas: 3 # 最小副本数
maxReplicas: 20 # 最大副本数
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # CPU使用率超过70%扩容
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80 # 内存使用率超过80%扩容
behavior:
scaleUp:
stabilizationWindowSeconds: 30 # 扩容冷却30秒
policies:
- type: Percent
value: 100 # 每次最多翻倍
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300 # 缩容冷却5分钟
policies:
- type: Percent
value: 25 # 每次最多缩25%
periodSeconds: 60
五、CI/CD 流水线
5.1 GitLab CI 流水线
# .gitlab-ci.yml
stages:
- build
- test
- docker
- deploy
variables:
IMAGE_NAME: registry.cn-hangzhou.aliyuncs.com/myapp/order-service
IMAGE_TAG: ${CI_COMMIT_SHORT_SHA}
# 构建
build:
stage: build
image: maven:3.9-eclipse-temurin-17
script:
- mvn clean package -DskipTests
artifacts:
paths:
- target/*.jar
cache:
paths:
- .m2/repository
# 测试
test:
stage: test
image: maven:3.9-eclipse-temurin-17
script:
- mvn test
coverage: '/Total.*?([0-9]{1,3})%/'
# Docker镜像构建与推送
docker-build:
stage: docker
image: docker:24
services:
- docker:24-dind
script:
- docker build -t ${IMAGE_NAME}:${IMAGE_TAG} .
- docker tag ${IMAGE_NAME}:${IMAGE_TAG} ${IMAGE_NAME}:latest
- docker login -u ${REGISTRY_USER} -p ${REGISTRY_PASSWORD}
- docker push ${IMAGE_NAME}:${IMAGE_TAG}
- docker push ${IMAGE_NAME}:latest
only:
- main
# K8s部署
deploy-prod:
stage: deploy
image: bitnami/kubectl:1.28
script:
- kubectl config use-context production
- kubectl set image deployment/order-service
order-service=${IMAGE_NAME}:${IMAGE_TAG}
-n production
- kubectl rollout status deployment/order-service -n production
environment:
name: production
only:
- main
5.2 滚动发布流程
v1.0.0 (3 replicas) v1.0.0 v1.1.0
┌─────┐ ┌─────┐ ┌─────┐
│ Pod1│ ← 新版替换 │ Pod1│ │Pod1'│
│ Pod2│ │ Pod2│ │ │
│ Pod3│ │ Pod3│ │ │
└─────┘ └─────┘ └─────┘
步骤1: 启动 v1.1.0 Pod1',就绪后...
步骤2: 下线 v1.0.0 Pod1,启动 v1.1.0 Pod2'
步骤3: 下线 v1.0.0 Pod2,启动 v1.1.0 Pod3'
步骤4: 下线 v1.0.0 Pod3
→ 零停机,逐步替换
六、K8s 常用命令速查
# 集群信息
kubectl cluster-info
kubectl get nodes -o wide
# Pod操作
kubectl get pods -n production -o wide
kubectl describe pod <pod-name> -n production
kubectl logs <pod-name> -n production -f
kubectl exec -it <pod-name> -n production -- /bin/sh
# Deployment操作
kubectl get deployments -n production
kubectl rollout status deployment/order-service -n production
kubectl rollout history deployment/order-service -n production
kubectl rollout undo deployment/order-service -n production
kubectl scale deployment/order-service --replicas=5 -n production
# Service操作
kubectl get services -n production
kubectl get endpoints -n production
# 调试
kubectl run debug --image=busybox -it --rm --restart=Never -- /bin/sh
kubectl port-forward service/order-service 8080:80 -n production
七、云原生最佳实践
| 实践 | 说明 |
|---|---|
| 镜像最小化 | 多阶段构建 + Alpine基础镜像 |
| 健康检查 | 配置 liveness + readiness 探针 |
| 优雅停机 | preStop hook + terminationGracePeriod |
| 资源限制 | 必须设置 requests 和 limits |
| 配置分离 | ConfigMap + Secret,不硬编码 |
| 无状态 | 状态存外部(数据库/缓存),Pod可随时销毁 |
| 日志输出到stdout | 不写文件,由集群统一收集 |
| HPA自动扩缩容 | 根据CPU/内存/QPS自动调整 |
八、总结
云原生的核心价值是让应用天生为云而生——容器化保证环境一致性,K8s 提供自动化编排和自愈能力,CI/CD 实现持续交付。
学习路径建议:
- 先掌握 Docker(容器化、Dockerfile、docker-compose)
- 学习 K8s 核心概念(Pod、Deployment、Service)
- 实战 K8s 部署(YAML编写、命令操作)
- 进阶 K8s 运维(HPA、Ingress、监控)
- 搭建 CI/CD 流水线
⚠️ 提醒:不要为了云原生而云原生。小项目用 Docker Compose 就够了,K8s 的运维成本不低。
觉得有帮助的话,点赞收藏关注三连!评论区交流你的云原生实践经验。
更多推荐
所有评论(0)