Kubernetes 集群
本章节中,我们介绍如何将 Jmix 应用程序部署至 k8s 集群。我们使用由 minikube 提供的单节点集群,你可以安装到开发机器上,本地测试部署。
我们主要关注为了使应用程序能运行在 k8s 中,需要做什么配置。即使没有任何 k8s 的经验,也可以通过本指南将你的应用程序准备好部署至这样的环境。但是,如果是生产环境的部署,最好还是有一些技术基础。
配置应用程序
镜像构建
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' implementation 'com.hazelcast:hazelcast-kubernetes:2.2.3'
-
通过在
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 用户界面 要求单个用户的所有请求都发送至同一个服务端。因此,在多服务的集群环境,需要一个粘性会话的负载均衡器。下面是带 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 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