LAB: GitLab CI/CD Docker ๋ฐฐํฌ to AWS EC2

๋ฐœํ–‰: (2026๋…„ 2์›” 21์ผ ์˜ค์ „ 09:02 GMT+9)
5 ๋ถ„ ์†Œ์š”
์›๋ฌธ: Dev.to

Iโ€™m ready to translate the article for you, but Iโ€™ll need the full text youโ€™d like translated. Could you please paste the content (excluding the source line you already provided) here? Once I have it, Iโ€™ll translate it into Korean while preserving the original formatting, markdown syntax, and technical terms.

๐ŸŽฏ 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

๐Ÿ—๏ธ ์•„ํ‚คํ…์ฒ˜

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

๐Ÿ”น ๋‹จ๊ณ„

STEPโ€ฏ1 โ€” GitLab Pages ๊ธฐ๋ณธ ํŒŒ์ดํ”„๋ผ์ธ

.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

ํŒŒ์ดํ”„๋ผ์ธ ํŠธ๋ฆฌ๊ฑฐ:

git commit --allow-empty -m "Trigger pipeline"
git push origin master

STEPโ€ฏ2 โ€” Docker ๋นŒ๋“œ ๋‹จ๊ณ„ ์ถ”๊ฐ€

Dockerfile ์ƒ์„ฑ (ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ):

FROM nginx:alpine
COPY public /usr/share/nginx/html
EXPOSE 80

.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 โ€” GitLab ์ปจํ…Œ์ด๋„ˆ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋กœ ํ‘ธ์‹œ

ํ‘ธ์‹œ ์ž‘์—… ์ถ”๊ฐ€:

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

๐Ÿ”ด ์˜ค๋ฅ˜ ๋ฐ ํ•ด๊ฒฐ์ฑ…

์˜ค๋ฅ˜ #1 โ€” ์ด๋ฏธ์ง€ ์ฐพ์„ ์ˆ˜ ์—†์Œ

์˜ค๋ฅ˜

An image does not exist locally with the tag

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•
build ๋‹จ๊ณ„์™€ push ๋‹จ๊ณ„์—์„œ ๋™์ผํ•œ $IMAGE_NAME์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

STEPโ€ฏ6 โ€” AWS EC2์— ๋ฐฐํฌ

Deploy ์ž‘์—…:

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
      "

์˜ค๋ฅ˜ #2 โ€” SSH ํ˜ธ์ŠคํŠธ ์ด๋ฆ„์„ ํ™•์ธํ•  ์ˆ˜ ์—†์Œ

์›์ธ
CI/CD ๋ณ€์ˆ˜๋“ค์ด ์„ค์ •๋˜์ง€ ์•Š์Œ.

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•
Settings โ†’ CI/CD โ†’ Variables ์—์„œ ๋‹ค์Œ ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค (๋ณดํ˜ธ๋˜์ง€ ์•Š์œผ๋ฉฐ, ํ‘œ์‹œ ๊ฐ€๋Šฅ):

ํ‚ค (Key)๊ฐ’ (Value)
EC2_HOSTEC2 ํผ๋ธ”๋ฆญ IP ์ฃผ์†Œ
EC2_KEY.pem ํŒŒ์ผ ์ „์ฒด ๋‚ด์šฉ

์˜ค๋ฅ˜ #3 โ€” ํฌํŠธโ€ฏ80 ์ด๋ฏธ ์‚ฌ์šฉ ์ค‘

ํŒŒ์ดํ”„๋ผ์ธ ์˜ค๋ฅ˜

failed to bind host port 80
address already in use

์กฐ์‚ฌ ๋ฐฉ๋ฒ•

ssh -i key.pem ubuntu@$EC2_HOST
sudo lsof -i :80

๊ฒฐ๊ณผ์— nginx ๊ฐ€ ํฌํŠธโ€ฏ80์„ ์‚ฌ์šฉ ์ค‘์ธ ๊ฒƒ์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

sudo systemctl stop nginx
sudo systemctl disable nginx

ํŒŒ์ดํ”„๋ผ์ธ์„ ๋‹ค์‹œ ์‹คํ–‰ โ†’ ์„ฑ๊ณต.

๐Ÿ”น ์ตœ์ข… ๊ฒฐ๊ณผ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

http://

๐Ÿง  ์‹ค์ œ DevOps ๋ฌธ์ œ ํ•ด๊ฒฐ ๊ตํ›ˆ

๋ฌธ์ œ์‚ฌ์šฉ ๋„๊ตฌ
SSH ๊ฑฐ๋ถ€ssh-add
ํŒŒ์ดํ”„๋ผ์ธ ๋ณ€์ˆ˜ ๋ˆ„๋ฝGitLab CI/CD variables
Docker ํƒœ๊ทธ ๋ถˆ์ผ์น˜Inspect $IMAGE_NAME
SSH ํ˜ธ์ŠคํŠธ๋ช… ์˜ค๋ฅ˜Verify variables
ํฌํŠธ ์ถฉ๋Œlsof -i :80
Nginx ์ถฉ๋Œsystemctl stop

