DevOpsClicks
← Home
🐙 Cloud-Native CI/CD

GitHub Actions Complete Guide

YAML workflows, marketplace actions, matrix builds, security scanning, Docker deployments, and Kubernetes CD for every tech stack.

12
Chapters
25+
Workflows
100%
Free
01🐙

Introduction to GitHub Actions

CI/CD Built Into GitHub

GitHub Actions is GitHub's built-in CI/CD system. Every time you push code, open a pull request, or create a release, Actions can automatically build, test, and deploy your code. No separate CI server to manage — it's part of GitHub itself. Free for public repos, 2000 minutes/month free for private repos.
Key Concepts
📄
Workflow
A YAML file in .github/workflows/ that defines your automation. You can have multiple workflows per repo. Each workflow handles a different task.
🎯
Event/Trigger
What starts the workflow: push, pull_request, schedule (cron), release, manual (workflow_dispatch). Multiple triggers per workflow.
💼
Job
A set of steps that run on one runner (machine). Jobs run in parallel by default. Add needs: to create dependencies.
👣
Step
One command or action inside a job. Runs sequentially. Can be a shell command (run:) or a marketplace action (uses:).
🔧
Action
A reusable piece of automation from the GitHub Marketplace. actions/checkout checks out code, actions/setup-java installs Java. 15,000+ actions available.
🏃
Runner
The machine that executes your workflow. GitHub-hosted (ubuntu, windows, macos) or self-hosted (your own servers).
02📝

Workflow Basics

Your First Workflow File

Workflow files live in .github/workflows/ directory. Name them anything.yml. GitHub detects them automatically.
WORKFLOW# .github/workflows/ci.yml name: CI Pipeline # Display name in GitHub UI on: # WHEN to run push: branches: [main, develop] pull_request: branches: [main] jobs: # WHAT to run build: runs-on: ubuntu-latest # WHERE to run steps: - uses: actions/checkout@v4 # Step 1: checkout code - uses: actions/setup-java@v4 # Step 2: install Java with: java-version: '17' distribution: 'temurin' - run: mvn clean package # Step 3: build - run: mvn test # Step 4: test
03🎯

Triggers & Events

When Workflows Run

YAML# Push to specific branches on: push: branches: [main, release/*] paths: ['src/**', 'pom.xml'] # Only when these files change # Pull request events on: pull_request: types: [opened, synchronize, reopened] # Scheduled (cron) on: schedule: - cron: '0 2 * * *' # Every day at 2 AM UTC # Manual trigger (button in GitHub UI) on: workflow_dispatch: inputs: environment: type: choice options: [staging, production] # On release published on: release: types: [published]
04💼

Jobs, Steps & Matrix

Parallel Builds & Multi-Version Testing

YAMLjobs: test: runs-on: ubuntu-latest strategy: matrix: java: [11, 17, 21] # Test on 3 Java versions os: [ubuntu-latest, windows-latest] steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: java-version: ${{ matrix.java }} - run: mvn test # Runs 6 combinations: Java11-ubuntu, Java11-windows, Java17-ubuntu... deploy: needs: test # Wait for ALL test jobs to pass if: github.ref == 'refs/heads/main' # Only on main branch runs-on: ubuntu-latest steps: - run: echo "Deploying..."
05🔨

CI Pipeline Examples

Every Stack — Java, Node, React, Python, Flutter

Java Spring Boot
YAMLname: Java CI on: { push: { branches: [main] } } jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: { java-version: '17', distribution: 'temurin' } - run: mvn clean package # Artifact: target/app.jar (fat JAR ~40MB)
Node.js / React
YAMLname: Node CI on: { push: { branches: [main] } } jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: '20' } - run: npm ci - run: npm run lint - run: npm test -- --coverage --watchAll=false - run: npm run build # React artifact: build/ folder (static HTML/JS/CSS ~5MB) # Node artifact: dist/ folder (compiled TypeScript)
Python
YAMLname: Python CI on: { push: { branches: [main] } } jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: { python-version: '3.12' } - run: pip install -r requirements.txt - run: python -m pytest tests/ --junitxml=results.xml
Flutter
YAMLname: Flutter CI on: { push: { branches: [main] } } jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: subosito/flutter-action@v2 with: { flutter-version: '3.19' } - run: flutter pub get - run: flutter test - run: flutter build apk --release # Artifact: build/app/outputs/flutter-apk/app-release.apk
06🐳

Docker Build & Push

Containerize and Push to Any Registry

YAMLname: Docker Build on: { push: { branches: [main] } } jobs: docker: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # Login to registry - uses: docker/login-action@v3 with: registry: ghcr.io # GitHub Container Registry username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} # Auto-provided! # Build and push - uses: docker/build-push-action@v5 with: push: true tags: ghcr.io/${{ github.repository }}:${{ github.sha }} # For AWS ECR: - uses: aws-actions/amazon-ecr-login@v2 # For Azure ACR: - uses: docker/login-action@v3 with: registry: myacr.azurecr.io username: ${{ secrets.ACR_USERNAME }} password: ${{ secrets.ACR_PASSWORD }}
07🛡️

Security Scanning

SonarQube, Trivy & CodeQL

