Кластер 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 -Pvaadin.productionMode=true 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