์ด๋Š” ์ผ๋ฐ˜์ ์ธ ํ”„๋กœ๋•์…˜ ์ˆ˜์ค€ ๋””๋ฒ„๊น… ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค.

๐ŸŽ“ ์ธํ„ฐ๋ทฐ ์„ค๋ช… ๋ฒ„์ „

๋ฉด์ ‘๊ด€์ด โ€œGitLab CI/CD๋ฅผ ์‚ฌ์šฉํ•ด EC2์— ๋ฐฐํฌํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•˜๋‚˜์š”?โ€ ๋ผ๊ณ  ๋ฌผ์œผ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‹ตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  1. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์šฉ Dockerfile์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ฉ€ํ‹ฐโ€‘์Šคํ…Œ์ด์ง€ .gitlab-ci.yml ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค (๋นŒ๋“œ, ํ‘ธ์‹œ, ๋ฐฐํฌ).
  3. Docker ์ด๋ฏธ์ง€๋ฅผ ๋นŒ๋“œํ•˜๊ณ  GitLab Container Registry์— ํ‘ธ์‹œํ•ฉ๋‹ˆ๋‹ค.
  4. EC2 SSH ๊ฐœ์ธ ํ‚ค์™€ ํ˜ธ์ŠคํŠธ IP๋ฅผ CI/CD ๋ณ€์ˆ˜๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  5. deploy ๋‹จ๊ณ„์—์„œ EC2 ์ธ์Šคํ„ด์Šค์— SSH๋กœ ์ ‘์†ํ•˜๊ณ , ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ๋กœ๊ทธ์ธํ•œ ๋’ค ์ด๋ฏธ์ง€๋ฅผ ํ’€(pull)ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ์กด ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ค‘์ง€ยท์‚ญ์ œํ•˜๊ณ , ์ƒˆ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํฌํŠธโ€ฏ80์—์„œ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  6. ์ผ๋ฐ˜์ ์ธ ๋ฌธ์ œ(๋ณ€์ˆ˜ ๋ˆ„๋ฝ, ํฌํŠธ ์ถฉ๋Œ, ๊ธฐ์กด ์„œ๋น„์Šค ๋“ฑ)๋ฅผ ์ฒ˜๋ฆฌํ•˜์—ฌ **๋ฉฑ๋“ฑ(idempotent)**ํ•˜๊ณ  ํ”„๋กœ๋•์…˜์— ์ ํ•ฉํ•œ ๋ฐฐํฌ๋ฅผ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.
0 ์กฐํšŒ
Back to Blog

๊ด€๋ จ ๊ธ€

๋” ๋ณด๊ธฐ ยป

โ€˜Lazyโ€™ ๋ฐฑ์—”๋“œ ๊ตฌ์ถ•์„ ๋ฉˆ์ถฐ๋ผ: ๋ฏธ๋ž˜๋Š” Agentic FaaS์™€ MDL์ด๋‹ค

์šฐ๋ฆฌ๋Š” ํ˜„์žฌ ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐฉ์‹์— ํฐ ๋ณ€ํ™”๋ฅผ ๊ฒช๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋ก ํŠธ์—”๋“œ๋Š” ๋ฏฟ์„ ์ˆ˜ ์—†์„ ์ •๋„๋กœ ๋™์ ์ด ๋˜์—ˆ์ง€๋งŒ, ๋ฐฑ์—”๋“œโ€”์šด์˜์˜ โ€œ๋‘๋‡Œโ€โ€”๋Š” ์•„์ง๋„โ€ฆ

์„œ๋ธŒ๋„ทํŒ… ์„ค๋ช…

Subnetting์ด๋ž€ ๋ฌด์—‡์ธ๊ฐ€? ํฐ ์•„ํŒŒํŠธ ๊ฑด๋ฌผ์„ ์—ฌ๋Ÿฌ ์ธต์œผ๋กœ ๋‚˜๋ˆ„๋Š” ๊ฒƒ๊ณผ ๊ฐ™๋‹ค. ๊ฐ ์ธต ์„œ๋ธŒ๋„ท์€ ์ž์ฒด ๋ฒˆํ˜ธ๊ฐ€ ๋งค๊ฒจ์ง„ ์œ ๋‹›(hosts)์„ ๊ฐ€์ง€๊ณ , ๊ทธ๋ฆฌ๊ณ  ๊ฑด๋ฌผโ€ฆ

API test scripts ์ž‘์„ฑ์„ ์ค‘๋‹จํ•˜์„ธ์š”. ๋Œ€์‹  ํ‰๋ฒ”ํ•œ ์˜์–ด๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

๊ฐœ์š” Octrafic๋Š” API ํ…Œ์ŠคํŠธ๋ฅผ ํ‰๋ฒ”ํ•œ ์˜์–ด๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธํ•˜๊ณ  ์‹ถ์€ ๋‚ด์šฉ์„ ์„ค๋ช…ํ•˜๋ฉด, AI๊ฐ€ ๊ท€ํ•˜์˜ OpenAPI๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ ์ ˆํ•œ HTTP ์š”์ฒญ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.