Docker 与 Kubernetes 部署 Java 应用容器化最佳实践别叫我大神叫我 Alex 就好。今天我们来聊聊 Docker 与 Kubernetes 部署 Java 应用的最佳实践这是现代应用部署的重要技术。一、容器化概述容器化是将应用程序及其依赖打包为容器的过程它提供了环境一致性、快速部署和资源隔离等优势。Java 应用通过容器化可以更高效地部署和管理。核心优势环境一致性容器在任何环境中都能以相同的方式运行快速部署容器启动速度快部署时间短资源隔离容器之间相互隔离避免资源冲突可扩展性易于水平扩展和管理版本控制容器镜像可以版本化管理二、Docker 容器化最佳实践1. Dockerfile 优化# 使用官方基础镜像 FROM eclipse-temurin:25-jre-alpine # 设置工作目录 WORKDIR /app # 复制应用 COPY target/my-application.jar app.jar # 非 root 用户运行 RUN addgroup -S appgroup adduser -S appuser -G appgroup USER appuser # 环境变量 ENV JAVA_OPTS-XX:UseG1GC -XX:MaxGCPauseMillis200 -XX:UseStringDeduplication # 暴露端口 EXPOSE 8080 # 启动命令 ENTRYPOINT [java, $JAVA_OPTS, -jar, app.jar]2. 多阶段构建# 构建阶段 FROM eclipse-temurin:25-jdk-alpine as builder WORKDIR /app COPY pom.xml . COPY src src # 构建应用 RUN mvn package -DskipTests # 运行阶段 FROM eclipse-temurin:25-jre-alpine WORKDIR /app # 从构建阶段复制 jar 文件 COPY --frombuilder /app/target/my-application.jar app.jar # 非 root 用户运行 RUN addgroup -S appgroup adduser -S appuser -G appgroup USER appuser EXPOSE 8080 ENTRYPOINT [java, -jar, app.jar]3. 容器安全# 使用最小基础镜像 FROM eclipse-temurin:25-jre-alpine # 设置工作目录 WORKDIR /app # 复制应用 COPY target/my-application.jar app.jar # 创建非 root 用户 RUN addgroup -S appgroup adduser -S appuser -G appgroup USER appuser # 限制容器能力 RUN apk --no-cache add tini # 暴露端口 EXPOSE 8080 # 使用 tini 作为 init 进程 ENTRYPOINT [/sbin/tini, --, java, -jar, app.jar]4. 构建优化# 构建镜像 docker build -t my-application:latest . # 构建时使用缓存 docker build --build-arg MAVEN_OPTS-Dmaven.repo.local/mvnrepo -t my-application:latest . # 推送到镜像仓库 docker tag my-application:latest registry.example.com/my-application:latest docker push registry.example.com/my-application:latest三、Kubernetes 部署最佳实践1. 部署配置apiVersion: apps/v1 kind: Deployment metadata: name: my-application labels: app: my-application spec: replicas: 3 selector: matchLabels: app: my-application template: metadata: labels: app: my-application spec: containers: - name: my-application image: my-application:latest ports: - containerPort: 8080 resources: limits: cpu: 1 memory: 1Gi requests: cpu: 500m memory: 512Mi readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 30 periodSeconds: 10 livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 60 periodSeconds: 302. 服务配置apiVersion: v1 kind: Service metadata: name: my-application spec: selector: app: my-application ports: - port: 80 targetPort: 8080 type: ClusterIP3. 水平扩展apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: my-application-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: my-application minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 804. 配置管理apiVersion: v1 kind: ConfigMap metadata: name: my-application-config data: application.properties: | spring.profiles.activeprod spring.datasource.url${DATABASE_URL} spring.datasource.username${DATABASE_USER} spring.datasource.password${DATABASE_PASSWORD} --- apiVersion: v1 kind: Secret metadata: name: my-application-secret type: Opaque data: database-password: cGFzc3dvcmQ --- apiVersion: apps/v1 kind: Deployment metadata: name: my-application spec: template: spec: containers: - name: my-application env: - name: DATABASE_URL value: jdbc:mysql://mysql:3306/mydb - name: DATABASE_USER value: root - name: DATABASE_PASSWORD valueFrom: secretKeyRef: name: my-application-secret key: database-password volumeMounts: - name: config-volume mountPath: /app/config volumes: - name: config-volume configMap: name: my-application-config四、Helm 部署1. Helm Chart 结构my-application/ ├── Chart.yaml ├── values.yaml ├── charts/ └── templates/ ├── deployment.yaml ├── service.yaml ├── hpa.yaml ├── configmap.yaml └── secret.yaml2. Chart.yamlapiVersion: v2 name: my-application version: 1.0.0 description: A Helm chart for my Java application3. values.yamlreplicaCount: 3 image: repository: my-application tag: latest pullPolicy: IfNotPresent resources: limits: cpu: 1 memory: 1Gi requests: cpu: 500m memory: 512Mi probes: readiness: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 30 periodSeconds: 10 liveness: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 60 periodSeconds: 30 env: spring: profiles: active: prod database: url: jdbc:mysql://mysql:3306/mydb user: root4. 部署命令# 安装 Helm chart helm install my-application ./my-application # 升级 Helm chart helm upgrade my-application ./my-application # 卸载 Helm chart helm uninstall my-application # 查看 Helm releases helm list五、CI/CD 集成1. GitHub Actions 配置name: CI/CD Pipeline on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 - name: Set up JDK 25 uses: actions/setup-javav3 with: java-version: 25 distribution: temurin cache: maven - name: Build with Maven run: mvn clean package -DskipTests - name: Run tests run: mvn test - name: Build Docker image run: docker build -t my-application:${{ github.sha }} . - name: Login to Docker Hub uses: docker/login-actionv2 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_TOKEN }} - name: Push Docker image run: docker push my-application:${{ github.sha }} deploy: needs: build runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkoutv3 - name: Set up kubectl uses: azure/setup-kubectlv3 with: version: v1.26.0 - name: Configure Kubernetes context run: | echo ${{ secrets.KUBE_CONFIG }} | base64 -d ~/.kube/config - name: Deploy to Kubernetes run: | sed -i s|my-application:latest|my-application:${{ github.sha }}|g kubernetes/deployment.yaml kubectl apply -f kubernetes/2. GitLab CI 配置stages: - build - test - deploy build: stage: build script: - mvn clean package -DskipTests - docker build -t my-application:$CI_COMMIT_SHA . - docker push my-application:$CI_COMMIT_SHA test: stage: test script: - mvn test deploy: stage: deploy script: - kubectl set image deployment/my-application my-applicationmy-application:$CI_COMMIT_SHA - kubectl rollout status deployment/my-application六、监控与日志1. 应用监控apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: my-application labels: release: prometheus spec: selector: matchLabels: app: my-application endpoints: - port: http path: /actuator/prometheus interval: 15s2. 日志管理apiVersion: apps/v1 kind: DaemonSet metadata: name: fluentd namespace: kube-system spec: selector: matchLabels: name: fluentd template: metadata: labels: name: fluentd spec: containers: - name: fluentd image: fluent/fluentd-kubernetes-daemonset:v1.14-debian-elasticsearch7 env: - name: FLUENT_ELASTICSEARCH_HOST value: elasticsearch.default.svc.cluster.local - name: FLUENT_ELASTICSEARCH_PORT value: 9200 volumeMounts: - name: varlog mountPath: /var/log - name: varlibdockercontainers mountPath: /var/lib/docker/containers readOnly: true volumes: - name: varlog hostPath: path: /var/log - name: varlibdockercontainers hostPath: path: /var/lib/docker/containers七、实践案例电商平台部署场景描述部署一个电商平台包含用户服务、产品服务、订单服务和支付服务。实现方案# 用户服务 deployment apiVersion: apps/v1 kind: Deployment metadata: name: user-service spec: replicas: 2 selector: matchLabels: app: user-service template: metadata: labels: app: user-service spec: containers: - name: user-service image: user-service:latest ports: - containerPort: 8080 resources: limits: cpu: 1 memory: 1Gi requests: cpu: 500m memory: 512Mi readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 30 periodSeconds: 10 livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 60 periodSeconds: 30 # 用户服务 service apiVersion: v1 kind: Service metadata: name: user-service spec: selector: app: user-service ports: - port: 80 targetPort: 8080 type: ClusterIP # 产品服务 deployment apiVersion: apps/v1 kind: Deployment metadata: name: product-service spec: replicas: 2 selector: matchLabels: app: product-service template: metadata: labels: app: product-service spec: containers: - name: product-service image: product-service:latest ports: - containerPort: 8080 resources: limits: cpu: 1 memory: 1Gi requests: cpu: 500m memory: 512Mi # 产品服务 service apiVersion: v1 kind: Service metadata: name: product-service spec: selector: app: product-service ports: - port: 80 targetPort: 8080 type: ClusterIP # 订单服务 deployment apiVersion: apps/v1 kind: Deployment metadata: name: order-service spec: replicas: 3 selector: matchLabels: app: order-service template: metadata: labels: app: order-service spec: containers: - name: order-service image: order-service:latest ports: - containerPort: 8080 resources: limits: cpu: 1 memory: 1Gi requests: cpu: 500m memory: 512Mi # 订单服务 service apiVersion: v1 kind: Service metadata: name: order-service spec: selector: app: order-service ports: - port: 80 targetPort: 8080 type: ClusterIP # 支付服务 deployment apiVersion: apps/v1 kind: Deployment metadata: name: payment-service spec: replicas: 2 selector: matchLabels: app: payment-service template: metadata: labels: app: payment-service spec: containers: - name: payment-service image: payment-service:latest ports: - containerPort: 8080 resources: limits: cpu: 1 memory: 1Gi requests: cpu: 500m memory: 512Mi # 支付服务 service apiVersion: v1 kind: Service metadata: name: payment-service spec: selector: app: payment-service ports: - port: 80 targetPort: 8080 type: ClusterIP八、总结与建议Docker 与 Kubernetes 为 Java 应用的部署提供了强大的工具。以下是一些关键建议容器化应用使用 Docker 容器化 Java 应用提高部署一致性优化 Dockerfile使用多阶段构建减小镜像大小合理配置 Kubernetes根据应用需求配置资源、探针和扩缩容策略使用 Helm通过 Helm 管理应用部署简化配置管理集成 CI/CD建立自动化部署流程提高部署效率监控与日志集成监控和日志系统提高系统可观测性安全最佳实践使用非 root 用户运行容器限制容器能力持续优化根据实际运行情况不断优化部署配置这其实可以更优雅一点通过合理使用 Docker 和 Kubernetes我们可以构建出更高效、更可靠的 Java 应用部署方案。别叫我大神叫我 Alex 就好。希望这篇文章能帮助你更好地理解和应用 Docker 与 Kubernetes 部署 Java 应用。欢迎在评论区分享你的使用经验