มาลองทำ GitOps ด้วย ArgoCD

Kubernetes 1 ก.ค. 2022

เนื่องจากว่าช่วงนี้ผมกำลังหา tools ใหม่ๆ สำหรับการทำโปรเจคจบ ซึ่งผมได้ออกแบบไว้ว่าจะใช้ Kubernetes ในการรัน applications โดยสำหรับ Kubernetes แล้ว เรามี "ท่า" มากมายในการทำ CI/CD โดยไม่ว่าจะเป็น kubectl apply ตรงๆ หรือว่าการใช้ Kustomize ซึ่งในงานที่ผ่าน ๆ มา ผมได้เลือกใช้ GitHub Actions ในการรัน kubectl apply เป็นส่วนใหญ่ ครั้งนี้จึงอยากที่จะลองวิธีใหม่ ๆ บ้าง จนได้มาเจอกับ GitOps

GitOps

GitOps คือการสร้างระบบ Continuous Delivery (CD) ด้วย tools ที่เราใช้กันเป็นอยู่แล้ว ซึ่งก็คือ Git นั้นเอง โดยเราจะทำการเก็บสิ่งต่าง ๆ ที่ใช้ในการสร้าง infrastructure ให้ application ของเรา ให้อยู่ใน Git repository และเมื่อข้อมูลในนั้นมีการเปลี่ยนแปลง (มี commit ใหม่) ระบบก็จะจัดการสร้างสิ่งต่าง ๆ ที่เราทำการระบุไว้ใน Git ให้โดยอัตโนมัติ

โดยข้อดีของ GitOps ที่ผมชอบมากๆ ก็คือการที่เราใช้ Git นั้นเป็น single source of truth สิ่งที่มันอยู่ใน Git ก็จะตรงกับสิ่งที่เราใช้งานอยู่เสมอ การแก้ไขทุกอย่างจะต้องทำผ่าน Git ทำให้เราไม่มี configuration ที่ผิดเพี้ยนไปจากที่เราเขียนไว้ และเมื่อเราใช้ Git เราก็จะได้ประโยชน์จากการทำงานของ Git ด้วยอย่างเช่น การ revert commit ที่ทำได้ง่ายดายและการจัดการประวัติการแก้ไขทั้งหมด

ถ้าหากใครสนใจเรื่อง GitOps สามารถอ่านบทความของคุณ Somkiat ได้ที่ GitOps คืออะไร

Argo CD

ซึ่ง tools ที่ผมสนใจและเลือกมาทดลองใช้ก็คือ Argo CD โดยตัวของ Argo CD ทำงานในรูปแบบ pull deployment ซึ่ง Argo CD ที่เราติดตั้งลงไปใน Kubernetes Cluster ของเรา จะเฝ้าดู Git Repository และทำให้ states ใน Cluster ของเราตรงกับที่ config ที่อยู่ใน Git และเมื่อมี commit ใหม่ใน Git repository มันก็จะทำการจัดการ สร้าง ลบ อัพเดท resources ต่างๆ ใน cluster ของเรา ให้ตรงกับใน Git นั้นเอง

Setup Argo CD

ก่อนที่เราจะเริ่มใช้งาน Argo CD เรามีสองอย่างที่เราต้องมีก็คือ

1) ติดตั้ง Argo CD ใน Kubernetes Cluster

เราสามารถติดตั้ง Argo CD ได้ผ่านคำสั่ง

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

ซึ่งคำสั่งนี้เป็นการติดตั้งแบบ Non-High Availability ซึ่งไม่แนะนำสำหรับการใช้ใน production การติดตั้งรูปแบบอื่นสามารถดูได้จาก Installation Manual ของ Argo CD

2) Git repository ที่เก็บ Kubernetes manifest ไว้

