知识模块
☕ Java 知识模块
十三、DevOps 与运维
Docker 与 CI/CD

Docker 与 CI/CD

Docker 容器化技术和 CI/CD 持续集成/持续部署是现代 DevOps 的核心实践。掌握 Docker 基础、Dockerfile 编写、CI/CD 流程设计,是 Java 开发者向 DevOps 工程师进阶的必备技能。

面试高频考点:Docker 核心概念、Dockerfile 最佳实践、CI/CD 流程设计、容器化部署方案


一、Docker 核心概念

1.1 什么是 Docker

Docker 是一个开源的容器化平台,它允许开发者将应用程序及其依赖打包到一个轻量级、可移植的容器中,从而实现"一次构建,到处运行"。

┌─────────────────────────────────────────────────────────────┐
│                    传统虚拟机架构                            │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────┐  ┌─────────┐  ┌─────────┐                     │
│  │  App A  │  │  App B  │  │  App C  │                     │
│  ├─────────┤  ├─────────┤  ├─────────┤                     │
│  │ Bin/Lib │  │ Bin/Lib │  │ Bin/Lib │                     │
│  ├─────────┤  ├─────────┤  ├─────────┤                     │
│  │Guest OS │  │Guest OS │  │Guest OS │  ← 每个虚拟机独立OS  │
│  └─────────┘  └─────────┘  └─────────┘                     │
│  ┌─────────────────────────────────────┐                   │
│  │            Hypervisor               │                   │
│  └─────────────────────────────────────┘                   │
│  ┌─────────────────────────────────────┐                   │
│  │            Host OS                  │                   │
│  └─────────────────────────────────────┘                   │
│  ┌─────────────────────────────────────┐                   │
│  │          Physical Server            │                   │
│  └─────────────────────────────────────┘                   │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                    Docker 容器架构                           │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────┐  ┌─────────┐  ┌─────────┐                     │
│  │  App A  │  │  App B  │  │  App C  │                     │
│  ├─────────┤  ├─────────┤  ├─────────┤                     │
│  │ Bin/Lib │  │ Bin/Lib │  │ Bin/Lib │  ← 共享主机内核      │
│  └─────────┘  └─────────┘  └─────────┘                     │
│  ┌─────────────────────────────────────┐                   │
│  │           Docker Engine             │                   │
│  └─────────────────────────────────────┘                   │
│  ┌─────────────────────────────────────┐                   │
│  │            Host OS                  │                   │
│  └─────────────────────────────────────┘                   │
│  ┌─────────────────────────────────────┐                   │
│  │          Physical Server            │                   │
│  └─────────────────────────────────────┘                   │
└─────────────────────────────────────────────────────────────┘

1.2 Docker vs 虚拟机

对比项Docker 容器虚拟机
启动速度秒级分钟级
资源占用MB 级GB 级
性能接近原生有损耗
隔离性进程级隔离完全隔离
操作系统共享主机内核独立操作系统
移植性极高较低

1.3 核心组件

┌────────────────────────────────────────────────────────────┐
│                    Docker 架构                              │
├────────────────────────────────────────────────────────────┤
│                                                            │
│    ┌─────────────┐         ┌─────────────────────────┐    │
│    │   Client    │ ──────► │       Docker Host       │    │
│    │  (docker)   │         │                         │    │
│    └─────────────┘         │  ┌───────┐ ┌─────────┐  │    │
│                            │  │daemon │ │ images  │  │    │
│                            │  └───┬───┘ └─────────┘  │    │
│                            │      │                   │    │
│                            │      ▼                   │    │
│                            │  ┌───────────────────┐  │    │
│                            │  │    containers    │  │    │
│                            │  └───────────────────┘  │    │
│                            └─────────────────────────┘    │
│                                       │                   │
│                                       ▼                   │
│                            ┌─────────────────────────┐    │
│                            │      Registry           │    │
│                            │  (Docker Hub/私有仓库)  │    │
│                            └─────────────────────────┘    │
│                                                            │
└────────────────────────────────────────────────────────────┘
组件说明
Docker Client命令行工具(docker CLI)或 API 客户端
Docker Daemon后台守护进程,负责构建、运行、分发容器
Docker Image只读模板,包含创建容器的指令
Docker Container镜像的运行实例,独立运行的进程
Docker Registry镜像仓库,如 Docker Hub、Harbor

