====== 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