Kotlin: Kotlin项目部署详解

最后更新:2026-08-26

代码写完了,最后一英里——Charlie 将 OrderProcessor 容器化、编排 CI/CD 流水线、配置监控告警,从 到生产上线全自动化。

1. 你将学到


2. 一个架构师的真实故事

(1) 痛点:手动部署的人肉流水线

Charlie 的团队手动部署:SSH 到服务器 → → → → 。一次部署 30 分钟,每月 2-3 次人为失误。

(2) CI/CD 全自动化的解法

TEXT 📖 仅展示
Before: git push → SSH → build → deploy (30 min, error-prone)
After:  git push → GitHub Actions → Docker build → deploy (5 min, zero-touch)

容器化 + CI/CD = 部署从 30 分钟人肉操作变为 5 分钟全自动流水线。


3. Docker 多阶段构建

(1) Dockerfile

DOCKERFILE
# Stage 1: Build
FROM gradle:8.5-jdk17 AS builder
WORKDIR /app
COPY build.gradle.kts settings.gradle.kts ./
COPY gradle ./gradle
COPY src ./src
RUN gradle bootJar --no-daemon -x test

# Stage 2: Runtime (lightweight JRE)
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY --from=builder /app/build/libs/*.jar app.jar

# Non-root user for security
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s \
  CMD wget -qO- http://localhost:8080/actuator/health || exit 1

ENTRYPOINT ["java", "-jar", "app.jar"]

(2) 多阶段构建对比

维度 单阶段 多阶段
镜像大小 ~800MB (JDK + source) ~150MB (JRE only)
安全性 源码在镜像中 源码不进入运行镜像
构建缓存 无分层 每层独立缓存
构建时间 每次全量 依赖层缓存复用

4. Docker Compose 编排

(1) docker-compose.yml

YAML
version: '3.8'

services:
  order-processor:
    build: .
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - SPRING_DATASOURCE_URL=r2dbc:postgresql://postgres:5432/orderdb
      - SPRING_DATASOURCE_USERNAME=order_user
      - SPRING_DATASOURCE_PASSWORD=order_pass
      - SPRING_REDIS_HOST=redis
      - MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE=health,info,prometheus
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - order-net

  postgres:
    image: postgres:16-alpine
    environment:
      - POSTGRES_DB=orderdb
      - POSTGRES_USER=order_user
      - POSTGRES_PASSWORD=order_pass
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U order_user -d orderdb"]
      interval: 5s
      timeout: 5s
      retries: 5
    networks:
      - order-net

  redis:
    image: redis:7-alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
    networks:
      - order-net

  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"
    networks:
      - order-net

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    depends_on:
      - prometheus
    networks:
      - order-net

volumes:
  pgdata:

networks:
  order-net:
    driver: bridge

(2) 一键部署

BASH
# Start all services
docker-compose up -d

# Check status
docker-compose ps

# View logs
docker-compose logs -f order-processor

# Stop all
docker-compose down

5. CI/CD 流水线

(1) GitHub Actions

YAML
# .github/workflows/deploy.yml
name: Build and Deploy

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Cache Gradle
        uses: actions/cache@v3
        with:
          path: ~/.gradle/caches
          key: gradle-${{ hashFiles('**/*.gradle.kts') }}

      - name: Run tests
        run: ./gradlew test

      - name: Build JAR
        run: ./gradlew bootJar

      - name: Build Docker image
        run: docker build -t order-processor:${{ github.sha }} .

      - name: Push to registry
        if: github.ref == 'refs/heads/main'
        run: |
          docker tag order-processor:${{ github.sha }} registry.example.com/order-processor:latest
          docker push registry.example.com/order-processor:latest

      - name: Deploy
        if: github.ref == 'refs/heads/main'
        run: |
          ssh deploy@prod-server "docker pull registry.example.com/order-processor:latest && docker-compose up -d"

(2) CI/CD 流水线图

100%
flowchart TD
    A[git push] --> B[GitHub Actions]
    B --> C[Checkout Code]
    C --> D[Setup JDK 17]
    D --> E[Cache Gradle]
    E --> F[Run Tests]
    F --> G{Tests Pass?}
    G -->|Yes| H[Build JAR]
    G -->|No| I[Notify Team]
    H --> J[Build Docker Image]
    J --> K{Main Branch?}
    K -->|Yes| L[Push to Registry]
    K -->|No| M[Stop]
    L --> N[Deploy to Production]
    N --> O[Health Check]
    O --> P{Healthy?}
    P -->|Yes| Q[Live]
    P -->|No| R[Rollback]