二、Docker 基础命令

2.1 镜像管理

# 搜索镜像
docker search nginx
docker search openjdk:17
 
# 拉取镜像
docker pull nginx:latest
docker pull openjdk:17-jdk-slim
docker pull mysql:8.0
 
# 查看本地镜像
docker images
docker images | grep nginx
 
# 删除镜像
docker rmi nginx:latest
docker rmi -f $(docker images -q)  # 删除所有镜像
 
# 镜像标签
docker tag nginx:latest myregistry.com/nginx:v1.0
 
# 推送镜像
docker push myregistry.com/nginx:v1.0
 
# 导出/导入镜像
docker save -o nginx.tar nginx:latest
docker load -i nginx.tar
 
# 查看镜像详情
docker inspect nginx:latest
 
# 查看镜像历史
docker history nginx:latest

2.2 容器管理

# 创建并运行容器
docker run -d --name my-nginx -p 80:80 nginx:latest
docker run -d --name my-mysql \
  -e MYSQL_ROOT_PASSWORD=root \
  -e MYSQL_DATABASE=mydb \
  -p 3306:3306 \
  mysql:8.0
 
# 查看运行中的容器
docker ps
docker ps -a  # 查看所有容器
 
# 启动/停止/重启容器
docker start my-nginx
docker stop my-nginx
docker restart my-nginx
 
# 进入容器
docker exec -it my-nginx /bin/bash
docker exec -it my-nginx sh
 
# 查看容器日志
docker logs my-nginx
docker logs -f --tail 100 my-nginx  # 实时跟踪最新100行
 
# 查看容器详情
docker inspect my-nginx
 
# 查看容器资源使用
docker stats my-nginx
 
# 复制文件
docker cp app.jar my-nginx:/app/
docker cp my-nginx:/etc/nginx/nginx.conf ./
 
# 删除容器
docker rm my-nginx
docker rm -f $(docker ps -aq)  # 强制删除所有容器

2.3 常用参数说明

参数说明示例
-d后台运行docker run -d nginx
-p端口映射-p 8080:80
-P随机端口映射docker run -P nginx
-v挂载卷-v /host/path:/container/path
-e环境变量-e MYSQL_ROOT_PASSWORD=root
--name容器名称--name my-nginx
--network网络--network mynet
--restart重启策略--restart always
-m内存限制-m 512m
--cpusCPU 限制--cpus 1.5

2.4 容器生命周期

┌──────────┐     docker create     ┌──────────┐
│  Image   │ ────────────────────► │ Created  │
└──────────┘                       └────┬─────┘
                                        │ docker start

┌──────────┐     docker stop      ┌──────────┐
│  Stopped │ ◄────────────────────│ Running  │
└────┬─────┘                       └────┬─────┘
     │                                  │
     │ docker rm                        │ docker kill
     ▼                                  ▼
┌──────────┐                       ┌──────────┐
│  Deleted │                       │  Killed  │
└──────────┘                       └──────────┘

# docker run = docker create + docker start

三、Dockerfile 编写

3.1 Dockerfile 基本结构

# 基础镜像
FROM openjdk:17-jdk-slim
 
# 维护者信息
LABEL maintainer="dev@example.com"
 
# 设置工作目录
WORKDIR /app
 
# 复制文件
COPY target/app.jar /app/app.jar
 
# 设置环境变量
ENV JAVA_OPTS="-Xms256m -Xmx512m"
ENV SPRING_PROFILES_ACTIVE="prod"
 
# 暴露端口
EXPOSE 8080
 
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:8080/actuator/health || exit 1
 
# 启动命令
ENTRYPOINT ["java", "-jar", "/app/app.jar"]

