Tools: LAB: GitLab CI/CD Docker Deploy to AWS EC2

Tools: LAB: GitLab CI/CD Docker Deploy to AWS EC2

🎯 Lab Objective ## 🏗️ Architecture ## 🔹 STEP 1 — GitLab Pages Basic Pipeline ## 🔹 STEP 2 — Add Docker Build Stage ## 🔹 STEP 5 — Push to GitLab Container Registry ## 🔴 ERROR #1 — Image Not Found ## 🔹 STEP 6 — Deploy to AWS EC2 ## 🔴 ERROR #2 — SSH Hostname Not Resolved ## Variable 1 ## Variable 2 ## 🔴 ERROR #3 — Port 80 Already in Use ## 🔹 Final Result ## 🧠 Real DevOps Troubleshooting Lessons ## 🎓 Interview Explanation Version Build a full CI/CD pipeline that: Create Dockerfile (ROOT of project): Update .gitlab-ci.yml: Fix: Make sure build and push stages use SAME $IMAGE_NAME. Cause: CI/CD variables not set. Settings → CI/CD → Variables Key: EC2_HOST Value: EC2 Public IP Key: EC2_KEY Value: FULL .pem file content Re-run pipeline → SUCCESS. This is REAL production debugging. "How would you deploy using GitLab CI/CD to EC2?" That is senior-level answer. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to ? It will become hidden in your post, but will still be visible via the comment's permalink. as well , this person and/or CODE_BLOCK: 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 CODE_BLOCK: 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 CODE_BLOCK: 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 CODE_BLOCK: image: busybox pages: stage: deploy script: - echo "The site will be deployed" artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH CODE_BLOCK: image: busybox pages: stage: deploy script: - echo "The site will be deployed" artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH CODE_BLOCK: image: busybox pages: stage: deploy script: - echo "The site will be deployed" artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH COMMAND_BLOCK: git commit --allow-empty -m "Trigger pipeline" git push origin master COMMAND_BLOCK: git commit --allow-empty -m "Trigger pipeline" git push origin master COMMAND_BLOCK: git commit --allow-empty -m "Trigger pipeline" git push origin master CODE_BLOCK: FROM nginx:alpine COPY public /usr/share/nginx/html EXPOSE 80 CODE_BLOCK: FROM nginx:alpine COPY public /usr/share/nginx/html EXPOSE 80 CODE_BLOCK: FROM nginx:alpine COPY public /usr/share/nginx/html EXPOSE 80 CODE_BLOCK: 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 . CODE_BLOCK: 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 . CODE_BLOCK: 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 . CODE_BLOCK: 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 CODE_BLOCK: 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 CODE_BLOCK: 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 CODE_BLOCK: An image does not exist locally with the tag CODE_BLOCK: An image does not exist locally with the tag CODE_BLOCK: An image does not exist locally with the tag COMMAND_BLOCK: 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 " COMMAND_BLOCK: 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 " COMMAND_BLOCK: 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 " CODE_BLOCK: failed to bind host port 80 address already in use CODE_BLOCK: failed to bind host port 80 address already in use CODE_BLOCK: failed to bind host port 80 address already in use COMMAND_BLOCK: sudo lsof -i :80 COMMAND_BLOCK: sudo lsof -i :80 COMMAND_BLOCK: sudo lsof -i :80 CODE_BLOCK: nginx running CODE_BLOCK: nginx running CODE_BLOCK: nginx running COMMAND_BLOCK: sudo systemctl stop nginx sudo systemctl disable nginx COMMAND_BLOCK: sudo systemctl stop nginx sudo systemctl disable nginx COMMAND_BLOCK: sudo systemctl stop nginx sudo systemctl disable nginx CODE_BLOCK: http://EC2_PUBLIC_IP CODE_BLOCK: http://EC2_PUBLIC_IP CODE_BLOCK: http://EC2_PUBLIC_IP - Connects GitLab to Mac terminal - Builds Docker image - Pushes image to GitLab Registry - SSH into EC2 - Deploys container - Handles real-world production errors - NOT protected - Separate variables - Create Dockerfile - Configure multi-stage pipeline - Build image - Push to registry - Store SSH key & host as CI variables - Use SSH in deploy stage - Handle container replacement safely - Troubleshoot port conflicts - Ensure idempotent deployment