从零到一:实战在Kubernetes中部署Java+Python多层微服务应用

2026/01/17 k8s 共 6537 字,约 19 分钟

从零到一:实战在Kubernetes中部署Java+Python多层微服务应用

在云原生时代,Kubernetes(K8s)已成为容器化应用编排和管理的事实标准。对于现代Web应用,尤其是采用微服务架构的应用,其后台可能由多种技术栈(如Java、Python、Go等)共同构建。本文将带领大家完成一次完整的实战演练:将一个模拟的“用户订单分析”多层Web应用部署到K8s集群中。该应用包含一个Java Spring Boot用户服务、一个Python Flask订单分析服务和一个简单的Nginx前端。

一、 应用架构与准备

我们的示例应用由三个独立的服务组成,模拟了一个简单的业务场景:

  1. 用户服务 (User-Service): 使用Java Spring Boot开发,提供RESTful API管理用户信息,并将数据存入MySQL数据库。
  2. 分析服务 (Analytics-Service): 使用Python Flask开发,从用户服务获取数据,进行模拟分析(如统计用户数量),并提供分析结果API。
  3. 前端服务 (Frontend): 使用Nginx托管一个简单的HTML/JS页面,该页面会同时调用Java和Python服务的API来展示综合信息。

部署目标: 将这三个服务、一个MySQL数据库全部容器化,并在K8s集群中运行,实现服务发现、负载均衡和配置管理。

前提条件

  • 一个可用的Kubernetes集群(可以是Minikube、Kind、或云厂商托管的K8s服务)。
  • 已安装kubectl命令行工具。
  • 已安装Docker,并了解基本的镜像构建知识。

二、 容器化应用(构建Docker镜像)

首先,我们需要为每个服务创建Docker镜像。

1. 容器化Java用户服务

假设Java项目的可执行Jar包为 user-service.jar,依赖一个 application.yml 配置文件。

Dockerfile:

# 使用官方OpenJDK运行时作为父镜像
FROM openjdk:11-jre-slim

# 设置工作目录
WORKDIR /app

# 将jar包和配置文件复制到容器中
COPY target/user-service.jar /app/user-service.jar
COPY src/main/resources/application.yml /app/config/application.yml

# 声明运行时容器暴露的端口
EXPOSE 8080

# 指定容器启动时执行的命令
ENTRYPOINT ["java", "-jar", "/app/user-service.jar", "--spring.config.location=/app/config/application.yml"]

构建命令:docker build -t your-registry/user-service:1.0.0 .

2. 容器化Python分析服务

假设Python服务主文件为 app.py,依赖 requirements.txt

Dockerfile:

# 使用官方Python精简版作为父镜像
FROM python:3.9-slim

WORKDIR /app

# 复制依赖文件并安装
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 暴露端口
EXPOSE 5000

# 启动命令
CMD ["python", "app.py"]

构建命令:docker build -t your-registry/analytics-service:1.0.0 .

3. 容器化前端服务

创建一个简单的 index.htmlnginx.conf 配置文件。

Dockerfile:

FROM nginx:alpine

# 将自定义的nginx配置复制到容器中,覆盖默认配置
COPY nginx.conf /etc/nginx/nginx.conf
# 将前端静态文件复制到nginx服务目录
COPY index.html /usr/share/nginx/html/

EXPOSE 80

构建命令:docker build -t your-registry/frontend:1.0.0 .

请将镜像推送到你的容器镜像仓库(如Docker Hub、Harbor等)。

三、 定义Kubernetes资源清单

我们将为每个组件创建K8s的YAML配置文件。

1. 部署MySQL数据库(StatefulSet & Service)

首先部署有状态的数据服务。我们使用ConfigMap来配置MySQL,使用Secret来管理密码,并使用PersistentVolumeClaim(PVC)来持久化数据。

mysql-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
type: Opaque
data:
  # 使用 echo -n 'yourpassword' | base64 生成
  root-password: cGFzc3dvcmQxMjM= # password123

mysql-configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
data:
  my.cnf: |
    [mysqld]
    character-set-server=utf8mb4
    collation-server=utf8mb4_unicode_ci

mysql-pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

mysql-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: root-password
        - name: MYSQL_DATABASE
          value: "userdb"
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-config
          mountPath: /etc/mysql/conf.d/my.cnf
          subPath: my.cnf
        - name: mysql-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-config
        configMap:
          name: mysql-config
      - name: mysql-storage
        persistentVolumeClaim:
          claimName: mysql-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-service
spec:
  selector:
    app: mysql
  ports:
    - protocol: TCP
      port: 3306
      targetPort: 3306
  # 使用ClusterIP,只在集群内部访问
  type: ClusterIP

2. 部署Java用户服务(Deployment & Service)