สำหรับ Git repository ก็ต้องอยู่ในที่ ที่ Argo CD จะสามารถเข้าถึงได้ ไม่ว่าจะเป็น GitHub หรือที่อื่นๆ โดยถ้าหากเป็น private repository เราก็จะต้องเพิ่ม credential ให้ Argo CD เข้าถึงได้ด้วย แต่ผมจะขอใช้เป็น public repository เพื่อความง่ายในการ demo

ซึ่งสิ่งที่ผมจะเอามา demo ก็เป็น Todo app ง่าย ๆ ที่เคยทำไว้ตอนไปพูดเรื่อง Basic of Kubernetes with Google Kubernetes Engine สามารถเข้าไปดู Code ได้ที่ repo นี้เลย

การที่เราจะให้ Argo CD จัดการสร้าง Kubernetes resources ขึ้นมา เราจะต้องสร้างสิ่งที่เรียกว่า Application ขึ้นมา ในเว็บไซต์เขาให้คำจำกัดความไว้ว่า มันคือ

A group of Kubernetes resources as defined by a manifest

แปลเป็นไทยก็คือ Kubernetes resources จำนวนหนึ่งหรือมากกว่า ที่ถูกเขียนไว้ใน config/manifest file อย่างเช่น YAML หรือ Helm Chart

ดังนั้นเราจะสร้าง application ขึ้นมา 2 ตัวก็คือ nginx-ingress ที่เราจะเอามาจาก Helm Chart และ todo-app ที่จะสร้างจาก Kubernetes manifest (YAML) ซึ่งประกอบไปด้วย backend, frontend, และ database รวมไปถึง PVC และ service ต่าง ๆ ด้วย

Access Argo CD UI Interface

Argo CD มีช่องทางให้เราเข้าไปจัดการการทำงานของตัวมันได้อยู่หลายวิธี ไม่ว่าจะเป็น CLI,  Web UI หรือ delarative file โดยเพื่อความง่ายในการจัดการเราสามารถเข้าถึง Web UI ได้โดยการเข้าถึง service argocd-server ที่ port 443 ซึ่งผมจะใช้วิธีการ forward port เพื่อเข้าถึง service นี้ผ่านคำสั่ง

kubectl port-forward svc/argocd-server -n argocd 8080:443

ทีนี้ถ้าเราเข้าไปที่ http://localhost:8080 เราก็จะเจอกับหน้า login ของ Argo CD ที่ทำงานอยู่ใน cluster ของเราแล้ว โดยมี username เป็น admin และ password สามารถดูได้จากการรันคำสั่ง kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}"| base64 -d;echo

พอเข้ามาในหน้า UI แล้วเราก็จะเจอกับ dashboard ที่บอกเราว่าเรายังไม่มี application อะไรอยู่เลย ดังนั้นเราจะเพิ่ม application เข้าไปให้ Argo CD นำไปสร้าง resources ใน Kubernetes cluster ของเรากัน

Deploy Application with Helm Chart

สำหรับตัว nginx-ingress เราจะใช้ Helm Chart ในการ deploy ดังนั้น เราก็สามารถกดเลือก Create Application โดยสิ่งที่เราต้องใส่ก็จะมีตามนี้

General

  • Application Name: ชื่อเรียกของ Application ของเราใน Argo CD
  • Project Name: ชื่อ project ใน Argo CD โดยปกติแล้วจะมีอยู่อันเดียวคือ default ซึ่งเราสามารถสร้างเพิ่มได้
  • Sync Policy: คือการตั้งค่าว่าเราต้องการจะให้ Argo CD สร้าง ปรับเปลี่ยน เพิ่มลด Kubernetes resource โดยอัตโนมัติเลยรึเปล่า ซึ่งในกรณีนี้เราต้องการ ดังนั้นให้เลือกเป็น Automatic ถ้าหากเราเลือกเป็นแบบ Manual เราก็จะต้องมากด Sync ให้มันทำงานเอง
  • Prune Resources: กำหนดว่าถ้าเราลบ manifest นั้นออกจาก Git ไป ให้ Argo CD ลบ resource นั้นออกจาก cluster เราด้วยรึเปล่า ซึ่งให้เลือกตัวนี้ด้วย
  • Self Heal: ใช้กำหนดว่าถ้าหากมีใครแก้ไขอะไรที่ทำให้ states ของ Cluster ไม่ตรงกับ Git จะให้ Argo CD บังคับให้กลับเป็นเหมือนใน Git ซึ่งให้เลือกตัวนี้ด้วยเช่นกัน

