프론트엔드 기초 다시 쌓기 챌린지 13일차.
Week 3 "실전 배포 흐름"의 세 번째 수업.
Day 11에서 CI/CD를, Day 12에서 Docker를 각각 배웠다면,
오늘은 이 둘을 합쳐서 완성된 배포 파이프라인을 만드는 시간이었다.
지금까지 배운 걸 레스토랑으로 쭉 이어보면:
수동 시대 (Day 11 이전)
셰프가 직접 시장 가서 재료 삼
→ 직접 손질
→ 직접 주방 세팅
→ 직접 불 켬
→ 하루 5번이면 셰프가 쓰러짐
CI/CD만 도입 (Day 11)
레시피 제출하면 로봇이 자동으로 처리
→ 근데 2호점은 주방 환경이 달라서 맛이 다름 😩
Docker만 도입 (Day 12)
주방 통째로 박스에 넣어서 보내면 어디서든 같은 맛
→ 근데 박스 만들고 보내는 걸 사람이 직접 해야 함 😩
CI/CD + Docker (오늘!)
셰프가 레시피북에 새 레시피 적어 넣으면 (git push)
→ 로봇이 자동으로 이동식 주방(이미지) 만들고
→ 중앙 창고(Docker Hub)에 보관하고
→ 각 지점(서버)에서 꺼내서 영업 시작
→ 셰프는 레시피만 잘 쓰면 됨!
오늘의 핵심. 개발자가 하는 일은 git push 하나뿐이다. 나머지는 전부 자동.
[1. 개발자]
코드 수정 → git push to main
↓
[2. GitHub Actions (CI)]
코드 체크아웃
→ docker build (이미지 생성)
→ 테스트 실행 (lint, 빌드 확인)
→ docker push (이미지를 Docker Hub에 업로드)
↓
[3. Docker Hub (창고)]
이미지 보관 중...
↓
[4. GitHub Actions (CD)]
SSH로 서버 접속
→ docker pull (이미지 다운로드)
→ docker run (컨테이너 실행)
↓
[5. 서버]
컨테이너 안에서 yarn start 자동 실행
→ Nginx가 요청을 컨테이너로 전달
↓
[6. 사용자]
사이트 접속 → 새 버전 확인!
Day 11에서는 Docker 없이 배포하는 YAML을 봤다.
오늘은 Docker를 합친 버전이다.
# .github/workflows/deploy.yml
name: Docker 배포 자동화
on:
push:
branches: [main]
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
# 1단계: 코드 가져오기
- name: 코드 체크아웃
uses: actions/checkout@v4
# 2단계: Docker Hub 로그인
- name: Docker Hub 로그인
run: echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
# 3단계: Docker 이미지 빌드
- name: 이미지 빌드
run: docker build -t myusername/my-nextjs-app:latest .
# 4단계: Docker Hub에 업로드
- name: 이미지 푸시
run: docker push myusername/my-nextjs-app:latest
deploy:
needs: build-and-push # 위의 job이 끝나야 실행
runs-on: ubuntu-latest
steps:
# 5단계: 서버에 접속해서 새 이미지로 실행
- name: 서버 배포
run: |
ssh -i ${{ secrets.SSH_KEY }} ubuntu@${{ secrets.SERVER_IP }} << 'EOF'
docker pull myusername/my-nextjs-app:latest
docker stop my-app || true
docker rm my-app || true
docker run -d --name my-app -p 5008:5008 myusername/my-nextjs-app:latest
EOF
코드 체크아웃 → 재료 창고에서 레시피 가져오기
Docker Hub 로그인 → 중앙 창고 출입증 찍기
이미지 빌드 → 이동식 주방 조립 (Dockerfile 기반)
이미지 푸시 → 완성된 주방을 중앙 창고에 보관
서버 배포:
docker pull → 지점에서 창고에서 주방 꺼내오기
docker stop/rm → 기존 주방 정리
docker run → 새 주방 세팅하고 영업 시작!
needs: build-and-pushJob 간 순서를 지정하는 것이다.
Job 1: build-and-push (이미지 만들고 창고에 올리기)
Job 2: deploy (서버에 배포하기)
needs = "Job 1이 끝나야 Job 2를 시작해"
당연하다. 이미지가 창고에 올라가지도 않았는데 서버에서 꺼내올 수는 없으니까.
docker stop → docker rm → docker run 3단계docker stop my-app || true # 기존 컨테이너 멈춤
docker rm my-app || true # 기존 컨테이너 삭제
docker run -d --name my-app -p 5008:5008 myusername/my-nextjs-app:latest
왜 3단계인가?
1. docker stop → 기존 푸드트럭 영업 종료
2. docker rm → 기존 푸드트럭 철거
3. docker run → 새 푸드트럭 세팅하고 영업 시작
기존 컨테이너가 5008 포트를 쓰고 있으니까, 안 지우고 새 걸 띄우면 포트 충돌이 난다.
하나의 포트에 두 개의 앱이 동시에 붙을 수 없다 (Day 9에서 배운 내용).
|| true는 "혹시 기존 컨테이너가 없어도 에러 내지 말고 넘어가"라는 뜻이다.
처음 배포할 때는 기존 컨테이너가 없을 수 있으니까.
-d 플래그 = 백그라운드 실행docker run my-app → 터미널에 로그가 쭉 뜸, 터미널 닫으면 멈춤
docker run -d my-app → 백그라운드에서 조용히 실행, 터미널 닫아도 계속 돌아감
Day 7에서 배운 "SSH 끊으면 프로세스가 죽는 문제"를 -d가 해결해준다.
| Day 11 (Docker 없이) | Day 13 (Docker로) | |
|---|---|---|
| 서버에서 하는 일 | git pull → yarn install → yarn build → pm2 restart | docker pull → docker run |
| 빌드 위치 | 서버에서 직접 빌드 | GitHub Actions에서 빌드 (이미지 안에 포함) |
| 서버에 필요한 것 | Node.js, yarn, pm2 전부 설치 | Docker만 설치 |
| 환경 차이 문제 | 발생 가능 | 없음 (이미지 안에 다 들어있음) |
| 서버 2대로 늘릴 때 | 2대 다 환경 세팅 필요 | docker run만 하면 됨 |
지금까지 배운 모든 게 하나의 파이프라인 안에 들어있다.
[개발자] 코드 작성 + git push
↓
[GitHub Actions] CI/CD (Day 11)
↓
[Docker] 이미지 빌드 + 푸시 (Day 12)
↓
[서버] docker pull + docker run (Day 13 - 오늘)
↓
[pm2 또는 Docker] 프로세스 관리 (Day 8)
↓
[Nginx] 요청을 앱으로 전달 (Day 9)
↓
[사용자] 사이트 접속!
↓
[로그] 문제 생기면 확인 (Day 10)
Week 1에서 배운 빌드, Week 2에서 배운 서버·pm2·Nginx,
Week 3에서 배운 CI/CD·Docker가 전부 하나로 연결된다.
| 레스토랑 | 서버 |
|---|---|
| 레시피 적고 레시피북에 넣기 | git push |
| 로봇이 이동식 주방 자동 조립 | GitHub Actions + docker build |
| 완성된 주방을 중앙 창고에 보관 | docker push → Docker Hub |
| 지점에서 창고에서 주방 꺼냄 | docker pull |
| 기존 주방 철거 | docker stop + docker rm |
| 새 주방 세팅하고 영업 시작 | docker run -d |
| "이전 작업 끝나야 다음 시작" | needs: build-and-push |
Q1. CI/CD + Docker 배포에서 개발자가 하는 일은?
→ 정답: git push 하나뿐. 이후 GitHub Actions가 docker build → docker push → 서버에서 docker pull → docker run까지 전부 자동으로 처리.
Q2. Day 11 방식과 Day 13 방식에서 "서버에서 하는 일"의 차이는?
→ 정답: Docker 없이는 서버에서 git pull → yarn install → yarn build → pm2 restart를 직접 해야 한다. Docker로는 docker pull → docker run만 하면 끝. 빌드는 이미지 안에 이미 완료되어 있기 때문.
Q3. docker stop → docker rm → docker run 3단계를 거치는 이유는?
→ 정답: 기존 컨테이너가 포트를 잡고 있어서, 안 지우고 새 걸 띄우면 포트 충돌이 난다. 기존 걸 멈추고(stop), 지우고(rm), 새로 띄우는(run) 순서.
Day 11에서 CI/CD를 배웠을 때는 "자동화 편하겠다" 정도였고,
Day 12에서 Docker를 배웠을 때는 "환경 통일 좋겠다" 정도였다.
오늘 이 둘을 합치니까 비로소 "아, 이게 현대적인 배포구나" 가 느껴졌다.
git push 하나로 빌드부터 배포까지 전부 자동. 환경도 동일 보장.
Week 1~3에서 배운 빌드, 서버, pm2, Nginx, CI/CD, Docker가
전부 하나의 파이프라인 안에 들어있다는 게 신기했다.
하나하나 따로 배울 때는 몰랐는데, 합치니까 전부 연결된다.
Day 14: 빌드 에러 해결 패턴 + 롤백 개념
자동 배포가 완성됐는데... 배포한 버전에 버그가 있으면?
"되돌리기"는 어떻게 하는가!
#프론트엔드 #Docker #CI/CD #GitHubActions #배포파이프라인 #2년차개발자 #기초다시쌓기