Docker+K8s 集成部署实战

Docker+K8s 集成部署实战

在微服务和云原生普及的今天,Docker 的容器标准化能力与 Kubernetes 的大规模编排能力,已成为企业级部署的黄金组合。但从本地开发到生产落地,很多开发者会卡在 "集成配置""资源优化""故障排查" 等关键环节。本文结合电商订单系统的部署升级经验,从核心概念、集成要点到生产实战,一步步拆解 Docker 与 K8s 的协同逻辑,同时分享 5 个高频踩坑案例及解决方案。

一、Docker 与 K8s 的核心关系:不是替代,而是互补

Docker 和 K8s 的定位截然不同,却构成了容器化部署的完整链路,理解二者的分工是集成的基础。

1.1 核心定位与职责划分

工具 核心能力 核心价值
Docker 容器打包、单机运行 将应用及依赖打包为标准化镜像,确保"一次构建,到处运行",解决环境一致性问题
K8s 集群编排、自动化管理 对大规模容器进行部署、扩缩容、自愈、网络调度,解决分布式环境下的运维复杂性问题

注意:K8s 1.24+ 版本已移除内置的 dockershim 组件,不再直接对接 Docker,但可通过 Docker 内置的 containerd 运行时实现集成------这是当前生产环境的主流方案,无需额外安装独立的 containerd。

1.2 关键概念对应关系

Docker 概念 K8s 对应概念 核心作用说明
镜像(Image) 镜像(Image) K8s 通过镜像拉取策略(Always/IfNotPresent/Never)从仓库拉取镜像创建容器
容器(Container) Pod 内的容器 K8s 最小调度单元是 Pod,一个 Pod 可包含 1~N 个容器,共享网络和存储资源
Docker Compose Deployment/StatefulSet Compose 适用于单机小规模编排,K8s 控制器实现集群级高可用编排
Docker Network CNI 插件 + Service Docker 仅支持单机网络互通,K8s 通过 CNI(如 Calico)实现跨节点 Pod 通信,Service 提供固定访问入口

二、Docker 与 K8s 集成的 4 个核心落地要点

集成的关键在于 "标准化""适配性" ------Docker 镜像需满足 K8s 的拉取要求,K8s 配置需兼容 Docker 的运行特性,以下 4 个要点是落地必经之路。

2.1 镜像标准化:K8s 拉取成功的前提

镜像的规范程度直接影响部署稳定性,生产环境需重点关注 3 点:

(1)镜像命名规范

必须遵循 [仓库地址]:[端口]/[命名空间]/[镜像名]:[标签] 格式,示例:

复制代码
harbor.example.com/apps/order-service:v1.2.3-8f7d6a5
  • 禁止使用 latest 标签:避免版本漂移导致的部署不一致,建议用"版本号 + Git Commit ID"命名,便于追溯问题。
  • 私有仓库前缀不可少:明确指定私有仓库地址(如 Harbor),避免与公仓镜像混淆。
(2)镜像优化技巧

通过多阶段构建减小体积,降低拉取时间和存储成本,以 Go 语言应用为例:

dockerfile 复制代码
# 构建阶段:使用完整编译环境
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY . .
RUN go mod download && CGO_ENABLED=0 GOOS=linux go build -o order-service .

# 运行阶段:使用轻量基础镜像
FROM alpine:3.18
RUN apk --no-cache add ca-certificates  # 解决HTTPS证书问题
WORKDIR /app
COPY --from=builder /app/order-service .
USER nobody  # 非root用户运行,降低安全风险
EXPOSE 8080
CMD ["./order-service"]

优化效果:镜像体积可从 2G+ 压缩至 80M 以内,同时移除冗余依赖,提升安全性。

(3)私有仓库集成配置

K8s 拉取私有仓库镜像需配置认证信息,步骤如下:

  1. 创建镜像拉取密钥:
bash 复制代码
kubectl create secret docker-registry harbor-secret \
  --docker-server=harbor.example.com \
  --docker-username=admin \
  --docker-password=123456
  1. 在 Deployment 中引用密钥:
yaml 复制代码
spec:
  template:
    spec:
      imagePullSecrets:
        - name: harbor-secret  # 与创建的Secret名称一致

