จดๆ ลงมือทำ Helm Essential#04 (Workflow / Writing Verifying Chart / Hooks)

สำหรับวันนี้เป็นวันสุดท้ายของ Helm Essential Class ของคุณคุณโจโจ้ JumpBox แล้วครับ วันนี้มา output เป็นการบ้านอีก Blog ครับ โดยมีหัวข้อ ดังนี้

Designing Solution (Workflow)

key: ทำให้ดี คนอื่นมาดูต่อได้ operational work / แล้วค่อยมาปรับ perf

Source - ทำมือ หรือ จะเอาพวก CI/CD มาช่วย

Share / Publish เวลาเราเอา Chart เอาไป Share ในทีม หรือ องค์ เพราะเราอาจจะไม่ได้ใช้คนเดียวนะ ซึ่งมันมีหลายวิธีการตั้งแต่ง่ายๆ

Comsume - การเรียกใช้

  • Add Repository เข้าไปตรงๆ
  • หรือ ใช้วิธีการ Proxy เราอยาก Add แค่ Source เพียงแหล่งเดียว แล้วให้ตัว Tools มันวิ่งไปหาจาก Data Source ที่ Map ไว้ อย่างเคสของ Helm Proxy จาก Artifacthub.io / Helm Data (ภายใน) ข้อดีทำ Cache ภายใน และ map จุดเดียว Tools ที่แนะนำ nexus

Record - จดบันทึกกการตัดสินใจ จะได้จำได้ว่าเราทำอะไรลงไป สมัยนี้จะเป็นเอกสาร ADR

อันนี้ของแชร์ของตัวเองบ้าง เพราะมี Software หลายตัว

  • อย่างตัว Package Repo ตอนแรกใช้ NuGet.Server เก็บของ แล้วมาพบปัญหาว่าพอเวลาจะไปดึง nuget.org มันมี Traffic สูงมาก โดยเฉพาะช่วงนี้ Jenkins มัน Trigger เลยเลือกใช้ Nexus เพราะมัน Cache ได้ และเก็บได้อย่างทั้ง NuGet / Maven / NPM / Container ตอนนี้มี Helm
  • ส่วน GitLab มีใช้นะ แต่ทำไมใช้ Repository ของมัน จริงๆกลัวเรื่อง Vendor Lock เพราะใช้ตัว Community + Self Manage ถ้ามีอะไรเปลี่ยน อย่าง License มันจะลำบากเลยแยก nexus ออกมา โดดๆอีกตัว แล้วให้มันคุยโยนของกันผ่าน Protocal https แทน

Helm in Nexus ตอนนี้ ถ้าดูใน Helm ยังมี

  • helm (hosted) - ใช้กับภายใน Local
  • helm (proxy) - ให้ nexus เป็นตัวแทนเราไปดึง จาก url ที่กำหนด เช่น https://artifacthub.io/ แล้วมันจะช่วย Cache ให้ด้วย
  • helm (group) - ยังไม่มี แต่อันนี้มีคนเปิด Ticker ไว้แล้ว อีกไม่นาน จะได้เห็น Add Helm group repository #409

Verying Helm Chart

การตรวจสอบ Helm Chart ของเราที่ทำ ว่ามัน work ไหม โดยมี 3 วิธี (helm lint / helm template / --dry-run) และ 1 พิเศษ --debug ( แบบสั่งบะหมี่เลย)

- helm lint
helm lint <path_to_helm> <option>
//sample
helm lint .

lint - บอก Syntax / ตรวจ โครงสร้างของ Chart คร่าวๆ / ตรวจ yaml format เรื่อง indent + space

  • พอมาลองจริง นอกจาก Error แล้ว มันยังแนะนำตาม Rule ด้วยนะ อย่างอันนี้ผมเอาตัว Helm ที่ใช้ได้มาลอง มันบอก ควรใส่รูป icon นะ

