Chuyển tới nội dung

Triển khai ứng dụng với helm chart qua ArgoCD

Tổng quan

Yêu cầu

Workflow CI/CD Tổng thể

  1. Developer Push Code → Git Repository nhận webhook
  2. Jenkins CI → Build Docker Image + Đóng gói Helm Chart
  3. Push to Harbor → Lưu trữ Docker Image & Helm Chart
  4. ArgoCD CD → Tự động deploy lên Kubernetes Cluster
  5. Kubernetes → Ứng dụng chạy và được expose qua Ingress

Nội dung bài lab

PHẦN I – Làm việc thủ công với Helm: Tạo Helm Chart template, cấu hình các file manifest (deployment, service, ingress), đóng gói và đẩy lên Harbor Registry để hiểu rõ cấu trúc cơ bản.

PHẦN II – Cấu hình Harbor: Tạo Project trên Harbor, cấu hình quyền truy cập và thực hiện push Helm Chart lên Registry một cách thủ công.

PHẦN III – Tự động hóa với Jenkins & ArgoCD: Xây dựng pipeline Jenkins để tự động build, đóng gói và push artifacts. Sau đó sử dụng ArgoCD để tự động triển khai ứng dụng lên Kubernetes theo phương pháp GitOps.

🎯 PART I – Tạo Helm Chart trên K8S

Bước 1: Chuẩn bị Môi trường (Helm & Plugin)

Đầu tiên, chúng ta cần cài đặt plugin helm-push (để đẩy chart lên OCI registry như Harbor) và đăng nhập vào Harbor.

# 1. Cài đặt plugin helm(nếu chưa có)
iadmin@srv025-aio:~$ cd ~/devops/
iadmin@srv025-aio:~/devops$ mkdir helm-chart
iadmin@srv025-aio:~/devops$ cd helm-chart
iadmin@srv025-aio:~/devops/helm-chart$ wget https://get.helm.sh/helm-v4.0.1-linux-amd64.tar.gz
iadmin@srv025-aio:~/devops/helm-chart$ tar xvfz helm-v4.0.1-linux-amd64.tar.gz
iadmin@srv025-aio:~/devops/helm-chart$ sudo cp linux-amd64/helm  /usr/local/bin/

# Kiểm tra
iadmin@srv025-aio:~/devops/helm-chart$ helm version
version.BuildInfo{Version:"v4.0.1", GitCommit:"12500dd401faa7629f30ba5d5bff36287f3e94d3", GitTreeState:"clean", GoVersion:"go1.25.4", KubeClientVersion:"v1.34"}
# 2. Cài đặt plugin helm 
iadmin@srv025-aio:~/devops/helm-chart$ helm plugin install https://github.com/chartmuseum/helm-push --verify=false
# 3. Đăng nhập vào Harbor Registry
# (Đăng nhập bằng user "admin" đã được cấp quyền "Project Admin")
iadmin@srv025-aio:~/devops$ helm registry login harbor.diendo.pro.vn -u beobeo
Password: 
Login Succeeded

Bước 2: Tạo và “Dọn dẹp” Helm Chart (Cách chuẩn)

Chúng ta sẽ dùng helm create để tạo cấu trúc thư mục chuẩn, sau đó “dọn dẹp” (làm rỗng) các file mẫu không cần thiết bằng echo.

# 1. Tạo thư mục làm việc
mkdir ~/devops/helm-chart/
cd ~/devops/helm-chart/

# 2. Tạo chart mẫu với tên "helm create template-ha-config"
helm create template-ha-config

# 3. Dọn dẹp các file YAML mẫu (Cách làm "chuẩn")
echo "" > template-ha-config/templates/service.yaml
echo "" > template-ha-config/templates/deployment.yaml
echo "" > template-ha-config/templates/ingress.yaml

⚠️ QUAN TRỌNG – Sắp xếp tài nguyên trên K8s:

Chúng ta sẽ KHÔNG đưa file namespace.yaml và registry-secret.yaml vào Helm chart.

Lý do: Đây là các tài nguyên “cơ sở hạ tầng” (Infrastructure), nên được quản lý riêng biệt và tạo trước.

Thứ tự triển khai đúng:
1️⃣ Tạo Namespace trước (infrastructure layer)

kubectl create namespace ha-config

2️⃣ Tạo Registry Secret trong namespace đó

