====== Helm - от основ до универсального чарта ====== * [[https://habr.com/ru/articles/792802/|Шаблонизатор GO text template для новичков]] * [[https://helm.sh/docs/chart_template_guide/getting_started|Helm Getting Started]] * [[https://habr.com/ru/articles/548720/|Основы работы с Helm чартами и темплейтами — Часть 2]] * [[https://github.com/camptocamp/helm-application|Kubernetes HELM chart for a simple application]] * [[https://phoenixnap.com/kb/helm-environment-variables|How to Use Environment Variables with Helm Charts]] * [[https://temofeev.ru/info/articles/universalnyy-helm-chart-dlya-vashikh-prilozheniy/|Универсальный Helm чарт для ваших приложений]] * [[https://habr.com/ru/companies/nixys/articles/668782/|Универсальный Helm-чарт v2.0]] * [[https://habr.com/ru/companies/flant/articles/529158/|Пример использования helmfile для деплоя в несколько окружений]] ===== Реклама ===== * Нас ждет еще один, воспроизводимый в домашних условиях вебинар, на котором мы освоим "магический" синтаксис шаблонизатора из языка программирования Golang, который лежит в основе самого современного способа развертывания программного обеспечения - Kubernetes + Helm Charts + ArgoCD ===== Техническое задание ===== * Освоить синтаксис написания Helm чартов * Написать универсальный чарт для развёртывание множества приложений * Установить ArgoCD и провести развертывание приложений в Kubernetes ===== Запись вебинара ===== * Ютуб: [[https://youtu.be/8BbRGP2t7_Q]] * Рутуб: [[https://rutube.ru/video/private/963e0e91656ec459a4377456b350bd8c/]] * Вк: [[https://vkvideo.ru/video-2190892_456239497]] * Тэги: Kubernetes, Helm, ArgoCD ===== Шаг 1. Что у нас есть, для начала ===== * [[Технология Docker#Приложение golang gowebd]] ver1.1 и ver1.2 * [[https://hub.docker.com/_/httpd]] * [[Технология Docker#Приложение python pywebd]] с данными, ver1.1 (http) с переменными конфигурации, ver1.2 (https) без переменных конфигурации * [[Технология Docker#Приложение apwebd]] ver1.1 * Образы в [[Инструмент GitLab#GitLab Docker Registry]] * DNS записи A для всех приложений указывают на Ingress * [[Система Kubernetes]] * [[Система Kubernetes#Ingress]] для gowebd, pywebd:ver1.1, apwebd * [[Система Kubernetes#MetalLB]] для Ingress и pywebd:ver1.2 * [[Система Kubernetes#cert-manager]] + FreeIPA [[Решение FreeIPA#Поддержка ACME]] ===== Шаг 2. Разворачиваем первое приложение через манифесты ===== * [[Система Kubernetes#Deployment]], [[Система Kubernetes#Service]] для gowebd (gitlab.corpX.un:5000/student/gowebd:ver1.1) ===== Шаг 3. Последовательно изучаем синтаксис Helm, решая возникающие задачи ===== * Заменяем [[Система Kubernetes#Manifest]]-ы на [[Система Kubernetes#Helm]] шаблоны * Основные файлы и каталоги чарта для [[Система Kubernetes#Развертывание своего приложения]] kube1:~/webd-k8s# mkdir -p uni-webd-chart/templates/ mv -v my-webd-deployment.yaml uni-webd-chart/templates/ mv -v my-webd-service.yaml uni-webd-chart/templates/ * Проверка, генерация манифеста и установка приложения ... kube1:~/webd-k8s# helm upgrade -i my-gowebd uni-webd-chart/ -n my-ns --create-namespace * Подстановка переменных в .Values в шаблон (image.repository, image.tag, replicaCount), замена gowebd на httpd * Использование функции default (replicaCount и image.tag) * Деплой в один NS двух приложений и ипользование .Release.Name в назании объектов (Deployment, Service) и меток (можно показать отдельно) kube1:~/webd-k8s# helm upgrade -i my-htwebd uni-webd-chart/ -n my-ns --create-namespace * Оператор if, функции hasKey, использование знака "-" (targetPort) для приложения pywebd kube1:~/webd-k8s# helm upgrade -i my-pywebd uni-webd-chart/ -n my-ns --create-namespace * Включение через enabled, цикл range (host в [[Система Kubernetes#ingress example]]) и знак "$" (.Release.Name) ... server# curl http://pywebd.corpX.un * Добавляем tls, общий env.yaml, комментарии, tpl, [], quote kube1:~/webd-k8s# helm template -f env.yaml my-pywebd uni-webd-chart/ #--debug kube1:~/webd-k8s# helm upgrade -i my-pywebd uni-webd-chart/ -f env.yaml -n my-ns --create-namespace kube1:~/webd-k8s# curl https://pywebd.corpX.un -kv * Добавляем Сertificate через [[Система Kubernetes#cert-manager]], все похоже на Ingress ... kube1:~/webd-k8s# curl https://pywebd.corpX.un * Меняем запись А на свободный IP [[Система Kubernetes#MetalLB]] в DNS для приложения pywebd, используем ver1.1, функции eq, and ([[Система Kubernetes#Service]] loadBalancerIP) тестируем без Ingress и Сertificate ... kube1:~/webd-k8s# curl http://pywebd.corpX.un * Функции toYaml, nindent, оператор with (env, volumes, volumeMounts в [[Система Kubernetes#Deployment]] и [[Система Kubernetes#ConfigMap, Secret]] для pywebd:ver1.2) ... kube1:~/webd-k8s# curl https://pywebd.corpX.un ==== Итоговый чарт ==== kube1:~/webd-k8s# cat uni-webd-chart/Chart.yaml apiVersion: v2 name: webd-chart version: 0.1.0 kube1:~/webd-k8s# cat uni-webd-chart/values.yaml #hostname: webd #replicaCount: 2 #image: # repository: gitlab.corpX.un:5000/student/webd # tag: ver1.1 #env: # PYWEBD_DOC_ROOT: /var/www/ # PYWEBD_PORT: 4443 service: port: 80 # targetPort: 4080 # type: LoadBalancer # ip: 192.168.X.65 ingress: enabled: false className: nginx hosts: - hostTemplate: "{{ .Values.hostname }}.{{ .Values.domain }}" ##- host: webd.corpX.un ##- host: corpX.un tls: [] # tls: # - secretName: webd-tls # hosts: # - "{{ .Values.hostname }}.{{ .Values.domain }}" ## - webd.corpX.un ## - corpX.un certificate: enabled: false secretName: webd-tls dnsNames: - "{{ .Values.hostname }}.{{ .Values.domain }}" ##- webd.corpX.un ##- "*.corpX.un" issuerRef_name: freeipa-dns-clusterissuer issuerRef_kind: ClusterIssuer volumes: [] #volumes: #- name: secret-tls-volume # secret: # secretName: pywebd-tls volumeMounts: [] #volumeMounts: #- name: secret-tls-volume # subPath: tls.crt # mountPath: /etc/pywebd/pywebd.crt #- name: secret-tls-volume # subPath: tls.key # mountPath: /etc/pywebd/pywebd.key kube1:~/webd-k8s# cat uni-webd-chart/templates/my-webd-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Release.Name }}-dep spec: selector: matchLabels: app: {{ .Release.Name }}-lab replicas: {{ default 1 .Values.replicaCount }} template: metadata: labels: app: {{ .Release.Name }}-lab spec: containers: - name: my-webd image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default "latest" }}" {{- with .Values.env }} env: {{- range $key, $val := . }} - name: {{$key}} value: {{$val|quote}} {{- end}} {{- end}} {{- with .Values.volumeMounts }} volumeMounts: {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.volumes }} volumes: {{- toYaml . | nindent 6 }} {{- end }} kube1:~/webd-k8s# cat uni-webd-chart/templates/my-webd-service.yaml apiVersion: v1 kind: Service metadata: name: {{ .Release.Name }}-svc spec: selector: app: {{ .Release.Name }}-lab ports: - protocol: TCP port: {{ .Values.service.port }} {{- if hasKey .Values.service "targetPort" }} targetPort: {{ .Values.service.targetPort }} {{- end }} type: {{ .Values.service.type | default "ClusterIP" }} {{- if and (hasKey .Values.service "ip") (eq .Values.service.type "LoadBalancer") }} loadBalancerIP: {{ .Values.service.ip }} {{- end }} kube1:~/webd-k8s# cat uni-webd-chart/templates/my-ingress.yaml {{- if .Values.ingress.enabled -}} apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: {{ .Release.Name }}-ingress spec: ingressClassName: {{ .Values.ingress.className }} rules: {{- range .Values.ingress.hosts }} {{- /* - host: {{ .host }} */}} - host: {{ tpl .hostTemplate $ }} http: paths: - backend: service: name: {{ $.Release.Name }}-svc port: number: {{ default $.Values.service.port $.Values.service.targetPort}} path: / pathType: Prefix {{- end }} {{- if .Values.ingress.tls }} tls: {{- range .Values.ingress.tls }} - hosts: {{- range .hosts }} - {{ tpl . $ | quote }} {{- end }} secretName: {{ .secretName }} {{- end }} {{- end }} {{- end }} kube1:~/webd-k8s# cat env.yaml domain: corpX.un kube1:~/webd-k8s# cat uni-webd-chart/templates/my-certificate.yaml {{- if .Values.certificate.enabled -}} apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: {{ .Release.Name }}-cert spec: secretName: {{ .Values.certificate.secretName }} dnsNames: {{- range .Values.certificate.dnsNames }} - {{ tpl . $ | quote }} {{- end }} issuerRef: name: {{ .Values.certificate.issuerRef_name }} kind: {{ .Values.certificate.issuerRef_kind }} privateKey: rotationPolicy: Always {{- end }} ===== Шаг 4. Используем персональный values файл для каждого приложения ===== kube1:~/webd-k8s# ###cp uni-webd-chart/values.yaml apps/gowebd/values.yaml kube1:~/webd-k8s# ###cp uni-webd-chart/values.yaml apps/pywebd/values.yaml kube1:~/webd-k8s# vim uni-webd-chart/values.yaml Комментируем для документации, для демонстрации наследования можно оставить то, что часто используется по умолчанию kube1:~/webd-k8s# cat apps/gowebd/values.yaml hostname: gowebd replicaCount: 2 image: repository: gitlab.corpX.un:5000/student/gowebd tag: ver1.1 ingress: enabled: true tls: - secretName: gowebd-tls hosts: - "{{ .Values.hostname }}.{{ .Values.domain }}" certificate: enabled: true secretName: gowebd-tls kube1:~/webd-k8s# helm template my-gowebd uni-webd-chart/ -f apps/gowebd/values.yaml -f env.yaml kube1:~/webd-k8s# helm upgrade -i my-gowebd uni-webd-chart/ -f env.yaml -f apps/gowebd/values.yaml -n my-ns --create-namespace kube1:~/webd-k8s# cat apps/pywebd/values.yaml hostname: pywebd image: repository: gitlab.corpX.un:5000/student/pywebd tag: ver1.2 env: PYWEBD_DOC_ROOT: /var/www/ PYWEBD_PORT: 4443 service: # port: 80 port: 443 targetPort: 4443 type: LoadBalancer ip: 192.168.X.65 certificate: enabled: true secretName: pywebd-tls volumes: - name: secret-tls-volume secret: secretName: pywebd-tls volumeMounts: - name: secret-tls-volume subPath: tls.crt mountPath: /etc/pywebd/pywebd.crt - name: secret-tls-volume subPath: tls.key mountPath: /etc/pywebd/pywebd.key kube1:~/webd-k8s# helm template my-pywebd uni-webd-chart/ -f apps/pywebd/values.yaml -f env.yaml kube1:~/webd-k8s# helm upgrade -i my-pywebd uni-webd-chart/ -f env.yaml -f apps/pywebd/values.yaml -n my-ns --create-namespace Развернем через ArgoCD kube1:~/webd-k8s# cat apps/apwebd/values.yaml hostname: apwebd image: repository: gitlab.corpX.un:5000/student/apwebd tag: ver1.1 env: APWEBD_HOSTNAME: "apwebd.corpX.un" KEYCLOAK_HOSTNAME: "keycloak.corpX.un" REALM_NAME: "corpX" ingress: enabled: true tls: - secretName: apwebd-tls hosts: - "{{ .Values.hostname }}.{{ .Values.domain }}" certificate: enabled: true secretName: apwebd-tls ===== Шаг 5. Используем ArgoCD для развертывания приложений ===== * [[Контроллер ArgoCD]] ==== Одно приложение ==== kube1:~/webd-k8s# cat argocd/application.yaml * [[Контроллер ArgoCD#Управление приложениями через kubectl]] * Увеличиваем версию gowebd ==== Множество приложений ==== * [[Контроллер ArgoCD#Развертывание множества приложений через ApplicationSet]] * Добавляем apwebd ===== Подготовка к вебинару ===== * Удаляем AppSet ArgoCD * Удаляем проект webd-k8s из GitLab * gowebd A -> ingress