แล้วถ้าลองให้ Error

  • yaml มันบอกนะ พวก space error นะ ที่เจอปัญหาพวกนี้ เอา vscode plugin Prettier มาช่วยได้
  • ที่ลองมาพวก pre-define จะ Error อย่างพวก .Release.xxx / .Chart.xxx / .Capabilities ที่มันมีตัวแปรพิเศษที่มัน build-in มันจะตรวจให้ อย่าง .Capabilities.KubeVersion > .Capabilities.Kubeversion น่าจะชื่อไม่ตรงกับ Struct
  • แต่ถ้าเป็นกลุ่ม .Values.xxx มันจะดักได้เฉพาะ ส่วนแรก Values ถ้าเขียนผิด มันดักได้ส่วนค่าข้างหลังตรวจไม่ได้
  • ลองแก้นามสกุลของไฟล์เป็น json มันตรวจได้นะ

==> Linting .
[INFO] Chart.yaml: icon is recommended
[ERROR] templates/configmap.json: file extension '.json' not valid. Valid extensions are .yaml, .yml, .tpl, or .txt

- helm template

Template - ลองให้ helm render yaml ของ k8s ว่าค่าที่ได้จะเป็นยังไง

สำหรับที่เรียนมา มันตอบปัญหาที่ผมจดไว้ใน Blog ตอนก่อนหน้าด้วย ตอนแรก ผมเข้าใจว่า พวก Release Name มันต้องลงจริง ถึงจะได้ค่ามา แต่จริงๆแล้ว Syntax Helm Template

helm template <relase_name> <path_to_chart> <option>
//หิวพอดี ตั้งชื่อ release ชายสี 5555
helm template chai4 . 

ลองดูเต็มๆได้จาก Blog ของตอนที่ 3: จดๆ ลงมือทำ Helm Essential > Helm Package

- helm .... --dry-run

ลองต่อกับ Kube Cluster แล้วให้มันส่งผลลัพธ์กลับมา โดย option --dry-run มีเกือบทุก Command ของ Helm แต่ต้องตรวจสอบด้วย ดูจาก help ของแต่ละคำสั่ง โดย dry-run

ปล Sample dry-run ดูได้จาก blog ตอนที่ 2 ตอนนั้นสงสัยว่า kubectl มี dry-run client แลัว helm มีไหมเลยได้ลอง และ cap จดๆไว้นิดหน่อย

ค่าที่เป็นไปได้ ลองใส่มั่วๆให้มันด่า มันบอกว่ามี 5 ค่า

PS D:\2024Helm\sample> helm template . --dry-run=foo
Error: Invalid dry-run flag. Flag must one of the following: false, true, none, client, server

ถ้าอยากรู้ว่ามันใช้ได้/ไม่ได้ อีกท่าที่คุณโจ้สอน เอาสิ่งที่ helm template มา render สงให้ kube ลองเลย ผมจะประมาณนี้ kubectl apply -f - ตัว - ดึงจากตัว std io ที่ helm template print มายัด

helm template chai4 . | kubectl apply -f - --dry-run=client
helm template chai4 . | kubectl apply -f - --dry-run=server 

#หรือ ส่งไป Run จริงเลย 
helm template chai4 . | kubectl apply -f -
- helm .... --debug

--debug เปิด debug mode ของ go มาดูว่าพังที่ไหน โดยเป็น Global Flag ของ helm โดยดูจาก help มันจะเรียกใช้ได้ทุกคำสั่ง ดังนั้น helm lint / helm template / --dry-run เอา --debug มาให้คู่เสริมได้เหมือนกัน อารมณ์แบบสั่งพิเศษ

สุดท้ายการที่มี Lint / Template / --dry-run / --debug มันแค่เป็นการลดความเสี่ยงที่จะเอาไปติดตั้งบน kube แล้วพังเท่านั้น อย่าลืมลองจริง ก่อนส่งงานด้วยนะ

Writing Helm Chart

- helm function

