Infra & DevOps

[FE] ๋ชจ๋ฐ”์ผ ์ฒญ์ฒฉ์žฅ - ๋ฐฐํฌ ์ž๋™ํ™” ๊ตฌํ˜„

hyeyeonismm 2025. 6. 18. 18:08
GitHub Actions, AWS ECR, EC2, Docker, Nginx๋ฅผ ์กฐํ•ฉํ•˜์—ฌ ์ž๋™ ๋ฐฐํฌ DevOps ํŒŒ์ดํ”„๋ผ์ธ์„ ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„ํ–ˆ๋‹ค.

 

1. ์•„ํ‚คํ…์ฒ˜ ์„ค๊ณ„

์ „์ฒด ์ž๋™ํ™” ํ๋ฆ„์€ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ตฌ์„ฑํ–ˆ๋‹ค.
(1) ๊นƒํ—ˆ๋ธŒ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์— ์ฝ”๋“œ๋ฅผ ํ‘ธ์‹œํ•˜๋ฉด, GitHub Actions์ด ํŠธ๋ฆฌ๊ฑฐ๋˜์–ด Dockerfile์„ ๊ธฐ๋ฐ˜์œผ๋กœ nginx ๊ธฐ๋ฐ˜ ์ด๋ฏธ์ง€๊ฐ€ ๋นŒ๋“œ๋œ๋‹ค.
(2) AWS ECR์— ๋นŒ๋“œ๋œ ์ด๋ฏธ์ง€๋ฅผ pushํ•˜๊ณ , EC2 ์ธ์Šคํ„ด์Šค์—์„œ pull ๋ฐ›๋Š”๋‹ค.

 

2. GitHub Actions

GitHub Actions๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ ํ‘ธ์‹œ, PR ๋“ฑ์˜ ์ด๋ฒคํŠธ๋ฅผ ํŠธ๋ฆฌ๊ฑฐ๋กœ ์‚ผ์•„ ์ž๋™ํ™”๋œ ์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค.
์›Œํฌํ”Œ๋กœ์šฐ๋Š” ๋นŒ๋“œ, ํ…Œ์ŠคํŠธ, ๋ฐฐํฌ์™€ ๊ฐ™์€ ์ผ๋ จ์˜ ์ž‘์—…๋“ค์„ ์ •์˜ํ•œ ๊ตฌ์„ฑ ํŒŒ์ผ์ด๋ฉฐ Repository ๋‚ด .github/workflows ๋””๋ ‰ํ„ฐ๋ฆฌ์— YAML ํŒŒ์ผ๋กœ ์œ„์น˜ํ•œ๋‹ค.

๋‚˜๋Š” GitHub Actions๋ฅผ ํ†ตํ•ด ์ฝ”๋“œ๊ฐ€ main ๋ธŒ๋žœ์น˜์— ํ‘ธ์‹œ๋  ๋•Œ ์ž๋™์œผ๋กœ Docker ์ด๋ฏธ์ง€๋ฅผ ๋นŒ๋“œํ•˜๊ณ , ์ด๋ฅผ ECR์— ์—…๋กœ๋“œํ•œ ๋’ค EC2 ์ธ์Šคํ„ด์Šค์—์„œ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์žฌ์‹œ์ž‘ํ•˜๋„๋ก ์„ค์ •ํ•ด์•ผ ํ–ˆ๋‹ค.

๋”ฐ๋ผ์„œ, ๋จผ์ € ์•„๋ž˜์˜ ํŒŒ์ผ ์œ„์น˜์— yaml ํŒŒ์ผ์„ ์ž‘์„ฑํ•ด์คฌ๋‹ค.

name: Deploy Frontend

on:
  push:
   branches:
     - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout source code
        uses: actions/checkout@v3
  • name: ์›Œํฌํ”Œ๋กœ์šฐ์˜ ์ด๋ฆ„
  • on - push: ์›Œํฌํ”Œ๋กœ์šฐ๊ฐ€ main branch์˜ push ์ด๋ฒคํŠธ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์‹คํ–‰๋œ๋‹ค๋Š” ๋œป
  • jobs: ์›Œํฌํ”Œ๋กœ์šฐ์—์„œ ์‹คํ–‰ํ•  ์ž‘์—…๋“ค์˜ ์ง‘ํ•ฉ์„ ์ •์˜
  • runs-on: deploy๋ž€ job์ด ์–ด๋–ค OS ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰๋ ์ง€๋ฅผ ์ •ํ•˜๋Š” ๋ถ€๋ถ„์œผ๋กœ ์ตœ์‹  Ubuntu ๊ฐ€์ƒ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰ํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ (์‹คํ–‰๋˜๋Š” ์„œ๋ฒ„๋Š” GitHub Actions์ด ๋งค ์›Œํฌํ”Œ๋กœ์šฐ ์‹คํ–‰ ์‹œ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์‚ญ์ œํ•˜๋Š” ์ผ์‹œ์ ์ธ ๋จธ์‹ ์„ ๋œปํ•œ๋‹ค.)
  • actions/checkout@v3: GitHub์ด ๊ณต์‹ ์ œ๊ณตํ•˜๋Š” ์•ก์…˜ ์ค‘ ํ•˜๋‚˜๋กœ, ๋จธ์‹ ์— ํ˜„์žฌ ๋ธŒ๋žœ์น˜์˜ ์ฝ”๋“œ๋ฅผ ๋‚ด๋ ค๋ฐ›๋Š”๋‹ค๋Š” ๋œป

 

 