6. 监控

(1) Spring Boot Actuator 配置

KOTLIN
// application.yml
// management:
//   endpoints:
//     web:
//       exposure:
//         include: health,info,prometheus,metrics
//   metrics:
//     export:
//       prometheus:
//         enabled: true
//   endpoint:
//     health:
//       show-details: always

(2) Micrometer 自定义指标

KOTLIN
import io.micrometer.core.instrument.Counter
import io.micrometer.core.instrument.MeterRegistry
import io.micrometer.core.instrument.Timer

class OrderMetrics(registry: MeterRegistry) {
    private val ordersCreated = Counter.builder("orders.created.total")
        .description("Total orders created")
        .register(registry)

    private val orderProcessingTime = Timer.builder("orders.processing.time")
        .description("Order processing time")
        .register(registry)

    fun recordOrderCreated() { ordersCreated.increment() }

    fun `<T>` recordProcessingTime(block: () -> T): T {
        return orderProcessingTime.recordCallable { block() } ?: block()
    }
}

(3) 监控指标

指标 类型 告警阈值
Counter -
Timer P99 > 2s
Gauge > 80%
Gauge > 90%
Timer P99 > 5s
/ Gauge Free < 10%

7. 健康检查与生产就绪

(1) 健康检查端点

KOTLIN
// Spring Boot Actuator health endpoint
// GET /actuator/health
// {
//   "status": "UP",
//   "components": {
//     "db": { "status": "UP" },
//     "redis": { "status": "UP" },
//     "diskSpace": { "status": "UP" }
//   }
// }

(2) 生产就绪清单

类别 检查项 状态
安全 非 root 用户运行
安全 无硬编码密钥
安全 HTTPS 配置
可靠性 健康检查端点
可靠性 优雅关闭(SIGTERM)
可靠性 数据库连接池配置
可观测 日志结构化输出
可观测 Prometheus 指标暴露
可观测 告警规则配置
性能 JVM 堆大小配置
性能 GC 策略选择
部署 Docker 镜像 < 200MB
部署 CI/CD 流水线
部署 回滚策略

8. 完整示例:一键部署演示

KOTLIN
// ============================================
// OrderProcessor - Deployment Simulation
// Feature: Docker + CI/CD + Health check demo
// ============================================

import kotlin.system.measureTimeMillis

data class DeployResult(val service: String, val status: String, val time: Long)

class DeploySimulator {
    private val services = mutableListOf`<DeployResult>`()
    private var deployed = false

    fun build(): DeploySimulator {
        print("  Building Docker image...")
        val time = measureTimeMillis { Thread.sleep(800) }
        println(" Done (${time}ms)")
        return this
    }

    fun test(): DeploySimulator {
        print("  Running tests...")
        val time = measureTimeMillis { Thread.sleep(300) }
        println(" Passed (${time}ms)")
        return this
    }

    fun push(): DeploySimulator {
        print("  Pushing to registry...")
        val time = measureTimeMillis { Thread.sleep(500) }
        println(" Done (${time}ms)")
        return this
    }

    fun deploy(service: String, port: Int): DeploySimulator {
        print("  Deploying $service on port $port...")
        val time = measureTimeMillis { Thread.sleep(400) }
        services.add(DeployResult(service, "RUNNING", time))
        println(" Running (${time}ms)")
        return this
    }

    fun healthCheck(): DeploySimulator {
        print("  Health check...")
        val time = measureTimeMillis { Thread.sleep(200) }
        val allHealthy = services.all { it.status == "RUNNING" }
        println(if (allHealthy) " ALL HEALTHY" else " UNHEALTHY DETECTED")
        return this
    }

    fun summary() {
        println("\n=== Deployment Summary ===")
        services.forEach { s ->
            println("  ${s.service}: ${s.status} (${s.time}ms)")
        }
        println("\n  Total services: ${services.size}")
        println("  Health: ${if (services.all { it.status == "RUNNING" }) "ALL GREEN" else "ISSUES DETECTED"}")
        deployed = true
    }

    fun isDeployed() = deployed
}