งานที่มันซ้ำ หรือ ต้องใช้บ่อยๆ ไม่ต้องมาเขียนเอง แบบพวก string upper / lower เป็นต้น โดยเราสามารถเรียกใช้ function ได้ อย่างเช่น

  • ลองใช้ตัวเดียว ตัว default
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: {{ default "dotnetapp" .Values.appName }} 
    release: {{ .Release.Name }}
  name: {{ .Values.appName }}
...

ถ้าต้องการใช้ 2-3 อันต่อกันทำยังไง

  • ใช้ pipe ต่อกัน  app: {{ default "dotnetapp" .Values.appName | upper | quote }}
  • เรียก function ซ้อนกัน app: {{ quote (upper (default "dotnetapp" .Values.appName)) }} เหมือน coding เลย ตัว Helm ทำจาก Go เลยใช้แบบนี้ได้

ตัว _ หน้าชื่อไฟล์ _xxx.yaml บอกว่า ให้ helm ไม่ต้อง Generate

- helm control flow
  • if / else เหมือนใน coding ทั่วไป
{{- if <expression> }}
...
{{- else if <expression> }}
...
{{- end }}
  • โดยที่ต้องเติม - หน้า if เพราะต้องการตัดบรรทัดเกิน ทำให้อ่านยาก โดย {{ template direction }} มีรูปแบบ trim ดังนี้
{{- trims all whitespace to the left of the expression.
trims all whitespace to the right of the expression. -}} 

