0

Lab 1 — GitOps Fundamentals

🎯 Mục tiêu

Sau lab này, bạn sẽ:

  • Hiểu GitOps là gì và tại sao Git có thể trở thành Source of Truth.
  • Phân biệt được cách deploy truyền thốngdeploy theo GitOps.
  • Hiểu vai trò của Git Repository, CI, CD và Kubernetes trong GitOps.
  • Hiểu khái niệm Desired StateActual State.
  • Tự xây dựng một workflow GitOps đơn giản bằng Kubernetes và Git.

1. 🤔 Vấn đề thực tế

Hãy tưởng tượng bạn đang vận hành một Kubernetes cluster.

Một ngày bình thường, developer yêu cầu:

"Anh deploy version v1.2.0 lên production giúp em."

Bạn có thể làm:

kubectl set image deployment/todo-backend \
  todo-backend=myapp:v1.2.0

Kiểm tra:

kubectl rollout status deployment/todo-backend

Mọi thứ có vẻ ổn.

Nhưng vài ngày sau, một vấn đề xảy ra.

Một DevOps Engineer khác chạy:

kubectl set image deployment/todo-backend \
  todo-backend=myapp:v1.1.0

Production lại quay về version cũ.

Vấn đề nằm ở đâu?

Kubernetes hiện tại đang chứa trạng thái:

Production Kubernetes

todo-backend
└── image: myapp:v1.1.0

Nhưng Git repository lại ghi:

Git

todo-backend
└── image: myapp:v1.2.0

Hai nơi đang có hai sự thật khác nhau.

       Git
       │
       │ v1.2.0
       ▼
   ┌─────────┐
   │   ???   │
   └─────────┘
       ▲
       │ v1.1.0
       │
  Kubernetes

Đây chính là một trong những vấn đề GitOps muốn giải quyết.


2. 🧠 GitOps là gì?

GitOps là cách quản lý và vận hành hệ thống trong đó:

Git repository là nơi lưu trạng thái mong muốn của hệ thống.

Thay vì DevOps Engineer trực tiếp thay đổi production bằng:

kubectl apply
kubectl edit
kubectl set image

ta thay đổi configuration trong Git:

Git
 │
 │ git push
 ▼
GitOps Repository
 │
 ▼
GitOps Tool
 │
 ▼
Kubernetes

Ví dụ:

Bạn muốn deploy:

myapp:v1.2.0

Thay vì:

kubectl set image ...

Bạn sửa Git:

image: myapp:v1.2.0

Sau đó:

git add .
git commit -m "Deploy myapp v1.2.0"
git push

GitOps tool sẽ phát hiện thay đổi và đưa Kubernetes về trạng thái đó.


3. 🔑 Hai khái niệm quan trọng: Desired State và Actual State

Đây là phần quan trọng nhất để hiểu GitOps.

3.1. 🎯 Desired State

Desired State là trạng thái mà bạn muốn hệ thống có.

Ví dụ Git chứa:

replicas: 3

image: myapp:v1.2.0

Điều đó có nghĩa:

Tôi muốn Kubernetes chạy 3 Pod với image myapp:v1.2.0.

Đây chính là Desired State.


3.2. ⚙️ Actual State

Actual State là trạng thái thực tế đang chạy trên Kubernetes.

Ví dụ:

Kubernetes

replicas: 3
image: myapp:v1.1.0

Khi đó:

Desired State
image: v1.2.0

       ≠

Actual State
image: v1.1.0

Có sự khác biệt.

GitOps tool sẽ phát hiện:

        Git
    Desired State
         │
         │ compare
         ▼
    ┌───────────┐
    │ GitOps    │
    │   Tool    │
    └─────┬─────┘
          │
          │ difference
          ▼
    Kubernetes
     Actual State

Sau đó nó thực hiện reconciliation.

Reconciliation = đưa Actual State về lại Desired State.


4. 🔄 GitOps hoạt động như thế nào?

Một workflow GitOps cơ bản:

Developer
    │
    │ git push
    ▼
┌───────────────┐
│ Git Repository│
│               │
│ Desired State │
└───────┬───────┘
        │
        │ detect change
        ▼
┌───────────────┐
│ GitOps Tool   │
│               │
│ Compare       │
│ Reconcile     │
└───────┬───────┘
        │
        │ apply
        ▼
┌────────────────┐
│ Kubernetes     │
│                │
│ Actual State   │
└────────────────┘

