DevOps Bootcamp
— Complete Notes
All 17 modules. Every tool explained in plain language — what it is, what problem it solves, then how to use it. Your GitHub repos from this course become your job portfolio.
What is DevOps?
The culture, the why, and what it actually means day-to-day.
What is DevOps?
DevOps is a way of working where Development (people who write code) and Operations (people who run servers) work together instead of separately. Before DevOps, developers threw code "over the wall" to ops, who then scrambled to deploy it. Bugs found in production got blamed back and forth. DevOps breaks down that wall.
DevOps is not a tool or a job title — it's a culture backed by automation. The goal: ship software faster, more reliably, and with fewer manual steps.
| Topic | Traditional (Siloed) | DevOps |
|---|---|---|
| Releases | Every 3–6 months, big-bang deploy | Daily or hourly, small increments |
| Deployment | Manual, error-prone, weekend work | Automated pipeline — one button or auto |
| Dev ↔ Ops | Separate teams, blame culture | Shared responsibility, shared tools |
| Failure handling | Find someone to blame | Blameless postmortem — fix the process |
| Infrastructure | Manually configured servers | Code — Terraform, Ansible, reproducible |
| Monitoring | User complaints = first alert | Automated alerts before users notice |
- CI
- Continuous Integration — code is merged and tested automatically on every push.
- CD
- Continuous Delivery/Deployment — tested code is automatically deployed to staging or production.
- IaC
- Infrastructure as Code — servers and networks defined in files, version-controlled like software.
- SRE
- Site Reliability Engineering — Google's version of DevOps. Focus on reliability, SLOs, error budgets.
- Blameless Postmortem
- After an outage, document what happened and fix the process — don't punish people.
- Shift Left
- Move testing and security earlier in the pipeline — catch bugs before they reach production.
The DevOps Roadmap
What to learn, in what order, and why — the complete career path.
The Learning Path
DevOps has many tools and it's easy to get overwhelmed. The key is order — each skill builds on the previous one. Try to learn Docker before you understand Linux and you'll struggle. Learn Kubernetes before Docker and you'll be lost. Follow this sequence and every tool will make sense.
Phase 1 — Foundation (must before anything else) Linux basics → Terminal, files, users, processes, networking Git → Version control, branching, GitHub Phase 2 — Scripting & Automation Bash scripting → Loops, conditions, cron, functions Python basics → Scripts, boto3, file parsing Phase 3 — Containers Docker → Images, containers, Dockerfile, Compose Podman → Rootless containers, RHEL environments Phase 4 — CI/CD GitHub Actions → Workflows, triggers, secrets Jenkins (optional) → Older pipelines, enterprise Phase 5 — Infrastructure as Code Terraform → Cloud provisioning, state, modules Ansible → Server configuration, playbooks, roles Phase 6 — Cloud AWS → EC2, VPC, S3, RDS, IAM, Lambda, CLI Phase 7 — Orchestration Kubernetes → Pods, deployments, services, kubectl Phase 8 — Monitoring & Observability Prometheus + Grafana → Metrics, dashboards, alerts Loki → Log aggregation Phase 9 — Advanced GitOps / ArgoCD → Declarative K8s deployments Secrets Management → Vault, AWS Secrets Manager
Don't try to learn everything at once. Master Linux and Git first — everything else builds on them. A DevOps engineer who knows Linux deeply is worth more than someone who touched 10 tools shallowly.
Linux for DevOps
The non-negotiable foundation — every DevOps tool runs on Linux.
Why Linux is Non-Negotiable
Every Docker container runs Linux. Every Kubernetes node runs Linux. Every AWS EC2 instance defaults to Linux. Every CI/CD runner uses Linux. If you can't navigate a Linux terminal, you can't do DevOps. This module covers the specific Linux skills DevOps engineers use daily — not everything, just what matters.
# Process management — what's running, what's eating CPU ps aux | grep docker top / htop systemctl status nginx journalctl -u nginx -f --since "1 hour ago" # Network — what's listening, what's connecting ss -tulnp # open ports curl -I https://example.com # test HTTP endpoint netstat -rn # routing table # File operations DevOps engineers use constantly tail -f /var/log/nginx/access.log # watch logs live grep -r "ERROR" /var/log/ # search logs find / -name "*.conf" 2>/dev/null # find config files sed -i 's/old/new/g' file.conf # replace in file awk '{print $1}' access.log # extract columns # Permissions DevOps needs chmod 400 ~/.ssh/id_rsa # SSH key — must be this chmod +x deploy.sh # make script executable chown -R nginx:nginx /var/www/ # web server ownership # Disk & performance df -h # disk usage du -sh /var/lib/docker # docker using how much? free -h # RAM usage iostat -x 1 # disk I/O live
Git & Version Control
Track every change, collaborate without chaos, never lose work again.
What is Git?
Git is a version control system — it tracks every change to every file over time. Think of it as unlimited Ctrl+Z for your entire project, with the ability to see exactly who changed what, when, and why. GitHub is a website that hosts Git repositories so teams can collaborate. Every DevOps pipeline starts with a Git push.
| Action | Git Command | What Happens |
|---|---|---|
| Start tracking | git init | Creates .git folder — repo starts here |
| Stage changes | git add . | Mark files ready to commit |
| Save snapshot | git commit -m "msg" | Permanent record of changes |
| Push to GitHub | git push origin main | Upload commits to remote repo |
| Get latest | git pull | Download + merge remote changes |
| New branch | git checkout -b feature | Isolated workspace for new work |
| Merge branch | git merge feature | Combine branch back into main |
# First time setup git config --global user.name "Kamran Kabeer" git config --global user.email "kamran@devriston.com.pk" # Clone a repo git clone https://github.com/muhammadkamrankabeer-oss/repo.git cd repo # Create a feature branch — never work directly on main git checkout -b feature/add-nginx-config # Make changes, then commit git add nginx.conf git commit -m "feat: add nginx virtual host config for devriston.com.pk" # Push branch to GitHub git push origin feature/add-nginx-config # On GitHub: open Pull Request → review → merge to main # Common fixes git log --oneline # see commit history git diff # see what changed git stash # temporarily save uncommitted changes git stash pop # restore stashed changes git reset --hard HEAD~1 # undo last commit (dangerous — use carefully)
Bash Scripting
Automate repetitive tasks — do in 2 seconds what takes 10 minutes manually.
Why Bash for DevOps?
Bash is the glue of DevOps. It's available on every Linux server with zero installation. CI/CD pipelines run bash. Docker entrypoints run bash. Deployment scripts are bash. Monitoring checks are bash. If you can write a bash script, you can automate almost anything on any server anywhere.
#!/bin/bash set -euo pipefail # exit on error, unset var, pipe failure # Variables APP="nginx" ENV=${1:-"staging"} # first argument, default "staging" DATE=$(date +%Y%m%d) # Conditions if systemctl is-active --quiet $APP; then echo "$APP is running" else echo "$APP is down — restarting" systemctl restart $APP fi # Loops SERVERS=("web-01" "web-02" "web-03") for SERVER in "${SERVERS[@]}"; do echo "Deploying to $SERVER..." ssh deploy@$SERVER "cd /app && git pull && systemctl restart app" done # Functions check_disk(){ local THRESHOLD=80 local USAGE=$(df / | awk 'NR==2{print $5}' | tr -d '%') if [ "$USAGE" -gt "$THRESHOLD" ]; then echo "WARNING: Disk at ${USAGE}%" return 1 fi } # Error handling deploy(){ git pull origin main || { echo "Git pull failed"; exit 1; } docker compose up -d --build || { echo "Docker build failed"; exit 1; } echo "Deploy successful" } check_disk && deploy
Docker — Containers
Package your app so it runs the same everywhere — no "works on my machine".
What is Docker?
Docker packages your application and all its dependencies into a container — a lightweight, isolated unit that runs identically on your laptop, a CI server, and a production cloud server. The classic problem: "It works on my machine." Docker solves this permanently. One container image = same behaviour everywhere.
| Feature | Container (Docker) | VM (VirtualBox) | Bare Metal |
|---|---|---|---|
| Startup time | Milliseconds | Minutes | Minutes |
| Size | MBs | GBs | Full OS |
| OS | Shares host kernel | Full guest OS | Full OS |
| Isolation | Process-level | Full hardware-level | None |
| Portability | Run anywhere with Docker | Import/export VM images | Hardware dependent |
| Use case | App packaging, microservices | Full OS simulation, testing | Max performance, databases |
# Images docker pull nginx # download image docker images # list local images docker build -t myapp:v1 . # build from Dockerfile docker rmi myapp:v1 # delete image # Containers docker run -d -p 80:80 --name web nginx # run in background docker ps # list running containers docker ps -a # all containers (including stopped) docker stop web && docker rm web # stop and delete docker exec -it web bash # shell inside container docker logs web -f # follow logs # Dockerfile example FROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt --no-cache-dir COPY . . EXPOSE 8000 CMD ["python", "app.py"] # Docker Compose — multi-container apps docker compose up -d # start all services docker compose down # stop and remove docker compose logs -f # follow all logs docker compose ps # service status
Podman — Docker's Alternative
Rootless containers — more secure, RHEL-native, daemonless.
What is Podman?
Podman does exactly what Docker does — build and run containers — but without a background daemon running as root. Docker requires a daemon (dockerd) running as root all the time, which is a security risk. Podman runs containers as your normal user (rootless) and has no daemon. It's the default on RHEL 8+.
| Feature | Podman | Docker |
|---|---|---|
| Daemon | No daemon — daemonless | dockerd always running as root |
| Rootless | Yes — runs as normal user | No — requires root daemon |
| Commands | Same as Docker (drop-in replacement) | docker run, docker build… |
| Compose | podman-compose (compatible) | docker compose |
| Default on | RHEL 8+, Fedora, CentOS Stream | Ubuntu, most other distros |
| Image format | OCI (compatible with Docker images) | OCI + Docker format |
| Security | Better — no root daemon | Root daemon is attack surface |
# Install on RHEL/AlmaLinux dnf install podman podman-compose -y # Commands are identical to Docker podman pull nginx podman run -d -p 80:80 --name web nginx podman ps podman logs web -f podman exec -it web bash podman stop web && podman rm web # Build image podman build -t myapp:v1 . # Run as systemd service (Podman feature — Docker can't do this easily) podman generate systemd --name web > /etc/systemd/system/web.service systemctl enable --now web # alias docker=podman (makes all your docker scripts work) echo "alias docker=podman" >> ~/.bashrc
CI/CD — Automate Your Deployments
Every code push automatically tested, built, and deployed — no manual steps.
What is CI/CD?
CI (Continuous Integration) means every time a developer pushes code, it's automatically tested — no waiting for a "test day". CD (Continuous Deployment) means after tests pass, the code is automatically deployed to staging or production. Together, CI/CD turns a deploy from a stressful event into a routine, automated process.
| Step | Manual | CI/CD Pipeline |
|---|---|---|
| Trigger | Someone decides "let's deploy" | Every git push to main |
| Tests | Maybe run, maybe forgotten | Always run — fail = stop pipeline |
| Build | Manually run build commands | Automated — same commands every time |
| Deploy | SSH in, run commands, hope | Automated script — reproducible |
| Time | 30–60 minutes of human time | 5–10 minutes, zero human time |
| Errors | Forgotten steps, wrong server | Consistent — same pipeline every time |
| Rollback | Manual, stressful | Re-run previous pipeline or trigger rollback job |
Code Push (git push)
│
▼
[1] Source Stage
└─ Checkout code from repo
[2] Build Stage
└─ Compile code, build Docker image
└─ Run: docker build -t myapp:$COMMIT_SHA .
[3] Test Stage
└─ Unit tests, integration tests, linting
└─ Run: pytest tests/ or npm test
[4] Security Scan (optional but recommended)
└─ Trivy scan Docker image for CVEs
└─ SonarQube for code quality
[5] Push Stage
└─ Push Docker image to registry (ECR, DockerHub)
└─ docker push myapp:$COMMIT_SHA
[6] Deploy Stage
└─ Update server or Kubernetes with new image
└─ Run: kubectl set image deploy/app app=myapp:$COMMIT_SHA
└─ Or: ssh server "docker compose pull && docker compose up -d"
[7] Verify Stage
└─ Health check — is the app responding?
└─ curl -f https://myapp.com/health || rollback
GitHub Actions
Write YAML workflows that run on every push — the most-used CI/CD tool today.
What is GitHub Actions?
GitHub Actions runs automated workflows triggered by events in your GitHub repo — a push, a PR, a schedule. You write a YAML file that defines what to run. GitHub provides free Linux runners that execute your workflow. It's free for public repos and has a generous free tier for private repos.
# .github/workflows/deploy.yml name: Build, Test and Deploy on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build-and-deploy: runs-on: ubuntu-latest steps: # 1 — Checkout code - name: Checkout uses: actions/checkout@v4 # 2 — Run tests - name: Run Tests run: | pip install -r requirements.txt pytest tests/ -v # 3 — Log in to AWS ECR - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ap-south-1 # 4 — Build and push Docker image - name: Build and Push to ECR run: | ECR_URI=123456789.dkr.ecr.ap-south-1.amazonaws.com/myapp aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_URI docker build -t $ECR_URI:${{ github.sha }} . docker push $ECR_URI:${{ github.sha }} # 5 — Deploy to EC2 - name: Deploy to EC2 run: | ssh -i key.pem ec2-user@${{ secrets.EC2_IP }} \ "cd /app && docker compose pull && docker compose up -d"
- Workflow
- A YAML file in .github/workflows/ that defines automated jobs.
- Job
- A group of steps that run on the same runner (machine).
- Step
- A single task — run a command or use a pre-built action.
- Runner
- The machine that executes your workflow. GitHub provides Ubuntu, Windows, macOS runners free.
- Secrets
- Encrypted variables (API keys, passwords) stored in repo settings — never in code.
- Action
- A reusable workflow step from the GitHub marketplace (e.g. actions/checkout).
Terraform — Infrastructure as Code
Write code that creates cloud infrastructure — reproducible, version-controlled.
What is Terraform?
Terraform lets you describe your entire cloud infrastructure in code files (.tf). Instead of clicking through AWS console to create a VPC, EC2, and RDS, you write code and run terraform apply. Terraform figures out what to create, in what order, and makes it happen. It also tracks what it created so it can update or destroy it cleanly later.
| Feature | Terraform | AWS Console | AWS CLI |
|---|---|---|---|
| Reproducible | Yes — same code = same infra | No — manual clicks | Partially — scripts drift |
| Version controlled | Yes — Git tracked | No | Yes if in scripts |
| Multi-cloud | Yes — AWS + GCP + Azure same tool | No — one console per cloud | No — one CLI per cloud |
| Destroy cleanly | terraform destroy | Manual delete everything | Manual scripts |
| Team collaboration | Remote state in S3 | No shared state | No shared state |
| Preview changes | terraform plan | No preview | No preview |
# main.tf terraform { required_providers { aws = { source = "hashicorp/aws", version = "~> 5.0" } } } provider "aws" { region = "ap-south-1" } # VPC resource "aws_vpc" "main" { cidr_block = "10.0.0.0/16" tags = { Name = "devriston-vpc" } } # Public Subnet resource "aws_subnet" "public" { vpc_id = aws_vpc.main.id cidr_block = "10.0.1.0/24" availability_zone = "ap-south-1a" map_public_ip_on_launch = true } # EC2 Instance resource "aws_instance" "web" { ami = "ami-0abcdef1234567890" instance_type = "t2.micro" subnet_id = aws_subnet.public.id tags = { Name = "web-server", Environment = "staging" } } # Commands # terraform init → download providers # terraform plan → preview what will be created # terraform apply → create the infrastructure # terraform destroy → delete everything
Ansible — Automate Server Config
Configure 1 or 100 servers simultaneously with YAML playbooks.
What is Ansible?
Ansible configures servers using YAML files called playbooks. You define what state a server should be in — nginx installed, user created, firewall rule added — and Ansible makes it happen. It connects via SSH, needs no agent installed on target servers, and if a task is already done it skips it (idempotent). Run the same playbook 10 times — same result every time.
| Feature | Ansible | Bash Script | Manual SSH |
|---|---|---|---|
| Multiple servers | One command — all servers | Loop through IPs | SSH each one individually |
| Idempotent | Yes — safe to re-run | Usually not | No |
| Error handling | Built-in — stops on failure | Manual set -e | Manual |
| Readable | YAML — easy to understand | Code — needs comments | N/A |
| Agent needed | No — just SSH | No | No |
| Best for | Server config, app deploy, user mgmt | Simple one-liners, pipelines | One-off emergency fixes |
# inventory.ini — servers to configure [webservers] web-01 ansible_host=192.168.1.10 web-02 ansible_host=192.168.1.11 [all:vars] ansible_user=ec2-user ansible_ssh_private_key_file=~/.ssh/id_ed25519 # playbook.yml — what to do on those servers --- - name: Configure Web Servers hosts: webservers become: yes # sudo tasks: - name: Install Nginx dnf: name: nginx state: present - name: Start and enable Nginx systemd: name: nginx state: started enabled: yes - name: Open firewall for HTTP firewalld: service: http permanent: yes state: enabled immediate: yes - name: Deploy index.html copy: content: "<h1>Deployed by Ansible</h1>" dest: /var/www/html/index.html owner: nginx mode: '0644' # Run the playbook ansible-playbook -i inventory.ini playbook.yml # Check syntax before running ansible-playbook playbook.yml --syntax-check # Dry run — see what would change without changing it ansible-playbook playbook.yml --check
Kubernetes — Container Orchestration
Manage containers at scale — self-healing, load balancing, rolling updates.
What is Kubernetes?
Kubernetes (K8s) manages containers at scale. Docker runs one container on one machine. Kubernetes runs hundreds of containers across dozens of machines — and keeps them healthy. If a container crashes, K8s restarts it. If traffic spikes, it adds more containers. If a server dies, it moves containers to healthy servers. All automatically.
| Feature | Docker (alone) | Kubernetes |
|---|---|---|
| Scale | Manual — run more containers by hand | Automatic — HPA scales based on CPU/memory |
| Self-healing | No — crashed container stays down | Yes — restarts failed containers automatically |
| Load balancing | Manual or external | Built-in Service load balancing |
| Rolling updates | Manual coordination | Automatic — zero-downtime by default |
| Multi-server | Docker Swarm (limited) | Built for multi-node clusters |
| Complexity | Simple to start | Steep learning curve |
# deployment.yml — run 3 replicas of nginx apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80 --- # service.yml — expose deployment to traffic apiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: app: nginx ports: - port: 80 targetPort: 80 type: LoadBalancer # Apply and manage kubectl apply -f deployment.yml kubectl get pods kubectl get services kubectl describe pod nginx-deployment-abc123 kubectl logs nginx-deployment-abc123 kubectl delete deployment nginx-deployment
Monitoring & Observability
Know your system is broken before your users do.
The Three Pillars of Observability
Metrics — numbers over time (CPU 80%, 500 requests/sec, 2ms latency). Logs — text records of what happened ("error: connection refused at 14:32:01"). Traces — the path a request took through your system. Prometheus handles metrics, Grafana visualises them, Loki collects logs, AlertManager sends alerts.
| Tool | What it Does | Windows Equivalent |
|---|---|---|
| Prometheus | Scrapes and stores metrics from your apps and servers | Performance Monitor (perfmon) |
| Grafana | Visualises metrics as dashboards — charts, graphs, gauges | Task Manager graphs (but beautiful) |
| AlertManager | Routes Prometheus alerts to email, Slack, PagerDuty | Windows Event alerts (basic) |
| Loki | Collects and indexes logs — like Elasticsearch but lighter | Event Viewer |
| Node Exporter | Exports Linux system metrics (CPU, RAM, disk) to Prometheus | WMI Exporter |
# docker-compose.yml services: prometheus: image: prom/prometheus:latest volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml ports: - "9090:9090" grafana: image: grafana/grafana:latest ports: - "3000:3000" environment: - GF_SECURITY_ADMIN_PASSWORD=devriston123 node-exporter: image: prom/node-exporter:latest ports: - "9100:9100" loki: image: grafana/loki:latest ports: - "3100:3100" # prometheus.yml — what to scrape scrape_configs: - job_name: 'node' static_configs: - targets: ['node-exporter:9100'] - job_name: 'prometheus' static_configs: - targets: ['localhost:9090'] # Useful PromQL queries # CPU usage % 100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) # RAM used % (1 - node_memory_MemAvailable_bytes/node_memory_MemTotal_bytes) * 100 # Disk used % (1 - node_filesystem_avail_bytes/node_filesystem_size_bytes) * 100
DevOps Workstation Setup
Set up your full DevOps environment in under 10 minutes with Ansible.
Why Automate Your Workstation?
Every DevOps engineer needs the same set of tools: Terraform, Docker, Ansible, AWS CLI, kubectl, Git, Python. Installing these manually takes an hour. Forgetting one step means things break later. The professional approach: write an Ansible playbook that installs everything in one shot. New laptop? Run the playbook. Done in 10 minutes, identical every time.
# workstation.yml --- - name: Setup DevOps Workstation hosts: localhost become: yes vars: terraform_version: "1.8.0" kubectl_version: "v1.29.0" tasks: - name: Install core tools dnf: name: - git - python3 - python3-pip - curl - wget - unzip - jq - vim - htop state: present - name: Install Docker block: - dnf: name=docker state=present - systemd: name=docker state=started enabled=yes - user: name="{{ ansible_user }}" groups=docker append=yes - name: Install AWS CLI shell: | curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip unzip -q /tmp/awscliv2.zip -d /tmp /tmp/aws/install --update args: creates: /usr/local/bin/aws - name: Install Terraform unarchive: src: "https://releases.hashicorp.com/terraform/{{ terraform_version }}/terraform_{{ terraform_version }}_linux_amd64.zip" dest: /usr/local/bin/ remote_src: yes mode: '0755' - name: Install Ansible pip: name: ansible state: present # Run it: ansible-playbook workstation.yml --ask-become-pass
Python for DevOps
Not a developer course — just what DevOps engineers actually use Python for.
Why Python for DevOps?
You don't need to be a software developer to use Python in DevOps. You need to read a script, modify it, write small automation tools, and use boto3 to interact with AWS programmatically. Python is the glue between your bash scripts, your AWS account, and your CI/CD pipeline.
# 1 — boto3: stop all dev EC2 instances import boto3 ec2 = boto3.client('ec2', region_name='ap-south-1') reservations = ec2.describe_instances( Filters=[{'Name':'tag:Env','Values':['dev']}, {'Name':'instance-state-name','Values':['running']}] )['Reservations'] ids = [i['InstanceId'] for r in reservations for i in r['Instances']] if ids: ec2.stop_instances(InstanceIds=ids) print(f"Stopped: {ids}") # 2 — Parse JSON config file import json with open('config.json') as f: config = json.load(f) db_host = config['database']['host'] print(f"Connecting to {db_host}") # 3 — HTTP health check import requests import sys def health_check(url): try: r = requests.get(url, timeout=5) if r.status_code == 200: print(f"✓ {url} — OK") else: print(f"✗ {url} — {r.status_code}") sys.exit(1) except requests.exceptions.ConnectionError: print(f"✗ {url} — UNREACHABLE") sys.exit(1) health_check("https://devriston.com.pk") # 4 — Read environment variables (secrets) import os DB_PASSWORD = os.environ.get('DB_PASSWORD') if not DB_PASSWORD: raise ValueError("DB_PASSWORD environment variable not set")
Secrets Management
Never put passwords in your code. Store and access secrets safely.
Why Secrets Management?
Secrets are passwords, API keys, SSH keys, database credentials — anything that gives access. Beginners put them in code files. That code goes to GitHub. GitHub is public. Your AWS account gets compromised in minutes. Secrets management means storing credentials in a secure vault and having applications fetch them at runtime — never hardcoded, never in Git.
| Location | Safe? | Why |
|---|---|---|
| Hardcoded in code | ❌ Never | Goes to Git, visible to everyone |
| .env file committed | ❌ Never | Same as hardcoded |
| Environment variables (local) | ✅ OK | Not in code, not persisted |
| GitHub Secrets | ✅ Good | Encrypted, only exposed in Actions runners |
| AWS Secrets Manager | ✅ Best | Centralized, audited, automatic rotation |
| HashiCorp Vault | ✅ Best | Self-hosted, full control, multi-cloud |
# Store a secret aws secretsmanager create-secret \ --name "prod/myapp/db-password" \ --secret-string "SuperSecurePassword123!" # Retrieve in your app (Python) import boto3, json def get_secret(secret_name): client = boto3.client('secretsmanager', region_name='ap-south-1') response = client.get_secret_value(SecretId=secret_name) return json.loads(response['SecretString']) secret = get_secret("prod/myapp/db-password") db_password = secret['password'] # GitHub Actions — use secrets in workflow # Add in repo Settings → Secrets → New secret # Then use in workflow: env: DB_PASSWORD: ${{ secrets.DB_PASSWORD }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
GitOps & ArgoCD
Your Git repo is the single source of truth — ArgoCD makes Kubernetes match it.
What is GitOps?
GitOps is a deployment model where your Git repository is the single source of truth for your infrastructure and application state. Instead of running kubectl commands manually, you push a change to Git — and a tool (ArgoCD) detects the change and automatically syncs your Kubernetes cluster to match. The cluster always reflects what's in Git. No manual kubectl, no SSH, no drift.
| Step | Traditional CI/CD | GitOps (ArgoCD) |
|---|---|---|
| Deploy trigger | Pipeline runs kubectl apply | Git push → ArgoCD detects and syncs |
| Source of truth | Pipeline script + manual state | Git repo — always |
| Drift detection | None — cluster can drift from code | ArgoCD alerts if cluster drifts from Git |
| Rollback | Re-run old pipeline | git revert → ArgoCD auto-syncs |
| Audit trail | Pipeline logs | Git history — who changed what, when |
| Access needed | Pipeline needs kubectl access | Only ArgoCD needs kubectl — pipeline just pushes Git |
# Install ArgoCD in Kubernetes kubectl create namespace argocd kubectl apply -n argocd -f \ https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml # Get admin password kubectl get secret argocd-initial-admin-secret \ -n argocd -o jsonpath="{.data.password}" | base64 -d # Port-forward to access UI kubectl port-forward svc/argocd-server -n argocd 8080:443 # Create an ArgoCD Application (YAML) apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: myapp namespace: argocd spec: project: default source: repoURL: https://github.com/muhammadkamrankabeer-oss/myapp targetRevision: main path: k8s/ # folder with K8s YAML files destination: server: https://kubernetes.default.svc namespace: production syncPolicy: automated: prune: true # delete resources removed from Git selfHeal: true # revert manual kubectl changes # Now: push a change to k8s/ folder → ArgoCD deploys it automatically
GitOps is the direction the industry is moving. If your company uses Kubernetes, there's a strong chance they're moving to or already using ArgoCD or Flux. This is a skill that makes you stand out in 2026 job interviews.
Ready to go beyond reading?
The live bootcamp includes hands-on labs, 5 real GitHub portfolio projects, Q&A sessions, and a final project deploying a full production stack. Same instructor who wrote these notes.
💬 Enroll via WhatsApp →Batch info & fee on request