แต่ มันต้องติดปีกกานะ
{{- if   << ทำงานได้
{{ - if  << error 

จากตัว if มันสามารถทำตัว feature toggle ขึ้นมาได้ เช่น

  • กำหนดจำนวน replica ใน prod เอาไปเลย ตามในไฟล์ value ที่กำหนด แต่ไม่ใช่ เช่น dev test ให้แต่ 2 ถ้าให้ label ผิด ให้ไปเลย 1 ตัว Deployment เดิม เราเติมเงื่อนไขเข้าไป ตามนี้
//deployment
spec:
  {{- if eq .Values.environment "prod" }}
  replicas: {{ .Values.replicaCount }}
  {{- else if or (eq .Values.environment "test") (eq .Values.environment "dev") }}
  replicas: 2
  {{- else }}
  replicas: 1
  {{- end }}
  selector:
    matchLabels:
      app: {{ .Values.appName }}
  strategy: {}
  • ไม่จำเป็นต้องสร้าง kube object เช่น service ถ้าใช้ภายในนั้น หรือ ให้ pod มันทำงานเงียบๆไป ก็ทำ if ครอบที่ต้น และท้ายไฟล์เลย

พวก operator ที่เป็นไปได้ Helm | Template Functions and Pipelines - Operators are functions

- helm with block

ตอนเรียน ผมฟังครั้งแรกนึกถึงพวก with ของ vba นะ มันเอาไล่ลดการอ้างอิง เรียกว่า Code สะอาดขึ้น สำหรับใน Helm ทำหน้าที่คล้ายๆกันนะ

  • ก่อนอื่นตัว Values.yaml มันแปลงเป็น tree ได้นะ > Binary tree ถ้าอยากให้เร็ว ลดลง level Optimize เรื่อง search
  • ตัว tree แล้วที่นี้ถ้าอยาก access ถึงค่านั้นเร็วๆ เรากำหนด scope ให้มันชัด มันจะเลื่อนมาจุดที่สนใจ
  • แต่มีข้อเสีย อยู่ใน with แล้ว เราจะอ้างอืงถึงข้อมูลอื่นๆไม่ได้นะ ถ้าต้องการจริงๆ $ เพื่อให้กลับไป root (Line 8-9)
{{- if .Values.service.enabled -}}
apiVersion: v1
kind: Service
{{- with .Values.service }}
metadata:
  name: {{ .name }}
  labels:
    app: {{ default "dotnetapp" $.Values.appName | upper | quote }} 
    version: {{ $.Chart.AppVersion }}
spec:
  selector:
    app: aspnetapp
  ports:
  - name: http
    protocol: TCP
    port: {{ .port }}
    targetPort: {{ .targetPort }}
    nodePort: {{ .externalPort }}
  type: NodePort
{{- end -}}
{{- end -}}

ควรมีกี่ level จริงๆแล้วแต่ Use-Case แต่ปกติ 3-5 เพราะ ถ้ายิ่งเยอะ จะยิ่งอ่านยาก สุดท้ายขึ้นกับข้อตกลงของทีม

  • อีกอัน เรื่องของ with การใช้ซ้อนกัน มันอาจจะอ่านยากขึ้น แบบตัวอย่างด้านล่าง ต้องมาแบ่งให้ดี อันนี้เอามาจาก appsetting ถ้าวาดเป็น Tree มันจะหนักขวา
apiVersion: v1
kind: ConfigMap
metadata:
  name: aspnetcore-config
data:
  {{- with .Values.appSettings }}
  appsettings.json: |
    {
    {{- with $.Values.appSettings.Logging.LogLevel }}
      "Logging": {
        "LogLevel": {
          "Default": {{ .Default | quote }},
          "Microsoft": {{ .Microsoft | quote }},
          "Microsoft.Hosting.Lifetime": {{ .MicrosoftHostingLifetime | quote }}
        }
      },
    {{- end }}
      "AllowedHosts": {{ .AllowedHosts | quote }},
      "ConnectionStrings": {
        "DefaultConnection": {{ .ConnectionStrings | quote }}
      }
    }
  {{- end }}
appSettings: 
  Logging: 
    LogLevel: 
      Default: Information
      Microsoft: Warning
      MicrosoftHostingLifetime: Information
  AllowedHosts: "example.com;localhost"
  ConnectionStrings: "example_connection_string"
  • และ helm lint ตรวจได้นะ ตามรูป

อีก usecase ของ with เอาไว้ set ค่าเยอะๆ ในกลุ่ม configmap กับ value.yaml นอกจากนี้แล้วมี kustomize มันเอา env / app.setting มาได้ เพราะบางอย่าง configmap มันต้องเอา value.yaml มา map อีกที

  {{- with .Values.favorite }}
  drink: {{ .drink | default "tea" | quote }}
  food: {{ .food | upper | quote }}
  release: {{ $.Release.Name }}
  {{- end }}

/////////////////////////////////////////
  {{- with .Values.favorite }}
  drink: {{ .drink | default "tea" | quote }}
  food: {{ .food | upper | quote }}
 {{- end }}
  release: {{ .Release.Name }}
- helm range

เอาไว้ให้ทำงานที่ซ้ำ เอาค่าในที่กำหนดไว้เป็น List มา for each ตัวอย่างผมเอามาจาก helm.sh ไปงมกับอีกโจทย์ที่อยากลอง

  • values.yaml
favorite:
  drink: coffee
  food: pizza
pizzaToppings:
  - mushrooms
  - cheese
  - peppers
  - onions

แล้วยัดค่าลงมา เริ่มบรรทัดที่ 9

  • บรรทัด 9 toppings: |- บอกว่าเป็น multiline string
  • บรรทัด 10-12 เข้า Loop ดึงค่าจาก pizzaToppings จากนั้นเข้า pipe
    - Title ทำให้ตัวใหญ่ขึ้น
    - quote
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  {{- with .Values.favorite }}
  drink: {{ .drink | default "tea" | quote }}
  food: {{ .food | upper | quote }}
  toppings: |-
    {{- range $.Values.pizzaToppings }}
    - {{ . | title | quote }}
    {{- end }}    
  {{- end }}

พอมาคิดว่าจะใช้จริงตรงไหนได้ configmap น่าจะ 1 ที และอีกจุดเลยย้อนมาคิดถุึง blog ลง Ingress-nginx ผิด พังยาวเลย ตรง ingress ที่เรา Config มันจะมี pattern น่าจะใช้ได้ เลยให้ map เอง คิด nested loop ตบตีมาครึ่งวันได้จะได้แบบนี้ //ถ้าถาม AI อาจจะไวกว่า 55

  • ingress template
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /
  name: ingress-production
  namespace: application
spec:
  ingressClassName: nginx
  rules:
  {{- range .Values.ingress.rules }}
    - host: {{ .host }}
      http:
        paths:
          {{- range .paths }}
          - path: {{ .path }}
            pathType: {{ .pathType }}
            backend:
              service:
                name: {{ .serviceName }}
                port:
                  number: {{ .servicePort }}
          {{- end }}
    {{- end }}
  • values.yaml ของมัน
ingress:
  rules:
    - host: admin.pingkunga.dev
      paths:
        - path: /
          pathType: ImplementationSpecific
          serviceName: admin-console
          servicePort: 4200
    - host: user.pingkunga.dev
      paths:
        - path: /
          pathType: ImplementationSpecific
          serviceName: user-console
          servicePort: 3000
    - host: api.pingkunga.dev
      paths:
        - path: /api/dashboard
          pathType: ImplementationSpecific
          serviceName: dashboard-service
          servicePort: 5000
        - path: /api/payment
          pathType: ImplementationSpecific
          serviceName: payment-service
          servicePort: 1323
        - path: /api/report
          pathType: ImplementationSpecific
          serviceName: report-service
          servicePort: 4000
        - path: /api/order
          pathType: ImplementationSpecific
          serviceName: order-service
          servicePort: 10456

ลองแล้วดูผ่านๆ เหมือนตันฉบับอยู่นะ แล้วด้วยความสงสัยไปส่อง Sample ของ helm ตอน new ขั้นมา มันซับซ้อนกว่าเยอะมาก แต่ดูทรงคล้ายๆกัน

- helm Named Templates

ปัญหา เรามีส่วนของ yaml ซ้ำซ้อนกันให้ทุกจุด และอยากให้การแก้ไข ทำได้จากจุดเดียว และให้ทุกจุดเอาไป Apply เอง จะตรงกันแนวคิด DRY (Don’t Repeat Yourself) นะ พอทุกจุดมันสอดคล้องกัน เราข้อมูลในจุดนั้นไปใช้งานต่อได้ เช่น กำหนด pattern ของ label เอาข้อมูลตรงนั้นมีวิเคราะห์ Cost (FinOps) ได้

ใน Helm มีตัวช่วยมาให้ โดยการทำ Named Templates ซึ่งจะมีไฟล์ _xxxxx.tpl

  • _ บอกให้ตัว helm ไม่เอาไป Generate
  • .tpl บอกให้ตัว helm รู้ว่าต้องเอา ข้อความจากนี้ไปตัดแปะต่อ เพราะในส่วนนี้มันเป็น partial ที่ถูกำหนดไว้ตาม {{- define <your_key> }} เท่าน้้น

การใช้งาน Named Templates

1. เรียกใช้ผ่าน {{- template <your_key> <replace_scope> }}

  • ถ้าไม่ใส่ <replace_scope> มันจะแก้ไขค่าตัวแปรไน template ไม่ได้ เพราะไม่รู้ Scope

ข้อเสียนี้ มันไม่จัด indent ให้นะ พวก yaml มันจะ error ได้ มันเอาค่ามา replace ตรงๆ

2. เรียกใช้ผ่าน {{- include <your_key> <replace_scope> }} ทำงานเหมือนกับตัวแรก มันเป็น function เลยเราเลยสามารถทำ pipeline เรียก func indent ได้

เรื่องของ replace scope หากเราส่ง . ไป หากมันถูกครอบด้วย with จะเกิดปัญหาหาของไม่เจอ บางทีต้องส่ง $ แทน

นอกจากนี้แล้ว ตัว Named Templates ถ้ามัน Common มากๆ จนเอาไปใช้งานกับหลายๆ Helm Chart ได้ จะถูกยกเป็น dependeny ให้ Chart อื่นๆได้นะ

Ref: Helm | Named Templates / https://stackoverflow.com/questions/63196657/helm-how-do-we-decide-indent-value-in-helm-templates


Chart Hooks

สำหรับตัว ChartHooks โดยผมมีอะไรที่สงสัยที่ลองแปะไว้ใน Blog ตอน 2 ลองวาด Flow ออกมาไว้เป็นภาพนี้

ภาพนี้เหมือนจะขาดในส่วน Test ไป

พอเรียนแล้วลองมาจด Recap กันต่อ ว่า Chart Hooks เป็นจุดให้ที่เราแทรก Action ต่างๆได้ ก่อนที่จะมี Action ต่างๆ install / upgrade / rollback / uninstall / test มี 5 ส่วน โดยแต่ละแบบ 2 กลุ่ม ตาม Event

  • Pre / Post Event- ก่อน action install / upgrade / rollback / uninstall
  • Test Event - เป็นกลุ่มพิเศษเลย

โดยก่อนจะเข้า action มันจะต้องผ่าน Step verify (ตาม Lint) / render (ตาม logic ที่เราเขียนลงไป) จากนั้นเข้าส่วนของ Chart Hooks โดยภาพใหม่ของผม จะประมาณนี้

ลองปรับจากภาพที่แล้วที่เข้าใจนิดหน่อย

ถ้าเริ่มทำ Chart Hooks โดยการที่จะรู้ว่าของอันนั้นเป็น Hook ต้องมี annotation ส่วนใหญ่ของใน Hook จะเป็นแบบ job ทำแล้วจบไป โดยมี annotations ที่เปลี่ยนข้อง

  • "helm.sh/hook": บอกว่า yaml นี้ อยู่ในส่วนไหนของ Hooks ถ้าไม่มี มันจัดเป็นส่วนนึงของ release เลย
  • "helm.sh/hook-weight": บอกลำดับของการ Hooks ตามกลุ่ม "helm.sh/hook" ถ้าเลขน้อย จะถูกทำเป็นตัวแรก สมมิตเลขเรียงตามนี้ -1 < 1 < 5 ลำดับเริ่มจาก -1 ก่อน
  • "helm.sh/hook-delete-policy": ป้องกันมี resource ของ hook เหลือ (Clean-Up) โดยมี 3 แบบ
    - before-hook-creation - ถ้ามีของเดิม ให้ลบทิ้ง (Default)
    - hook-succeeded - ลบเมื่อทำสำเร็จ
    - hook-failed - ลบแม้ว่าจะ fail

ตัว hook อาจจะไม่จำเป็นต้องใช้ได้ ก็ได้นะ ตัว helm เองจะการจัดการ state ของมัน เช่น ถ้ามัน fail ให้มัน

helm upgrade <release_name> <path_to_chart> -f [your_value.yaml] --cleanup-on-fail

แต่ถ้าลองแล้ว มันซับซ้อนกว่านั้นมาลอง implement pre-upgrade / post-upgrade

- ลองเล่น Chart Hooks

โจทย์ ก่อนจะ helm upgrade ลองส่งเมล์ดู จะอยู่ใน event pre-upgrade และเป็น job สั้นๆ

#==================
# Pre-upgrade Values
smtp:
  user: <sender_mail>@gmail.com
  pass: <sender_app_password>
  to: <recipient_mail@example.com?
  subject: "Helm Chart Upgrade Notification"
  body: "The Helm chart Start Upgrade."
  • ทีนี้ตัว helm chart ของเรามาเพิ่ม job ลง และแน่นอน คิดว่ามันไม่น่าจะ secure นะ เอา user pass replace โต้งๆ บรรทัดที่ 5-7 ส่วนสำคัญเลย ใส่ annotation บอก ตอนแรกผมใส่ Label ไป มันส่งทุกรอบ 555555
    - "helm.sh/hook": pre-upgrade //ให้ทำตอน pre-upgrade
    - "helm.sh/hook-delete-policy": hook-succeeded //ถ้าทำจบให้ delete job ทิ้ง
apiVersion: batch/v1
kind: Job
metadata:
  name: "{{ .Release.Name }}-pre-upgrade-email"
  annotations:
    "helm.sh/hook": pre-upgrade
    "helm.sh/hook-delete-policy": hook-succeeded
spec:
  template:
    spec:
      containers:
      - name: send-email
        image: alpine:3.12
        command: ["/bin/sh", "-c"]
        args:
          - |
            apk add --no-cache msmtp ca-certificates && \
            # Email details
            SMTP_USER="{{ .Values.smtp.user }}" \
            SMTP_PASS="{{ .Values.smtp.pass }}" \
            TO_EMAIL="{{ .Values.smtp.to }}" \
            SUBJECT="{{ .Values.smtp.subject }}" \
            BODY="{{ .Values.smtp.body }}" && \
            # Create msmtp configuration
            cat <<EOF > /etc/msmtprc
            defaults
            auth           on
            tls            on
            tls_trust_file /etc/ssl/certs/ca-certificates.crt
            logfile        /var/log/msmtp.log

            account        gmail
            host           smtp.gmail.com
            port           587
            from           ${SMTP_USER}
            user           ${SMTP_USER}
            password       ${SMTP_PASS}

            account default : gmail
            EOF

            # Send email
            echo -e "Subject:${SUBJECT}\n\n${BODY}" | msmtp --debug --from=${SMTP_USER} -t ${TO_EMAIL}
      restartPolicy: Never
  • ลอง install ของผมยังไม่ได้ pack ลองแบบนี้ helm install netapp .
  • จากนั้นไปที่ Chart.yaml แล้วแก้ตัว version: 0.1.1 ของผมแก้เป็น version: 0.1.2
  • ลอง upgrade helm upgrade netapp .
    แต่ก่อนจะรันแอบไปเปิด Terminal อีกอัน แล้ว run while (1) {kubectl get pod; sleep 1} //powershell นะ จะเห็น job มันทำงาน และเด้งเมล์มา

อีกอันที่ลองตรวจ version helm เหมือนมันจะเอ๋อๆอยู่ ถ้ามัน OK เขียนลงอีก blog ครับ อยากลองแบบพวก DB แต่ DB ยังสาย docker compose / VM อยู่

Ref: Helm | Chart Hooks

อื่นๆ

  • Q:ควรใช้ Chart เดียว หรือ แยก Sub Chart ย่อยๆเยอะๆ ทำ Common
    - ทำความเข้าใจ ก่อน
    -> อาจจะรวม Chart เดียว และทำ Feature Toggle
    -> แต่ถ้ามันเป็นคนละ Domain อย่าง เช่น ของ Bitnami Nginx / Nexus / Redmine อันนี้เค้าทำ Common ขึ้นมา เพื่อกำหนดแนวทางให้ไปทางเดียวกัน เช่น พวก partial / name / error
  • Q: กรณีเราใช้ third-party chart  ควรเป็น Value อย่างไร
    - เก็บที่ทำแยกไว้ ส่วน Chart ถ้ามี Repository ในองค์กร อย่าง nexus ก็โยนขึ้นไป รวมกันใช้ที่ Repo กลางแทน
  • พวก chart มี test ด้วยนะ และมี tools สำหรับทำ CI เช่น kind action - small k8s chart test / chart-testing Action

Blog ของท่านอื่น

เขียน blog นี้จบ ว่าจะหนีไป podman desktop / docker desktop มันกิน Ram เกิ๊นนน เรียนเสร็จ เหลือเอาไปลอง pack จริงๆและว่าจะเจออะไรบ้างครับ หากอ่านแล้วชอบสนใจเรียนติดต่อคุณโจโจ้ JumpBox ครับ ^__^


Discover more from naiwaen@DebuggingSoft

Subscribe to get the latest posts sent to your email.