前言

        前面的系列文章中,我们先后学习了Java基础、Spring全家桶、MySQL优化、Redis实战以及消息中间件。今天,我们进入云原生时代最核心的技术——容器化与Kubernetes。从Docker的基本操作,到编写Dockerfile、多阶段构建,再到Kubernetes集群的搭建、Pod、Service、Ingress、ConfigMap、存储卷、自动伸缩、Helm包管理,本文将带你全面掌握容器化部署与编排的必备技能。全文配有大量命令行示例和YAML配置,助你快速上手生产级容器化实践。


一、为什么需要容器化?

  • 环境一致:开发、测试、生产环境保持一致,避免“在我机器上能运行”。

  • 资源隔离:容器共享宿主机内核,但拥有独立的文件系统、网络、进程空间。

  • 快速启动:容器启动是毫秒级,远快于虚拟机。

  • 弹性伸缩:结合K8s,可根据负载自动增减实例。

  • 交付效率:将应用及其依赖打包成镜像,通过镜像仓库分发,实现一键部署。


二、Docker核心概念与安装

1. 核心概念

  • 镜像(Image):只读模板,包含应用及运行环境。

  • 容器(Container):镜像的可运行实例,拥有独立的文件系统和网络。

  • 仓库(Repository):存储镜像的地方(Docker Hub、私有Harbor)。

  • Dockerfile:定义镜像构建步骤的脚本。

2. 安装Docker(CentOS 7+)

# 卸载旧版本
sudo yum remove docker docker-client docker-client-latest docker-common
# 安装依赖
sudo yum install -y yum-utils
# 添加官方源
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 安装Docker引擎
sudo yum install docker-ce docker-ce-cli containerd.io
# 启动并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker
# 验证
docker version

三、Docker常用命令与实战

1. 镜像管理

docker pull nginx:1.24           # 拉取镜像
docker images                     # 列出镜像
docker rmi <image_id>             # 删除镜像
docker tag nginx:1.24 mynginx:v1  # 打标签
docker push myregistry/mynginx:v1 # 推送镜像

2. 容器管理

docker run -d --name mynginx -p 80:80 nginx:1.24   # 后台运行并映射端口
docker ps                         # 查看运行中容器
docker ps -a                      # 查看所有容器
docker stop <container_id>        # 停止容器
docker start <container_id>       # 启动已停止容器
docker rm <container_id>          # 删除容器(需先停止)
docker exec -it <container_id> bash  # 进入容器内部
docker logs -f <container_id>     # 查看日志

3. 数据卷(Volume)

docker volume create mydata       # 创建卷
docker run -v mydata:/app/data myapp  # 挂载卷
# 宿主机目录挂载(推荐)
docker run -v /host/path:/container/path myapp

4. 网络模式

  • bridge(默认):容器间通过NAT通信。

  • host:使用宿主机网络栈。

  • none:无网络。

  • container:共享其他容器的网络。

docker network create mynet
docker run --network mynet --name app1 myapp
docker run --network mynet --name app2 myapp  # app2可通过容器名访问app1

四、编写Dockerfile的最佳实践

1. 示例:Spring Boot应用

dockerfile

# 基础镜像(使用openjdk官方)
FROM openjdk:11-jre-slim

# 作者信息
LABEL maintainer="yourname@example.com"

# 设置工作目录
WORKDIR /app