Trong các lab tiếp theo, công cụ GitOps chúng ta sử dụng là Argo CD.


5. 🆚 Deploy truyền thống vs GitOps

5.1. 🛠️ Cách truyền thống

DevOps Engineer có thể trực tiếp chạy:

kubectl apply -f deployment.yaml

Hoặc:

kubectl set image ...

Flow:

Developer
    │
    ▼
DevOps Engineer
    │
    │ kubectl
    ▼
Kubernetes

Vấn đề:

  • Khó biết ai đã thay đổi production.
  • Có thể xảy ra thay đổi thủ công ngoài Git.
  • Khó audit.
  • Khó rollback.
  • Git không còn phản ánh chính xác production.

5.2. 🚀 GitOps

Với GitOps:

Developer
    │
    │ Pull Request
    ▼
Git Repository
    │
    │ Change detected
    ▼
Argo CD
    │
    │ Sync
    ▼
Kubernetes

Git trở thành Source of Truth.

Source of Truth là gì?

Hiểu đơn giản:

Đây là nơi chúng ta tin tưởng để biết hệ thống nên ở trạng thái nào.

Ví dụ:

Git

production/
└── deployment.yaml
    └── image: myapp:v1.2.0

Nếu Kubernetes đang chạy:

myapp:v1.1.0

thì GitOps tool biết rằng:

Expected: v1.2.0
Actual:   v1.1.0

→ OutOfSync

6. 🏗️ Architecture

Một GitOps architecture đơn giản:

                    Developer
                        │
                        │ git push
                        ▼
               ┌─────────────────┐
               │      Git        │
               │                 │
               │ Desired State   │
               └────────┬────────┘
                        │
                        │ Watch
                        ▼
               ┌─────────────────┐
               │     Argo CD     │
               │                 │
               │ Compare         │
               │ Sync            │
               │ Reconcile       │
               └────────┬────────┘
                        │
                        │ Apply
                        ▼
               ┌─────────────────┐
               │   Kubernetes    │
               │                 │
               │ Actual State    │
               │                 │
               │ ┌─────────────┐ │
               │ │ Application │ │
               │ └─────────────┘ │
               └─────────────────┘

Điểm quan trọng:

Developer không cần SSH vào Kubernetes để thay đổi application.

Thay đổi được thực hiện thông qua Git.


7. 🧪 Thực hành — Mô phỏng GitOps

Trong lab này chúng ta chưa cần Argo CD.

Mục đích là hiểu bản chất GitOps trước, sau đó Lab 3 mới đưa Argo CD vào.


7.1. 📁 Tạo GitOps Repository

Tạo một repository:

mkdir gitops-demo
cd gitops-demo

git init

Tạo cấu trúc:

gitops-demo/
└── app/
    └── deployment.yaml

Tạo file:

mkdir app
touch app/deployment.yaml

7.2. 📝 Tạo Desired State

Thêm vào app/deployment.yaml:

apiVersion: apps/v1
kind: Deployment

metadata:
  name: nginx

spec:
  replicas: 2

  selector:
    matchLabels:
      app: nginx

  template:
    metadata:
      labels:
        app: nginx

    spec:
      containers:
        - name: nginx
          image: nginx:1.27
          ports:
            - containerPort: 80

Ở đây chúng ta đang nói:

Tôi muốn:

Deployment: nginx
Replicas:   2
Image:      nginx:1.27

Đây chính là Desired State.


8. 🚀 Deploy Desired State

Apply configuration:

kubectl apply -f app/deployment.yaml

Kiểm tra:

kubectl get deployment nginx

Kết quả mong đợi:

NAME    READY   UP-TO-DATE   AVAILABLE
nginx   2/2     2            2

Kiểm tra image:

kubectl get deployment nginx \
  -o jsonpath='{.spec.template.spec.containers[0].image}'

Kết quả:

nginx:1.27

Bây giờ:

Git
Desired State
    │
    │ apply
    ▼
Kubernetes
Actual State

replicas = 2
image    = nginx:1.27

Hai trạng thái giống nhau.

Desired State == Actual State

             ✅

9. 💥 Mô phỏng Drift

Đây là phần rất quan trọng.

Giả sử một người nào đó trực tiếp thay đổi production:

kubectl scale deployment nginx --replicas=5

Kiểm tra:

kubectl get deployment nginx

Bạn sẽ thấy:

READY
5/5

Nhưng Git vẫn ghi:

replicas: 2

Chúng ta có:

Git
Desired State

replicas: 2
     │
     │
     │ ≠
     ▼
Kubernetes
Actual State

replicas: 5

Đây gọi là Drift.

Drift = Actual State đã lệch khỏi Desired State.


10. 🔧 Reconciliation thủ công

Trong GitOps thực tế, Argo CD sẽ phát hiện và xử lý drift.

Nhưng hiện tại chúng ta làm thủ công để hiểu bản chất.

Chạy:

kubectl apply -f app/deployment.yaml

Kiểm tra:

kubectl get deployment nginx

Kết quả:

READY
2/2

Kubernetes đã quay lại:

Desired State

replicas: 2

Đây chính là ý tưởng cốt lõi của GitOps:

             Git
        Desired State
             │
             │
             ▼
        Compare State
             │
             │ Drift?
             ▼
       Reconciliation
             │
             ▼
        Kubernetes
        Actual State

Argo CD sẽ tự động hóa quá trình này.


11. 🔄 Thay đổi Application bằng Git

Bây giờ hãy thay đổi:

replicas: 2

thành:

replicas: 3

Sau đó:

git add .
git commit -m "Scale nginx to 3 replicas"

Nếu repository đã kết nối với GitHub:

git push

Git bây giờ chứa:

Desired State

replicas: 3

Nhưng Kubernetes vẫn có thể đang chạy:

Actual State

replicas: 2

Argo CD trong các lab sau sẽ nhìn thấy:

Git:
3 replicas

Kubernetes:
2 replicas

→ OutOfSync

Sau đó Argo CD sẽ sync:

2 replicas
     │
     │ Sync
     ▼
3 replicas

12. 🧠 Explain → Do → See Result → Understand

Đây là cách bạn nên ghi nhớ GitOps.

Explain

Git chứa:

Desired State

Kubernetes chứa:

Actual State

Do

Thay đổi configuration trong Git:

replicas: 3

See Result

GitOps tool phát hiện:

Desired ≠ Actual

Understand

GitOps tool thực hiện:

Reconciliation

để đưa:

Actual State
      ↓
Desired State

13. 🧩 GitOps có phải chỉ là "deploy bằng Git" không?

Không.

Đây là một hiểu nhầm rất phổ biến.

Nếu bạn làm:

git push
   ↓
CI
   ↓
kubectl apply

thì chưa thể hiện đầy đủ tư duy GitOps.

Điểm quan trọng hơn là:

Git
 │
 │ Desired State
 ▼
GitOps Controller
 │
 │ Continuously compare
 ▼
Kubernetes
 │
 │ Actual State
 └──────────────┐
                │
                ▼
             Reconcile

GitOps thường có một controller liên tục quan sát và reconcile hệ thống.

Argo CD chính là một GitOps controller.


14. 🆚 Push Model và Pull Model

Đây là một concept rất quan trọng khi học GitOps.

14.1. 📤 Push Model

CI/CD pipeline chủ động deploy:

Git
 │
 ▼
CI/CD
 │
 │ kubectl apply
 ▼
Kubernetes

Ví dụ:

GitHub Actions
      │
      │ kubectl
      ▼
Kubernetes

CI cần quyền truy cập Kubernetes.


14.2. 📥 Pull Model

GitOps thường sử dụng Pull Model:

Git
 │
 │
 ▼
Argo CD
 │
 │ pull / watch
 ▼
Kubernetes

Argo CD chạy bên trong hoặc gần Kubernetes và chủ động theo dõi Git.

Git
 │
 │ "Desired State"
 ▼
Argo CD
 │
 │ Sync
 ▼
Kubernetes

Tại sao Pull Model tốt?

CI pipeline không nhất thiết phải giữ Kubernetes credentials để deploy.

Điều này giúp:

  • Giảm quyền truy cập từ bên ngoài vào cluster.
  • Tách CI và CD.
  • Dễ audit.
  • Dễ kiểm soát deployment.
  • Phù hợp với production environment.

15. 🔐 GitOps và Security

GitOps không tự động làm hệ thống secure.

Nhưng nó giúp tạo ra một boundary tốt hơn.

Ví dụ cách làm không tốt:

GitHub Actions
      │
      │ kubeconfig
      │ admin permission
      ▼
Production

