GitHub Actions Beginner to Advanced📚
Part-1
What is CI/CD
Before CI/CD, software development followed a traditional approach where multiple teams worked sequentially. The development team would write code and push it to repositories like GitHub. Then the integration team would manually build and merge the code, and finally the testing team would perform end-to-end testing.
This approach had several challenges:
Dependency on multiple teams
Manual handoffs between stages
Increased chances of integration errors
Slower delivery to clients
To overcome these issues, CI/CD (Continuous Integration and Continuous Delivery/Deployment) was introduced.
With Continuous Integration (CI):
Developers frequently push code to the repository
Each push automatically triggers a pipeline
Tools like Jenkins or GitHub Actions execute the pipeline
The pipeline performs:
Build
Unit testing
Basic validations
This ensures that integration happens continuously and issues are detected early without manual intervention.
With Continuous Delivery/Deployment (CD):
After successful CI, the application is automatically:
Delivered to staging environments (Continuous Delivery), or
Deployed to production (Continuous Deployment)
Overall, CI/CD does not replace teams but automates their repetitive tasks, reducing manual effort and improving efficiency.
As a result:
Faster feedback to developers
Early detection of bugs
Reduced manual work
Improved code quality
Faster and more reliable releases (often 40–50% improvement in delivery time)
CI/CD Using GitHub Actions
Now let’s map CI/CD into GitHub-native world.
GitHub Actions is an event-driven automation platform built into GitHub that allows you to define CI/CD workflows as code.
Here everything is triggered by an Event
Some events are below
push
pull_request
workflow_dispatch
schedule
release
Core Components of Github Actions are
Workflow -----> Job ----- > Steps -----> Action
Workflow
A workflow is the complete automation pipeline.
This is a Yaml File in .github/workflow/*.yml
Job
A job is a group of steps that run on a runner (machine).
Runs on VM or container
Each job is isolated
Jobs can run:
Parallel (default)
Sequential (using
needs)
A runner is the machine where your job runs.
Here runner is a like a node in jenkins means we can use github provided runnners or we can make self hosted runners
Github hosted runners examples
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
runs-on: windows-latest
runs-on: macos-latest
runs-on: ubuntu-22.04-arm
Self hosted runners examples
runs-on: self-hosted
runs-on: [self-hosted, linux, ec2]
runs-on: [self-hosted, linux, onprem]
Step
A step is an individual task inside a job.
It can do
Checkout code
Install dependencies
Run tests
Build app
steps:
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
Action
An action is a pre-built reusable component. it's like a plugin
- uses: actions/checkout@v4
Example of simple workflow
name: CI Pipeline
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4 # Action
- name: Install
run: npm install # Step
- name: Test
run: npm test # Step
Jenkins VS GitHub Actions
| Aspect | Jenkins | GitHub Actions |
|---|---|---|
| Hosting | Self-hosted | SaaS (GitHub) |
| Setup | Heavy (install, plugins) | Zero setup |
| Pipeline | Jenkinsfile | YAML |
| Trigger | Polling/Webhook | Native events |
| Plugins | Huge ecosystem | Actions marketplace |
| Scaling | Manual | Auto |
| Maintenance | High | Minimal |
Workflow Syntax Deep Dive
.github/workflows/*.yml
GitHub Actions workflows are stored inside the repository under:
.github/workflows/*.yml
This location is mandatory because GitHub has a built-in workflow engine that automatically scans this directory.
Whenever it finds YAML files in .github/workflows/:
It registers them as workflows
It links them to repository events (like push, pull request, etc.)
It triggers them based on the defined conditions
If a workflow file is placed outside this directory:
GitHub will not recognize it
The workflow will never be triggered
Name
This is not just a Name it identifies workflow in ui and helps in debugging and tracking
name: Deploy - ${{ github.ref_name }}
ON
This Defines when your pipeline need to be triggered
Types of Triggers
Code Events
push
pull_request
Manual
- workflow_dispatch
Scheduled
on:
schedule:
- cron: "0 2 * * *"
Needs
By default, in GitHub Actions, jobs run in parallel. However, if we want to execute them sequentially, we use the needs keyword.
When a job specifies needs, it will wait for the dependent job(s) to complete successfully before starting execution.
jobs:
build:
runs-on: ubuntu-latest
deploy:
needs: build
Uses VS Run
This is where every one get confused
run means excute commands directly
- name: Build
run: mvn clean install
uses is like pre-built action
- name: Checkout
uses: actions/checkout@v4
uses: actions/setup-java@v4
uses: docker/build-push-action@v5
Events and Triggers
PUSH Event
Triggered when code is pushed to a repository.
on:
push:
Branches: [main , dev]
Here pipeline will be triggered on branches Main , dev when code is pushed
Advance filtering
on:
push:
path:
- 'src/'
PULL_REQUEST Event
Triggered when PR activity happens.
on:
pull_request:
Branches: [main]
Advances filtering in pr
on:
pull_request:
types: [opened, synchornize, reopened]
synchronize means when a new commits happens to an existing pr
WORKFLOW_DISPATCH
Triggered manually workflow from UI
on:
workflow_dispatch:
inputs:
environment:
description: 'Select env'
required: true
When we manually trigger this it prompts to ask which env we need to type it then pipleline will be triggered
SCHEDULE
Runs workflow on a schedule
on:
schedule:
- cron : "0 2 * * *" // MIN HOUR DAY MONTH WEEKDAY
MULTIPLE TRIGGERS
Here we can combine multiple events
on:
push:
branches: [ main ]
pull_request:
workflow_dispatch:
Workflow runs if ANY event occurs
on:
push:
branches: [ dev ]
pull_request:
branches: [ main ]
workflow_dispatch:
REPOSITARY_DISPATCH
To Trigger a workflow using api
on:
repository_dispatch:
types: [deploy_event]
The repository_dispatch API is written in external systems like Jenkins pipelines, shell scripts, or backend services. It is used to programmatically trigger GitHub Actions workflows via REST API after certain events like build completion or external system actions.
RUNNERS
A runner is a machine that executes your jobs. think like a node in jenkins
Two Types of runners
GitHub Hosted Runners
GitHub provides ready-made machines for you. no need of any setup
runs-on: ubuntu-latest
Every job = new clean machine
Self-Hosted Runners
runs-on: self-hosted
It runs on
Your EC2 / VM
On-prem server
Kubernetes pod
Let's Create a Self Hosted runner on ec2
Step1 : Launch EC2 Instance
Go to AWS → EC2 → Launch instance
Recommended config:
OS: Ubuntu 22.04
Instance type:
t2.micro(for practice) / bigger for real workloadsStorage: 20 GB+
Security Group:
- Allow SSH (22)
Make sure instance has:
- Internet access (public IP or NAT)
Step2: Connect to EC2
ssh -i your-key.pem ubuntu@<public-ip>
Step3: Go to GitHub → Runner Setup
Open a repository
Settings → Actions → Runners → New self-hosted runner
Select:
OS: Linux
Architecture: x64
Step4: GitHub will give you commands like this
mkdir actions-runner && cd actions-runner
curl -o actions-runner-linux-x64.tar.gz -L https://github.com/actions/runner/releases/download/v2.x.x/actions-runner-linux-x64-2.x.x.tar.gz
tar xzf actions-runner-linux-x64.tar.gz
Excute these commands in your ec2
it will ask for url
https://github.com/<your-username>/<repo>
Step5: Token
In the same Ui page you will be getting the token copy and paste it
Step6: Runner name (Give a name to your runner)
./run.sh // Start the runnner
Step7: Use Runner in your workflow
jobs:
build:
runs-on: self-hosted
Scalling Runners :
handling multiple jobs efficiently
Scaling GitHub-Hosted Runners:
GitHub handles scaling automatically
jobs:
build:
test:
security-scan:
Here all three jobs run parallely
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
This creates Mutiple Runners parallely
Concurrency limits (depends on plan)
Job queue if limit exceeded
Scaling Self-Hosted Runners :
Option A: Having Multiple Ec2 servers
Options B: Using ASG ( Auto Scalling Group)
Actions MarketPlace
There are of 3 types of actions i.e
Pre-built
Third Party
Custom
Pre-Built Actions:
Actions created by GitHub or verified providers.
Maintained by GitHub
Stable and secure
Standard functionality
uses: actions/checkout@v4
uses: actions/setup-node@v4
uses: actions/upload-artifact@v4
Third Party Actions:
Actions built by community or companies and shared publicly.
uses: docker/build-push-action@v5
uses: slackapi/slack-github-action@v1
uses: aquasecurity/trivy-action@v0.20.0
BIG RISK
Supply chain attacks
Malicious code possible
Maintainer may abandon project
Custom Actions:
A custom action is a reusable automation component that encapsulates logic so multiple workflows can use it consistently.
Most used is Composite Actions
A YAML-based action that combines multiple steps.
.github/actions/docker-build/action.yml
action.yaml
name: "Docker Build and Push"
inputs:
image-name:
required: true
runs:
using: "composite"
steps:
- name: Build Image
run: docker build -t ${{ inputs.image-name }} .
- name: Push Image
run: docker push ${{ inputs.image-name }}
Using in workflow
- uses: ./.github/actions/docker-build
with:
image-name: my-app:latest
Secrets In GitHub Actions
Defined in GitHub UI → Settings → Secrets
env:
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- run: echo "Using secret"
