GitOps & Deployments
ArgoCD, Helm, Argo Rollouts দিয়ে progressive delivery — cluster state as code, automated sync, এবং এমন deployment যা নীরবে ভুল হয়ে যেতে পারে না।
বাস্তব জীবনের উদাহরণ
একটা version-controlled বিল্ডিং ব্লুপ্রিন্ট: ভল্টে রাখা ব্লুপ্রিন্ট (git)-ই সবসময় source of truth। কোনো contractor যখনই বিল্ডিংয়ে অননুমোদিত পরিবর্তন আনে (cluster drift), সিস্টেম সেটা ধরে ফেলে এবং ব্লুপ্রিন্টে ফিরিয়ে নেয়। বৈধ কোনো পরিবর্তন করতে হলে আপনি ব্লুপ্রিন্ট আপডেট করেন — সরাসরি বিল্ডিং নয়। ArgoCD হলো সেই সিস্টেম যা এটা enforce করে।
গল্পে বুঝি
সমরকন্দ শহরে নতুন একটা বড় লাইব্রেরি বানানো হচ্ছে। শহরের নিয়ম কড়া — বিল্ডিংয়ের আসল, অফিসিয়াল master blueprint শহরের আর্কাইভে তালাবদ্ধ থাকে, আর সেই blueprint-ই একমাত্র সত্য। কোন দেয়াল কোথায়, কোন দরজা কত চওড়া — সব ওখানে আঁকা। ইবনে সিনা হলেন প্রধান foreman। তার কাজ একটাই, কিন্তু সে সেটা অক্লান্তভাবে করে যায়: প্রতিদিন সে আসল বিল্ডিংটা ঘুরে দেখে আর আর্কাইভের master blueprint-এর সাথে মিলিয়ে দেখে, কোথাও এক চুল অমিল পেলেই সেটা ঠিক করে blueprint-এর মতো বানিয়ে দেয়।
একদিন রাতে এক শ্রমিক নিজের বুদ্ধিতে একটা বাড়তি দেয়াল তুলে ফেলল, যেটা blueprint-এ নেই। সকালে ইবনে সিনা এসে দেখল বিল্ডিং আর blueprint মিলছে না — সঙ্গে সঙ্গে সে সেই অননুমোদিত দেয়াল ভেঙে আগের অবস্থায় ফিরিয়ে দিল। কেউ যদি সত্যিই একটা নতুন দেয়াল চায়, তার একটাই পথ: আগে আর্কাইভে গিয়ে master blueprint-এ পরিবর্তনটা আঁকতে হবে, আল-খোয়ারিজমির মতো একজন যাচাই করে অনুমোদন দেবে, তারপরই সেটা বিল্ডিংয়ে ফুটে উঠবে। এভাবে প্রতিটা পরিবর্তনের একটা পরিষ্কার ইতিহাস থেকে যায় — কে, কবে, কী বদলাল, সব blueprint-এই লেখা।
এই গল্পটাই GitOps। আর্কাইভের master blueprint হলো আপনার Git repo — একমাত্র source of truth। foreman ইবনে সিনার ক্রমাগত বিল্ডিং আর blueprint মিলিয়ে দেখা হলো GitOps controller-এর continuous reconciliation — cluster-কে সবসময় Git-এর সাথে মেলানো। রাতের অননুমোদিত দেয়াল ভেঙে ফেলাটা হলো drift অটোমেটিক ঠিক করা — কেউ সরাসরি kubectl edit করলে controller সেটা Git-এর অবস্থায় revert করে দেয়। আর আগে blueprint আঁকতে হবে বলার মানে হলো, পরিবর্তন হয় শুধু commit/PR দিয়ে, সরাসরি cluster হাতে ধরে নয় — ফলে বিনামূল্যে পূর্ণ audit history পাওয়া যায়, আর rollback মানে শুধু আগের commit-এ ফিরে যাওয়া। বাস্তবে Argo CD বা Flux ঠিক এই foreman-এর কাজটাই করে — Git repo watch করে, drift ধরে, আর নীরবে cluster-কে source of truth-এর সাথে মিলিয়ে রাখে।
GitOps Principles
- Declarative — desired state ফাইলে বর্ণিত (YAML manifest, Helm chart)
- Versioned — সব state git-এ সংরক্ষিত; প্রতিটা পরিবর্তন একটা commit
- Pulled — ক্লাস্টারের ভেতরের একটা controller git থেকে pull করে (CI থেকে push করার বদলে)
- Reconciled — controller ক্রমাগত নিশ্চিত করে যে cluster state git-এর সাথে মেলে
সুবিধা:
- Cluster state সবসময় git-এ — বিনামূল্যে audit log
- একটা deployment রোলব্যাক করা =
git revert - Drift অটোমেটিক ধরা পড়ে এবং ঠিক হয়
- CI/CD pipeline থেকে kubectl access লাগে না (attack surface কমে)
Helm
Helm হলো Kubernetes-এর একটা package manager — template + values ফাইল = rendered manifest।
my-chart/
Chart.yaml # chart metadata
values.yaml # default values
values-production.yml # environment overrides
templates/
deployment.yaml
service.yaml
ingress.yaml
_helpers.tpl # reusable template snippets # templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: { { include "order-service.fullname" . } }
labels: { { - include "order-service.labels" . | nindent 4 } }
spec:
replicas: { { .Values.replicaCount } }
template:
spec:
containers:
- name: { { .Chart.Name } }
image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}'
resources: { { - toYaml .Values.resources | nindent 12 } } # values.yaml
replicaCount: 2
image:
repository: myorg/order-service
tag: latest
resources:
requests:
memory: 256Mi
cpu: 250m
limits:
memory: 512Mi
cpu: 1000m # values-production.yaml — override for production
replicaCount: 5
image:
tag: '1.2.0' # pin exact version in production
resources:
requests:
memory: 512Mi
cpu: 500m # Install
helm install order-service ./my-chart \
-f values.yaml \
-f values-production.yaml \
-n production
# Upgrade
helm upgrade order-service ./my-chart \
-f values.yaml \
-f values-production.yaml \
-n production
# Rollback
helm rollback order-service 2 -n production # rollback to revision 2
# List releases
helm list -n production ArgoCD
ArgoCD একটা git repo watch করে এবং নিশ্চিত করে যে ক্লাস্টার তার সাথে মেলে। যেকোনো git commit একটা sync ট্রিগার করে।
# Install ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Get initial admin password
kubectl get secret argocd-initial-admin-secret -n argocd -o jsonpath="{.data.password}" | base64 -d
# Access UI
kubectl port-forward svc/argocd-server -n argocd 8080:443 Application definition:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: order-service
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/k8s-config
targetRevision: main
path: apps/order-service
helm:
valueFiles:
- values.yaml
- values-production.yaml
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # delete resources removed from git
selfHeal: true # revert manual changes to cluster
syncOptions:
- CreateNamespace=true automated.selfHeal: true থাকলে, যেকোনো ম্যানুয়াল kubectl apply বা kubectl edit সঙ্গে সঙ্গে git-এর সাথে মেলাতে revert হয়ে যায়। Cluster state পুরোপুরি git দিয়ে নিয়ন্ত্রিত।
ArgoCD ApplicationSet — একই app একাধিক cluster/environment-এ deploy করুন:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: order-service
namespace: argocd
spec:
generators:
- list:
elements:
- cluster: staging
url: https://staging.k8s.example.com
values_file: values-staging.yaml
- cluster: production
url: https://production.k8s.example.com
values_file: values-production.yaml
template:
metadata:
name: 'order-service-{{cluster}}'
spec:
source:
repoURL: https://github.com/myorg/k8s-config
path: apps/order-service
helm:
valueFiles:
- values.yaml
- '{{values_file}}'
destination:
server: '{{url}}'
namespace: production Progressive Delivery with Argo Rollouts
স্ট্যান্ডার্ড Kubernetes rolling update বাইনারি — আপনি হয় পুরনো নয় নতুনে। Argo Rollouts এর সাথে যোগ করে:
- Canary — নতুন version-এ X% traffic পাঠান, metric দেখুন, ধীরে ধীরে বাড়ান
- Blue-green — দুই version একসাথে চালান, atomic-ভাবে traffic switch করুন
kubectl apply -n argo-rollouts \
-f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml analysis সহ Canary:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: order-service
namespace: production
spec:
replicas: 5
strategy:
canary:
steps:
- setWeight: 10 # send 10% to new version
- pause: { duration: 10m } # wait 10 minutes
- analysis:
templates:
- templateName: success-rate
- setWeight: 30
- pause: { duration: 10m }
- setWeight: 60
- pause: { duration: 10m }
- setWeight: 100 # fully roll out
canaryService: order-service-canary
stableService: order-service-stable
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: myorg/order-service:1.2.0 # AnalysisTemplate — query Prometheus, abort if error rate too high
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
namespace: production
spec:
metrics:
- name: success-rate
interval: 1m
successCondition: result[0] >= 0.99 # 99%+ success rate
failureLimit: 3
provider:
prometheus:
address: http://prometheus:9090
query: |
sum(rate(http_requests_total{
job="order-service",
status!~"5.."
}[5m])) /
sum(rate(http_requests_total{
job="order-service"
}[5m])) analysis ফেইল করলে: Argo Rollouts অটোমেটিক রোলব্যাক করে। কোনো মানুষের হস্তক্ষেপ লাগে না।
# Watch rollout progress
kubectl argo rollouts get rollout order-service -n production --watch
# Manually abort
kubectl argo rollouts abort order-service -n production
# Manually promote (skip pause)
kubectl argo rollouts promote order-service -n production CI/CD Pipeline
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and push image
run: |
docker build -t myorg/order-service:${{ github.sha }} .
docker push myorg/order-service:${{ github.sha }}
# Update the image tag in the GitOps repo
- name: Update image tag
run: |
git clone https://x-token:${{ secrets.GITOPS_TOKEN }}@github.com/myorg/k8s-config
cd k8s-config
# Update the tag in values file
sed -i "s/tag: .*/tag: \"${{ github.sha }}\"/" apps/order-service/values-production.yaml
git config user.email "ci@myorg.com"
git config user.name "CI"
git commit -am "deploy order-service ${{ github.sha }}"
git push
# ArgoCD detects the git change and syncs automatically CI pipeline কখনো সরাসরি kubectl বা ক্লাস্টার স্পর্শ করে না। এটা শুধু git আপডেট করে। বাকিটা ArgoCD সামলায়। এর মানে:
- CI-এর cluster credential লাগে না
- প্রতিটা deploy একটা git commit (পূর্ণ audit log)
- Rollback =
git revert+ ArgoCD sync করে