2.2 容器运行时集成(K8s 1.24+ 重点)

通过 Docker 内置的 containerd 对接 K8s,无需额外部署独立运行时,步骤如下:

  1. 安装 Docker 后,生成 containerd 配置文件:
bash 复制代码
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
  1. 修改配置文件,适配 K8s 要求:
    • 将 Sandbox 镜像改为国内源(避免拉取失败):

      复制代码
      sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.9"
    • 启用 CRI 接口(K8s 与 containerd 通信的标准接口)

  2. 重启 containerd 并设置开机自启:
bash 复制代码
systemctl restart containerd && systemctl enable containerd
  1. K8s 集群初始化时指定运行时:
bash 复制代码
kubeadm init --image-repository registry.aliyuncs.com/google_containers \
  --cri-socket unix:///run/containerd/containerd.sock \
  --pod-network-cidr=10.244.0.0/16

2.3 资源配置:Docker 限制与 K8s 配置的映射

Docker 的资源限制(如内存、CPU)需通过 K8s 的 resources 字段精准映射,避免容器超限被 Kill 或资源浪费:

Docker 限制方式 K8s 对应配置 说明
docker run --memory 1G limits.memory: 1Gi 容器最大可用内存,超限可能被 OOM Kill
docker run --cpus 1 limits.cpu: 1000m 容器最大可用 CPU(1000m=1 核)
docker run --restart always K8s 自愈机制 + replicas Deployment 通过 replicas 指定副本数,故障时自动重启并重新调度
生产环境配置示例(订单服务):
yaml 复制代码
resources:
  requests:  # 最小资源需求(K8s调度依据)
    cpu: 500m  # 0.5核
    memory: 512Mi
  limits:    # 最大资源限制
    cpu: 1000m # 1核
    memory: 1Gi
  • requests:确保 Pod 被调度到资源充足的节点,避免资源竞争;
  • limits:防止单个 Pod 占用过多资源,影响其他服务。

2.4 网络集成:从 Docker 单机网络到 K8s 跨节点通信

Docker 的单机网络无法满足分布式部署需求,K8s 通过 CNI 插件和 Service 实现网络互通:

(1)CNI 插件选择

生产环境优先选择 Calico(支持网络策略、跨节点通信稳定),安装命令:

bash 复制代码
kubectl apply -f https://docs.projectcalico.org/v3.25/manifests/calico.yaml

安装后,每个 Pod 会被分配独立 IP,跨节点 Pod 可直接通信,无需额外配置端口映射。

(2)服务暴露:Ingress 替代 NodePort

Docker 的 -p 8080:80 端口映射,在 K8s 中需通过 Service+Ingress 实现,生产环境禁止使用 NodePort(端口冲突风险高):

① 创建 ClusterIP 类型 Service(集群内访问):

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: order-service
spec:
  selector:
    app: order-service
  ports:
  - port: 8080
    targetPort: 8080
  type: ClusterIP

② 通过 Ingress 暴露对外访问入口(以 NGINX Ingress 为例):

yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: order-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: order.example.com  # 自定义域名
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: order-service
            port:
              number: 8080
  tls:  # 启用HTTPS
  - hosts:
    - order.example.com
    secretName: order-tls-secret  # 存储证书的Secret名称

Ingress 支持域名路由、路径转发、TLS 加密,是生产环境对外暴露服务的标准方案。

三、生产环境实战:电商订单系统从 Docker Compose 迁移到 K8s

以电商订单系统为例,分享从单机 Docker Compose 到 K8s 集群部署的完整迁移过程及思考。

3.1 迁移背景与目标

(1)原始架构痛点
  • 3 台物理机,用 Docker Compose 部署订单服务、库存服务、MySQL(单机)、Redis(单机);
  • 核心问题:容器故障需手动重启、扩缩容效率低、主机目录挂载导致数据易丢失、端口冲突频繁。
(2)迁移目标
  • 高可用:服务可用性从 99.5% 提升至 99.99%,支持故障自愈;
  • 自动化:支持一键扩缩容、滚动更新、版本回滚;
  • 可追溯:镜像版本与代码提交绑定,部署过程可审计;
  • 资源优化:提升节点 CPU/内存利用率,降低硬件成本。

