AWS Builder Center
From Code to Cloud: A Beginner’s Guide to CI/CD Deployment on AWS

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 CloudWatch
The 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
↓
Feedback
AWS 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:
  1. Download the source code.
  2. Install dependencies.
  3. Build the application.
  4. Run tests.
  5. 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/fails
This 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
↓
Production
Instead 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
↓
Deployment
CodePipeline 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.txt
while a Node.js application might execute:
1
2
npm install
npm run build

Amazon 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.yml
A 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 5000
The requirements.txt file contains:
1
2
Flask
gunicorn

7. Step 2: Push the Application to GitHub

Create a GitHub repository.
For example:
1
aws-devops-demo
Initialize the local project:
1
git init
Add 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 main
Now 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 5000
However, 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
↓
EC2
with 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 -y
or use the appropriate package manager for your chosen Linux distribution.

11. Install Required Software

Install Python:
1
sudo dnf install python3 -y
Create a project directory:
1
sudo mkdir -p /opt/my-application
Create a virtual environment:
1
python3 -m venv /opt/my-application/venv
Activate it:
1
source /opt/my-application/venv/bin/activate
Install dependencies:
1
pip install -r requirements.txt
For 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.py
the 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-application
We can start it using:
1
sudo systemctl start my-application
and enable it during boot:
1
sudo systemctl enable my-application
This 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.yml
Example:
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.2
This specifies the CodeBuild buildspec version.

Install Phase

1
2
3
install:
commands:
- pip install -r requirements.txt
This installs the dependencies required by the application.

Build Phase

1
2
3
build:
commands:
- python3 -m py_compile app.py
This performs a basic Python syntax check.
In a real project, you should run your automated tests here.
For example:
1
pytest

Post Build

1
2
3
post_build:
commands:
- echo Build completed successfully
This 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:
- pytest
The pipeline should behave like this:
1
2
3
4
5
6
7
8
9
10
11
Code pushed
↓
Build
↓
Tests
↓
┌───┴────┐
↓ ↓
PASS FAIL
↓ ↓
Deploy Stop
If 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-build
Choose 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.yml
inside 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 / CodeDeploy
Each 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 logs
rather than:
1
2
3
CodeBuild
↓
AdministratorAccess
The 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-pipeline
The pipeline can contain stages such as:
1
2
3
4
5
Source
↓
Build
↓
Deploy

19. Source Stage

The source stage obtains the latest version of our code.
For example:
1
2
3
GitHub
↓
CodePipeline
When 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 push
This can trigger:
1
2
3
4
5
6
7
GitHub
↓
CodePipeline
↓
CodeBuild
↓
Deployment
This is where CI/CD becomes powerful.

20. Build Stage

The build stage uses CodeBuild.
CodeBuild receives the source code and reads:
1
buildspec.yml
It 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 artifact
If 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 → EC2
or 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
↓
EC2

22. 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 push
The 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 application
the 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
#!/bin/bash

cd /opt/my-application

source venv/bin/activate

pip install -r requirements.txt

sudo systemctl restart my-application
This 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 health

25. Why Logs Are Important

Suppose the deployment succeeds but the application returns:
1
HTTP 500 Internal Server Error
The 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 stopped
This 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
↓
Notification
This 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
↓
CodeBuild
CodeBuild executes the validation.
The build fails.
Therefore:
1
2
3
Build FAILED
↓
Deployment STOPPED
The 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 3
If Version 3 causes problems:
1
2
3
4
5
6
7
Version 3
↓
Problem detected
↓
Rollback
↓
Version 2
More 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 2
Initially, users access Blue.
After deploying Version 2 to Green and verifying it:
1
2
3
4
Users
↓
Green
Version 2
If 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 credentials
For example, do not commit:
1
.env
containing 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 Services
This 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
↓
Application
AWS 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
CodePipeline
we 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
↓
Deployment
This 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 logs
With CI/CD:
1
2
3
4
5
6
7
8
9
10
11
Developer
↓
git push
↓
Automated Build
↓
Automated Test
↓
Automated Deployment
↓
Monitoring
The 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
↓
Feedback
This 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 logs
Look for:
1
COMMAND_EXECUTION_ERROR
or dependency installation errors.

Problem 2: EC2 application is unreachable

Check:
1
2
3
4
EC2 instance status
Security Group
Application process
Listening port
You can check listening ports using commands such as:
1
sudo ss -tulpn

Problem 3: Application stops after deployment

Check the service:
1
sudo systemctl status my-application
Then inspect logs:
1
sudo journalctl -u my-application

Problem 4: Permission denied

Check IAM roles and policies.
Avoid immediately giving:
1
AdministratorAccess
Instead, 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
↓
EC2
For 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
CloudWatch
This 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
↓
CloudFront

Containerized applications

1
2
3
4
5
Docker
↓
Amazon ECR
↓
Amazon ECS

Serverless applications

1
2
3
4
5
Code
↓
Lambda
↓
API Gateway

Kubernetes

1
2
3
4
5
Docker
↓
ECR
↓
Amazon EKS
The 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
↓
CloudWatch
The 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
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article