3.2 常用指令详解

指令说明示例
FROM指定基础镜像FROM openjdk:17-jdk-slim
LABEL添加元数据标签LABEL version="1.0"
ENV设置环境变量ENV APP_ENV=prod
WORKDIR设置工作目录WORKDIR /app
COPY复制文件COPY app.jar /app/
ADD复制文件(支持URL和解压)ADD app.tar.gz /app/
RUN执行命令RUN apt-get update
CMD容器启动默认命令CMD ["java", "-jar", "app.jar"]
ENTRYPOINT容器启动入口点ENTRYPOINT ["java"]
EXPOSE声明端口EXPOSE 8080
VOLUME创建挂载点VOLUME /data
ARG构建参数ARG VERSION=1.0
HEALTHCHECK健康检查HEALTHCHECK CMD curl -f ...
USER指定用户USER appuser

3.3 CMD vs ENTRYPOINT

# CMD:可被 docker run 参数覆盖
FROM nginx
CMD ["nginx", "-g", "daemon off;"]
# docker run my-nginx nginx -g "daemon off;" → 覆盖 CMD
 
# ENTRYPOINT:docker run 参数追加
FROM nginx
ENTRYPOINT ["nginx", "-g"]
CMD ["daemon off;"]
# docker run my-nginx "daemon off;" → 追加到 ENTRYPOINT
 
# 组合使用(推荐)
FROM openjdk:17-jdk-slim
ENTRYPOINT ["java", "-jar"]
CMD ["app.jar"]
# docker run myapp → java -jar app.jar
# docker run myapp app-prod.jar → java -jar app-prod.jar

3.4 多阶段构建

# 阶段1:构建
FROM maven:3.8-openjdk-17 AS builder
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests
 
# 阶段2:运行
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY --from=builder /build/target/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

多阶段构建优势

  • 构建环境和运行环境分离
  • 最终镜像更小
  • 安全性更高(不包含构建工具)

3.5 Dockerfile 最佳实践

# ✅ 推荐做法
 
# 1. 使用特定版本标签
FROM openjdk:17-jdk-slim  # 而不是 openjdk:latest
 
