Phân tích log và debug lỗi phổ biến trong Tekton Pipeline
Khi pipeline bị lỗi, nguyên nhân thường nằm ở việc thiếu token, lỗi quyền truy cập (RBAC) hoặc vấn đề mạng giữa Pod và Service bên ngoài. Bước đầu tiên là xác định Pod đang chạy bị lỗi.
Sử dụng lệnh sau để liệt kê các TaskRun hoặc PipelineRun đang ở trạng thái lỗi (Failed, Error):
tkn pipelinerun list --field-selector=status.conditions[-].status=Failed -n ci-cd
Kết quả mong đợi: Danh sách các PipelineRun có trạng thái Failed kèm theo thời gian tạo và thời gian hoàn thành.
Sau khi xác định tên PipelineRun, hãy kiểm tra chi tiết log của từng Task bên trong để tìm dòng lỗi cụ thể. Tekton chia log thành từng Task riêng biệt.
tkn pipelinerun logs -n ci-cd --follow
Kết quả mong đợi: Log được in ra theo thời gian thực, chia tách rõ ràng theo từng Task (ví dụ: build, test, deploy), giúp bạn nhanh chóng định vị bước gây lỗi.
Trong trường hợp log không rõ ràng, hãy inspect trực tiếp vào Pod của Tekton để xem sự kiện (Events) hoặc log container bị crash. Điều này hữu ích khi Pod không thể khởi động do lỗi OOM hoặc lỗi permission.
kubectl get pods -n ci-cd -l tekton.dev/pipelineRun= --show-labels
kubectl describe pod -n ci-cd
Kết quả mong đợi: Chi tiết trạng thái Pod, bao gồm phần "Events" ở cuối hiển thị lý do Pod bị xóa (ví dụ: OOMKilled, ImagePullBackOff, CrashLoopBackOff).
Để debug sâu hơn về biến môi trường hoặc secret không được mount đúng cách, hãy vào shell của Pod đang chạy (nếu chưa bị crash) hoặc tạo Pod tạm để kiểm tra cấu hình.
kubectl exec -it -n ci-cd -- /bin/bash
Kết quả mong đợi: Bạn vào được shell của container, có thể chạy lệnh `env` để kiểm tra biến môi trường hoặc `cat /var/run/secrets/kubernetes.io/serviceaccount/token` để kiểm tra token.
Xử lý các vấn đề về kết nối giữa ArgoCD và Vault
Vấn đề phổ biến nhất là ArgoCD không thể liên lạc với Vault do lỗi DNS, thiếu CA certificate, hoặc token hết hạn. ArgoCD cần mount secret chứa Vault token vào container của nó.
Đầu tiên, kiểm tra xem Pod của ArgoCD (argocd-repo-server) có thể resolve tên miền Vault hay không.
kubectl exec -it -n argocd -- nslookup vault-server.vault.svc.cluster.local
Kết quả mong đợi: Trả về địa chỉ IP của service Vault. Nếu lỗi "server can't find", bạn cần kiểm tra Service của Vault hoặc ConfigMap CoreDNS.
Nếu DNS ok nhưng kết nối bị từ chối (Connection Refused), kiểm tra xem Vault có đang lắng nghe trên port 8200 không và ArgoCD có quyền access không.
kubectl exec -it -n argocd -- curl -k https://vault-server.vault.svc.cluster.local:8200/v1/sys/health
Kết quả mong đợi: JSON trả về {"initialized": true, "sealed": false, "standby": false}. Nếu thấy lỗi "sealed", Vault đang bị khóa và cần unseal. Nếu lỗi "certificate unknown", cần cấu hình CA.
Để xử lý lỗi chứng chỉ (Self-signed certificate) giữa ArgoCD và Vault, bạn cần mount CA certificate của Vault vào ArgoCD và cấu hình trong Application.
Tạo Secret chứa CA certificate của Vault:
kubectl create secret generic vault-ca-cert --from-file=ca.crt=/path/to/vault-ca.crt -n argocd
Kết quả mong đợi: Secret "vault-ca-cert" được tạo thành công trong namespace argocd.
Chỉnh sửa manifest Application của ArgoCD để mount secret này vào container và chỉ định đường dẫn cho Vault CLI hoặc thư viện client sử dụng.
File cấu hình: /etc/argocd/config/application.yaml (ví dụ trong Git repo)
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/org/repo.git
targetRevision: HEAD
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated: {}
revisionHistoryLimit: 5
# Cấu hình đặc biệt cho Vault integration
sources:
- repoURL: https://github.com/org/repo.git
targetRevision: HEAD
ref: values
source:
chart: my-app
repoURL: https://helm-repo.example.com
targetRevision: 1.0.0
helm:
valuesObject:
vault:
enabled: true
address: "https://vault-server.vault.svc.cluster.local:8200"
authMethod: kubernetes
role: argocd-role
namespace: vault
path: secret
caCertSecret: vault-ca-cert
caCertPath: /vault/certs/ca.crt
destination:
server: https://kubernetes.default.svc
namespace: production
Kết quả mong đợi: ArgoCD sync thành công, container repo-server có thể đọc secret từ Vault mà không bị lỗi SSL/TLS.
Verify kết quả bằng cách kiểm tra log của ArgoCD repo-server để xem có thông báo lỗi kết nối Vault không.
kubectl logs -f -n argocd | grep -i vault
Kết quả mong đợi: Không có dòng log lỗi "connection refused" hoặc "certificate validation failed".
Tối ưu tài nguyên cluster cho các tác vụ CI/CD nặng
Các pipeline build nặng (compile Java, Go, hoặc Docker build) thường tiêu tốn nhiều CPU và RAM, gây nghẽn cổ chai cho các Pod khác. Cần giới hạn tài nguyên (Resource Limits) và thiết lập Request hợp lý.
Sửa Task trong Tekton để chỉ định request và limits cụ thể cho từng step. Tránh để mặc định (unbounded) gây OOM.
File cấu hình: /tekton-tasks/build-task.yaml
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: build-app
spec:
steps:
- name: compile
image: golang:1.21
script: |
CGO_ENABLED=0 go build -o bin/app ./cmd
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2"
memory: "4Gi"
- name: docker-build
image: docker:24
script: |
docker build -t my-app:latest .
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "4"
memory: "8Gi"
Kết quả mong đợi: Pod chạy Task sẽ không bị OOMKilled nếu sử dụng vượt quá limits, và scheduler sẽ ưu tiên phân bổ node có đủ tài nguyên.
Để xử lý các workload nặng, hãy sử dụng Node Affinity hoặc Taints/Tolerations để ép các Pod CI/CD chạy trên các node chuyên dụng (build nodes) tách biệt khỏi node chạy production.
Tạo một NodePool riêng hoặc đánh dấu node build:
kubectl label nodes node-type=ci-cd
Kết quả mong đợi: Node được gắn label "node-type=ci-cd".
Cấu hình Tekton Pipeline hoặc PodTemplate để yêu cầu chạy trên node có label đó.
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: heavy-build-run
spec:
pipelineRef:
name: heavy-build-pipeline
podTemplate:
nodeSelector:
node-type: ci-cd
tolerations:
- key: "ci-cd"
operator: "Equal"
value: "true"
effect: "NoSchedule"
Kết quả mong đợi: Pod PipelineRun chỉ được schedule lên các node có label "node-type=ci-cd", tránh ảnh hưởng hiệu năng cho workload production.
Tối ưu thêm bằng cách sử dụng "Spot Instances" hoặc "Preemptible VMs" cho các task CI/CD không quan trọng (như test unit) để giảm chi phí, chấp nhận rủi ro bị (preempt) nếu cluster thiếu tài nguyên.
kubectl taint nodes node-type=ci-cd-ci=ci-cd:NoSchedule
kubectl create -f pipeline-with-toleration.yaml
Kết quả mong đợi: Pod có toleration "node-type=ci-cd-ci" sẽ chạy trên node spot, tiết kiệm chi phí cloud.
Mẹo nâng cao: Sử dụng Webhook tùy chỉnh và tự động hóa bảo trì
Để tự động hóa việc làm sạch tài nguyên cũ (PipelineRun, TaskRun) mà không cần CronJob, hãy sử dụng Webhook hoặc EventSource của Tekton để kích hoạt Task dọn dẹp sau khi Pipeline hoàn thành.
Tạo một Task đơn giản để xóa các PipelineRun cũ hơn 24 giờ:
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: cleanup-pipelineruns
spec:
steps:
- name: cleanup
image: quay.io/tekton/pipelines-tools:latest
script: |
# Xóa các pipelinerun failed hoặc completed > 24h
tkn pipelinerun delete $(tkn pipelinerun list -n ci-cd --field-selector=status.conditions[-].status=Completed --no-headers | awk '{print $1}' | while read pr; do echo $pr; done | xargs -I {} date -d "$(tkn pipelinerun describe {} -n ci-cd --field-selector=status.conditions[-].status=Completed --no-headers | awk '{print $2}')" +%s 2>/dev/null | awk '{if (($(NOW)-$1)>86400) print $1}' --now=$(date +%s) | xargs -I {} tkn pipelinerun delete {} -n ci-cd -f)
resources:
requests:
cpu: "100m"
memory: "128Mi"
Kết quả mong đợi: Task chạy thành công và xóa các PipelineRun cũ, giải phóng không gian PersistentVolume và giảm số lượng object trong etcd.
Để tự động kích hoạt Task dọn dẹp này khi một Pipeline hoàn thành, sử dụng EventListener hoặc Custom Webhook. Ở đây ta dùng cơ chế Trigger của Tekton v0.26+ (Triggers).
Tạo TriggerTemplate và TriggerBinding để lắng nghe sự kiện PipelineRun hoàn thành:
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerTemplate
metadata:
name: cleanup-template
spec:
params:
- name: pipelinerun-name
resourcetemplates:
- apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
name: cleanup-taskrun-$(tt.params.pipelinerun-name)
spec:
taskRef:
name: cleanup-pipelineruns
---
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
name: pipeline-completed-binding
spec:
params:
- name: pipelinerun-name
value: $(body.metadata.name)
---
apiVersion: triggers.tekton.dev/v1alpha1
kind: Interceptor
metadata:
name: event-interceptor
spec:
cluster:
ref:
name: pipeline-completed
Kết quả mong đợi: Cấu hình Trigger được tạo sẵn sàng để lắng nghe sự kiện.
Cấu hình EventListener để lắng nghe sự kiện từ Kubernetes API (thông qua webhook của Tekton Triggers) và kích hoạt cleanup:
apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
name: cleanup-listener
spec:
serviceAccountName: tekton-triggers-admin
triggers:
- name: cleanup-trigger
bindings:
- ref: pipeline-completed-binding
template:
ref: cleanup-template
Kết quả mong đợi: Khi một PipelineRun hoàn thành, EventListener sẽ nhận sự kiện và tạo TaskRun cleanup tự động.
Để tăng cường bảo trì, hãy thiết lập Webhook tùy chỉnh (Custom Webhook) để gửi cảnh báo Slack/Teams khi pipeline bị lỗi liên tục hoặc khi Vault token sắp hết hạn.
Tạo Task gửi cảnh báo:
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: slack-alert
spec:
params:
- name: message
steps:
- name: send-alert
image: alpine/curl
script: |
curl -X POST -H 'Content-type: application/json' --data "{\"text\": \"$(params.message)\"}" $(SLACK_WEBHOOK_URL)
env:
- name: SLACK_WEBHOOK_URL
valueFrom:
secretKeyRef:
name: slack-webhook
key: url
Kết quả mong đợi: Khi Task này được gọi, thông báo lỗi sẽ được gửi đến kênh Slack đã cấu hình.
Tích hợp Task cảnh báo vào PipelineRun bằng cách thêm bước này vào cuối pipeline hoặc sử dụng Trigger khi trạng thái là Failed.
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: build-with-alert
spec:
pipelineRef:
name: my-build-pipeline
workspaces: []
tasks:
- name: build
taskRef:
name: build-app
- name: alert-on-failure
taskRef:
name: slack-alert
params:
- name: message
value: "Pipeline build failed! Check logs."
runAfter:
- build
when:
- input: "$(tasks.build.status)"
operator: in
values:
- Failed
Kết quả mong đợi: Nếu task "build" bị lỗi, task "alert-on-failure" sẽ chạy và gửi cảnh báo đến Slack. Nếu thành công, task alert sẽ bị bỏ qua.
Điều hướng series:
Mục lục: Series: Series: Xây dựng hệ thống CI/CD an toàn và tự động hóa cho Kubernetes với ArgoCD, Tekton và HashiCorp Vault
« Phần 7: Tự động hóa quy trình rollback và disaster recovery