DEV Community

Cover image for Day 23 - Github Actions CI/CD Pipeline
Rahul Joshi
Rahul Joshi

Posted on

Day 23 - Github Actions CI/CD Pipeline

In Present Time software teams need fast, secure, and automated delivery.

Earlier, release flow looked like this:

Developer writes code
        ↓
Manual build
        ↓
Manual test
        ↓
Manual deployment
        ↓
Production issue
Enter fullscreen mode Exit fullscreen mode

Today, GitHub Actions can automate this entire process directly from your GitHub repository.


πŸ”— Resources


What is GitHub Actions?

GitHub Actions is GitHub’s automation platform for building, testing, scanning, packaging, and deploying applications.

You define automation using YAML files inside:

.github/workflows/
Enter fullscreen mode Exit fullscreen mode

Example:

.github/workflows/ci-cd.yml
Enter fullscreen mode Exit fullscreen mode

A workflow can run when:

Code is pushed
Pull request is opened
Tag is created
Manual trigger is clicked
Schedule runs
External webhook/event triggers it
Enter fullscreen mode Exit fullscreen mode

GitHub supports workflow triggers for repository activity, schedules, and external events.


Why GitHub Actions?

GitHub Actions is powerful because it is close to the source code.

Benefits:

Code + CI/CD + Security + Packages + Deployments
Enter fullscreen mode Exit fullscreen mode

inside one platform.

It helps teams:

  • Build automatically
  • Test every pull request
  • Run security scans
  • Build Docker images
  • Push artifacts
  • Deploy to cloud
  • Deploy to Kubernetes
  • Use approval gates
  • Use OIDC instead of long-lived cloud keys

GitHub Actions Core Concepts

Workflow

A workflow is the complete automation file.

Example:

name: CI/CD Pipeline
Enter fullscreen mode Exit fullscreen mode

It contains triggers, jobs, permissions, and steps.


Event

An event starts the workflow.

Example:

on:
  push:
    branches: [ main ]
  pull_request:
Enter fullscreen mode Exit fullscreen mode

This means the workflow runs on push to main and pull requests.


Job

A job is a group of steps.

Example:

jobs:
  build:
    runs-on: ubuntu-latest
Enter fullscreen mode Exit fullscreen mode

Step

A step is a single command or action.

Example:

steps:
  - name: Checkout Code
    uses: actions/checkout@v4
Enter fullscreen mode Exit fullscreen mode

Action

An action is a reusable task.

Example:

uses: actions/setup-node@v4
Enter fullscreen mode Exit fullscreen mode

Actions help you reuse community or official automation components.


Runner

A runner is the machine that executes your job.

There are two main types:

GitHub-hosted runner
Self-hosted runner
Enter fullscreen mode Exit fullscreen mode

GitHub-hosted runners are managed by GitHub, while self-hosted runners are machines you manage yourself.


First Image

What are Private / Self-Hosted Runners?

A self-hosted runner is a machine deployed and managed by you to execute GitHub Actions jobs.

It can run on:

  • EC2
  • Azure VM
  • GCP VM
  • Kubernetes
  • On-prem server
  • Private subnet

Use self-hosted runners when your pipeline needs access to:

Private Kubernetes Cluster
Private Database
Internal Nexus
Private SonarQube
Internal APIs
Private VPC Resources
Enter fullscreen mode Exit fullscreen mode

Self-Hosted Runner Labels

When added, self-hosted runners automatically receive labels like:

self-hosted
linux
windows
macOS
x64
ARM
ARM64
Enter fullscreen mode Exit fullscreen mode

GitHub uses these labels to route jobs.

Example:

runs-on: [self-hosted, linux, x64]
Enter fullscreen mode Exit fullscreen mode

This job will run on a private Linux x64 runner.


Private Runner Example

jobs:
  deploy:
    runs-on: [self-hosted, linux, x64]

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Deploy to Private Kubernetes
        run: |
          kubectl get nodes
          kubectl apply -f k8s/
Enter fullscreen mode Exit fullscreen mode

This is useful when your Kubernetes API is not public.


Self-Hosted Runner Security Best Practices

Use private runners carefully.

Best practices:

Use ephemeral runners
Restrict repository access
Use runner groups
Avoid running untrusted fork PRs
Use least privilege
Patch runners regularly
Do not store secrets on runner disk
Enter fullscreen mode Exit fullscreen mode

For Kubernetes-based autoscaling runners, GitHub identifies Actions Runner Controller as the recommended Kubernetes solution for autoscaling self-hosted runners.


What is Pipeline YAML?

GitHub Actions pipeline is written in YAML.

Basic structure:

name: Pipeline Name

on:
  push:

jobs:
  job-name:
    runs-on: ubuntu-latest

    steps:
      - name: Step Name
        run: echo "Hello CI/CD"
Enter fullscreen mode Exit fullscreen mode

Important YAML Sections

name

name: Node.js CI/CD
Enter fullscreen mode Exit fullscreen mode