kubectl create secret docker-registry harbor-registry-creds \
--docker-server=harbor.diendo.pro.vn \
--docker-username=beobeo \
--docker-password=your-password \
--namespace=ha-config

3️⃣ Sau đó mới deploy Helm Chart (application layer)

helm install ha-config ./template-ha-config --namespace=ha-config

📌 Nguyên tắc: Infrastructure resources (namespace, secrets, configmaps shared) → Application resources (deployment, service, ingress via Helm)

Bước 3: Ghi đè file YAML (Cách chuẩn “Heredoc”)

Đây là bước cốt lõi. Chúng ta sẽ dùng lệnh cat <<EOF để ghi đè nội dung vào 3 file YAML.

3.1. Ghi đè deployment.yaml

cat <<EOF | tee template-ha-config/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Values.deployment.name }}
  namespace: {{ .Release.Namespace }} # <-- Tự động lấy namespace lúc cài
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Values.deployment.name }}
  template:
    metadata:
      labels:
        app: {{ .Values.deployment.name }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      containers:
      - name: ha-config-frontend
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        ports:
        - containerPort: {{ .Values.service.targetPort }}
        env:
        {{- if .Values.secret.enabled }}
        - name: REACT_APP_GEMINI_API_KEY
          valueFrom:
            secretKeyRef:
              name: {{ .Values.secret.name }}
              key: {{ .Values.secret.key }}
        {{- end }}
EOF

3.2. Ghi đè service.yaml

cat <<EOF | tee template-ha-config/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ .Values.service.name }}
  namespace: {{ .Release.Namespace }}
spec:
  type: {{ .Values.service.type }}
  selector:
    app: {{ .Values.deployment.name }}  # <-- Phải khớp với label của Deployment
  ports:
    - protocol: TCP
      port: {{ .Values.service.port }}
      targetPort: {{ .Values.service.targetPort }}
EOF

3.3. Ghi đè ingress.yaml

cat <<EOF | tee template-ha-config/templates/ingress.yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ .Values.service.name }}
  namespace: {{ .Release.Namespace }}
spec:
  type: {{ .Values.service.type }}
  selector:
    app: {{ .Values.deployment.name }} 
  ports:
    - protocol: TCP
      port: {{ .Values.service.port }}
      targetPort: {{ .Values.service.targetPort }}
EOF

Bước 4: Cấu hình values.yaml (Cách chuẩn)

cat <<EOF | tee template-ha-config/values.yaml
replicaCount: 1

deployment:
  name: ha-config

imagePullSecrets:
  - name: harbor-registry-creds

image:
  repository: harbor.diendo.pro.vn/haproxy-ops/ai-ha-config
  # Tag này sẽ được Jenkins cập nhật tự động khi build (ví dụ: "1.0.8")
  tag: "latest"
  pullPolicy: Always

service:
  name: ha-config-svc
  type: NodePort
  port: 80
  targetPort: 80
  # NodePort range: 30000-32767
  nodePort: 30007

ingress:
  enabled: true
  name: ha-config-ingress
  className: nginx
  host: "ha-config.diendo.pro.vn"

# Cấu hình Secret cho API Key
secret:
  enabled: true
  name: "gemini-api-key"   # Tên Secret trong Kubernetes
  key: "apiKey"            # Tên Key trong Secret
EOF

Bước 5: Tạo Secret trên Kubernetes để chạy app

# Thay thế YOUR_REAL_API_KEY bằng key thật của bạn
kubectl create secret generic gemini-api-key \
  --from-literal=apiKey=YOUR_REAL_API_KEY \
  --namespace haproxy-ops

🔧 PART II Cấu hình Harbor & Push Chart

Bước 5: Tạo repo helm trên Harbor

1. Ta login vào Harbor sau đó vào Projects > New Project.

2. Tại hộp thoại New Project:

  • Project Name: gõ tên project của bạn (chỉ dùng ký tự thường, không ký tự đặc biệt).
  • Access level: chọn public.

Còn lại để mặc định và bấm OK.

3. Tạo xong ta bấm vào project và bấm vào PUSH COMMAND sẽ thấy các lệnh hỗ trợ push helm và image lên.

Bước 6: Đóng gói và Đẩy (Push) lên Harbor

Bây giờ chart đã sẵn sàng. Chúng ta sẽ đóng gói (package) và đẩy (push) lên project template-ha-config trên Harbor.