# 2. 合并 RUN 命令减少层数
RUN apt-get update && apt-get install -y \
    curl \
    vim \
    && rm -rf /var/lib/apt/lists/*
 
# 3. 利用构建缓存,把不常变化的放前面
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY pom.xml ./
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package
 
# 4. 使用 .dockerignore 排除不需要的文件
# .dockerignore 文件内容:
# target/
# *.log
# .git
# .idea
 
# 5. 使用非 root 用户运行
RUN groupadd -r appuser && useradd -r -g appuser appuser
USER appuser
 
# 6. 优化镜像大小
FROM eclipse-temurin:17-jre-alpine  # 使用 Alpine 版本更小

四、Docker Compose

4.1 什么是 Docker Compose

Docker Compose 是用于定义和运行多容器应用的工具。通过 YAML 文件配置应用的服务、网络和卷。

4.2 docker-compose.yml 基本结构

version: '3.8'
 
services:
  # 应用服务
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: myapp
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - DB_HOST=db
    depends_on:
      - db
      - redis
    networks:
      - app-network
    restart: always
 
  # 数据库服务
  db:
    image: mysql:8.0
    container_name: mydb
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=mydb
    volumes:
      - db-data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "3306:3306"
    networks:
      - app-network
    restart: always
 
  # 缓存服务
  redis:
    image: redis:7-alpine
    container_name: myredis
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data
    networks:
      - app-network
    restart: always
 
# 网络定义
networks:
  app-network:
    driver: bridge
 
# 卷定义
volumes:
  db-data:
  redis-data:

4.3 Docker Compose 命令

# 启动所有服务
docker-compose up -d
 
# 查看服务状态
docker-compose ps
 
# 查看日志
docker-compose logs -f app
 
# 停止所有服务
docker-compose down
 
# 停止并删除卷
docker-compose down -v
 
# 重新构建服务
docker-compose build app
 
# 重启服务
docker-compose restart app
 
# 进入容器
docker-compose exec app /bin/bash
 
# 扩展服务
docker-compose up -d --scale app=3

4.4 Java 微服务编排示例

version: '3.8'
 
services:
  # 网关服务
  gateway:
    build: ./gateway
    ports:
      - "8080:8080"
    environment:
      - NACOS_SERVER_ADDR=nacos:8848
    depends_on:
      - nacos
    networks:
      - microservice-net
 
  # 用户服务
  user-service:
    build: ./user-service
    environment:
      - NACOS_SERVER_ADDR=nacos:8848
      - MYSQL_HOST=mysql
      - REDIS_HOST=redis
    depends_on:
      - nacos
      - mysql
      - redis
    networks:
      - microservice-net
    deploy:
      replicas: 2
 
  # 订单服务
  order-service:
    build: ./order-service
    environment:
      - NACOS_SERVER_ADDR=nacos:8848
      - MYSQL_HOST=mysql
      - REDIS_HOST=redis
    depends_on:
      - nacos
      - mysql
      - redis
    networks:
      - microservice-net
    deploy:
      replicas: 2
 
  # Nacos 注册中心
  nacos:
    image: nacos/nacos-server:v2.2.0
    environment:
      - MODE=standalone
    ports:
      - "8848:8848"
    networks:
      - microservice-net
 
  # MySQL 数据库
  mysql:
    image: mysql:8.0
    environment:
      - MYSQL_ROOT_PASSWORD=root
    volumes:
      - mysql-data:/var/lib/mysql
    ports:
      - "3306:3306"
    networks:
      - microservice-net
 
  # Redis 缓存
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data
    networks:
      - microservice-net
 
networks:
  microservice-net:
    driver: bridge
 
volumes:
  mysql-data:
  redis-data:

五、CI/CD 流程设计

5.1 CI/CD 概念

┌────────────────────────────────────────────────────────────────────┐
│                        CI/CD 流水线                                 │
├────────────────────────────────────────────────────────────────────┤
│                                                                    │
│  ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐       │
│  │  代码提交 │──►│  代码检查 │──►│  单元测试 │──►│  构建    │       │
│  └──────────┘   └──────────┘   └──────────┘   └──────────┘       │
│       │              │              │              │               │
│    Git Push     SonarQube      JUnit/Maven    Docker Build        │
│                                                                    │
│                           ▼                                        │
│                                                                    │
│  ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐       │
│  │  镜像推送 │──►│  部署测试 │──►│  集成测试 │──►│  部署生产 │       │
│  └──────────┘   └──────────┘   └──────────┘   └──────────┘       │
│       │              │              │              │               │
│   Push to        K8s Deploy      E2E Test      K8s Deploy         │
│   Registry       (Dev)                         (Prod)             │
│                                                                    │
└────────────────────────────────────────────────────────────────────┘

CI (Continuous Integration):持续集成
- 代码合并
- 自动构建
- 自动测试

CD (Continuous Delivery/Deployment):持续交付/部署
- 自动部署到测试环境
- 自动部署到生产环境

5.2 CI/CD 流程设计原则

原则说明
自动化所有步骤尽可能自动化
快速反馈问题尽早发现、尽早修复
可重复任何环境都能重复构建
版本控制所有配置文件纳入版本控制
安全合规代码扫描、安全检查

六、Jenkins CI/CD 配置

6.1 Jenkins Pipeline 语法

// Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any
    
    // 工具配置
    tools {
        maven 'Maven 3.8'
        jdk 'JDK 17'
    }
    
    // 环境变量
    environment {
        DOCKER_IMAGE = 'myregistry.com/myapp'
        DOCKER_TAG = "${BUILD_NUMBER}"
    }
    
    // 触发条件
    triggers {
        gitlab(triggerOnPush: true, triggerOnMergeRequest: true)
    }
    
    stages {
        // 阶段1:代码检出
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        
        // 阶段2:代码检查
        stage('Code Analysis') {
            steps {
                withSonarQubeEnv('SonarQube') {
                    sh 'mvn sonar:sonar'
                }
            }
        }
        
        // 阶段3:单元测试
        stage('Unit Test') {
            steps {
                sh 'mvn test'
            }
            post {
                always {
                    junit '**/target/surefire-reports/*.xml'
                }
            }
        }
        
        // 阶段4:构建
        stage('Build') {
            steps {
                sh 'mvn package -DskipTests'
            }
        }
        
        // 阶段5:构建镜像
        stage('Build Image') {
            steps {
                script {
                    docker.withRegistry('https://myregistry.com', 'docker-credentials') {
                        def app = docker.build("${DOCKER_IMAGE}:${DOCKER_TAG}")
                        app.push()
                        app.push('latest')
                    }
                }
            }
        }
        
        // 阶段6:部署到开发环境
        stage('Deploy Dev') {
            steps {
                sh """
                    kubectl set image deployment/myapp \
                        myapp=${DOCKER_IMAGE}:${DOCKER_TAG} \
                        -n dev
                """
            }
        }
        
        // 阶段7:部署到生产环境(需手动确认)
        stage('Deploy Prod') {
            when {
                branch 'main'
            }
            input {
                message "Deploy to Production?"
                ok "Deploy"
            }
            steps {
                sh """
                    kubectl set image deployment/myapp \
                        myapp=${DOCKER_IMAGE}:${DOCKER_TAG} \
                        -n prod
                """
            }
        }
    }
    
    // 构建后操作
    post {
        success {
            echo 'Build succeeded!'
            slackSend(color: 'good', message: "Build ${BUILD_NUMBER} succeeded")
        }
        failure {
            echo 'Build failed!'
            slackSend(color: 'danger', message: "Build ${BUILD_NUMBER} failed")
        }
        always {
            cleanWs()
        }
    }
}

6.2 Jenkins 常用配置

// 并行执行
stage('Parallel Tests') {
    parallel {
        stage('Unit Tests') {
            steps {
                sh 'mvn test'
            }
        }
        stage('Integration Tests') {
            steps {
                sh 'mvn verify -P integration-test'
            }
        }
    }
}
 
// 条件执行
stage('Deploy') {
    when {
        anyOf {
            branch 'main'
            branch 'release/*'
        }
    }
    steps {
        // 部署逻辑
    }
}
 
// 参数化构建
parameters {
    choice(name: 'ENV', choices: ['dev', 'test', 'prod'], description: 'Environment')
    booleanParam(name: 'SKIP_TESTS', defaultValue: false, description: 'Skip tests')
}
 
// 使用参数
stage('Test') {
    when {
        expression { !params.SKIP_TESTS }
    }
    steps {
        sh 'mvn test'
    }
}

七、GitLab CI 配置

7.1 GitLab CI 基本结构

# .gitlab-ci.yml
 
# 定义阶段
stages:
  - build
  - test
  - package
  - deploy
 
# 定义变量
variables:
  MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
  DOCKER_IMAGE: "myregistry.com/myapp"
 
# 缓存配置
cache:
  paths:
    - .m2/repository/
 
# 构建阶段
build:
  stage: build
  image: maven:3.8-openjdk-17
  script:
    - mvn compile
  artifacts:
    paths:
      - target/
    expire_in: 1 hour
 
# 测试阶段
test:
  stage: test
  image: maven:3.8-openjdk-17
  script:
    - mvn test
  coverage: '/Total.*?([0-9]{1,3})%/'
  artifacts:
    reports:
      junit: target/surefire-reports/*.xml
 
# 打包阶段
package:
  stage: package
  image: maven:3.8-openjdk-17
  script:
    - mvn package -DskipTests
  artifacts:
    paths:
      - target/*.jar
  only:
    - main
    - develop
 
# 构建 Docker 镜像
docker-build:
  stage: package
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $DOCKER_IMAGE:$CI_COMMIT_SHA .
    - docker push $DOCKER_IMAGE:$CI_COMMIT_SHA
    - docker push $DOCKER_IMAGE:latest
  only:
    - main
 
# 部署到开发环境
deploy-dev:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/myapp myapp=$DOCKER_IMAGE:$CI_COMMIT_SHA -n dev
  environment:
    name: development
    url: https://dev.example.com
  only:
    - develop
 
# 部署到生产环境
deploy-prod:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/myapp myapp=$DOCKER_IMAGE:$CI_COMMIT_SHA -n prod
  environment:
    name: production
    url: https://www.example.com
  when: manual
  only:
    - main

7.2 GitLab CI 高级特性

# 环境变量和密钥管理
deploy:
  stage: deploy
  script:
    - kubectl apply -f k8s/
  variables:
    KUBECONFIG: $KUBE_CONFIG
  only:
    - main
 
# 手动部署和审批
deploy-prod:
  stage: deploy
  script:
    - ./deploy.sh prod
  when: manual
  allow_failure: false
 
# 多环境部署
.deploy_template: &deploy_template
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/myapp myapp=$DOCKER_IMAGE:$CI_COMMIT_SHA -n $ENV
 
deploy-dev:
  <<: *deploy_template
  stage: deploy
  variables:
    ENV: dev
  only:
    - develop
 
deploy-prod:
  <<: *deploy_template
  stage: deploy
  variables:
    ENV: prod
  when: manual
  only:
    - main
 
# 触发下游项目
trigger-downstream:
  stage: deploy
  trigger:
    project: group/downstream-project
    branch: main

八、容器化部署实践

8.1 Kubernetes 部署配置

# k8s-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: prod
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myregistry.com/myapp:latest
        ports:
        - containerPort: 8080
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: "prod"
        - name: DB_HOST
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: db-host
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: app-secret
              key: db-password
        livenessProbe:
          httpGet:
            path: /actuator/health/liveness
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
      imagePullSecrets:
      - name: registry-secret
 
---
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  namespace: prod
spec:
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 8080
  type: ClusterIP
 
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ingress
  namespace: prod
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp-service
            port:
              number: 80

8.2 部署策略

┌─────────────────────────────────────────────────────────────┐
│                     部署策略对比                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 滚动更新 (Rolling Update)                               │
│     ┌─────────┐                                             │
│     │ v1 v1 v1│ → ┌─────────┐ → ┌─────────┐                │
│     └─────────┘   │ v2 v1 v1│   │ v2 v2 v1│                │
│                   └─────────┘   └─────────┘                │
│                   → ┌─────────┐                             │
│                     │ v2 v2 v2│                             │
│                     └─────────┘                             │
│     优点:零停机、渐进式                                     │
│     缺点:版本混合运行期间可能出现兼容性问题                  │
│                                                             │
│  2. 蓝绿部署 (Blue-Green)                                   │
│     ┌─────────────┐     ┌─────────────┐                    │
│     │ Blue (v1)   │     │ Green (v2)  │                    │
│     │ v1 v1 v1    │     │ v2 v2 v2    │                    │
│     └──────┬──────┘     └──────┬──────┘                    │
│            │                   │                            │
│            ▼                   │                            │
│     ┌─────────────┐           │                            │
│     │   Traffic   │───────────┘                            │
│     └─────────────┘   切换流量                              │
│     优点:快速回滚、完整测试                                 │
│     缺点:需要双倍资源                                       │
│                                                             │
│  3. 金丝雀发布 (Canary)                                     │
│     ┌─────────────────────────────────┐                    │
│     │ v1 v1 v1 v1 v2                  │                    │
│     └─────────────────────────────────┘                    │
│              ↓ 监控 ↓                                      │
│     ┌─────────────────────────────────┐                    │
│     │ v1 v1 v2 v2 v2                  │                    │
│     └─────────────────────────────────┘                    │
│     优点:风险可控、逐步验证                                 │
│     缺点:需要完善的监控                                     │
│                                                             │
└─────────────────────────────────────────────────────────────┘

8.3 配置管理

# ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  application.yml: |
    server:
      port: 8080
    spring:
      datasource:
        url: jdbc:mysql://mysql:3306/mydb
        username: root
    logging:
      level:
        root: INFO
        com.example: DEBUG
 
---
# Secret
apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: Opaque
stringData:
  db-password: mysecretpassword
  api-key: xxxxxx

九、常见面试题

Q1: Docker 镜像和容器的关系是什么?

A: 镜像是只读模板,容器是镜像的运行实例。类比:

  • 镜像 = 类(Class)
  • 容器 = 对象(Instance)

一个镜像可以创建多个容器,容器之间相互隔离。

Q2: Dockerfile 中 CMD 和 ENTRYPOINT 有什么区别?

A:

对比项CMDENTRYPOINT
作用默认启动命令固定入口点
覆盖可被 docker run 参数覆盖不可覆盖,只能追加
场景提供默认值定义固定命令
# CMD 示例
CMD ["nginx", "-g", "daemon off;"]
# docker run my-image nginx -h  # 覆盖整个 CMD
 
# ENTRYPOINT 示例
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]
# docker run my-image -h  # 等同于 nginx -h

Q3: 如何优化 Docker 镜像大小?

A:

  1. 使用精简基础镜像(如 alpine
  2. 多阶段构建,分离构建和运行环境
  3. 合并 RUN 命令减少层数
  4. 清理缓存和临时文件
  5. 使用 .dockerignore 排除不需要的文件
# 优化前:可能 500MB+
FROM openjdk:17-jdk
COPY target/app.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
 
# 优化后:可能 200MB
FROM eclipse-temurin:17-jre-alpine
COPY target/app.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]

Q4: 什么是 CI/CD?有什么好处?

A:

  • CI(持续集成):代码提交后自动构建、测试
  • CD(持续交付/部署):自动部署到各种环境

好处:

  • 尽早发现和修复问题
  • 减少手动操作错误
  • 加快交付速度
  • 提高代码质量

Q5: 如何实现零停机部署?

A:

  1. 滚动更新:逐步替换旧版本
  2. 蓝绿部署:先部署新版本,再切换流量
  3. 使用健康检查:确保新实例就绪后再接收流量
# Kubernetes 滚动更新配置
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1        # 最多可以多创建1个Pod
      maxUnavailable: 0  # 最少保证0个不可用

Q6: Docker Compose 和 Kubernetes 有什么区别?

A:

对比项Docker ComposeKubernetes
定位单机容器编排分布式容器编排
规模小型应用大规模集群
功能基本编排自动伸缩、滚动更新、自愈
适用场景开发、测试生产环境

Q7: 解释 Docker 的存储驱动和容器存储?

A:

  • 存储驱动:管理镜像层和容器层(如 overlay2)
  • Volume:持久化存储,独立于容器生命周期
  • Bind Mount:挂载主机目录
  • tmpfs:临时存储在内存中
# Volume 使用
docker volume create mydata
docker run -v mydata:/app/data myapp
 
# Bind Mount 使用
docker run -v /host/path:/container/path myapp

Q8: 如何保证容器中 Java 应用的时间正确?

A:

  1. 设置时区环境变量
  2. 挂载主机时区文件
# 方式1:环境变量
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
 
# 方式2:JVM 参数
ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai"

十、总结

知识点核心内容面试关键词
Docker 基础镜像、容器、仓库与虚拟机区别、核心组件
Dockerfile指令、最佳实践CMD vs ENTRYPOINT、多阶段构建
Docker Compose多容器编排YAML 配置、服务依赖
CI/CD持续集成/部署Jenkins Pipeline、GitLab CI
容器部署K8s 部署、策略滚动更新、蓝绿部署

最佳实践清单

  • 使用特定版本的基础镜像
  • 多阶段构建减小镜像大小
  • 使用非 root 用户运行容器
  • 配置健康检查
  • 合理设置资源限制
  • 使用 Volume 持久化数据
  • 自动化测试集成到 CI 流程
  • 生产环境使用 Kubernetes

最后更新:2026年3月16日