====== 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 ===== Запись вебинара ===== * Тэги: Kubernetes, Helm, ArgoCD ===== Шаг 1. Что у нас есть, для начала ===== * Приложение gowebd ver1.1 и ver1.2 на [[Язык программирования Golang]] * [[Технология Docker#Приложение apwebd]] ver1.1 * Приложение pywebd ver1.1 (http) и ver1.2 (https) на [[Язык программирования Python]] * Образы [[Технология Docker]] в [[Инструмент GitLab]] * [[Система Kubernetes]] * [[Система Kubernetes#Ingress]] для gowebd и apwebd * [[Система Kubernetes#MetalLB]] для pywebd * [[Система Kubernetes#cert-manager]] + FreeIPA [[Решение FreeIPA#Поддержка ACME]] ===== Шаг 2. Последовательно изучаем синтаксис Helm, решая возникающие задачи ===== * Разворачиваем первое приложение gowebd через [[Система Kubernetes#Manifest]] * Заменяем [[Система Kubernetes#Manifest]]ы на [[Система Kubernetes#Helm]] шаблоны kube1:~/webd-k8s# mkdir -p uni-webd-chart/templates/ kube1:~/webd-k8s# cp my-webd-deployment.yaml uni-webd-chart/templates/my-webd-deployment.yaml kube1:~/webd-k8s# cp my-webd-service.yaml uni-webd-chart/templates/my-webd-service.yaml kube1:~/webd-k8s# cp my-ingress.yaml uni-webd-chart/templates/my-ingress.yaml kube1:~/webd-k8s# cp my-certificate.yaml uni-webd-chart/templates/my-certificate.yaml ===== Итоговый чарт ===== 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.corp13.un:5000/student/webd # tag: "ver1.1" #env: # PYWEBD_DOC_ROOT: /var/www/ # PYWEBD_PORT: 4080 service: port: 80 # targetPort: 4080 # type: LoadBalancer # ip: 192.168.13.65 ingress: enabled: false className: nginx hosts: - hostTemplate: "{{ .Values.hostname }}.{{ .Values.domain }}" ##- host: webd.corp13.un ##- host: corp13.un tls: [] # tls: # - secretName: gowebd-tls # hosts: # - "{{ .Values.hostname }}.{{ .Values.domain }}" ## - webd.corp13.un ## - corp13.un certificate: enabled: false secretName: webd-tls dnsNames: - "{{ .Values.hostname }}.{{ .Values.domain }}" ##- webd.corp13.un ##- "*.corp13.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 }}" {{- 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 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 }} {{- end }} kube1:~/webd-k8s# cp uni-webd-chart/values.yaml apps/gowebd/values.yaml kube1:~/webd-k8s# cat apps/gowebd/values.yaml hostname: gowebd replicaCount: 2 image: repository: gitlab.corp13.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/apwebd/values.yaml hostname: apwebd image: repository: gitlab.corp13.un:5000/student/apwebd tag: "ver1.1" env: APWEBD_HOSTNAME: "apwebd.corp13.un" KEYCLOAK_HOSTNAME: "keycloak.corp13.un" REALM_NAME: "corp13" ingress: enabled: true tls: - secretName: apwebd-tls hosts: - "{{ .Values.hostname }}.{{ .Values.domain }}" certificate: enabled: true secretName: apwebd-tls kube1:~/webd-k8s# cat apps/pywebd/values.yaml hostname: pywebd image: repository: gitlab.corp13.un:5000/student/pywebd tag: "ver1.2" env: PYWEBD_DOC_ROOT: /var/www/ PYWEBD_PORT: 4080 service: # port: 80 port: 443 targetPort: 4080 type: LoadBalancer ip: 192.168.13.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# cat argocd/application.yaml apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: my-webd namespace: argocd finalizers: - resources-finalizer.argocd.argoproj.io spec: project: default source: repoURL: 'https://gitlab.corp13.un/student/webd-k8s.git' path: uni-webd-chart helm: valueFiles: - ../apps/gowebd/values.yaml - ../env.yaml destination: server: 'https://kubernetes.default.svc' namespace: my-ns syncPolicy: automated: {} syncOptions: - CreateNamespace=true kube1:~/webd-k8s# cat argocd/application-s.yaml apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: my-webd-s namespace: argocd finalizers: - resources-finalizer.argocd.argoproj.io spec: generators: - git: repoURL: 'https://gitlab.corp13.un/student/webd-k8s.git' revision: main directories: - path: apps/* template: metadata: name: '{{path.basename}}' labels: name: apps spec: project: default sources: - repoURL: 'https://gitlab.corp13.un/student/webd-k8s.git' targetRevision: main path: uni-webd-chart helm: valueFiles: - $values/apps/{{path.basename}}/values.yaml - $values/env.yaml - repoURL: 'https://gitlab.corp13.un/student/webd-k8s.git' targetRevision: main ref: values destination: server: 'https://kubernetes.default.svc' namespace: my-ns syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true