This repository contains the GitOps configuration for the TODO application using ArgoCD with an app-of-apps pattern.
todo-gitops/
├── app-of-apps.yaml # Main ArgoCD application managing all apps
├── applications/ # ArgoCD application definitions
│ ├── todo-dev.yaml # Development environment
│ ├── todo-staging.yaml # Staging environment
│ └── sealed-secrets.yaml # Sealed Secrets controller
├── environments/ # Environment-specific configurations
│ ├── dev/ # Development environment
│ │ └── redis-sealedsecret.yaml
│ └── staging/ # Staging environment
│ └── redis-sealedsecret.yaml
├── bootstrap/ # Cluster setup scripts
│ ├── setup.sh # Linux/WSL setup script
│ └── setup.bat # Windows setup script
└── docs/ # Documentation
# Install WSL2 with Ubuntu
wsl --install -d Ubuntu
# Install Docker Desktop with WSL2 backend
# Download from: https://www.docker.com/products/docker-desktop
# In WSL2 terminal:
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
# Install k3d
curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash
# Install Helm
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
# Install kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
# Install k3d
curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash
# Install Helm
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# Install ArgoCD CLI
curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
# Install kubeseal (for Sealed Secrets)
wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/kubeseal-0.24.0-linux-amd64.tar.gz
tar -xvzf kubeseal-0.24.0-linux-amd64.tar.gz kubeseal
sudo install -m 755 kubeseal /usr/local/bin/kubesealLinux/WSL2:
cd bootstrap
chmod +x setup.sh
./setup.shWindows:
cd bootstrap
setup.bat# Create k3d cluster
k3d cluster create todo-local \
--api-port 6550 \
--servers 1 \
--agents 2 \
--port "8080:80@loadbalancer" \
--port "8443:443@loadbalancer" \
--registry-create "k3d-registry.localhost:5001" \
--k3s-arg "--disable=traefik@server:0" \
--wait
# Install Traefik
helm repo add traefik https://traefik.github.io/charts
helm repo update
helm upgrade --install traefik traefik/traefik \
--namespace traefik-system \
--create-namespace \
--wait
# Install ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Wait for ArgoCD to be ready
kubectl wait --for=condition=available --timeout=600s deployment/argocd-server -n argocd
# Expose ArgoCD UI
kubectl patch svc argocd-server -n argocd -p '{"spec":{"type":"NodePort","ports":[{"port":80,"nodePort":30080},{"port":443,"nodePort":30443}]}}'
# Get ArgoCD admin password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -dAfter setup completion:
- ArgoCD UI: https://localhost:30443
- Username:
admin - Password: (from setup output)
- Username:
- TODO App (Dev): http://todo-dev.local:8080 (after deployment)
- Kubernetes API: https://localhost:6550
This repository uses Sealed Secrets for secure secret management in GitOps.
# Create a secret
echo -n 'my-secret-password' | kubeseal --raw --from-file=/dev/stdin --name redis-secret --namespace todo-dev
# Create sealed secret manifest
cat > redis-sealedsecret.yaml << EOF
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: redis-secret
namespace: todo-dev
spec:
encryptedData:
redis-password: <encrypted-value-from-above>
template:
metadata:
name: redis-secret
namespace: todo-dev
type: Opaque
EOF- Create new sealed secret with kubeseal
- Update the respective environment file
- Commit and push changes
- ArgoCD will automatically sync the new secret
- Auto-sync: Enabled
- Source:
todo-apprepository,mainbranch - Image Tag:
latest - Namespace:
todo-dev
- Auto-sync: Disabled (manual approval required)
- Source:
todo-apprepository,mainbranch - Image Tag:
stable - Namespace:
todo-staging
- Code Changes: Developers push to
todo-apprepository - CI/CD: GitHub Actions builds and pushes container image
- Auto-Deployment: ArgoCD detects changes and deploys to dev
- Manual Promotion: DevOps team manually syncs staging environment
- Monitoring: Health checks and metrics monitoring
# Check application health
kubectl get applications -n argocd
# Check pod status
kubectl get pods -n todo-dev
kubectl get pods -n todo-staging
# Check ArgoCD sync status
argocd app list
argocd app get todo-dev- Application Metrics: Available at
/metricsendpoint - Kubernetes Metrics: Metrics Server installed
- HPA Status:
kubectl get hpa -n todo-dev
# Application logs
kubectl logs -f deployment/todo -n todo-dev
# ArgoCD logs
kubectl logs -f deployment/argocd-server -n argocd# Sync development environment
argocd app sync todo-dev
# Sync staging environment
argocd app sync todo-staging
# Sync all applications
argocd app sync -l environment=dev# Update dev environment image tag
argocd app set todo-dev --parameter image.tag=v1.2.3
# Update staging environment image tag
argocd app set todo-staging --parameter image.tag=v1.2.3# Scale dev environment
kubectl scale deployment todo -n todo-dev --replicas=3
# Check HPA status
kubectl get hpa -n todo-dev# Create load generator pod
kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh
# Inside the pod, generate load
while true; do wget -q -O- http://todo.todo-dev.svc.cluster.local/api/todos; done# Install k6
sudo apt-get update
sudo apt-get install k6
# Create load test script
cat > load-test.js << 'EOF'
import http from 'k6/http';
import { check } from 'k6';
export let options = {
stages: [
{ duration: '2m', target: 20 },
{ duration: '5m', target: 20 },
{ duration: '2m', target: 0 },
],
};
export default function () {
let response = http.get('http://todo-dev.local:8080/api/todos');
check(response, { 'status was 200': (r) => r.status == 200 });
}
EOF
# Run load test
k6 run load-test.jsMonitor scaling:
# Watch HPA scaling
kubectl get hpa -n todo-dev -w
# Watch pod scaling
kubectl get pods -n todo-dev -wApplication Stuck in Progressing:
# Check application status
argocd app get todo-dev
# Check events
kubectl get events -n todo-dev --sort-by='.lastTimestamp'
# Force refresh
argocd app get todo-dev --refreshSync Failures:
# Check sync status
argocd app get todo-dev --show-operation
# Manual sync with prune
argocd app sync todo-dev --prune
# Reset application
argocd app actions run todo-dev restart --kind DeploymentPods Not Starting:
# Check pod status
kubectl describe pod <pod-name> -n todo-dev
# Check logs
kubectl logs <pod-name> -n todo-dev
# Check events
kubectl get events -n todo-dev --field-selector involvedObject.name=<pod-name>ImagePullBackOff:
# Check image exists in registry
docker pull k3d-registry.localhost:5001/todo-app:latest
# Check secret for private registries
kubectl get secrets -n todo-dev
kubectl describe secret <image-pull-secret> -n todo-devService Not Accessible:
# Check service
kubectl get svc -n todo-dev
kubectl describe svc todo -n todo-dev
# Check endpoints
kubectl get endpoints -n todo-dev
# Test internal connectivity
kubectl run debug --image=busybox -it --rm --restart=Never -- nslookup todo.todo-dev.svc.cluster.localIngress Issues:
# Check ingress
kubectl get ingress -n todo-dev
kubectl describe ingress todo -n todo-dev
# Check Traefik logs
kubectl logs -f deployment/traefik -n traefik-systemOut of Resources:
# Check node resources
kubectl top nodes
kubectl describe nodes
# Check pod resources
kubectl top pods -n todo-dev
# Check resource quotas
kubectl get resourcequota -n todo-devRollback Deployment:
# Check rollout history
kubectl rollout history deployment/todo -n todo-dev
# Rollback to previous version
kubectl rollout undo deployment/todo -n todo-dev
# Rollback to specific revision
kubectl rollout undo deployment/todo --to-revision=2 -n todo-devRollback via ArgoCD:
# View application history
argocd app history todo-dev
# Rollback to previous version
argocd app rollback todo-dev <revision-id>- ArgoCD Documentation
- Sealed Secrets Documentation
- k3d Documentation
- Helm Documentation
- Kubernetes Documentation
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes
- Test locally with the bootstrap script
- Commit your changes:
git commit -am 'Add some feature' - Push to the branch:
git push origin feature/my-feature - Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.