YAML# SonarQube SAST sonarqube: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: { fetch-depth: 0 } - uses: SonarSource/sonarqube-scan-action@master env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_HOST_URL: ${{ vars.SONAR_URL }} # Trivy Container Scan trivy: runs-on: ubuntu-latest steps: - uses: aquasecurity/trivy-action@master with: image-ref: ghcr.io/myorg/myapp:${{ github.sha }} severity: CRITICAL,HIGH exit-code: '1' # Fail if critical vulns found # GitHub CodeQL (free built-in SAST) codeql: runs-on: ubuntu-latest permissions: { security-events: write } steps: - uses: actions/checkout@v4 - uses: github/codeql-action/init@v3 with: { languages: javascript } - uses: github/codeql-action/analyze@v3
💡 CodeQL is Free

GitHub CodeQL provides free SAST scanning for public AND private repos. It catches SQL injection, XSS, and other vulnerabilities. Enable it in Security tab → Code scanning → Set up CodeQL.

08🚀

Deploy to Kubernetes

EKS, AKS, GKE Deployments

YAML# Deploy to AWS EKS deploy-eks: needs: [build, security] runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' environment: production # Requires approval! steps: - uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }} aws-region: ap-south-1 - run: aws eks update-kubeconfig --name my-cluster - run: | kubectl set image deployment/order-service \ app=$ECR_REGISTRY/order-service:${{ github.sha }} \ -n production kubectl rollout status deployment/order-service -n production
Deploy React to S3 + CloudFront
YAMLdeploy-frontend: needs: build runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: - uses: actions/download-artifact@v4 with: { name: frontend-build } - uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.AWS_KEY }} aws-secret-access-key: ${{ secrets.AWS_SECRET }} aws-region: ap-south-1 - run: aws s3 sync build/ s3://my-frontend-bucket --delete - run: aws cloudfront create-invalidation --distribution-id E12345 --paths '/*'
09🔐

Secrets & Environments

Secure Configuration

Secrets are encrypted variables stored in GitHub Settings. They are injected at runtime and masked in logs. Environments add approval gates for production deployments.
🔑
Repository Secrets
Settings → Secrets → Actions. Available to all workflows in the repo. Use for API keys, registry passwords.
🌍
Environment Secrets
Settings → Environments → production → Add secret. Only available to jobs targeting that environment. Use for prod-only credentials.
Environment Protection
Require reviewers (2 people must approve), wait timer (delay 30 min), branch restriction (only main can deploy to production).
🆓
GITHUB_TOKEN
Auto-generated token for each workflow run. Permissions scoped to the repo. Use for pushing Docker images to ghcr.io, creating releases.
10♻️

Reusable Workflows

DRY Across Repositories

YAML# .github/workflows/reusable-docker.yml (in shared repo) on: workflow_call: # Makes this workflow callable inputs: image_name: type: string required: true secrets: registry_password: required: true jobs: docker: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: docker build -t ghcr.io/org/${{ inputs.image_name }}:${{ github.sha }} . - run: docker push ghcr.io/org/${{ inputs.image_name }}:${{ github.sha }} # ═══ Calling it from another repo ═══ # .github/workflows/ci.yml jobs: build-docker: uses: myorg/shared-workflows/.github/workflows/reusable-docker.yml@main with: image_name: order-service secrets: registry_password: ${{ secrets.GHCR_TOKEN }}
11🏃

Self-Hosted Runners

Run on Your Own Infrastructure

GitHub-hosted runners are managed VMs (fresh each run). Self-hosted runners are YOUR machines registered with GitHub — faster (no VM spin-up), access to private networks, persistent tools.
FeatureGitHub-HostedSelf-Hosted
SetupZero — just use itInstall runner agent on your server
Speed~30s VM spin-upInstant (always running)
NetworkPublic internet onlyAccess to private VPCs, databases
Cost2000 min/month free, then $0.008/minYour server cost only
MaintenanceNone — GitHub managesYou patch, update, and monitor
12💼

Interview Questions

GitHub Actions Q&A

What is GitHub Actions?
Cloud-native CI/CD built into GitHub. Define workflows in YAML (.github/workflows/). Triggered by push, PR, schedule, manual. 2000 free minutes/month for private repos.
Workflow vs Job vs Step?
Workflow = YAML file (the recipe). Job = set of steps on one runner (a chapter). Step = one command or action (one instruction). Jobs run in parallel unless needs: is set.
What is the Marketplace?
Repository of 15,000+ pre-built Actions. actions/checkout, actions/setup-java, docker/build-push-action. Use with uses: keyword. Like plugins for your workflow.
How secrets work?
Stored encrypted in Settings → Secrets. Accessed as ${{ secrets.NAME }}. Masked in logs. Environment secrets add extra layer — only available to specific environment jobs.
GitHub Actions vs Jenkins?
GH Actions: cloud-hosted, YAML, zero maintenance, tight GitHub integration, 15K+ marketplace actions. Jenkins: self-hosted, Groovy, 1800+ plugins, full control, more complex.
GitHub Actions vs GitLab CI?
GH Actions: event-driven, marketplace-centric, uses: syntax. GitLab: all-in-one platform, built-in registry + security + boards. Both use YAML. GitLab is more complete, GH Actions is simpler.
What is a matrix strategy?
Run the same job across multiple configurations (Java 11/17/21 × ubuntu/windows). Creates one job per combination. Tests compatibility across versions and platforms.
Reusable workflows?
Define workflow with on: workflow_call. Other repos call it with uses: org/repo/.github/workflows/file.yml@main. Like Shared Libraries in Jenkins.