Pipeline display name.


on

on:
  push:
    branches: [ main ]
Enter fullscreen mode Exit fullscreen mode

Defines when pipeline runs.


permissions

permissions:
  contents: read
  id-token: write
Enter fullscreen mode Exit fullscreen mode

Defines workflow token permissions.

id-token: write is required for OIDC-based cloud authentication.


env

env:
  APP_NAME: my-app
Enter fullscreen mode Exit fullscreen mode

Defines environment variables.


jobs

jobs:
  build:
Enter fullscreen mode Exit fullscreen mode

Defines pipeline jobs.


runs-on

runs-on: ubuntu-latest
Enter fullscreen mode Exit fullscreen mode

Defines runner machine.


steps

steps:
  - run: npm install
Enter fullscreen mode Exit fullscreen mode

Commands or reusable actions.


Secrets in GitHub Actions

Secrets are encrypted sensitive values.

Examples:

AWS_ACCOUNT_ID
SONAR_TOKEN
DOCKERHUB_TOKEN
SLACK_WEBHOOK
DATABASE_PASSWORD
Enter fullscreen mode Exit fullscreen mode

Access secrets like this:

env:
  SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
Enter fullscreen mode Exit fullscreen mode

Never hardcode secrets in YAML.


Variables in GitHub Actions

Variables are non-sensitive configuration values.

Examples:

AWS_REGION=ap-south-1
APP_NAME=todo-api
ENVIRONMENT=dev
Enter fullscreen mode Exit fullscreen mode

GitHub supports variables and exposes them through the vars context.

Example:

env:
  AWS_REGION: ${{ vars.AWS_REGION }}
Enter fullscreen mode Exit fullscreen mode

Second Image


What is GITHUB_TOKEN?

GITHUB_TOKEN is an automatically generated token available in workflows.

It can be used for GitHub API operations like:

  • Checkout
  • Comment on PR
  • Create releases
  • Push tags
  • Update repo content

GitHub provides documentation explaining how GITHUB_TOKEN works for secure automation.

Example:

permissions:
  contents: read
  packages: write
Enter fullscreen mode Exit fullscreen mode

What is OIDC in GitHub Actions?

OIDC means OpenID Connect.

It allows GitHub Actions to authenticate with cloud providers without storing long-lived access keys.

Old approach:

Store AWS_ACCESS_KEY_ID
Store AWS_SECRET_ACCESS_KEY
Enter fullscreen mode Exit fullscreen mode

Better approach:

GitHub Actions
      ↓
OIDC Token
      ↓
AWS IAM Role
      ↓
Temporary Credentials
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • No long-lived cloud keys
  • Short-lived credentials
  • Better security
  • Easier rotation
  • Least privilege

AWS OIDC Example

permissions:
  id-token: write
  contents: read
Enter fullscreen mode Exit fullscreen mode
- name: Configure AWS Credentials using OIDC
  uses: aws-actions/configure-aws-credentials@v4
  with:
    role-to-assume: arn:aws:iam::123456789012:role/github-actions-deploy-role
    aws-region: ap-south-1
Enter fullscreen mode Exit fullscreen mode

What is a Webhook?

A webhook is an event notification sent from GitHub to another system.

Example:

GitHub Push Event
        ↓
Webhook
        ↓
External System
Enter fullscreen mode Exit fullscreen mode

Use cases:

  • Trigger Jenkins pipeline
  • Notify Slack
  • Trigger deployment platform
  • Send events to security tools

Branch Rules and Rulesets

Rules protect important branches.

Example:

main branch
Enter fullscreen mode Exit fullscreen mode

should not allow direct push.

Common rules:

  • Require pull request
  • Require approvals
  • Require status checks
  • Require signed commits
  • Restrict force pushes
  • Restrict deletions
  • Require linear history

Why Rulesets Matter

Rulesets enforce governance.

Example:

Developer opens PR
        ↓
CI pipeline runs
        ↓
Tests pass
        ↓
Security scan passes
        ↓
Approval received
        ↓
Merge allowed
Enter fullscreen mode Exit fullscreen mode

Without rulesets, someone may directly push insecure code to production branch.


Environment Protection Rules

GitHub Actions can control deployments using environments, concurrency groups, and protection rules.

Example:

environment:
  name: production
Enter fullscreen mode Exit fullscreen mode

You can configure:

  • Required reviewers
  • Wait timer
  • Deployment branches
  • Environment secrets

Environment secrets and protection rules are available depending on repository type and plan.


Full GitHub Actions CI/CD Pipeline Example

This example does:

Checkout
Install dependencies
Run tests
Run SAST
Build Docker image
Push to Amazon ECR
Deploy to Kubernetes
Enter fullscreen mode Exit fullscreen mode
name: GitHub Actions CI/CD Pipeline

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

permissions:
  contents: read
  id-token: write
  packages: write

