LAB: GitLab CI/CD Docker Deploy to AWS EC2
Source: Dev.to
๐ฏ Lab Objective
Build a full CI/CD pipeline that:
- Connects GitLab to Mac terminal
- Builds Docker image
- Pushes image to GitLab Registry
- SSH into EC2
- Deploys container
- Handles realโworld production errors
๐๏ธ Architecture
Mac Terminal
โ
GitLab Repo
โ
GitLab CI/CD Pipeline
โ
Docker Image Build
โ
Push to GitLab Container Registry
โ
SSH to AWS EC2
โ
Docker Pull & Run
โ
Application Live on Port 80
๐น Steps
STEPโฏ1 โ GitLab Pages Basic Pipeline
.gitlab-ci.yml
image: busybox
pages:
stage: deploy
script:
- echo "The site will be deployed"
artifacts:
paths:
- public
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
Trigger pipeline:
git commit --allow-empty -m "Trigger pipeline"
git push origin master
STEPโฏ2 โ Add Docker Build Stage
Create Dockerfile (project root):
FROM nginx:alpine
COPY public /usr/share/nginx/html
EXPOSE 80
Update .gitlab-ci.yml:
stages:
- build
- push
- deploy
variables:
IMAGE_NAME: registry.gitlab.com/$CI_PROJECT_PATH:latest
build_image:
stage: build
image: docker:24
services:
- docker:24-dind
script:
- docker build -t $IMAGE_NAME .
STEPโฏ5 โ Push to GitLab Container Registry
Add the push job:
push_image:
stage: push
image: docker:24
services:
- docker:24-dind
script:
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
- docker push $IMAGE_NAME
๐ด Errors & Fixes
ERROR #1 โ Image Not Found
Error
An image does not exist locally with the tag
Fix
Ensure the build and push stages use the same $IMAGE_NAME.
STEPโฏ6 โ Deploy to AWS EC2
Deploy job:
deploy_ec2:
stage: deploy
image: alpine
before_script:
- apk add --no-cache openssh
script:
- echo "$EC2_KEY" > key.pem
- chmod 600 key.pem
- ssh -o StrictHostKeyChecking=no -i key.pem ubuntu@$EC2_HOST "
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY &&
docker pull $IMAGE_NAME &&
docker stop web || true &&
docker rm web || true &&
docker run -d -p 80:80 --name web $IMAGE_NAME
"
ERROR #2 โ SSH Hostname Not Resolved
Cause
CI/CD variables not set.
Fix
Add the following variables in Settings โ CI/CD โ Variables (not protected, visible):
| Key | Value |
|---|---|
EC2_HOST | EC2 public IP address |
EC2_KEY | Full contents of the .pem file |
ERROR #3 โ Portโฏ80 Already in Use
Pipeline error
failed to bind host port 80
address already in use
Investigation
ssh -i key.pem ubuntu@$EC2_HOST
sudo lsof -i :80
Result shows nginx listening on portโฏ80.
Fix
sudo systemctl stop nginx
sudo systemctl disable nginx
Reโrun the pipeline โ SUCCESS.
๐น Final Result
The application is accessible at:
http://
๐ง Real DevOps Troubleshooting Lessons
| Issue | Tool Used |
|---|---|
| SSH denied | ssh-add |
| Pipeline variable missing | GitLab CI/CD variables |
| Docker tag mismatch | Inspect $IMAGE_NAME |
| SSH hostname error | Verify variables |
| Port conflict | lsof -i :80 |
| Nginx conflict | systemctl stop |
These are typical productionโlevel debugging steps.
๐ Interview Explanation Version
If an interviewer asks, โHow would you deploy using GitLab CI/CD to EC2?โ you can answer:
- Create a
Dockerfilefor the application. - Configure a multiโstage
.gitlab-ci.ymlpipeline (build, push, deploy). - Build the Docker image and push it to the GitLab Container Registry.
- Store the EC2 SSH private key and host IP as CI/CD variables.
- In the deploy stage, SSH into the EC2 instance, log in to the registry, pull the image, stop/remove any existing container, and run the new container on portโฏ80.
- Handle common issues (missing variables, port conflicts, existing services) to ensure an idempotent, productionโready deployment.