今天我们来聊聊 docker 与 kubernetes 部署 java 应用的最佳实践,这是容器化实践的重要技术。
一、容器化概述
容器化是一种将应用及其依赖打包为容器的技术,它提供了环境一致性、快速部署和资源隔离等优势。docker 是目前最流行的容器化平台,而 kubernetes 则是最流行的容器编排平台。
核心优势
- 环境一致性:容器在不同环境中运行一致
- 快速部署:容器启动速度快,部署时间短
- 资源隔离:容器之间相互隔离,避免干扰
- 资源利用率:容器占用资源少,提高服务器利用率
- 易于扩展:支持水平扩展,适应不同负载
二、docker 容器化实践
1. dockerfile 编写
# 基础镜像 from eclipse-temurin:25-jdk-alpine # 设置工作目录 workdir /app # 复制依赖文件 copy pom.xml ./ # 下载依赖 run mvn dependency:go-offline # 复制源代码 copy src ./src # 构建应用 run mvn package -dskiptests # 暴露端口 expose 8080 # 运行应用 cmd ["java", "-jar", "target/app.jar"]
2. 多阶段构建
# 构建阶段 from eclipse-temurin:25-jdk-alpine as build workdir /app copy pom.xml ./ run mvn dependency:go-offline copy src ./src run mvn package -dskiptests # 运行阶段 from eclipse-temurin:25-jre-alpine workdir /app copy --from=build /app/target/app.jar ./ expose 8080 cmd ["java", "-jar", "app.jar"]
3. 优化 dockerfile
# 使用最小基础镜像 from eclipse-temurin:25-jre-alpine # 设置时区 env tz=asia/shanghai run apk add --no-cache tzdata && ln -sf /usr/share/zoneinfo/$tz /etc/localtime && echo $tz > /etc/timezone # 创建非 root 用户 run addgroup -s appgroup && adduser -s appuser -g appgroup user appuser # 设置工作目录 workdir /app # 复制应用 copy target/app.jar ./ # 暴露端口 expose 8080 # 运行应用 cmd ["java", "-jar", "app.jar"]
4. 构建和运行
# 构建镜像 docker build -t my-java-app:latest . # 运行容器 docker run -d -p 8080:8080 --name my-app my-java-app:latest # 查看容器状态 docker ps # 查看容器日志 docker logs my-app # 进入容器 docker exec -it my-app /bin/sh
5. docker compose
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- spring_profiles_active=prod
- db_host=db
- db_port=5432
- db_name=mydb
- db_user=user
- db_password=password
depends_on:
- db
db:
image: postgres:13
environment:
- postgres_db=mydb
- postgres_user=user
- postgres_password=password
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
# 启动服务 docker-compose up -d # 停止服务 docker-compose down # 查看服务状态 docker-compose ps
三、kubernetes 部署实践
1. 部署配置
# deployment.yml
apiversion: apps/v1
kind: deployment
metadata:
name: my-java-app
spec:
replicas: 3
selector:
matchlabels:
app: my-java-app
template:
metadata:
labels:
app: my-java-app
spec:
containers:
- name: my-java-app
image: my-java-app:latest
ports:
- containerport: 8080
env:
- name: spring_profiles_active
value: "prod"
- name: db_host
value: "db-service"
- name: db_port
value: "5432"
- name: db_name
value: "mydb"
- name: db_user
value: "user"
- name: db_password
value: "password"
resources:
limits:
cpu: "1"
memory: "1gi"
requests:
cpu: "500m"
memory: "512mi"
2. 服务配置
# service.yml
apiversion: v1
kind: service
metadata:
name: my-java-app-service
spec:
selector:
app: my-java-app
ports:
- port: 8080
targetport: 8080
type: loadbalancer
3. 配置管理
# configmap.yml
apiversion: v1
kind: configmap
metadata:
name: my-java-app-config
data:
application.yml: |
spring:
profiles:
active: prod
datasource:
url: jdbc:postgresql://db-service:5432/mydb
username: user
password: password
jpa:
hibernate:
ddl-auto: update
properties:
hibernate:
format_sql: true
# deployment.yml (with configmap)
apiversion: apps/v1
kind: deployment
metadata:
name: my-java-app
spec:
replicas: 3
selector:
matchlabels:
app: my-java-app
template:
metadata:
labels:
app: my-java-app
spec:
containers:
- name: my-java-app
image: my-java-app:latest
ports:
- containerport: 8080
volumemounts:
- name: config-volume
mountpath: /app/config
resources:
limits:
cpu: "1"
memory: "1gi"
requests:
cpu: "500m"
memory: "512mi"
volumes:
- name: config-volume
configmap:
name: my-java-app-config
4. 密钥管理
# secret.yml apiversion: v1 kind: secret metadata: name: my-java-app-secret type: opaque data: db-password: dxnlci1wyxnzd29yza== # base64 encoded jwt-secret: c29tzs1qd3qtc2vjcmv0
# deployment.yml (with secret)
apiversion: apps/v1
kind: deployment
metadata:
name: my-java-app
spec:
replicas: 3
selector:
matchlabels:
app: my-java-app
template:
metadata:
labels:
app: my-java-app
spec:
containers:
- name: my-java-app
image: my-java-app:latest
ports:
- containerport: 8080
env:
- name: db_password
valuefrom:
secretkeyref:
name: my-java-app-secret
key: db-password
- name: jwt_secret
valuefrom:
secretkeyref:
name: my-java-app-secret
key: jwt-secret
resources:
limits:
cpu: "1"
memory: "1gi"
requests:
cpu: "500m"
memory: "512mi"
5. 持久化存储
# persistentvolumeclaim.yml
apiversion: v1
kind: persistentvolumeclaim
metadata:
name: my-java-app-pvc
spec:
accessmodes:
- readwriteonce
resources:
requests:
storage: 10gi
storageclassname: standard
# deployment.yml (with pvc)
apiversion: apps/v1
kind: deployment
metadata:
name: my-java-app
spec:
replicas: 3
selector:
matchlabels:
app: my-java-app
template:
metadata:
labels:
app: my-java-app
spec:
containers:
- name: my-java-app
image: my-java-app:latest
ports:
- containerport: 8080
volumemounts:
- name: data-volume
mountpath: /app/data
resources:
limits:
cpu: "1"
memory: "1gi"
requests:
cpu: "500m"
memory: "512mi"
volumes:
- name: data-volume
persistentvolumeclaim:
claimname: my-java-app-pvc
6. 水平自动伸缩
# horizontalpodautoscaler.yml
apiversion: autoscaling/v2
kind: horizontalpodautoscaler
metadata:
name: my-java-app-hpa
spec:
scaletargetref:
apiversion: apps/v1
kind: deployment
name: my-java-app
minreplicas: 3
maxreplicas: 10
metrics:
- type: resource
resource:
name: cpu
target:
type: utilization
averageutilization: 70
- type: resource
resource:
name: memory
target:
type: utilization
averageutilization: 80
7. 健康检查
# deployment.yml (with health checks)
apiversion: apps/v1
kind: deployment
metadata:
name: my-java-app
spec:
replicas: 3
selector:
matchlabels:
app: my-java-app
template:
metadata:
labels:
app: my-java-app
spec:
containers:
- name: my-java-app
image: my-java-app:latest
ports:
- containerport: 8080
readinessprobe:
httpget:
path: /actuator/health/readiness
port: 8080
initialdelayseconds: 30
periodseconds: 10
livenessprobe:
httpget:
path: /actuator/health/liveness
port: 8080
initialdelayseconds: 60
periodseconds: 30
resources:
limits:
cpu: "1"
memory: "1gi"
requests:
cpu: "500m"
memory: "512mi"
四、ci/cd 集成
1. jenkins 流水线
pipeline {
agent any
stages {
stage('build') {
steps {
sh 'mvn clean package -dskiptests'
}
}
stage('test') {
steps {
sh 'mvn test'
}
}
stage('build docker image') {
steps {
sh 'docker build -t my-java-app:${build_number} .'
sh 'docker tag my-java-app:${build_number} my-java-app:latest'
}
}
stage('push to registry') {
steps {
sh 'docker push my-java-app:${build_number}'
sh 'docker push my-java-app:latest'
}
}
stage('deploy to kubernetes') {
steps {
sh 'kubectl apply -f k8s/deployment.yml'
sh 'kubectl apply -f k8s/service.yml'
sh 'kubectl rollout status deployment/my-java-app'
}
}
}
}
2. github actions
name: ci/cd pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: set up jdk 25
uses: actions/setup-java@v2
with:
java-version: '25'
distribution: 'adopt'
- name: build with maven
run: mvn clean package -dskiptests
- name: run tests
run: mvn test
- name: build docker image
run: docker build -t my-java-app:${{ github.sha }} .
- name: push to docker hub
run: |
docker tag my-java-app:${{ github.sha }} my-java-app:latest
docker login -u ${{ secrets.docker_username }} -p ${{ secrets.docker_password }}
docker push my-java-app:${{ github.sha }}
docker push my-java-app:latest
- name: deploy to kubernetes
run: |
kubectl config use-context my-cluster
kubectl apply -f k8s/deployment.yml
kubectl apply -f k8s/service.yml
kubectl rollout status deployment/my-java-app
五、监控与日志
1. 监控
# prometheus.yml
apiversion: monitoring.coreos.com/v1
kind: servicemonitor
metadata:
name: my-java-app-monitor
labels:
release: prometheus
spec:
selector:
matchlabels:
app: my-java-app
endpoints:
- port: 8080
path: /actuator/prometheus
interval: 15s
2. 日志
# deployment.yml (with logging)
apiversion: apps/v1
kind: deployment
metadata:
name: my-java-app
spec:
replicas: 3
selector:
matchlabels:
app: my-java-app
template:
metadata:
labels:
app: my-java-app
spec:
containers:
- name: my-java-app
image: my-java-app:latest
ports:
- containerport: 8080
env:
- name: logging_level_root
value: "info"
- name: logging_level_com_example
value: "debug"
resources:
limits:
cpu: "1"
memory: "1gi"
requests:
cpu: "500m"
memory: "512mi"
六、实践案例:java 微服务部署
场景描述
部署一个包含用户服务、订单服务、产品服务的 java 微服务架构到 kubernetes。
实现方案
1. 服务配置
用户服务
# user-service-deployment.yml
apiversion: apps/v1
kind: deployment
metadata:
name: user-service
spec:
replicas: 3
selector:
matchlabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: user-service:latest
ports:
- containerport: 8080
env:
- name: spring_profiles_active
value: "prod"
- name: eureka_client_serviceurl_defaultzone
value: "http://eureka-service:8761/eureka/"
resources:
limits:
cpu: "1"
memory: "1gi"
requests:
cpu: "500m"
memory: "512mi"
---
apiversion: v1
kind: service
metadata:
name: user-service
spec:
selector:
app: user-service
ports:
- port: 8080
targetport: 8080
type: clusterip
订单服务
# order-service-deployment.yml
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
env:
- name: spring_profiles_active
value: "prod"
- name: eureka_client_serviceurl_defaultzone
value: "http://eureka-service:8761/eureka/"
resources:
limits:
cpu: "1"
memory: "1gi"
requests:
cpu: "500m"
memory: "512mi"
---
apiversion: v1
kind: service
metadata:
name: order-service
spec:
selector:
app: order-service
ports:
- port: 8080
targetport: 8080
type: clusterip
产品服务
# product-service-deployment.yml
apiversion: apps/v1
kind: deployment
metadata:
name: product-service
spec:
replicas: 3
selector:
matchlabels:
app: product-service
template:
metadata:
labels:
app: product-service
spec:
containers:
- name: product-service
image: product-service:latest
ports:
- containerport: 8080
env:
- name: spring_profiles_active
value: "prod"
- name: eureka_client_serviceurl_defaultzone
value: "http://eureka-service:8761/eureka/"
resources:
limits:
cpu: "1"
memory: "1gi"
requests:
cpu: "500m"
memory: "512mi"
---
apiversion: v1
kind: service
metadata:
name: product-service
spec:
selector:
app: product-service
ports:
- port: 8080
targetport: 8080
type: clusterip
eureka 服务
# eureka-service-deployment.yml
apiversion: apps/v1
kind: deployment
metadata:
name: eureka-service
spec:
replicas: 1
selector:
matchlabels:
app: eureka-service
template:
metadata:
labels:
app: eureka-service
spec:
containers:
- name: eureka-service
image: eureka-service:latest
ports:
- containerport: 8761
resources:
limits:
cpu: "1"
memory: "1gi"
requests:
cpu: "500m"
memory: "512mi"
---
apiversion: v1
kind: service
metadata:
name: eureka-service
spec:
selector:
app: eureka-service
ports:
- port: 8761
targetport: 8761
type: clusterip
api 网关
# gateway-service-deployment.yml
apiversion: apps/v1
kind: deployment
metadata:
name: gateway-service
spec:
replicas: 3
selector:
matchlabels:
app: gateway-service
template:
metadata:
labels:
app: gateway-service
spec:
containers:
- name: gateway-service
image: gateway-service:latest
ports:
- containerport: 8080
env:
- name: spring_profiles_active
value: "prod"
- name: eureka_client_serviceurl_defaultzone
value: "http://eureka-service:8761/eureka/"
resources:
limits:
cpu: "1"
memory: "1gi"
requests:
cpu: "500m"
memory: "512mi"
---
apiversion: v1
kind: service
metadata:
name: gateway-service
spec:
selector:
app: gateway-service
ports:
- port: 8080
targetport: 8080
type: loadbalancer
2. 部署步骤
- 构建镜像:为每个服务构建 docker 镜像
- 推送镜像:将镜像推送到 docker 仓库
- 部署服务:使用 kubectl 部署所有服务
- 验证部署:检查服务状态和日志
- 配置监控:设置 prometheus 和 grafana 监控
七、最佳实践总结
1. docker 最佳实践
- 使用多阶段构建:减小镜像大小
- 优化基础镜像:使用最小基础镜像
- 非 root 用户:使用非 root 用户运行容器
- 环境变量:使用环境变量配置应用
- 健康检查:添加健康检查端点
- 日志管理:使用标准输出和标准错误
2. kubernetes 最佳实践
- 资源限制:为每个容器设置资源限制
- 健康检查:配置就绪探针和存活探针
- 水平伸缩:使用 hpa 实现自动伸缩
- 配置管理:使用 configmap 管理配置
- 密钥管理:使用 secret 管理敏感数据
- 持久化存储:使用 pvc 管理持久化数据
- 服务发现:使用 kubernetes 服务实现服务发现
3. ci/cd 最佳实践
- 自动化构建:使用 jenkins 或 github actions 自动化构建
- 自动化测试:在构建过程中运行测试
- 自动化部署:自动部署到测试和生产环境
- 版本管理:使用语义化版本控制
- 回滚机制:在部署失败时能够回滚
4. 监控与日志
- 应用监控:使用 prometheus 监控应用指标
- 系统监控:监控 kubernetes 集群状态
- 日志聚合:使用 elk 或 loki 聚合日志
- 告警机制:设置合理的告警规则
- 仪表盘:使用 grafana 创建监控仪表盘
八、总结与建议
docker 与 kubernetes 部署 java 应用是现代应用部署的重要方式。通过合理使用容器化技术,我们可以:
- 提高部署效率:快速部署和扩展应用
- 增强系统可靠性:通过健康检查和自动伸缩提高系统可用性
- 改善资源利用率:容器占用资源少,提高服务器利用率
- 简化环境管理:容器在不同环境中运行一致
- 提高开发效率:开发环境与生产环境一致,减少环境问题
这其实可以更优雅一点,通过合理使用 docker 和 kubernetes,我们可以构建出更现代化、更可靠的 java 应用部署方案。
到此这篇关于docker与kubernetes部署java应用容器化实践指南的文章就介绍到这了,更多相关docker与k8s部署java应用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论