Nếu GitHub Actions bị compromise, attacker có thể có quyền rất lớn trên cluster.

Một mô hình tốt hơn:

GitHub Actions
      │
      │ Build / Test
      ▼
Container Registry


GitOps Repository
      │
      ▼
   Argo CD
      │
      ▼
Production

CI không nhất thiết phải có quyền admin trên production cluster.


16. 💡 Kinh nghiệm Production

16.1. 🚫 Không sửa trực tiếp Production

Tránh:

kubectl edit deployment
kubectl set image
kubectl scale

để thay đổi cấu hình lâu dài trong production.

Nếu cần thay đổi:

Change Git
    ↓
Pull Request
    ↓
Review
    ↓
Merge
    ↓
Argo CD
    ↓
Production

Bạn vẫn có thể dùng kubectl để debug.

Nhưng:

kubectl nên được xem là công cụ vận hành/debug, không phải nơi lưu Desired State.


16.2. 📝 Mọi thay đổi nên trace được

Một thay đổi production tốt nên có:

Who?
What?
Why?
When?

Ví dụ:

PR #152

Author: Thong
Change: nginx 1.27 → 1.28
Reason: Security update
Review: Approved
Deployment: Argo CD

Sau này nếu có incident, việc điều tra dễ hơn rất nhiều.


16.3. 🔙 Rollback dễ hơn

Nếu Git có:

Commit A
   ↓
nginx:1.27

Commit B
   ↓
nginx:1.28

Và version 1.28 có vấn đề:

Revert Commit B
       ↓
Git
       ↓
Argo CD
       ↓
Kubernetes
       ↓
nginx:1.27

Git trở thành một lịch sử thay đổi của infrastructure/application.


17. 🧪 Bài tập thực hành

Exercise 1 — Deployment

  • [ ] Tạo Git repository gitops-demo.
  • [ ] Tạo Deployment nginx.
  • [ ] Deploy lên Kubernetes.
  • [ ] Kiểm tra Desired State và Actual State.

Exercise 2 — Drift

  • [ ] Đặt replicas: 2 trong Git.
  • [ ] Deploy lên Kubernetes.
  • [ ] Dùng kubectl scale để tăng lên 5.
  • [ ] Quan sát sự khác biệt.
  • [ ] Apply lại configuration từ Git.
  • [ ] Kiểm tra Kubernetes quay về 2 replicas.

Exercise 3 — Git Change

Thay đổi:

replicas: 2

thành:

replicas: 3

Sau đó:

git add .
git commit -m "Scale nginx to 3 replicas"

Quan sát:

Git
replicas: 3

Kubernetes
replicas: 2

Bạn đã tạo ra một Drift theo hướng ngược lại.

Ở các lab sau, Argo CD sẽ tự động xử lý phần này.


18. 🧠 Tổng kết

Nếu chỉ nhớ 5 điều, hãy nhớ:

1️⃣ GitOps không đơn giản là "deploy bằng Git"

Nó là một cách vận hành hệ thống dựa trên:

Git = Desired State

2️⃣ Kubernetes có Actual State

Desired State
      ≠
Actual State

thì xảy ra Drift.

3️⃣ GitOps Controller thực hiện Reconciliation

Desired State
      ↓
Compare
      ↓
Drift?
      ↓
Reconcile
      ↓
Actual State

4️⃣ Argo CD là GitOps Controller

Argo CD sẽ theo dõi Git và Kubernetes để giữ cho chúng đồng bộ.

5️⃣ Production nên thay đổi thông qua Git

Thay vì:

kubectl → Production

ưu tiên:

Git
 ↓
Pull Request
 ↓
Review
 ↓
Argo CD
 ↓
Kubernetes

19. 🚀 Lab tiếp theo

Ở Lab 1, chúng ta mới mô phỏng GitOps bằng tay.

Lab tiếp theo sẽ giải quyết một câu hỏi thực tế:

Nếu một project có Dev, Staging và Production thì nên tổ chức GitOps Repository như thế nào?

Trong Lab 2 — GitOps Repository Structure, chúng ta sẽ xây dựng cấu trúc:

gitops-repo/
├── apps/
│   └── todo-app/
│
├── environments/
│   ├── dev/
│   ├── staging/
│   └── production/
│
└── README.md

và tìm hiểu tại sao việc thiết kế repository ngay từ đầu lại rất quan trọng khi hệ thống bắt đầu có nhiều application và nhiều environment.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí