Kubernetes 集群
配置应用程序
镜像构建
Spring Boot Gradle 插件提供 bootBuildImage 任务,可以构建应用程序并创建 Docker 镜像。如需指定镜像名称,在 build.gradle 文件添加下列内容:
bootBuildImage {
    imageName = 'mycompany/sample-app'
}
Hazelcast 配置
Jmix 框架的模块使用了多种缓存:JPA 实体和查询缓存、悲观锁、动态属性配置等。在集群环境运行时,Jmix 应用程序需要在集群节点之间协调缓存。
所有 Jmix 的缓存都支持通过 Hazelcast 协调。本指南中,我们将使用 Hazelcast 的嵌入(embedded)模式,以及用于在 k8s 环境自动发现的 hazelcast-kubernetes 插件。
按照下列步骤配置 Hazelcast,支持在 k8s 集群中协调缓存。
- 
在
build.gradle添加 Hazelcast 依赖:implementation 'com.hazelcast:hazelcast' - 
通过在
application.properties文件添加下列属性指定使用 Hazelcast 作为 JCache provider:spring.cache.jcache.provider = com.hazelcast.cache.HazelcastMemberCachingProvider - 
在
resources根目录创建hazelcast.yaml文件:hazelcast: network: join: multicast: enabled: false kubernetes: enabled: false service-name: sample-app-service 
hazelcast.network.join.kubernetes.service-name 属性必须指向定义在 应用程序服务配置文件 中的应用程序服务。
注意,文件中 hazelcast.network.join.kubernetes.enabled 设置为 false。应用程序在无 k8s 的环境本地运行时,需要设置为 false。但是如果运行在 k8s 中,要求设置为 true,可以在应用程序服务配置文件中使用 HZ_NETWORK_JOIN_KUBERNETES_ENABLED 环境变量配置。
创建 Kubernetes 配置文件
在项目根目录创建 k8s 文件夹,添加下列文件。
数据库服务配置
该文件定义名称为 sample-db-service 的 PostgreSQL 数据库服务。
apiVersion: v1
kind: ConfigMap
metadata:
  name: sample-db-config
data:
  db_user: root
  db_password: root
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sample-db-pvclaim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-db
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sample-db
  strategy: {}
  template:
    metadata:
      labels:
        app: sample-db
    spec:
      volumes:
        - name: sample-db-storage
          persistentVolumeClaim:
            claimName: sample-db-pvclaim
      containers:
      - image: postgres
        name: sample-db
        env:
          - name: POSTGRES_USER
            valueFrom:
              configMapKeyRef:
                name: sample-db-config
                key: db_user
          - name: POSTGRES_PASSWORD
            valueFrom:
              configMapKeyRef:
                name: sample-db-config
                key: db_password
          - name: PGDATA
            value: /var/lib/postgresql/data/pgdata
          - name: POSTGRES_DB
            value: sample
        ports:
          - containerPort: 5432
            name: sample-db
        volumeMounts:
          - name: sample-db-storage
            mountPath: /var/lib/postgresql/data
---
apiVersion: v1
kind: Service
metadata:
  name: sample-db-service
spec:
  type: ClusterIP
  ports:
    - port: 5432
  selector:
    app: sample-db
应用程序服务配置
该文件定义名称为 sample-app-service 的应用程序服务。使用 mycompany/sample-app Docker 镜像。
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
        - image: mycompany/sample-app
          imagePullPolicy: IfNotPresent
          name: sample-app
          env:
            - name: DB_USER
              valueFrom:
                configMapKeyRef:
                  name: sample-db-config
                  key: db_user
            - name: DB_PASSWORD
              valueFrom:
                configMapKeyRef:
                  name: sample-db-config
                  key: db_password
            - name: DB_HOST
              value: sample-db-service
            - name: SPRING_PROFILES_ACTIVE
              value: k8s
            - name: HZ_NETWORK_JOIN_KUBERNETES_ENABLED
              value: "true"
          lifecycle:
            preStop:
              exec:
                command: [ "sh", "-c", "sleep 10" ]
          ports:
            - containerPort: 8080
            - containerPort: 5701
---
apiVersion: v1
kind: Service
metadata:
  name: sample-app-service
spec:
  type: NodePort
  ports:
    - port: 8080
      name: sample-app-app
    - port: 5701
      name: sample-app-hazelcast
  selector:
    app: sample-app
负载均衡配置
Jmix 用户界面(UI) 要求单个用户的所有请求都发送至同一个服务端。因此,在多服务的集群环境,需要一个粘性会话的负载均衡器。下面是带 session affinity 的 NGINX Ingress Controller 配置。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: balancer
  annotations:
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/affinity-mode: "persistent"
    nginx.ingress.kubernetes.io/session-cookie-hash: "sha1"
    nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
spec:
  defaultBackend:
    service:
      name: sample-app-service
      port:
        number: 8080
  rules:
    - http:
        paths:
          - backend:
              service:
                name: sample-app-service
                port:
                  number: 8080
            path: /
            pathType: Prefix
Hazelcast 访问控制配置
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: hazelcast-cluster-role
rules:
  - apiGroups:
      - ""
    resources:
      - endpoints
      - pods
      - nodes
      - services
    verbs:
      - get
      - list
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: hazelcast-cluster-role-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: hazelcast-cluster-role
subjects:
  - kind: ServiceAccount
    name: default
    namespace: default
设置本地 Kubernetes
- 
确保你的机器有 Docker 在运行。下面命令展示 Docker 版本:
docker -v如果命令失败,参阅 Docker 文档 了解如何安装并运行 Docker。
 - 
按照 说明 安装 Minikube。
 - 
运行 Minikube:
minikube start --vm-driver=virtualbox - 
启用 Ingress Controller:
minikube addons enable ingress - 
配置 k8s 命令行工具使用 Minikube:
kubectl config use-context minikube - 
在浏览器打开 k8s 仪表板,在一个单独的终端运行:
minikube dashboard 
构建运行应用程序
- 
构建 Docker 镜像:
./gradlew -Pvaadin.productionMode=true bootBuildImage - 
加载镜像至 Minikube:
minikube image load mycompany/sample-app:latest - 
应用 k8s 配置文件:
kubectl apply -f ./k8s - 
如需增加应用程序实例数量,使用下列命令:
kubectl scale deployment sample-app --replicas=2 - 
查找集群 IP 地址:
minikube ip使用这个地址在浏览器打开应用程序,示例:
http://192.168.99.100