3.2 核心迁移步骤

(1)镜像重构:从 "能用" 到 "生产级"

原 Dockerfile 基于 Ubuntu,包含冗余工具(如 vim、gcc),镜像体积达 2.3G,重构后:

  • 采用多阶段构建,体积压缩至 78M;
  • 敏感配置(如 MySQL 密码)从镜像中移除,通过 K8s Secret 挂载;
  • 镜像标签改为 v1.2.3-8f7d6a5(版本号 + Git Commit ID)。
(2)存储方案升级:从 hostPath 到 PVC

原架构用 -v /data/logs:/app/logs 挂载主机目录,节点故障后日志丢失,优化方案:

  1. 部署 NFS 分布式存储,提供共享存储能力;
  2. 创建 PersistentVolume(PV)和 PersistentVolumeClaim(PVC):
yaml 复制代码
# PV配置
apiVersion: v1
kind: PersistentVolume
metadata:
  name: order-logs-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  nfs:
    server: 192.168.1.100
    path: /nfs/order/logs

# PVC配置
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: order-service-logs-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
  1. 在 Deployment 中引用 PVC:
yaml 复制代码
volumeMounts:
- name: logs
  mountPath: /app/logs
volumes:
- name: logs
  persistentVolumeClaim:
    claimName: order-service-logs-pvc
(3)部署文件编写:Docker Compose 转 K8s 资源

原 Docker Compose 配置(订单服务):

yaml 复制代码
version: '3'
services:
  order-service:
    image: order-service:latest
    ports:
      - "8080:8080"
    volumes:
      - ./config:/app/config
      - /data/logs:/app/logs
    restart: always
    environment:
      - MYSQL_HOST=192.168.1.100
      - REDIS_HOST=192.168.1.101

重构为 K8s Deployment+Service+ConfigMap+Secret,完整配置如下:

yaml 复制代码
# 配置文件存储(ConfigMap)
apiVersion: v1
kind: ConfigMap
metadata:
  name: order-service-config
data:
  MYSQL_HOST: "mysql-service"  # 用Service名替代固定IP,实现服务发现
  REDIS_HOST: "redis-service"
  LOG_LEVEL: "info"
---
# 敏感信息存储(Secret)
apiVersion: v1
kind: Secret
metadata:
  name: order-service-secret
type: Opaque
data:
  MYSQL_PASSWORD: "cGFzc3dvcmQxMjM="  # base64加密(echo -n "password123" | base64)
---
# 部署控制器(Deployment)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
spec:
  replicas: 3  # 3副本确保高可用
  selector:
    matchLabels:
      app: order-service
  strategy:
    rollingUpdate:  # 滚动更新策略
      maxSurge: 1    # 最多可额外创建1个Pod
      maxUnavailable: 1  # 最多允许1个Pod不可用
  template:
    metadata:
      labels:
        app: order-service
    spec:
      imagePullSecrets:
        - name: harbor-secret
      containers:
      - name: order-service
        image: harbor.example.com/apps/order-service:v1.2.3-8f7d6a5
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: 500m
            memory: 512Mi
          limits:
            cpu: 1000m
            memory: 1Gi
        env:
        - name: MYSQL_HOST
          valueFrom:
            configMapKeyRef:
              name: order-service-config
              key: MYSQL_HOST
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: order-service-secret
              key: MYSQL_PASSWORD
        volumeMounts:
        - name: logs
          mountPath: /app/logs
        readinessProbe:  # 就绪探针,确保Pod就绪后才接收流量
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
      volumes:
      - name: logs
        persistentVolumeClaim:
          claimName: order-service-logs-pvc
---
# 服务访问入口(Service)
apiVersion: v1
kind: Service
metadata:
  name: order-service
spec:
  selector:
    app: order-service
  ports:
  - port: 8080
    targetPort: 8080
  type: ClusterIP
(4)滚动更新与回滚配置

生产环境部署新版本时,需避免服务中断,K8s 滚动更新机制可实现零停机部署:

  1. 触发更新(修改镜像版本):