# 1. Đóng gói thư mục thành file .tgz
# (Đang đứng ở thư mục project-helm-build)
helm package ./template-ha-config
# > Kết quả: Successfully packaged chart and saved it to: .../template-ha-config-0.1.0.tgz

# 2. Đẩy (Push) file .tgz lên Harbor
# (Fix lỗi 401: URL chuẩn OCI là: oci://[HOST]/[PROJECT]/[CHART_NAME])
helm push template-ha-config-0.1.0.tgz oci://harbor.diendo.pro.vn/template-ha-config/ha-config

Hoàn tất! Kết quả trên Harbor:

🚀PART III: Triển khai với ArgoCD

Bước 1: Chuẩn bị Jenkins

  • Jenkins bạn phải đảm bảo rằng đã cài helm push. Trường hợp chưa có bạn có thể cài bằng cách vào trực tiếp container Jenkins:
# 1. Truy cập vào container Jenkins
# docker exec -it container_id_Jenkins_cua_Bạn /bin/bash
iadmin@srv025-aio:~$ docker exec -it devops-jenkins-1 /bin/bash

# Sau đó tiến hành cài wget bằng lệnh:
apt-get update && apt-get install -y wget
# 2. Cài Helm Chart
wget https://get.helm.sh/helm-v3.17.4-linux-amd64.tar.gz
tar vxf helm-v3.17.4-linux-amd64.tar.gz
sudo mv linux-amd64/helm /usr/bin/
# 3. Cài helm push
helm plugin install https://github.com/chartmuseum/helm-push

Cách chuẩn chính nhất là đưa các thành phần cài này vào DockerFile của Jenkins khi mới build:

# Start from the official Jenkins LTS image using JDK 17
FROM jenkins/jenkins:lts-jdk17
# Switch to root user to install packages
USER root
# Install prerequisites and Docker GPG key
RUN apt-get update && apt-get install -y ca-certificates curl gnupg
RUN install -m 0755 -d /etc/apt/keyrings
RUN curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
RUN chmod a+r /etc/apt/keyrings/docker.asc
# Add Docker repository
RUN echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker CLI
RUN apt-get update && apt-get install -y docker-ce-cli
RUN curl -fsSL "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" -o /usr/local/>
        && chmod +x /usr/local/bin/kubectl /usr/bin/docker || true \
        && apt-get clean && rm -rf /var/lib/apt/lists/*

ENV HELM_VERSION=v3.17.4
RUN curl -L "https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz" | tar -xz \
    && mv linux-amd64/helm /usr/local/bin/helm \
    && chmod +x /usr/local/bin/helm \
    && helm plugin install https://github.com/chartmuseum/helm-push

# Switch back to jenkins user
USER jenkins

# Final verification check
RUN kubectl version --client && helm version

Bước 2: Đưa các thành phần triển khai lên git

Đây là cấu trúc của source code chứa các thành phần triển khai:

Cụ thể thông tin về các file template bạn kiểm tra tại: https://github.com/diendt/haproxy-config

Bước 3: Tạo helm chart template trên Jenkins

Trên Jenkins ta tiến hành vào pipeline đã tạo từ các bài trước và thay đổi Jenkins.

Với Jenkinsfile.txt thì flow sẽ là:

Listen webhook từ git -> đóng gói docker image -> đưa lên Harbor Registry.

Sau đó tiếp tục tạo Helm Template nếu chưa có -> và tiến hành đưa các nội dung của template dành riêng cho dự án từ thư mục helm ở trên git đưa vào values và template -> Đóng gói helm lại -> Push lên Helm Harbor Registry.

Bước 4: Triển khai với helm lưu trữ trên Harbor bằng ArgoCD

4.1. Tạo repo connect

Tại ArgoCD ta vào Setting -> Repositories.

Bấm vào Connect Repo:

Ta tiến hành kết nối Harbor Repo theo thứ tự như hình bên dưới:

Helm Repo đã được kết nối thành công:

4.2. Tạo ArgoCD App

Tại phần Repo đã tạo thành công ta bấm vào dấu 3 chấm -> Create application.

ArgoCD đã triển khai lên cụm K8S thành công:

Deployment Success

4.3. Tại Cloudflare Zero Trust tạo Record Tunnel

Tạo cho haconfig.diendo.pro.vn

4.4. Kiểm tra lại ứng dụng đã chạy hay chưa

Liên hệ