Source

  • Repository URL: คือ Repo URL ของ Chart หรือ Git นั้นๆ อย่างเช่น https://kubernetes.github.io/ingress-nginx
  • Chart: ชื่อของ Chart ที่เราต้องการ ซึ่งคือ ingress-nginx
  • Version: Version ของ Chart ที่เราต้องการจะใช้ 4.1.4 ก็จะเป็น version ล่าสุดของ ingress-nginx

Destination

  • Cluster URL: เลือก https://kubernetes.default.svc เนื่องจากเราต้องการสร้าง resource บน cluster ที่ Argo CD ทำงานอยู่
  • Namespace: คือ namespace ที่เราต้องการสร้าง resources ลงไป

ถ้าเราลองกดมุมขวาบน ตรงคำว่า EDIT AS YAML เราจะสามารถดูและแก้ไข configuration ของ Application ที่เรากำลังจะสร้างได้ ถ้าหากเราเซฟเก็บไว้ เราก็จะสามารถใช้คำสั่ง kubectl apply -n argocd -f <file-name> กับไฟล์นี้ได้เลย และถ้าหากเรามี Argo CD ที่ทำงานอยู่ใน cluster แล้ว มันก็จะให้ผลเหมือนกับการสร้าง Application ผ่านหน้า Web UI นั้นเอง

โดยเมื่อเรากด Create เราจะเห็นว่า Status ของ Application เรานั้นเป็น OutOfSync หมายความว่า Resource ใน manifest (ในที่นี้คือ Helm Chart) ไม่ตรงกับ Resource ที่อยู่ใน Cluster ของเรา และในเมื่อเราตั้ง Sync Policy เป็น Automatic ไว้ Argo CD จะทำการ Sync หรือว่าทำยังไงก็ได้ให้ Resource ใน cluster ของเรา ตรงกับ manifest เมื่อเรารอไปสักพักจะเห็นว่า Status เปลี่ยนเป็น Synced เมื่อมันทำการสร้าง resource เสร็จเรียบร้อย

K8S Manifest in Git

หลังจากเราได้ nginx-ingress มาแล้ว เราก็จะมา deploy todo application กัน โดยขั้นตอนก็จะเหมือนกับ nginx-ingress เลย ต่างกันแค่ตรงที่เราจะเลือก source ให้เป็น Git และใส่ Git repository URL ลงไปแทน โดยสำหรับการสร้าง Application ผมจะขอใช้เป็นแบบ declarative หรือว่าการเขียน config แล้วทำการ kubectl apply -f แทนการใช้ Web UI ตัว Configuration ก็จะมีหน้าตาประมาณนี้

# todo-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: todo-app # ชื่อของ application
  namespace: argocd # namespace ที่จะสร้าง resource นี้ ต้องตรงกับ namespace ที่เราติดตั้ง Argo CD ไว้
spec:
  destination:
    namespace: default # deploy ลงไปที่ default namespace
    server: 'https://kubernetes.default.svc'
  source:
    path: k8s # directory ที่เก็บไฟล์ manifest ไว้
    repoURL: 'https://github.com/thetkpark/argo-cd-example.git' # Git repo 
    targetRevision: HEAD # จุดใน Git ที่ให้ Argo CD นำไปใช้
    directory:
      recurse: true # ให้หาไฟล์ manifest ที่อยู่ใน sub-directory ด้วย
  project: default
  syncPolicy:
    automated:
      prune: true # ลบ resource ที่ไม่ได้อยู่ใน Git แล้วทิ้ง
      selfHeal: true # จัดการให้ states ของ cluster เหมือนกับใน manifest โดนอัตโนมัติ
todo-app.yaml

เราก็เพียงใช้คำสั่ง kubectl apply -f todo-app.yaml เพียงเท่านี้ เราก็จะได้ Application ที่ Argo CD จะช่วยจัดการเรียบร้อยแล้ว

Explore the Web UI

หน้าหลักที่แสดง Application ใน Argo CD ทั้งหมด

Web UI ของ Argo CD เป็นสิ่งที่อำนวยความสะดวกให้เราสามารถสร้าง Application ได้อย่างง่ายดาย นอกจากนี้มันยังเป็น dashboard เพื่อบอกสถานะของ Application ของเราได้อย่างดีอีกด้วย

Resources ใน cluster ที่ Argo CD ดูแลอยู่

เมื่อเราคลิกเข้ามาดูใน Application ที่เราสร้างไว้ เราจะเห็นกราฟว่า Application ของเรา ประกอบไปด้วย resources อะไรบ้าง และสถานะของแต่ละอย่างเป็นอย่างไร ทำให้เราสามารถที่จะดูและ debug ปัญหาที่เกิดขึ้นได้อย่าง่ายดายมาก ๆ

Log จาก Pods

เราสามารถที่จะกดเข้าไปดูใน resources แต่ละตัว อย่างเช่น Pod ที่ทำงานอยู่ เพื่อดู event และ logs ได้เช่นกัน

Event ของ Pods

When Changes Occured

จากที่เราได้บอกไปแล้วว่า Argo CD คือสิ่งที่ทำงานกับ GitOps แล้วถ้าเราต้องการจะเปลี่ยน config ยกตัวอย่างเช่นเปลี่ยน image tag ของ deployment เราจะทำได้อย่างไร

ง่าย ๆ เลยครับ ก็คือแก้สิ่งที่เราจะแก้ แล้วก็ commit, push ขึ้น Git repository เท่านั้นเอง สมมติว่าผมอยากเปลี่ยน image tag ของ todo-backend ให้เป็น v2 ผมก็ทำการแก้ไข YAML ของ backend-depl เป็นดังนี้

apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend-depl
spec:
  replicas: 3
  selector:
    matchLabels:
      app: todo-backend
  template:
    metadata:
      labels:
        app: todo-backend
    spec:
      restartPolicy: Always
      containers:
      - name: backend-depl
        image: thetkpark/gdsc-basic-k8s-todo-server:v2
        resources:
          limits:
            memory: "32Mi"
            cpu: "20m"
        ports:
        - containerPort: 5050
        envFrom:
          - configMapRef: 
              name: todo-app-configmap
          - secretRef:
              name: todo-app-secret
backend-depl.yaml

แล้วจึงทำการ commit และ push ไป

Argo CD ก็จะพบว่ามี commit ใหม่ขึ้นมา และทำการดูไฟล์ manifest ว่ามีอะไรไม่ตรงกับ state ของ cluster ตอนนี้รึเปล่า และถ้ามีก็จะจัดการทำให้มันตรงกัน อย่างในกรณีนี้ก็คือการเปลี่ยน image ของ backend-depl ใน todo-app นั้นเอง

todo-backend เปลี่ยนเป็น version 2 เรียบร้อย

ซึ่งกระบวนการการเช็ค Git Repository จะมีการเช็คทุก ๆ 3 นาที ซึ่งเราสามารถที่จะปรับแต่งได้ตามใจเรา ส่วนถ้าหากใครต้องการเห็นผลเลย เราก็สามารถกดปุ่ม Refresh เพื่อบังคับให้ Argo CD ทำการเช็ค Git Repository ได้เลย

ใน Sync status จะแสดงว่า commit ที่ sync เข้ามาล่าสุดคือ commit อะไร

แท็ก

Sethanant Pipatpakorn

Innovation Engineer @ KLabs, KBTG CS20 SKN36