3. ECR ์ƒ์„ฑ๊ณผ IAM ๊ถŒํ•œ ๋ถ€์—ฌ

ECR์€ AWS์—์„œ ์ œ๊ณตํ•˜๋Š” Docker ์ด๋ฏธ์ง€ ์ €์žฅ์†Œ๋กœ, ๋‚ด๊ฐ€ ๋นŒ๋“œํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ด๋ฏธ์ง€๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ €์žฅํ•˜๊ณ , EC2๋‚˜ ECS์™€ ๊ฐ™์€ AWS ๋ฆฌ์†Œ์Šค์—์„œ ์‰ฝ๊ฒŒ pullํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค. (๋„์ปคํ—ˆ๋ธŒ์™€ ๋น„์Šทํ•œ ์—ญํ• )

(1) ECR ์ƒ์„ฑ

GitHub Actions์—์„œ ๋นŒ๋“œํ•œ Docker ์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก ECR ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ–ˆ๋‹ค.

๋˜ํ•œ, GitHub Actions์—์„œ ๋งค๋ฒˆ docker build ํ›„ docker push ํ•˜๋ฉด์„œ ์ƒˆ ์ด๋ฏธ์ง€๊ฐ€ ์Œ“์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ์œ„ํ•œ ์ˆ˜๋ช…์ฃผ๊ธฐ์ •์ฑ…์„ ์„ค์ •ํ•ด์คฌ๋‹ค.

 

(2) IAM ๊ถŒํ•œ ๋ถ€์—ฌ

ECR๊ณผ EC2์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” IAM ๊ถŒํ•œ์ด ํ•„์š”ํ•˜๋‹ค.
GitHub Actions์—์„œ ECR์— ๋กœ๊ทธ์ธํ•˜์—ฌ ์ด๋ฏธ์ง€๋ฅผ pushํ•ด์•ผ ํ•˜๊ณ , ECR์—์„œ ์ด๋ฏธ์ง€๋ฅผ pull ๋ฐ›์•„ EC2 ์ธ์Šคํ„ด์Šค์— ๋ฐฐํฌํ•ด์•ผ ํ•œ๋‹ค.
๋”ฐ๋ผ์„œ IAM ์ฝ˜์†”์—์„œ ์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž๋ฅผ ์ƒ์„ฑํ•˜๊ณ , AmazonEC2ContainerRegistryFullAccess ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•ด์คฌ๋‹ค.

 

(3) GitHub Secret ๋“ฑ๋กํ•˜๊ธฐ

IAM ์‚ฌ์šฉ์ž์˜ AWS Secret Key, Access Key๋ฅผ ๋ฐœ๊ธ‰ ๋ฐ›์•„ ์ด ํ‚ค๋ฅผ ํ†ตํ•ด ECR์— ๋กœ๊ทธ์ธํ•ด์•ผ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ GitHub ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์˜ Settings → Secrets and variables → Actions์— ํ•ด๋‹น ํ‚ค๋“ค์„ ๋“ฑ๋กํ–ˆ๋‹ค.

๋“ฑ๋ก ํ›„, build job์˜ ์ด yaml ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

jobs:
  build:
    name: Build Docker Image and Push to ECR
    runs-on: ubuntu-latest
    steps:
      - name: Checkout source code
        uses: actions/checkout@v3

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-2
      
      - name: Login to AWS ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Build Docker Image
        run: docker build -t $REPOSITORY_NAME:$IMAGE_TAG .
      
      - name: Tag Docker Image
        run: docker tag $REPOSITORY_NAME:$IMAGE_TAG ${{ steps.login-ecr.outputs.registry }}/$REPOSITORY_NAME:$IMAGE_TAG
      
      - name: Push Image to ECR
        run: docker push ${{ steps.login-ecr.outputs.registry }}/$REPOSITORY_NAME:$IMAGE_TAG

 

4. EC2์—์„œ ๋ฐฐํฌ

