
From Code to Cloud: A Beginner’s Guide to CI/CD Deployment on AWS
Learn how to automate application deployment on AWS using a practical CI/CD pipeline. This guide walks through source control, build, deployment, monitoring, and best practices for shipping applications faster and more reliably.
Below is a complete AWS Builder-ready article body. I’ve made it practical and detailed, focusing on a real DevOps workflow using GitHub → AWS CodePipeline → CodeBuild → EC2 → CloudWatch.
From GitHub to Production: Building a CI/CD Pipeline on AWS
Modern applications need to be updated frequently. Manually connecting to a server, copying files, installing dependencies, restarting services, and checking whether the application works can become repetitive and error-prone.
This is where DevOps and CI/CD become important.
In this article, we will build a practical CI/CD workflow on AWS that automatically takes application code from GitHub, builds it, and deploys it to an Amazon EC2 instance.
The overall workflow will look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Developer
|
| git push
v
GitHub Repository
|
v
AWS CodePipeline
|
v
AWS CodeBuild
|
| Build + Test
v
Deployment
|
v
Amazon EC2
|
v
Running Application
|
v
Amazon CloudWatchThe goal is not just to understand individual AWS services, but to understand how they work together as a DevOps system.
1. What is DevOps?
DevOps is a combination of development and operations practices.
Traditionally, developers write application code while operations teams deploy and maintain the application.
This separation can create problems:
- Deployment takes a long time.
- Human errors can occur.
- Developers have to manually provide deployment files.
- Testing may not happen consistently.
- Rollbacks can be difficult.
- Releasing small changes becomes inconvenient.
DevOps tries to solve these problems by automating the software lifecycle.
A typical DevOps lifecycle is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Plan
↓
Code
↓
Build
↓
Test
↓
Release
↓
Deploy
↓
Monitor
↓
FeedbackAWS provides services that can support almost every stage of this lifecycle.
2. What is CI/CD?
CI/CD stands for:
CI — Continuous Integration
CD — Continuous Delivery / Continuous Deployment
Continuous Integration
Continuous Integration means developers frequently push their code into a shared repository.
Whenever new code is pushed, an automated process can:
- Download the source code.
- Install dependencies.
- Build the application.
- Run tests.
- Check whether the application can be successfully built.
For example:
1
2
3
4
5
6
7
8
9
10
11
Developer changes code
↓
git push
↓
Build starts automatically
↓
Dependencies installed
↓
Tests executed
↓
Build succeeds/failsThis helps identify problems early.
3. What is Continuous Deployment?
Continuous Deployment goes one step further.
If the build and tests are successful, the application can automatically be deployed to the production environment.
For example:
1
2
3
4
5
6
7
8
9
10
11
Git Push
↓
Build
↓
Test
↓
Success
↓
Deploy
↓
ProductionInstead of manually logging into an EC2 server every time, the deployment process can happen automatically.
4. AWS Services Used in This Project
We will use several AWS services.
Amazon EC2
Amazon EC2 provides the virtual server where our application will run.
Think of EC2 as:
A computer in the AWS Cloud that we can configure and use to run our application.
Our final application will run on this server.
AWS CodePipeline
CodePipeline coordinates the CI/CD workflow.
It connects the different stages together.
For example:
1
2
3
4
5
6
7
GitHub
↓
CodePipeline
↓
CodeBuild
↓
DeploymentCodePipeline is essentially the orchestrator.
AWS CodeBuild
CodeBuild performs the build process.
It can:
- Install dependencies
- Compile code
- Run tests
- Generate build artifacts
- Prepare applications for deployment
For example, a Python application might execute:
1
pip install -r requirements.txtwhile a Node.js application might execute:
1
2
npm install
npm run buildAmazon CloudWatch
CloudWatch helps us monitor the application and AWS resources.
We can use it to monitor:
- Logs
- CPU utilization
- Application activity
- Errors
- Metrics
- Alarms
Monitoring is an important part of production deployment.
5. Project Architecture
Our architecture will look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
+----------------+
| Developer |
+-------+--------+
|
| git push
v
+----------------+
| GitHub |
+-------+--------+
|
v
+----------------+
| AWS CodePipeline|
+-------+--------+
|
v
+----------------+
| CodeBuild |
+-------+--------+
|
v
+----------------+
| Deployment |
+-------+--------+
|
v
+----------------+
| EC2 |
| |
| Application |
+-------+--------+
|
v
+----------------+
| CloudWatch |
| Logs & Metrics |
+----------------+6. Step 1: Create the Application
For this example, let's assume we have a simple Python application.
Our repository could have the following structure:
1
2
3
4
5
6
my-application/
│
├── app.py
├── requirements.txt
├── buildspec.yml
└── appspec.ymlA simple
app.py could look like:1
from flask import Flaskapp = Flask(__name__)@app.route("/")def home(): return "Application deployed successfully on AWS!"if __name__ == "__main__": app.run(host="0.0.0.0", port=5000)The application listens on:
1
Port 5000The
requirements.txt file contains:1
2
Flask
gunicorn7. Step 2: Push the Application to GitHub
Create a GitHub repository.
For example:
1
aws-devops-demoInitialize the local project:
1
git initAdd the files:
1
git add .Create the first commit:
1
git commit -m "Initial application"Connect the GitHub repository:
1
git remote add origin <repository-url>Push the code:
1
2
git branch -M main
git push -u origin mainNow our source code is available in GitHub.
8. Step 3: Create the EC2 Instance
Next, we need a server to run the application.
Open the AWS Management Console and navigate to:
EC2 → Instances → Launch Instance
Choose an appropriate Linux AMI.
For a learning project, you can use an instance size suitable for your workload and budget.
Configure:
- Instance name
- AMI
- Instance type
- Key pair
- Network
- Security group
- Storage
9. Configure the Security Group
The security group acts as a virtual firewall.
For example, if our application uses port
5000, we need appropriate inbound access.Typical rules might include:
1
2
3
4
SSH 22
HTTP 80
HTTPS 443
Custom 5000However, exposing application ports directly to the internet is not always the best production architecture.
A better production design is often:
1
2
3
4
5
Internet
↓
Load Balancer
↓
EC2with the EC2 instance accepting traffic only from the load balancer.
For our learning project, we can keep the architecture simple.
10. Connect to EC2
After launching the instance, connect using SSH.
For example:
1
ssh -i my-key.pem ec2-user@<EC2-PUBLIC-IP>The exact username depends on the AMI.
After connecting, update the server:
1
sudo dnf update -yor use the appropriate package manager for your chosen Linux distribution.
11. Install Required Software
Install Python:
1
sudo dnf install python3 -yCreate a project directory:
1
sudo mkdir -p /opt/my-applicationCreate a virtual environment:
1
python3 -m venv /opt/my-application/venvActivate it:
1
source /opt/my-application/venv/bin/activateInstall dependencies:
1
pip install -r requirements.txtFor a production application, it is better to run the application through a process manager such as
systemd and an appropriate application server.12. Why Should We Use systemd?
If we simply run:
1
python app.pythe application may stop when the terminal session ends.
We want the application to behave like a proper server service.
systemd can:- Start the application automatically.
- Restart it if it crashes.
- Start it when the server boots.
- Manage application status.
For example:
1
sudo systemctl status my-applicationWe can start it using:
1
sudo systemctl start my-applicationand enable it during boot:
1
sudo systemctl enable my-applicationThis is especially useful for production deployments.
13. Step 4: Create buildspec.yml
AWS CodeBuild needs instructions describing how the application should be built.
Create:
1
buildspec.ymlExample:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
version: 0.2
phases:
install:
commands:
- echo Installing dependencies
- python3 -m pip install --upgrade pip
- pip install -r requirements.txt
build:
commands:
- echo Running application checks
- python3 -m py_compile app.py
post_build:
commands:
- echo Build completed successfully
artifacts:
files:
- '**/*'Let's understand this.
14. Understanding buildspec.yml
Version
1
version: 0.2This specifies the CodeBuild buildspec version.
Install Phase
1
2
3
install:
commands:
- pip install -r requirements.txtThis installs the dependencies required by the application.
Build Phase
1
2
3
build:
commands:
- python3 -m py_compile app.pyThis performs a basic Python syntax check.
In a real project, you should run your automated tests here.
For example:
1
pytestPost Build
1
2
3
post_build:
commands:
- echo Build completed successfullyThis runs after the build stage.
15. Add Automated Testing
CI/CD becomes much more useful when tests are included.
For example:
1
2
3
build:
commands:
- pytestThe pipeline should behave like this:
1
2
3
4
5
6
7
8
9
10
11
Code pushed
↓
Build
↓
Tests
↓
┌───┴────┐
↓ ↓
PASS FAIL
↓ ↓
Deploy StopIf tests fail, the deployment should not continue.
This prevents broken code from reaching production.
16. Step 5: Configure CodeBuild
Open:
AWS Console → CodeBuild → Build projects → Create build project
Provide a project name such as:
1
my-application-buildChoose the source provider connected to your repository.
Configure the environment with a suitable managed image.
Then configure the build specification.
You can select:
Use a buildspec file
CodeBuild will then look for:
1
buildspec.ymlinside the repository.
17. IAM Permissions
IAM is one of the most important parts of AWS DevOps.
AWS services need permissions to interact with other AWS resources.
For example:
1
2
3
4
5
CodePipeline
↓
CodeBuild
↓
S3 / EC2 / CodeDeployEach service should receive only the permissions it actually needs.
This is called the:
Principle of Least Privilege
Instead of giving a service administrator-level permissions, give it only the required permissions.
For example:
1
2
3
4
5
CodeBuild
↓
Read required artifacts
↓
Write build logsrather than:
1
2
3
CodeBuild
↓
AdministratorAccessThe second approach is unnecessarily risky.
18. Step 6: Create CodePipeline
Now we can create the pipeline.
Navigate to:
AWS Console → CodePipeline → Create pipeline
Give it a name:
1
my-application-pipelineThe pipeline can contain stages such as:
1
2
3
4
5
Source
↓
Build
↓
Deploy19. Source Stage
The source stage obtains the latest version of our code.
For example:
1
2
3
GitHub
↓
CodePipelineWhen a new commit is pushed, the pipeline can detect the change and start a new execution.
For example:
1
2
3
git add .
git commit -m "Update homepage"
git pushThis can trigger:
1
2
3
4
5
6
7
GitHub
↓
CodePipeline
↓
CodeBuild
↓
DeploymentThis is where CI/CD becomes powerful.
20. Build Stage
The build stage uses CodeBuild.
CodeBuild receives the source code and reads:
1
buildspec.ymlIt then performs the required commands.
For example:
1
2
3
4
5
6
7
8
9
Download source
↓
Install Python
↓
Install dependencies
↓
Run tests
↓
Create artifactIf the build succeeds, the pipeline continues.
If the build fails, the pipeline stops.
21. Deployment Stage
The deployment stage takes the successfully built application and deploys it to the target environment.
There are multiple AWS approaches.
For example:
1
CodeDeploy → EC2or other deployment architectures depending on the application.
For EC2-based applications, AWS CodeDeploy can coordinate application deployments onto instances.
The general flow becomes:
1
2
3
4
5
6
7
8
9
GitHub
↓
CodePipeline
↓
CodeBuild
↓
CodeDeploy
↓
EC222. What Happens During Deployment?
Suppose we modify:
1
return "Version 2 of my application"Then we push:
1
2
3
git add .
git commit -m "Release version 2"
git pushThe pipeline automatically starts.
Stage 1 — Source
The latest source code is retrieved.
Stage 2 — Build
Dependencies are installed and tests are executed.
Stage 3 — Deployment
The new version is transferred to the EC2 environment.
Stage 4 — Application Restart
The application service is restarted if required.
Stage 5 — Verification
We verify that the new version is running.
So instead of manually doing:
1
2
3
4
5
6
7
SSH
↓
git pull
↓
pip install
↓
restart applicationthe pipeline automates the process.
23. Deployment Scripts
A deployment process can use scripts to perform tasks such as:
1
2
3
4
5
6
7
8
9
cd /opt/my-application
source venv/bin/activate
pip install -r requirements.txt
sudo systemctl restart my-applicationThis ensures that every deployment follows the same process.
Automation reduces the chance of someone forgetting an important command.
24. Step 7: Monitoring with CloudWatch
Deployment is not the end of DevOps.
After deployment, we need to know whether the application is actually working.
This is where monitoring becomes important.
Amazon CloudWatch can help collect:
- Logs
- Metrics
- Application information
- System performance data
- Alarms
For example, we might monitor:
1
2
3
4
5
CPU Utilization
Memory usage
Application errors
Request failures
Instance health25. Why Logs Are Important
Suppose the deployment succeeds but the application returns:
1
HTTP 500 Internal Server ErrorThe pipeline might still show that deployment completed successfully.
This demonstrates an important concept:
Successful deployment does not always mean a healthy application.
Logs help us understand what happened.
For example:
1
2
3
Application started
Database connection failed
Application stoppedThis immediately gives us a direction for troubleshooting.
26. CloudWatch Alarms
We can create CloudWatch alarms for important metrics.
For example:
1
2
3
4
5
CPU > 80%
↓
CloudWatch Alarm
↓
NotificationThis allows the team to react before users experience major problems.
27. CI/CD Failure Scenario
Let's consider a common scenario.
A developer changes:
1
@app.route("/")def home() return "Hello"There is a syntax error because the function declaration is missing a colon.
The developer pushes the code.
The pipeline starts:
1
2
3
4
5
GitHub
↓
CodePipeline
↓
CodeBuildCodeBuild executes the validation.
The build fails.
Therefore:
1
2
3
Build FAILED
↓
Deployment STOPPEDThe broken application never reaches production.
This is one of the major benefits of CI/CD.
28. Rollback Strategy
Deployment failures can happen even when tests pass.
For production systems, we should have a rollback strategy.
A simple approach is to maintain previous application versions.
For example:
1
2
3
Version 1
Version 2
Version 3If Version 3 causes problems:
1
2
3
4
5
6
7
Version 3
↓
Problem detected
↓
Rollback
↓
Version 2More advanced architectures can use:
- Blue/green deployments
- Rolling deployments
- Canary deployments
29. Blue/Green Deployment
Blue/green deployment uses two environments.
1
2
3
4
5
6
Load Balancer
|
+-------+-------+
| |
Blue Green
Version 1 Version 2Initially, users access Blue.
After deploying Version 2 to Green and verifying it:
1
2
3
4
Users
↓
Green
Version 2If Version 2 has problems, traffic can be switched back to Blue.
This reduces deployment risk.
30. Security Best Practices
DevOps is not only about automation.
Security should be included throughout the pipeline.
Never store secrets in GitHub
Avoid committing:
1
2
3
4
passwords
API keys
AWS access keys
database credentialsFor example, do not commit:
1
.envcontaining production secrets.
Instead, use appropriate AWS services and secure configuration mechanisms.
31. Use IAM Roles
Instead of storing AWS credentials inside scripts, use IAM roles wherever possible.
For example:
1
2
3
4
5
EC2
↓
IAM Role
↓
AWS ServicesThis is safer than putting access keys directly into the application.
32. Use HTTPS
Production applications should normally use HTTPS.
A typical architecture is:
1
2
3
4
5
6
7
User
↓
HTTPS
↓
Load Balancer / CloudFront
↓
ApplicationAWS Certificate Manager can be used to manage TLS certificates in supported architectures.
33. Infrastructure as Code
Manually creating AWS resources through the console is useful for learning.
However, production environments often benefit from Infrastructure as Code.
Instead of manually creating:
1
2
3
4
5
EC2
Security Group
IAM Role
CodeBuild
CodePipelinewe can define infrastructure using tools such as:
- AWS CloudFormation
- AWS CDK
- Terraform
Then infrastructure can be version controlled along with the application.
For example:
1
2
3
4
5
6
7
Infrastructure Code
↓
Version Control
↓
Review
↓
DeploymentThis makes environments easier to reproduce.
34. Why CI/CD Is Useful
Without CI/CD:
1
2
3
4
5
6
7
8
9
10
11
Developer
↓
SSH into server
↓
Copy files
↓
Install dependencies
↓
Restart application
↓
Check logsWith CI/CD:
1
2
3
4
5
6
7
8
9
10
11
Developer
↓
git push
↓
Automated Build
↓
Automated Test
↓
Automated Deployment
↓
MonitoringThe second approach is more repeatable and scalable.
35. Real-World DevOps Workflow
A mature production workflow might look like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Developer
↓
GitHub
↓
Pull Request
↓
Code Review
↓
CI Build
↓
Automated Tests
↓
Security Checks
↓
Artifact Creation
↓
Staging Deployment
↓
Integration Tests
↓
Production Approval
↓
Production Deployment
↓
CloudWatch Monitoring
↓
FeedbackThis is much closer to how larger engineering teams operate.
36. Cost Considerations
AWS DevOps services can incur charges depending on usage.
When creating a learning environment:
- Shut down resources that are not required.
- Remove unused EC2 instances.
- Delete unnecessary build artifacts.
- Review CloudWatch logs and retention.
- Monitor your AWS Billing dashboard.
- Set up AWS Budgets or billing alerts.
Do not assume that every AWS service is completely free.
Always check the current AWS pricing and free-tier eligibility for your account and region before deploying resources.
37. Common Problems
Problem 1: CodeBuild fails
Check:
1
CodeBuild → Build history → Build logsLook for:
1
COMMAND_EXECUTION_ERRORor dependency installation errors.
Problem 2: EC2 application is unreachable
Check:
1
2
3
4
EC2 instance status
Security Group
Application process
Listening portYou can check listening ports using commands such as:
1
sudo ss -tulpnProblem 3: Application stops after deployment
Check the service:
1
sudo systemctl status my-applicationThen inspect logs:
1
sudo journalctl -u my-applicationProblem 4: Permission denied
Check IAM roles and policies.
Avoid immediately giving:
1
AdministratorAccessInstead, identify the exact permission that is missing.
38. Improving the Architecture
Our initial architecture is good for learning:
1
2
3
4
5
6
7
GitHub
↓
CodePipeline
↓
CodeBuild
↓
EC2For a production application, we could improve it to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
GitHub
|
v
AWS CodePipeline
|
v
AWS CodeBuild
|
v
AWS CodeDeploy
|
v
+----------------+
| Load Balancer |
+-------+--------+
|
+--------+--------+
| |
v v
EC2 EC2
Instance A Instance B
| |
+--------+--------+
|
v
CloudWatchThis architecture provides better availability and scalability.
39. Beyond EC2
EC2 is only one deployment option.
Depending on the application, AWS provides many other choices.
For example:
Static websites
1
2
3
4
5
React/Vite
↓
S3
↓
CloudFrontContainerized applications
1
2
3
4
5
Docker
↓
Amazon ECR
↓
Amazon ECSServerless applications
1
2
3
4
5
Code
↓
Lambda
↓
API GatewayKubernetes
1
2
3
4
5
Docker
↓
ECR
↓
Amazon EKSThe correct deployment architecture depends on the application's requirements.
40. DevOps Is More Than CI/CD
A common misconception is:
DevOps = CI/CD
CI/CD is an important part of DevOps, but DevOps is broader.
It includes:
- Collaboration
- Automation
- Continuous integration
- Continuous delivery
- Infrastructure as Code
- Monitoring
- Security
- Reliability
- Incident response
- Continuous improvement
The ultimate goal is to create a reliable process for delivering software quickly and safely.
41. Final Architecture
Our complete learning project can be summarized as:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
+-------------+
| Developer |
+------+------+
|
git push
|
v
+-------------+
| GitHub |
+------+------+
|
v
+-------------------+
| CodePipeline |
+---------+---------+
|
v
+-------------------+
| CodeBuild |
| Build + Test |
+---------+---------+
|
v
+-------------------+
| CodeDeploy |
+---------+---------+
|
v
+-------------------+
| EC2 |
| Running App |
+---------+---------+
|
v
+-------------------+
| CloudWatch |
| Logs + Monitoring |
+-------------------+42. Conclusion
Building a CI/CD pipeline on AWS provides a practical introduction to DevOps.
Instead of manually deploying every application change, we can create an automated workflow:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Code
↓
GitHub
↓
CodePipeline
↓
CodeBuild
↓
Test
↓
Deploy
↓
EC2
↓
CloudWatchThe biggest advantage is repeatability.
Every deployment can follow the same process, reducing manual work and human errors.
Once this basic pipeline is understood, it can be extended with:
- Automated testing
- Security scanning
- Docker containers
- Amazon ECR
- ECS
- Load Balancers
- Auto Scaling
- Blue/green deployments
- Infrastructure as Code
- CloudWatch alarms
- AWS CDK
- Terraform
- Multi-environment deployments
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article