Кластер Kubernetes
В данном разделе описывается развертывание приложения Jmix в кластер Kubernetes. Мы будем использовать одноузловой кластер, предоставляемый minikube. Вы можете установить его на свою машину разработки, чтобы протестировать развертывание локально.
Данное руководство сфокусировано на настройке приложения для запуска в Kubernetes. По нему вы можете подготовить свое приложение к такому развертыванию без каких-либо предварительных знаний о Kubernetes. Однако для реального развертывания в продакшн вы должны быть хорошо знакомы с этой технологией.
Более подробная информация о работе Jmix-приложений в кластере приведена в разделе Кластерное взаимодействие.
Настройка приложения
Настройка создания образа
Плагин Spring Boot Gradle предоставляет задачу bootBuildImage
, которая собирает ваше приложение и создает образ Docker. Чтобы указать имя образа, добавьте следующий раздел в файл build.gradle
:
bootBuildImage {
imageName = 'mycompany/sample-app'
}
Настройка Hazelcast
Модули фреймворка Jmix используют различные кэши: кэши сущностей JPA и запросов, пессимистические блокировки, конфигурации динамических атрибутов и т.д. При запуске в кластере приложение Jmix требует координации кэшей между узлами кластера.
Все кэши Jmix поддерживают координацию через Hazelcast. В данном руководстве мы будем использовать Hazelcast во встроенном режиме вместе с плагином hazelcast-kubernetes для автоматического обнаружения в среде Kubernetes.
Следуйте приведенной ниже инструкции, чтобы настроить Hazelcast для координации кэшей в кластере Kubernetes.
-
Добавьте зависимость Hazelcast в
build.gradle
:implementation 'com.hazelcast:hazelcast'
-
Укажите Hazelcast в качестве провайдера JCache, добавив следующее свойство в файл
application.properties
:spring.cache.jcache.provider = com.hazelcast.cache.HazelcastMemberCachingProvider
-
Создайте файл
hazelcast.yaml
в корнеresources
: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
. Это сделано для того, чтобы иметь возможность запускать приложение локально без Kubernetes. Свойство устанавливается в true
, когда приложение фактически запускается в Kubernetes, используя переменную окружения HZ_NETWORK_JOIN_KUBERNETES_ENABLED
в файле конфигурации сервиса приложения.
Создание конфигурационных файлов Kubernetes
Создайте папку k8s
в корне проекта и добавьте в нее перечисленные ниже файлы.
Конфигурация службы базы данных
Этот файл определяет службу базы данных PostgreSQL с именем sample-db-service
.
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
. Использует образ Docker mycompany/sample-app
для приложения.
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 ожидает, что все запросы от пользователя поступают на один и тот же сервер. В кластерной среде с несколькими серверами для этого требуется балансировщик нагрузки с "липкими сессиями" (sticky sessions). Ниже приведена конфигурация NGINX Ingress Controller с session affinity.
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 о том, как установить и запустить Docker.
-
Установите Minikube, как описано в инструкции по установке.
-
Запустите Minikube:
minikube start --vm-driver=virtualbox
-
Включите Ingress Controller:
minikube addons enable ingress
-
Настройте инструмент командной строки Kubernetes для использования Minikube:
kubectl config use-context minikube
-
Чтобы открыть панель мониторинга Kubernetes в веб-браузере, выполните следующую команду в отдельном терминале:
minikube dashboard
Сборка и запуск приложения
-
Соберите образ Docker:
./gradlew bootBuildImage
-
Загрузите образ в Minikube:
minikube image load mycompany/sample-app:latest
-
Примените конфигурационные файлы Kubernetes:
kubectl apply -f ./k8s
-
Чтобы увеличить количество экземпляров приложения, используйте следующую команду:
kubectl scale deployment sample-app --replicas=2
-
Определите IP-адрес кластера:
minikube ip
Используйте этот адрес для открытия приложения в веб-браузере, например:
http://192.168.99.100