# 复制jar包(利用docker缓存,将变动频率低的放前面)
COPY target/*.jar app.jar

# 创建非root用户
RUN groupadd -r spring && useradd -r -g spring spring
USER spring

# 暴露端口
EXPOSE 8080

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/actuator/health || exit 1

# 启动命令
ENTRYPOINT ["java", "-jar", "app.jar"]

2. 多阶段构建(减小镜像体积)

dockerfile

# 第一阶段:编译
FROM maven:3.8-openjdk-11 AS builder
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests

# 第二阶段:运行
FROM openjdk:11-jre-slim
COPY --from=builder /build/target/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]

3. 构建与运行

docker build -t myapp:1.0 .
docker run -d -p 8080:8080 --name myapp myapp:1.0

4. 镜像优化建议

  • 选择轻量级基础镜像(alpineslim版本)。

  • 合并RUN命令,减少层数。

  • 清理临时文件(apt-get cleanrm -rf /var/lib/apt/lists/*)。

  • 使用.dockerignore排除无用文件。


五、Docker Compose:多容器编排

1. 安装Compose

sudo curl -L "https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

2. 编写docker-compose.yml

yml

version: '3.8'

services:
  mysql:
    image: mysql:8.0
    container_name: mysql
    environment:
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: mydb
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
    networks:
      - appnet

  redis:
    image: redis:7-alpine
    container_name: redis
    ports:
      - "6379:6379"
    networks:
      - appnet

  app:
    build: .
    container_name: spring-app
    ports:
      - "8080:8080"
    depends_on:
      - mysql
      - redis
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/mydb?useSSL=false
      SPRING_REDIS_HOST: redis
    networks:
      - appnet

volumes:
  mysql_data:

networks:
  appnet:
    driver: bridge

3. 启动与停止

docker-compose up -d        # 后台启动
docker-compose logs -f app  # 查看app日志
docker-compose down         # 停止并删除容器、网络(保留数据卷)
docker-compose down -v      # 同时删除数据卷

六、Kubernetes核心概念

Kubernetes是一个开源的容器编排平台,用于自动部署、扩展和管理容器化应用。

1. 架构组件

  • Master节点

    • kube-apiserver:集群统一入口,REST API。

    • etcd:分布式键值存储,保存集群状态。

    • kube-scheduler:调度Pod到合适的Node。

    • kube-controller-manager:运行各种控制器(Node、Deployment等)。

  • Worker节点

    • kubelet:与Master通信,管理Pod和容器。

    • kube-proxy:维护网络规则,实现Service负载均衡。

    • 容器运行时(Docker/containerd)。

2. 资源对象

  • Pod:最小部署单元,一个Pod包含一个或多个容器(共享网络和存储)。

  • Service:为一组Pod提供稳定的访问入口(ClusterIP、NodePort、LoadBalancer)。

  • Deployment:无状态应用的管理器,支持滚动更新、回滚、副本扩缩容。

  • StatefulSet:有状态应用(如数据库),提供稳定的网络标识和持久化存储。

  • ConfigMap / Secret:管理配置和敏感信息。

  • Ingress:七层路由,将外部请求转发到Service。

  • Namespace:资源隔离(类似虚拟集群)。


七、搭建K8s集群(使用Minikube或kubeadm)

1. 本地开发:Minikube

curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
minikube start --driver=docker --cpus=2 --memory=4096

2. 生产级:kubeadm(Ubuntu 20.04示例)

# 所有节点:安装容器运行时和kubeadm
sudo apt update && sudo apt install -y docker.io
sudo systemctl enable --now docker
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt update && sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

# 初始化Master(仅主节点)
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

# 安装网络插件(Flannel)
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml

# Worker节点加入集群(主节点输出token)
kubeadm join <master-ip>:6443 --token <token> --discovery-token-ca-cert-hash <hash>

八、Kubernetes核心资源操作

1. Pod

yaml

# pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.24
    ports:
    - containerPort: 80
bash

kubectl apply -f pod.yaml
kubectl get pods -o wide
kubectl exec -it nginx-pod -- /bin/bash
kubectl delete pod nginx-pod
2. Deployment + Service
yaml

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:1.0
        ports:
        - containerPort: 8080
        env:
        - name: ENV
          value: "prod"
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
spec:
  type: NodePort
  selector:
    app: myapp
  ports:
  - port: 8080
    targetPort: 8080
    nodePort: 30080
kubectl apply -f deployment.yaml -f service.yaml
kubectl get deploy,svc,po

3. 滚动更新与回滚

# 更新镜像
kubectl set image deployment/myapp-deploy myapp=myapp:2.0
# 查看更新状态
kubectl rollout status deployment/myapp-deploy
# 回滚到上一个版本
kubectl rollout undo deployment/myapp-deploy
# 查看历史版本
kubectl rollout history deployment/myapp-deploy

4. Ingress(七层路由)

yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp-svc
            port:
              number: 8080

需要安装Ingress Controller(如Nginx Ingress):

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/cloud/deploy.yaml

5. ConfigMap 和 Secret

yaml

# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  application.yml: |
    server:
      port: 8080
    database:
      url: jdbc:mysql://mysql-svc:3306/mydb
---
# secret.yaml(密码base64编码)
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:
  password: cm9vdDEyMw==   # echo -n 'root123' | base64

在Pod中使用:

yaml

env:
- name: DB_PASSWORD
  valueFrom:
    secretKeyRef:
      name: db-secret
      key: password

6. 持久化存储(PV/PVC)

yaml

# 静态PV
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /mnt/data
---
# PVC申请
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
Pod挂载PVC:

yaml

volumes:
- name: mydata
  persistentVolumeClaim:
    claimName: mypvc
containers:
- volumeMounts:
  - name: mydata
    mountPath: /data

7. 自动伸缩(HPA)

# 安装metrics-server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# 创建HPA(基于CPU)
kubectl autoscale deployment myapp-deploy --cpu-percent=50 --min=2 --max=10
# 查看HPA状态
kubectl get hpa

九、Helm:K8s应用包管理器

1. 安装Helm

curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

2. 创建Chart

helm create mychart
# 目录结构
# mychart/
#   Chart.yaml      # 元数据
#   values.yaml     # 默认配置
#   templates/      # 模板文件
#   charts/         # 依赖子Chart

3. 模板示例(templates/deployment.yaml

yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Values.appName }}
spec:
  replicas: {{ .Values.replicaCount }}
  template:
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        ports:
        - containerPort: {{ .Values.service.port }}

4. 安装与升级

helm install my-release ./mychart --set image.tag=1.0
helm upgrade my-release ./mychart --set replicaCount=3
helm list
helm uninstall my-release

十、生产环境最佳实践

1. 资源限制

  • 为每个容器设置requestslimits,避免资源争抢和节点不稳定。

  • 命名空间设置ResourceQuota限制总资源消耗。

2. 健康检查

  • livenessProbe:探测容器是否存活,失败则重启。

  • readinessProbe:探测容器是否准备好接收流量,失败则从Service端点移除。

yaml

livenessProbe:
  httpGet:
    path: /actuator/health
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10
readinessProbe:
  httpGet:
    path: /actuator/health/readiness
    port: 8080
  initialDelaySeconds: 10

3. 优雅终止

  • Pod删除时,K8s发送SIGTERM,应用需在terminationGracePeriodSeconds(默认30s)内处理完现有请求并关闭。

yaml

spec:
  terminationGracePeriodSeconds: 60
  containers:
  - lifecycle:
      preStop:
        exec:
          command: ["/bin/sh", "-c", "sleep 5"]

4. 使用PodDisruptionBudget保证可用性

yaml

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: myapp-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: myapp

5. 镜像拉取策略

  • IfNotPresent(默认):节点上没有才拉取。

  • Always:每次启动都拉取(适合latest标签)。

  • 生产环境推荐使用固定版本标签,避免意外拉取失败。

6. 日志与监控

  • 日志:容器标准输出由kubelet收集,推荐使用Fluentd/Filebeat发送到ES或Loki。

  • 监控:Prometheus + Grafana(kube-prometheus-stack一键部署)。

  • 事件kubectl get events --watch,或使用开源工具(如KubeSphere)。

7. 安全加固

  • 使用RBAC限制权限(不创建cluster-admin角色给普通用户)。

  • 启用PodSecurityPolicy(或K8s 1.25+的Pod Security Admission)。

  • 运行容器时使用非root用户(如前面Dockerfile中创建的spring用户)。

  • 扫描镜像漏洞(Trivy、Clair)。


十一、CI/CD集成示例(GitLab + K8s)

1. .gitlab-ci.yml

stages:
  - build
  - deploy

variables:
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

build:
  stage: build
  script:
    - docker build -t $IMAGE_TAG .
    - docker push $IMAGE_TAG

deploy:
  stage: deploy
  script:
    - kubectl set image deployment/myapp-deploy myapp=$IMAGE_TAG -n prod
    - kubectl rollout status deployment/myapp-deploy -n prod
  only:
    - main

十二、常见问题与排查

1. Pod一直处于Pending状态

  • 原因:资源不足(CPU/内存),节点没有满足nodeSelectoraffinity

  • 解决:kubectl describe pod <pod-name> 查看事件,添加节点或降低资源请求。

2. CrashLoopBackOff

  • 原因:容器启动后立即退出(如命令错误、依赖缺失、健康检查失败)。

  • 解决:kubectl logs <pod-name> --previous查看上次日志,检查启动命令和环境。

3. Service无法访问

  • 检查kubectl get endpoints是否有Pod IP(如果为空,检查selector是否匹配)。

  • 确认网络插件(Calico/Flannel)正常工作。

  • 测试ClusterIP:kubectl run test --rm -it --image=busybox -- wget -O- http://<service-ip>:<port>

4. 证书过期

  • kubeadm集群:sudo kubeadm certs renew all 并重启kubelet。

  • 设置证书自动轮换:kubelet --rotate-certificates


结语

容器化和Kubernetes已经彻底改变了软件交付和运维的方式。从单个Docker容器到大规模K8s集群,掌握这些技术将极大提升你的工程效率和架构能力。

学习建议

  1. 本地用Minikube或Kind搭建实验环境,动手部署自己的应用。

  2. 学习常用kubectl命令和YAML配置,熟练使用kubectl explain

  3. 尝试部署一个完整微服务(前端、后端、数据库、缓存),并配置Ingress和HPA。

  4. 阅读K8s官方文档,理解Controller、Scheduler、Operator等高级概念。

  5. 考取CKA(Certified Kubernetes Administrator)认证,系统化验证能力。

下期预告:服务网格与云原生架构实战(Istio + Envoy)。
如果本文对你有帮助,欢迎点赞、收藏、转发

更多推荐