bash 复制代码
kubectl set image deployment/order-service order-service=harbor.example.com/apps/order-service:v1.2.4-9a3b7c2
  1. 查看更新状态:
bash 复制代码
kubectl rollout status deployment/order-service
  1. 若新版本出现问题,快速回滚:
bash 复制代码
# 回滚到上一版本
kubectl rollout undo deployment/order-service

# 回滚到指定版本(先查看历史版本)
kubectl rollout history deployment/order-service
kubectl rollout undo deployment/order-service --to-revision=2

3.3 生产踩坑与解决方案(高频 5 例)

坑点 现象 原因 解决方案
1. 镜像拉取认证错误 kubectl describe pod 显示 Failed to pull image: unauthorized: authentication required imagePullSecrets 配置在 Deployment 的 spec 层级,而非 spec.template.spec 层级 确保 imagePullSecrets 配置在 Pod 模板中,且 Secret 名称与创建的一致
2. Pod 被 OOM Kill Pod 状态显示 OOMKilled,事件提示 MemoryLimitExceeded limits.memory 配置过小,requests 配置过低 1. 压测调整合理资源配置;2. 启用 VPA 自动调整: yaml<br>apiVersion: autoscaling.k8s.io/v1<br>kind: VerticalPodAutoscaler<br>metadata:<br> name: order-service-vpa<br>spec:<br> targetRef:<br> apiVersion: apps/v1<br> kind: Deployment<br> name: order-service<br> updatePolicy:<br> updateMode: Auto<br> resourcePolicy:<br> containerPolicies:<br> - containerName: '*'<br> minAllowed:<br> cpu: 500m<br> memory: 512Mi<br> maxAllowed:<br> cpu: 2000m<br> memory: 4Gi<br>
3. Ingress 路由 404 访问 order.example.com 提示 404,Pod 和 Service 状态正常 pathType 配置错误,或 rewrite-target 注解未正确设置 1. 明确 pathType: Prefix;2. 配置路径重写注解: ```yaml annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2 spec: rules: - host: order.example.com http: paths: - path: /api(/
4. 滚动更新服务不可用 更新过程中部分用户访问提示"连接超时" 未配置就绪探针,新 Pod 未完全启动就接收流量 添加就绪探针(Readiness Probe),确保 Pod 就绪后才加入负载均衡池
5. PVC 挂载失败 Pod 处于 Pending 状态,提示 PersistentVolumeClaim is not bound PV 与 PVC 的 accessModes 不匹配,或 NFS 未授权 K8s 节点访问 1. 确保 PV/PVC accessModes 一致;2. 配置 NFS 授权: /nfs/order/logs 192.168.1.0/24(rw,sync,no_root_squash)

总结

  1. 排版优化核心:通过分级标题、表格、代码块格式化、重点内容加粗,让文档结构更清晰,关键信息更易查找;
  2. 格式规范:统一代码块语法高亮、标准化配置示例格式,符合技术文档的阅读习惯;
  3. 信息整合:将分散的踩坑案例整理为表格,对比展示问题、原因和解决方案,提升实用性。
相关推荐
叱咤少帅(少帅)3 小时前
基于ELK 收集K8S的日志
elk·容器·kubernetes
我爱娃哈哈3 小时前
SpringBoot + Docker + Jenkins:一键构建、测试、部署流水线,DevOps 从入门到上手
spring boot·docker·jenkins
未既3 小时前
防火墙端口以及docker访问规则链配置允许特定ip访问
java·tcp/ip·docker
学Linux的语莫12 小时前
k8s常用命令
linux·容器·kubernetes
火山引擎开发者社区12 小时前
Seedance 2.0上线火山方舟体验中心,API即将开放
docker·vim·emacs
freephp12 小时前
睡前讲一段docker编译镜像的故事
docker
帷幄庸者16 小时前
跨网的Kubernetes集群:从零构建混合云架构
容器·架构·kubernetes
bepeater123416 小时前
使用Kubernetes部署Spring Boot项目
spring boot·容器·kubernetes
终生成长者18 小时前
Kubernetes常用操作与概念总结--从服务器导出mongo数据,并下载到本地
服务器·容器·kubernetes