fun main() {
    println("=== OrderProcessor CI/CD Pipeline ===\n")

    println("[1/6] Build Stage:")
    DeploySimulator()
        .build()
        .test()

    println("\n[2/6] Push Stage:")
    DeploySimulator().push()

    println("\n[3/6] Deploy Stage:")
    val deployer = DeploySimulator()
        .deploy("postgres", 5432)
        .deploy("redis", 6379)
        .deploy("order-processor", 8080)
        .deploy("prometheus", 9090)
        .deploy("grafana", 3000)

    println("\n[4/6] Health Check:")
    deployer.healthCheck()

    println("\n[5/6] Smoke Test:")
    println("  GET /actuator/health -> 200 OK")
    println("  GET /api/v1/orders -> 200 OK")

    println("\n[6/6] Production Ready Checklist:")
    val checks = listOf(
        "Non-root user" to true,
        "No hardcoded secrets" to true,
        "Health endpoint exposed" to true,
        "Prometheus metrics enabled" to true,
        "Graceful shutdown configured" to true,
        "Docker image < 200MB" to true,
        "CI/CD pipeline active" to true,
        "Rollback strategy defined" to true
    )
    checks.forEach { (item, passed) ->
        println("  ${if (passed) "✅" else "❌"} $item")
    }

    val passCount = checks.count { it.second }
    println("\n  Result: $passCount/${checks.size} checks passed")

    if (passCount == checks.size) {
        println("\n  🚀 OrderProcessor is LIVE!")
    }
}

输出:

TEXT 📖 仅展示
=== OrderProcessor CI/CD Pipeline ===

[1/6] Build Stage:
  Building Docker image... Done (804ms)
  Running tests... Passed (301ms)

[2/6] Push Stage:
  Pushing to registry... Done (502ms)

[3/6] Deploy Stage:
  Deploying postgres on port 5432... Running (401ms)
  Deploying redis on port 6379... Running (401ms)
  Deploying order-processor on port 8080... Running (401ms)
  Deploying prometheus on port 9090... Running (401ms)
  Deploying grafana on port 3000... Running (401ms)

[4/6] Health Check:
  Health check... ALL HEALTHY

[5/6] Smoke Test:
  GET /actuator/health -> 200 OK
  GET /api/v1/orders -> 200 OK

[6/6] Production Ready Checklist:
  ✅ Non-root user
  ✅ No hardcoded secrets
  ✅ Health endpoint exposed
  ✅ Prometheus metrics enabled
  ✅ Graceful shutdown configured
  ✅ Docker image < 200MB
  ✅ CI/CD pipeline active
  ✅ Rollback strategy defined

  Result: 8/8 checks passed

  🚀 OrderProcessor is LIVE!

❓ 常见问题

Q Docker 多阶段构建的好处是什么?
A 最终镜像只包含运行时依赖(JRE),不含源码和构建工具,镜像从 800MB 降到 150MB,攻击面更小,启动更快。
Q 如何实现零停机部署?
A 蓝绿部署或滚动更新。蓝绿部署维护两个环境交替切换;滚动更新逐个替换实例。Kubernetes 原生支持滚动更新。
Q 如何回滚失败的部署?
A Docker 镜像每次构建打 Git SHA 标签,回滚只需 。CI/CD 自动回滚更理想。
Q 密钥怎么管理?
A 不用环境变量或配置文件存密钥。使用 Vault、AWS Secrets Manager 或 Kubernetes Secrets。CI/CD 从密钥管理器注入。
Q 如何监控 JVM 应用?
A Spring Boot Actuator + Micrometer + Prometheus + Grafana 是标准组合。JVM 特有指标:堆内存、GC 次数/时间、线程数。
Q 生产环境的 JVM 参数怎么设?
A 和 设相同值(避免堆扩容开销),用 G1GC(),容器环境加 。

📖 小节


📝 作业

  1. 基础题(难度⭐):为 OrderProcessor 编写 Dockerfile(单阶段即可),基于 。提示:
  2. 进阶题(难度⭐⭐):编写 docker-compose.yml,包含 OrderProcessor + PostgreSQL,配置健康检查。提示:
  3. 挑战题(难度⭐⭐⭐):编写完整的 GitHub Actions CI/CD 流水线,包含构建、测试、Docker 推送和部署步骤。提示:

← 上一课 | 下一课 →

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