DevOps Shack _Step-by-Step GitHub Actions Guide
DevOps Shack _Step-by-Step GitHub Actions Guide
DevOps Shack
GitHub Actions Step By Step Guide:
From Code to Cloud Using Docker, EC2 & GitHub
Actions
Step-by-Step Workflow
1. Initialize Project → Push to GitHub
→ Set up your application locally (e.g., Node.js, Python, etc.)
→ Initialize a Git repository
→ Push the code to a GitHub repository for version control
2
6. Set Up GitHub Actions → Automate CI
→ Create a GitHub Actions workflow
→ Automatically run tests and build your Docker image on each push
Outcome
A fully automated, secure, scalable deployment pipeline:
GitHub → Docker Hub → EC2 → LIVE App — all hands-free after setup!
3
Step 1: Set Up Your Project Repository
This is the foundational step where you create your application code and
initialize it with Git so it can be pushed to GitHub.
Prerequisites
• Git installed
• A GitHub account
• Basic knowledge of CLI or terminal
Steps
1.1 Create a new project folder
mkdir demo-app
cd demo-app
4
Update it like this:
{
"name": "demo-app",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "node index.js"
}
}
5
git push -u origin main
Done! You now have a Node.js project set up in a GitHub repo and ready to
build your CI/CD pipeline.
6
Step 2: Create a Dockerfile for Your Application
In this step, you'll containerize your app using Docker by writing a Dockerfile.
This lets us package the app with its dependencies into a consistent
environment that runs anywhere.
What is a Dockerfile?
A Dockerfile is a script that contains a list of instructions Docker uses to build
an image of your application.
Think of it like a recipe for building your app into a portable box.
7
# Set working directory inside the container
WORKDIR /app
Line Meaning
FROM node:18-
Uses a lightweight Node.js image as the base
alpine
WORKDIR /app Sets /app as the working directory inside the container
COPY package*.json
Copies package.json and package-lock.json (if exists)
./
8
Line Meaning
COPY . . Copies the rest of your project files into the container
EXPOSE 3000 (Optional) Documents the port the app will listen on
Note: If your app runs on a different port (like 8080 or 5000), update the
EXPOSE line accordingly.
9
Step 3: Test Your Docker Image Locally
Before pushing your app into a CI/CD pipeline or deploying it to the cloud, it's
critical to make sure your Dockerfile works properly, and your app runs
successfully in a containerized environment.
This helps you catch any issues with dependencies, ports, or file structure early
on.
Step-by-Step Instructions
3.1 Build the Docker Image
Use the docker build command:
docker build -t demo-app .
Let’s break this down:
• docker build — Tells Docker to build an image
• -t demo-app — Names your image demo-app
• . — Specifies the build context (current folder)
If successful, you’ll see output similar to:
Step 1/7 : FROM node:18-alpine
---> c92c00334ec6
Step 2/7 : WORKDIR /app
---> Using cache
...
10
Successfully built 123456789abc
Successfully tagged demo-app:latest
Congrats! Your app just ran inside a container, isolated from your host
machine.
11
To stop a running container:
docker stop <container-id>
Common Troubleshooting
Issue Solution
Clean Up (Optional)
To free up space:
• Remove all stopped containers:
docker container prune
• Remove unused images:
docker image prune
12
Step 4: Push Your Project to GitHub
This step is all about getting your code from your local machine into the cloud
via GitHub. This is important because GitHub will serve as the central source
for your CI/CD workflow in GitHub Actions.
Step-by-Step Instructions
13
In your local terminal (inside the demo-app folder):
git remote add origin https://github.com/your-username/demo-app.git
Replace your-username with your actual GitHub username.
index.js
package.json
Dockerfile
.gitignore
All your project files should be there, perfectly synced.
14
What You’ve Achieved
15
Step 5: Create a GitHub Actions Workflow File
This step is where your CI/CD pipeline begins. You’ll define an automated
workflow that builds your Docker image, tests it (if needed), and optionally
pushes it to a container registry.
GitHub Actions uses a special folder and YAML files to manage workflows.
Step-by-Step Instructions
on:
16
push:
branches:
- main
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
17
What This Workflow Does:
Section Purpose
18
What You’ve Achieved
• The pipeline builds your Docker image every time you push code
19
Step 6: Define Build and Test Steps in the
Workflow
Now that your GitHub Actions workflow builds your Docker image, it’s time to
make it smarter by adding build validations and automated tests (if you have
them). This step helps catch bugs early—before they ever reach staging or
production.
Step-by-Step Instructions
on:
push:
branches:
- main
pull_request:
jobs:
build-and-test:
21
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
Step Purpose
22
Step Purpose
So, if a test fails, your pipeline stops immediately. This saves time and prevents
bad code from reaching staging or production.
23
Step 7: Build and Push Docker Image to a
Container Registry
Now that your CI pipeline builds and tests your app, the next big move is to
publish your Docker image to a container registry—so it can be pulled later by
staging or production environments.
We'll use Docker Hub here for simplicity, but you can adapt it for GitHub
Container Registry (GHCR), AWS ECR, GCP GCR, or Azure ACR as well.
Step-by-Step Instructions
24
3. Add the following secrets:
o DOCKER_USERNAME: your Docker Hub username
o DOCKER_PASSWORD: your Docker Hub password or a personal
access token
on:
push:
branches:
- main
pull_request:
jobs:
build-test-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
26
Logs in to Docker
Builds your image
Pushes it to Docker Hub!
Check hub.docker.com to confirm. Your new image will be live there.
27
Step 8: Deploy to a Cloud Platform — AWS EC2
(In Detail)
Goal:
Deploy your Docker image (from Docker Hub) to an EC2 server so it runs 24/7
and can be accessed via a public IP or domain.
Pre-requisites
• A Dockerized app pushed to Docker Hub
• AWS account with EC2 access
• A public key-pair (.pem) to SSH into your EC2 instance
• Basic CLI knowledge
Step-by-Step Guide
28
8.2 SSH Into EC2
ssh -i path/to/your-key.pem ubuntu@<EC2-Public-IP>
• Replace <EC2-Public-IP> with your instance IP (from AWS dashboard)
• Use ec2-user for Amazon Linux, ubuntu for Ubuntu
29
docker ps
Now go to:
http://<EC2-Public-IP> → You should see your app live!
Optional Enhancements
30
Add Domain & HTTPS (with NGINX + Certbot)
• Point your domain to EC2 IP via A record
• Install NGINX and Certbot
• Reverse proxy Docker container with HTTPS
31
Step 9: Set Up Domain & HTTPS (Optional but
Pro)
By default, platforms like Render or Railway give you a free subdomain like:
https://demo-app.onrender.com
That’s cool for testing—but for a real project or product, you want:
https://www.yourbrand.com
32
2. Open your deployed web service
3. Click Settings > Custom Domains
4. Add a domain like:
www.yourdomain.com
Render will now give you instructions to add DNS records.
• You can show off your project to the world like a pro
33
Step 10: Automate Full CI/CD with GitHub Actions
+ EC2 Deployment
Goal: Every time you push code to GitHub, your EC2 server should
automatically pull the latest image and restart the container. Fully hands-free
deployment.
Step-by-Step Guide
34
2. Paste the public key into ~/.ssh/authorized_keys:
nano ~/.ssh/authorized_keys
Paste contents of deploy-key.pub and save.
Now GitHub will be able to SSH into the EC2 box.
EC2_HOST ec2-user@<EC2-IP>
EC2_PORT 22
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
35
steps:
- name: Checkout code
uses: actions/checkout@v3
Workflow Explanation
• GitHub runs CI tests
• Pushes the Docker image
• SSHes into EC2
• Pulls the latest image
• Restarts the running container
37
Full CI/CD DevOps Pipeline
Dockerized microservice
Tests + Linting
Automated deployment to your own cloud infrastructure
Production-ready setup with custom domain and HTTPS
38
Conclusion
In today’s fast-paced software world, it’s not enough to just write code—you
also need to deliver it efficiently, reliably, and securely. This guide walked you
through a complete DevOps pipeline, transforming a basic application into a
cloud-deployed, production-ready service.
We started by organizing our source code with GitHub, establishing a
foundation of version control and team collaboration. From there, we added
unit tests to ensure that every piece of code works as expected—because
quality matters from the start.
Next, we moved into containerization with Docker, allowing us to package our
app with all its dependencies, ensuring that it runs the same everywhere—
from your laptop to the cloud. With Docker Hub, we made that container
available globally, so it could be pulled and run on any server.
We didn’t stop at manual deployment. By launching an AWS EC2 instance, we
took the first real-world step into the cloud—where your app becomes
accessible to the world. We configured the environment, deployed our Docker
container, and verified it was working live over the internet.
Then came the real magic: automation. Using GitHub Actions, we built a
Continuous Integration/Continuous Deployment (CI/CD) pipeline that runs
tests, builds Docker images, and deploys the latest version to EC2—all triggered
by a simple code push. This kind of automation reduces human error, speeds
up delivery, and allows teams to focus on building, not babysitting servers.
We even touched on the polish: mapping a custom domain, enabling HTTPS,
and preparing for future scalability. With this setup, you now have a
professional-grade delivery system similar to what top tech companies use to
ship features and updates daily.
39