云原生架构入门:容器化与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提供稳定的网络访问负载均衡器
IngressHTTP层路由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 实现持续交付。

学习路径建议

  1. 先掌握 Docker(容器化、Dockerfile、docker-compose)
  2. 学习 K8s 核心概念(Pod、Deployment、Service)
  3. 实战 K8s 部署(YAML编写、命令操作)
  4. 进阶 K8s 运维(HPA、Ingress、监控)
  5. 搭建 CI/CD 流水线

⚠️ 提醒:不要为了云原生而云原生。小项目用 Docker Compose 就够了,K8s 的运维成本不低。


觉得有帮助的话,点赞收藏关注三连!评论区交流你的云原生实践经验。

更多推荐