用户服务需要连接MySQL。我们通过环境变量注入数据库连接信息,并引用MySQL的Service名称(mysql-service)进行服务发现。

user-service-deployment.yaml

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: your-registry/user-service:1.0.0 # 替换为你的镜像
        ports:
        - containerPort: 8080
        env:
        - name: SPRING_DATASOURCE_URL
          value: "jdbc:mysql://mysql-service:3306/userdb?useSSL=false&allowPublicKeyRetrieval=true"
        - name: SPRING_DATASOURCE_USERNAME
          value: "root"
        - name: SPRING_DATASOURCE_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: root-password
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  selector:
    app: user-service
  ports:
    - protocol: TCP
      port: 80 # 集群内其他服务访问的端口
      targetPort: 8080 # 容器内应用监听的端口
  type: ClusterIP

3. 部署Python分析服务(Deployment & Service)

分析服务需要调用用户服务的API。我们通过环境变量注入用户服务的地址(http://user-service)。

analytics-service-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: analytics-service
spec:
  replicas: 1
  selector:
    matchLabels:
      app: analytics-service
  template:
    metadata:
      labels:
        app: analytics-service
    spec:
      containers:
      - name: analytics-service
        image: your-registry/analytics-service:1.0.0 # 替换为你的镜像
        ports:
        - containerPort: 5000
        env:
        - name: USER_SERVICE_URL
          value: "http://user-service" # 使用K8s Service名进行服务发现
        livenessProbe: # 存活探针
          httpGet:
            path: /health
            port: 5000
          initialDelaySeconds: 30
          periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: analytics-service
spec:
  selector:
    app: analytics-service
  ports:
    - protocol: TCP
      port: 80
      targetPort: 5000
  type: ClusterIP

4. 部署前端服务(Deployment & Service)

前端服务需要暴露给集群外部访问,因此我们使用NodePortLoadBalancer类型的Service。

frontend-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: frontend
        image: your-registry/frontend:1.0.0 # 替换为你的镜像
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: frontend-service
spec:
  selector:
    app: frontend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  # 使用NodePort,便于在开发测试环境通过节点IP访问
  # 在生产环境,通常使用LoadBalancer或Ingress
  type: NodePort

四、 部署与验证

  1. 依次应用所有配置文件
    kubectl apply -f mysql-secret.yaml
    kubectl apply -f mysql-configmap.yaml
    kubectl apply -f mysql-pvc.yaml
    kubectl apply -f mysql-deployment.yaml
    # 等待MySQL完全启动(可以使用 `kubectl get pods` 查看状态)
    kubectl apply -f user-service-deployment.yaml
    kubectl apply -f analytics-service-deployment.yaml
    kubectl apply -f frontend-deployment.yaml
    
  2. 检查部署状态
    kubectl get pods # 查看所有Pod是否都处于Running状态
    kubectl get svc  # 查看服务,注意frontend-service的NodePort端口
    kubectl get deployments
    
  3. 访问应用
    • 找到frontend-service的NodePort(例如 32718)。
    • 如果使用Minikube,运行 minikube service frontend-service --url 获取访问URL。
    • 在浏览器中打开该URL,应该能看到前端页面,并成功调用后端Java和Python服务。
  4. 故障排查常用命令
    # 查看Pod日志
    kubectl logs <pod-name>
    kubectl logs -f <pod-name> # 实时查看
    # 进入Pod内部调试
    kubectl exec -it <pod-name> -- /bin/sh
    # 查看Service和Endpoints
    kubectl describe svc user-service
    kubectl get endpoints user-service
    

五、 总结与扩展

通过本次实战,我们完成了将一个多层异构应用完整部署到Kubernetes的流程,涵盖了:

  • 多语言镜像构建(Java, Python, Nginx)。
  • 核心K8s资源使用:Deployment, Service, ConfigMap, Secret, PVC。
  • 服务发现与通信:通过Service名称在Pod间进行网络通信。
  • 配置与敏感信息管理:使用ConfigMap和Secret。

后续扩展方向

  1. 使用Ingress管理外部访问:替代NodePort,提供基于域名的路由、SSL终止等功能。
  2. 配置应用健康检查:为Java和Python服务添加readinessProbe(就绪探针)和livenessProbe(存活探针)。
  3. 使用Helm进行包管理:将这一系列YAML文件打包成Helm Chart,便于版本管理和一键部署。
  4. 集成CI/CD流水线:将镜像构建和K8s部署自动化。
  5. 增加监控与日志:集成Prometheus监控指标和EFK/ELK日志收集栈。

Kubernetes的强大之处在于其声明式的API和丰富的生态系统。通过将应用拆分为微服务并利用K8s进行编排,可以极大地提升系统的可维护性、可扩展性和可靠性。希望本文能为你部署自己的复杂应用到K8s提供一个清晰的起点。

文档信息

Search

    Table of Contents