云原生技术已经成为现代应用开发和部署的核心基础设施,今天我们来完整梳理从Docker镜像构建到CI/CD流水线再到自动化部署的全流程。这套技术栈能够显著提升开发效率,实现环境标准化,是每个后端开发和运维人员都需要掌握的核心技能。
1. 核心能力速览
| 能力项 | 说明 |
|---|---|
| 技术栈 | Docker + Kubernetes + CI/CD工具链 |
| 主要功能 | 镜像构建、持续集成、自动化部署 |
| 环境要求 | Linux/Windows/macOS,Docker环境 |
| 部署方式 | 本地部署、云平台集成 |
| 适合场景 | 微服务架构、多环境部署、团队协作开发 |
2. 适用场景与使用边界
这套技术组合特别适合以下场景:
- 微服务架构项目的标准化部署
- 需要多环境(开发、测试、生产)隔离的项目
- 团队协作开发,需要统一的构建和部署流程
- 追求快速迭代和自动化运维的互联网项目
不适用场景:
- 单体小项目,部署频率低的传统应用
- 对容器化技术栈不熟悉的团队
- 资源受限,无法承担容器编排系统开销的环境
3. 环境准备与前置条件
在开始之前,确保你的系统满足以下基本要求:
操作系统要求:
- Linux: Ubuntu 16.04+, CentOS 7+, 或其他主流发行版
- Windows: Windows 10 专业版/企业版/教育版(版本1903+)
- macOS: macOS 10.13+
软件依赖:
- Docker Engine 20.10+
- Docker Compose 1.29+(可选)
- Git 2.0+
- 至少4GB可用磁盘空间
网络要求:
- 稳定的互联网连接(用于下载镜像和依赖)
- 如果使用云服务,需要相应的云平台账号
4. Docker镜像构建实战
4.1 Dockerfile编写规范
一个标准的Dockerfile应该包含以下关键部分:
# 基础镜像选择 FROM openjdk:8-jre-slim # 维护者信息 LABEL maintainer="dev-team@company.com" # 设置工作目录 WORKDIR /app # 复制应用文件 COPY target/myapp.jar app.jar COPY config/application.properties config/ # 暴露端口 EXPOSE 8080 # 设置环境变量 ENV JAVA_OPTS="-Xmx512m -Xms256m" ENV PROFILE="prod" # 健康检查 HEALTHCHECK --interval=30s --timeout=3s \ CMD curl -f http://localhost:8080/health || exit 1 # 启动命令 ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar --spring.profiles.active=$PROFILE"]4.2 多阶段构建优化
对于需要编译的项目,推荐使用多阶段构建来减小镜像体积:
# 构建阶段 FROM maven:3.8.4-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 WORKDIR /app COPY --from=builder /build/target/app.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]4.3 镜像构建命令
# 基础构建 docker build -t myapp:1.0.0 . # 多标签构建 docker build -t myapp:1.0.0 -t myapp:latest . # 指定Dockerfile路径 docker build -f Dockerfile.prod -t myapp:prod . # 构建参数传递 docker build --build-arg VERSION=1.0.0 -t myapp:1.0.0 .5. 本地镜像测试验证
构建完成后,必须进行本地测试:
# 运行容器测试 docker run -d -p 8080:8080 --name myapp-test myapp:1.0.0 # 检查容器状态 docker ps docker logs myapp-test # 健康检查验证 curl http://localhost:8080/health # 停止测试容器 docker stop myapp-test docker rm myapp-test6. CI/CD流水线搭建
6.1 流水线设计原则
一个完整的CI/CD流水线应该包含以下阶段:
- 代码检出 → 2. 依赖安装 → 3. 单元测试 → 4. 构建镜像 → 5. 镜像推送 → 6. 部署测试 → 7. 人工审核 → 8. 生产部署
6.2 Jenkins流水线配置示例
pipeline { agent any environment { REGISTRY = "registry.example.com" IMAGE_NAME = "myapp" VERSION = "${env.BUILD_NAG}-${env.GIT_COMMIT}" } stages { stage('代码检出') { steps { git branch: 'main', url: 'https://github.com/company/myapp.git' } } stage('单元测试') { steps { sh 'mvn test' } post { always { junit 'target/surefire-reports/*.xml' } } } stage('构建镜像') { steps { script { docker.build("${IMAGE_NAME}:${VERSION}") } } } stage('推送镜像') { steps { script { docker.withRegistry("https://${REGISTRY}", 'registry-credentials') { docker.image("${IMAGE_NAME}:${VERSION}").push() } } } } stage('部署测试环境') { steps { sh """ kubectl set image deployment/myapp myapp=${REGISTRY}/${IMAGE_NAME}:${VERSION} -n test kubectl rollout status deployment/myapp -n test """ } } stage('人工审核') { steps { input message: '是否部署到生产环境?', ok: '确认部署' } } stage('生产部署') { steps { sh """ kubectl set image deployment/myapp myapp=${REGISTRY}/${IMAGE_NAME}:${VERSION} -n prod kubectl rollout status deployment/myapp -n prod """ } } } post { always { cleanWs() } success { slackSend channel: '#deployments', message: "部署成功: ${IMAGE_NAME}:${VERSION}" } failure { slackSend channel: '#deployments', message: "部署失败: ${IMAGE_NAME}:${VERSION}" } } }6.3 GitLab CI配置示例
image: docker:latest services: - docker:dind variables: DOCKER_HOST: tcp://docker:2375 DOCKER_DRIVER: overlay2 stages: - test - build - deploy before_script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY unit-test: stage: test script: - docker run --rm -v $(pwd):/app -w /app maven:3.8.4-openjdk-11 mvn test build-image: stage: build script: - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA . - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA deploy-to-test: stage: deploy script: - apk add --no-cache kubectl - kubectl config use-context test-cluster - kubectl set image deployment/myapp myapp=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA -n test - kubectl rollout status deployment/myapp -n test only: - main deploy-to-prod: stage: deploy script: - apk add --no-cache kubectl - kubectl config use-context prod-cluster - kubectl set image deployment/myapp myapp=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA -n prod - kubectl rollout status deployment/myapp -n prod when: manual only: - main7. Kubernetes部署配置
7.1 Deployment配置
apiVersion: apps/v1 kind: Deployment metadata: name: myapp namespace: prod labels: app: myapp spec: replicas: 3 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: myapp image: registry.example.com/myapp:1.0.0 ports: - containerPort: 8080 env: - name: SPRING_PROFILES_ACTIVE value: "prod" resources: requests: memory: "512Mi" cpu: "250m" limits: memory: "1Gi" cpu: "500m" livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 5 periodSeconds: 57.2 Service配置
apiVersion: v1 kind: Service metadata: name: myapp-service namespace: prod spec: selector: app: myapp ports: - port: 80 targetPort: 8080 type: ClusterIP7.3 Ingress配置
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myapp-ingress namespace: prod annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - host: myapp.example.com http: paths: - path: / pathType: Prefix backend: service: name: myapp-service port: number: 808. 自动化部署策略
8.1 蓝绿部署
apiVersion: v1 kind: Service metadata: name: myapp-service spec: selector: app: myapp version: v1.0.0 # 通过版本标签控制流量 ports: - port: 80 targetPort: 8080 --- apiVersion: apps/v1 kind: Deployment metadata: name: myapp-v2 spec: replicas: 3 selector: matchLabels: app: myapp version: v2.0.0 template: metadata: labels: app: myapp version: v2.0.0 spec: containers: - name: myapp image: registry.example.com/myapp:v2.0.08.2 金丝雀发布
# 先部署少量实例进行测试 kubectl scale deployment myapp-v2 --replicas=1 # 将部分流量导入新版本 kubectl patch service myapp-service -p '{ "spec": { "selector": { "app": "myapp", "version": "v2.0.0" } } }' # 监控新版本运行状况 kubectl get pods -l app=myapp,version=v2.0.0 kubectl logs -l app=myapp,version=v2.0.09. 监控与日志收集
9.1 应用监控配置
apiVersion: v1 kind: ConfigMap metadata: name: prometheus-config data: prometheus.yml: | global: scrape_interval: 15s scrape_configs: - job_name: 'myapp' static_configs: - targets: ['myapp-service:8080']9.2 日志收集配置
apiVersion: apps/v1 kind: DaemonSet metadata: name: fluentd spec: selector: matchLabels: name: fluentd template: metadata: labels: name: fluentd spec: containers: - name: fluentd image: fluent/fluentd-kubernetes-daemonset:v1.16-debian-elasticsearch8-1 env: - name: FLUENT_ELASTICSEARCH_HOST value: "elasticsearch-logging" - name: FLUENT_ELASTICSEARCH_PORT value: "9200"10. 常见问题与排查方法
10.1 Docker构建问题
问题1:构建上下文过大
# 解决方案:使用.dockerignore文件 echo "node_modules/" >> .dockerignore echo ".git/" >> .dockerignore echo "*.log" >> .dockerignore问题2:镜像层缓存失效
# 优化Dockerfile,将不经常变动的层放在前面 # 使用--cache-from参数利用缓存 docker build --cache-from=myapp:latest -t myapp:new .10.2 Kubernetes部署问题
问题1:镜像拉取失败
# 检查镜像仓库认证 kubectl create secret docker-registry regcred \ --docker-server=registry.example.com \ --docker-username=username \ --docker-password=password # 在Deployment中引用secret spec: template: spec: imagePullSecrets: - name: regcred问题2:资源不足
# 检查节点资源 kubectl describe nodes # 检查Pod资源请求和限制 kubectl describe pod myapp-pod # 调整资源配置 kubectl set resources deployment/myapp --limits=memory=1Gi,cpu=500m10.3 网络连接问题
问题1:服务无法访问
# 检查服务端点 kubectl get endpoints myapp-service # 检查网络策略 kubectl get networkpolicies # 测试服务连通性 kubectl run test --image=busybox --rm -it -- wget -O- myapp-service:8011. 最佳实践与优化建议
11.1 镜像优化
- 使用Alpine或Distroless基础镜像减小体积
- 多阶段构建分离构建环境和运行环境
- 合并RUN指令减少镜像层数
- 定期清理无用的镜像和容器
11.2 安全实践
- 使用非root用户运行容器
- 定期更新基础镜像安全补丁
- 扫描镜像中的安全漏洞
- 限制容器权限和资源访问
11.3 性能优化
- 合理设置资源请求和限制
- 使用就绪性和存活性探针
- 配置HPA自动扩缩容
- 优化应用启动时间
这套云原生技术栈虽然学习曲线较陡,但一旦掌握就能显著提升开发部署效率。建议从简单的单应用开始实践,逐步扩展到微服务架构,最终实现全自动化的CI/CD流水线。