env:
  AWS_REGION: ap-south-1
  ECR_REPOSITORY: my-node-app
  IMAGE_TAG: ${{ github.sha }}

jobs:
  ci:
    name: Build, Test and Scan
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install Dependencies
        run: npm ci

      - name: Run Unit Tests
        run: npm test

      - name: Run Semgrep SAST
        uses: semgrep/semgrep-action@v1
        with:
          config: auto

      - name: Build Docker Image
        run: |
          docker build -t $ECR_REPOSITORY:$IMAGE_TAG .

  deploy:
    name: Build Image and Deploy
    needs: ci
    runs-on: [self-hosted, linux, x64]
    if: github.ref == 'refs/heads/main'

    environment:
      name: production

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Configure AWS Credentials using OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-actions-deploy-role
          aws-region: ${{ env.AWS_REGION }}

      - name: Login to Amazon ECR
        run: |
          aws ecr get-login-password --region $AWS_REGION | \
          docker login --username AWS --password-stdin \
          123456789012.dkr.ecr.$AWS_REGION.amazonaws.com

      - name: Build and Push Docker Image
        run: |
          IMAGE_URI=123456789012.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPOSITORY:$IMAGE_TAG
          docker build -t $IMAGE_URI .
          docker push $IMAGE_URI
          echo "IMAGE_URI=$IMAGE_URI" >> $GITHUB_ENV

      - name: Deploy to Kubernetes
        run: |
          kubectl set image deployment/my-node-app \
            my-node-app=$IMAGE_URI \
            -n production

          kubectl rollout status deployment/my-node-app -n production
Enter fullscreen mode Exit fullscreen mode

Pipeline Flow Explained

Developer Pushes Code
        ↓
GitHub Actions Triggered
        ↓
CI Job Runs on GitHub Runner
        ↓
Tests + SAST
        ↓
Deploy Job Runs on Private Runner
        ↓
OIDC Authenticates to AWS
        ↓
Docker Image Pushed to ECR
        ↓
Kubernetes Deployment Updated
Enter fullscreen mode Exit fullscreen mode

Build Automation

Build automation means converting source code into a deployable artifact.

Examples:

Java β†’ JAR/WAR
Node.js β†’ Bundle
Dockerfile β†’ Docker Image
Helm Chart β†’ Versioned Package
Enter fullscreen mode Exit fullscreen mode

Example:

- name: Build Docker Image
  run: docker build -t my-app:${{ github.sha }} .
Enter fullscreen mode Exit fullscreen mode

Deploy Automation

Deploy automation means moving the artifact to the target environment.

Examples:

ECR β†’ EKS
ACR β†’ AKS
Docker Hub β†’ Kubernetes
S3 β†’ CloudFront
Lambda ZIP β†’ AWS Lambda
Enter fullscreen mode Exit fullscreen mode

Example:

- name: Deploy to Kubernetes
  run: kubectl apply -f k8s/
Enter fullscreen mode Exit fullscreen mode

GitOps Deployment Alternative

In modern Kubernetes setups, GitHub Actions should often do only CI.

CD should be handled by ArgoCD or Flux.

Flow:

GitHub Actions
      ↓
Build Image
      ↓
Push to Registry
      ↓
Update GitOps Repo
      ↓
ArgoCD / Flux Deploys
Enter fullscreen mode Exit fullscreen mode

This avoids giving CI pipeline direct cluster-admin deployment access.


GitOps Example Step

- name: Update GitOps Manifest
  run: |
    git config user.name "github-actions"
    git config user.email "actions@github.com"

    sed -i "s|image: .*|image: $IMAGE_URI|g" k8s/deployment.yaml

    git add k8s/deployment.yaml
    git commit -m "Update image to $IMAGE_TAG"
    git push
Enter fullscreen mode Exit fullscreen mode

Then ArgoCD or Flux detects the manifest change and deploys it.


Recommended Pre Production Pipeline

Third Image


GitHub Actions Best Practices

Use:

OIDC instead of access keys
Environment approvals for production
Branch rulesets
Private runners for private infra
Least privilege permissions
Pinned action versions
Secrets only for sensitive values
Variables for non-sensitive config
Concurrency control
Artifact retention policies
Enter fullscreen mode Exit fullscreen mode

Final Thoughts

GitHub Actions is more than a CI/CD tool.

It is an automation platform tightly integrated with GitHub.

It can handle:

  • CI pipelines
  • Security scanning
  • Docker builds
  • Cloud authentication
  • Kubernetes deployment
  • Release automation
  • GitOps workflows

For modern DevOps and DevSecOps teams, GitHub Actions becomes even more powerful when combined with:

Private runners
OIDC
Rulesets
Environment approvals
ArgoCD / Flux
Security scanning
Enter fullscreen mode Exit fullscreen mode

A strong production pipeline is not only about deploying fast.

It is about deploying:

Fast
Securely
Repeatably
With control
Enter fullscreen mode Exit fullscreen mode

Top comments (0)