deploy job์„ ์ƒˆ๋กœ ์„ ์–ธํ•ด์ค€๋‹ค. ECR์— ์˜ฌ๋ผ๊ฐ„ Docker Image๋ฅผ EC2 ์ธ์Šคํ„ด์Šค์—์„œ pullํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š” ๋‹จ๊ณ„์ด๋‹ค.
nees: build๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ build ํ›„ ์‹คํ–‰๋˜๋„๋ก ์„ค์ •ํ•ด์ค€๋‹ค.

runner ์„œ๋ฒ„์—์„œ ssh๋ฅผ ํ†ตํ•ด์„œ ec2์— ์ ‘์†ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, github secrets์— EC2์™€ ๊ด€๋ จ๋œ ๋ณ€์ˆ˜๋„ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.
PEM ํ‚ค๋ฅผ ๋„ฃ์„๋• ๊ผญ -----BEGIN RSA PRIVATE KEY----- ๋ถ€ํ„ฐ ๋๊นŒ์ง€ ๋„ฃ์–ด์•ผํ•จ..!!

GitHub Actions์—์„œ ์ œ๊ณตํ•˜๋Š” ssh-action์„ ์‚ฌ์šฉํ–ˆ๋‹ค.
env ํŒŒ์ผ์„ workflow์— ์„ ์–ธํ•˜๊ณ  jobs๋“ค์—์„œ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ–ˆ์œผ๋‚˜... ec2์— ssh๋กœ ์ ‘์†ํ•˜๋ฉด์„œ ์ „์—ญ๋ณ€์ˆ˜์ธ env๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฒŒ ๋˜์–ด ์—๋Ÿฌ๊ฐ€ ๋‚ฌ๋‹ค.

outputs์œผ๋กœ registry๋ฅผ ์„ ์–ธํ•˜๊ณ  ๋ฐ›๋Š” ๋ฐฉ์‹๋„ ํ•ด๋ดค์ง€๋งŒ ์‹คํŒจ..

์ด๋ ‡๊ฒŒ ์Šคํฌ๋ฆฝํŠธ ๋‚ด๋ถ€์—์„œ export ํ•˜๋Š” ๋ฐฉ์‹๋„ ์‹คํŒจ...

์—„์ฒญ ํ—ค๋งค๋‹ค๊ฐ€ ๊ฒฐ๊ตญ ... secrets์— ecr uri์— ๋“ค์–ด๊ฐ€๋Š” account id๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๊ณ  env ๋ณ€์ˆ˜๋ฅผ ํ•˜๋‚˜ํ•˜๋‚˜ ๋„ฃ์–ด์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ํ•ด๊ฒฐํ–ˆ์Œ ใ…  ์ด๊ฒŒ ์ตœ์„ ์ธ์ง€๋Š” ๋ชจ๋ฅธ๋‹ค..
๋”ฐ๋ผ์„œ ๊ฒฐ๊ณผ์ ์œผ๋กœ deploy ๋ถ€๋ถ„์˜ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  deploy:
    name: Deploy to EC2
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Deploy to EC2 via SSH
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ec2-user
          key: ${{ secrets.EC2_SSH_KEY }}
          script: |
            docker stop ${{ env.REPOSITORY_NAME }} || true
            docker rm ${{ env.REPOSITORY_NAME }} || true

            aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin ${{ env.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com/${{ env.REPOSITORY_NAME }}
            docker pull ${{ env.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com/${{ env.REPOSITORY_NAME }}:latest
            docker run -d --name ${{ env.REPOSITORY_NAME }} -p 80:80 ${{ env.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com/${{ env.REPOSITORY_NAME }}:latest

 

๊ทธ๋Ÿฐ๋ฐ๋„ ์œ„์˜ ์—๋Ÿฌ๊ฐ€ ๋œจ๋ฉฐ ์•ˆ๋ผ์„œ ์ฐพ์•„๋ณด๋‹ˆ.. EC2์—๋Š” AWS key๊ฐ’์ด ์ „๋‹ฌ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ECR์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์—ญํ• ์„ ๋ถ™์—ฌ์ค˜์•ผ ํ–ˆ๋‹ค.
IAM์˜ ์—ญํ•  ์ƒ์„ฑ์—์„œ EC2 ์„œ๋น„์Šค์— AmazonEC2ContainerRegistryFullAccess ์ •์ฑ…์„ ์—ฐ๊ฒฐํ•ด์ฃผ๊ณ , ์ด ์—ญํ• ์„ ๋‚ด๊ฐ€ ๋งŒ๋“  ์ธ์Šคํ„ด์Šค์— ๋ถ€์—ฌํ•ด์คฌ๋‹ค.

 

๋“œ๋””์–ด ์„ฑ๊ณต ,, 
์ด์ œ ํผ๋ธ”๋ฆญ IP๋กœ ์ ‘์†ํ•˜๋ฉด ์›น์ด ๋ณด์ด๊ฒŒ ๋˜์—ˆ๋‹ค!