본문 바로가기
✨ Club|Project/카카오테크 부트캠프 | AI

💛카부커넥션💛 : CI/CD(GitHub Actions) + docker 보기

by 정람지 2024. 8. 26.

- 프론트 배포 과정을 맡은 세호오빠의 코드를 구경하자

- docker를 실행시켜 보자 

http://kaboo.site

 

카부카부

 

kaboo.site

오빠가 도메인도 사서 연결했다..!

엇 임베딩 이미지? 저건 어떻게 설정하더라 

알았는데


🐠 GitHub Actions

GitHub Actions는 GitHub 리포지토리 내에서 CI/CD 파이프라인을 자동화하고,

소프트웨어 개발 워크플로우를 간소화할 수 있는 강력한 도구

 

- GitHub 이벤트(예: 푸시, 풀 요청, 이슈 생성 등)을 생성할 때 자동으로 빌드, 테스트, 배포 등의 작업을 수행할 수 있음

 

- .yml 또는 .yaml 파일로 워크플로우를 정의( 리포지토리의 .github/workflows 디렉토리에 저장)

YAML은 구성 파일을 작성하는 데 일반적으로 사용되며 사람이 읽을 수 있는 다목적 데이터 직렬화 언어

 

- 워크플로우는 여러 잡(job)으로 구성되며, 각 잡은 다양한 스텝(step)으로 나누어짐

- 각 스텝에서는 액션을 실행하거나 쉘 명령어를 실행할 수 있음


우리 .yaml  파일

name: Deploy to AWS EC2 using Docker

on:
  push:
    branches:
      - main

env:
  DOCKER_IMAGE_NAME: ${{ secrets.DOCKER_IMAGE_NAME }}
  EC2_HOST: ${{ secrets.EC2_HOST }}
  EC2_SSH_USER: ${{ secrets.EC2_SSH_USER }}
  PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}

jobs:
  build-and-push-docker:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Build the Docker image
        run: docker build . --file Dockerfile --tag ${{ env.DOCKER_IMAGE_NAME }}:latest

      - name: Login to Docker Hub using Access Token
        run: echo "${{ secrets.DOCKERHUB_TOKEN }}" | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin

      - name: Push the Docker image
        run: docker push ${{ env.DOCKER_IMAGE_NAME }}:latest

  deploy-to-ec2:
    needs: build-and-push-docker
    runs-on: ubuntu-latest

    steps:
      - name: Deploy to EC2
        uses: appleboy/ssh-action@master
        with:
          host: ${{ env.EC2_HOST }}
          username: ${{ env.EC2_SSH_USER }}
          key: ${{ env.PRIVATE_KEY }}
          script: |
            CONTAINER_ID=$(sudo docker ps -aq --filter "name=kaboo-connection-container")

            if [ ! -z "$CONTAINER_ID" ]; then
              sudo docker stop $CONTAINER_ID || true
              sudo docker rm -f $CONTAINER_ID || true
            fi

            sudo docker pull ${{ env.DOCKER_IMAGE_NAME }}:latest
            sudo docker run --name kaboo-connection-container -d -p 80:80 -e TZ=Asia/Seoul ${{ env.DOCKER_IMAGE_NAME }}:latest
            sudo docker image prune -f

 

이 GitHub Actions 워크플로우는 

main 브랜치에 코드가 푸시될 때마다 AWS EC2 인스턴스에 Docker 이미지를 배포하는 과정을 자동화

 

 

<두 가지 주요 작업(job)>

 

1. build-and-push-docker 작업

  • 목적: Docker 이미지를 빌드하고 Docker Hub에 푸시
  • 실행 환경: ubuntu-latest에서 실행
  • 주요 단계:
    • Checkout: 코드를 체크아웃
    • Docker 이미지 빌드: Dockerfile을 사용해 이미지를 빌드 (이미지 태그는 latest)
    • Docker Hub 로그인: Docker Hub에 접속 토큰을 사용하여 로그인
    • Docker 이미지 푸시: 빌드된 이미지를 Docker Hub에 푸시

2. deploy-to-ec2 작업

  • 목적: 빌드된 Docker 이미지를 AWS EC2 인스턴스에 배포
  • 실행 환경: ubuntu-latest에서 실행
  • 종속성: build-and-push-docker 작업이 성공적으로 완료되어야 실행
  • 주요 단계:
    • EC2 배포: appleboy/ssh-action 액션을 사용하여 EC2 서버에 SSH 접속한 후, 다음 작업을 수행
      • 실행 중인 동일 이름의 컨테이너가 있으면 중지 및 제거
      • Docker Hub에서 최신 이미지를 풀
      • 새 컨테이너를 시작하고 필요한 환경 설정을 진행
      • 사용하지 않는 이미지를 정리

🐠 Docker

Docker는 개발자가 어플리케이션을 컨테이너라는 격리된 환경에서 실행할 수 있게 해주는 오픈 소스 플랫폼

개발, 테스트, 그리고 프로덕션 환경에서의 일관성을 보장

# Base image
FROM node:18-alpine as build

# Set working directory
WORKDIR /app

# Install dependencies
COPY package.json package-lock.json ./
RUN npm install

# Copy all files
COPY . .

# Build the application
RUN npm run build

# Production image
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html

RUN rm /etc/nginx/conf.d/default.conf
COPY ./nginx.conf /etc/nginx/conf.d


# Expose port 80
EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

 

이 Dockerfile는 두 단계의 빌드 프로세스를 거쳐

Node.js 어플리케이션을 빌드하고 결과물을 Nginx 서버를 사용하여 제공하는 멀티-스테이지 빌드 과정을 설명

 

멀티-스테이지 빌드는 빌드 환경과 프로덕션 환경을 분리하여 이미지 크기를 최소화하고 보안을 강화하는 데 유용

 

  1. FROM node:18-alpine as build
    • node:18-alpine 이미지를 기반으로 첫 번째 빌드 스테이지를 시작 (Node.js 18 버전이 설치된 경량화된 알파인 리눅스)
  2. WORKDIR /app
    • 컨테이너 내에서 /app 디렉토리를 작업 디렉토리로 설정
  3. COPY package.json package-lock.json ./
    • 호스트 머신에서 package.json과 package-lock.json 파일을 컨테이너의 현재 작업 디렉토리(/app)로 복사(의존성 관리용)
  4. RUN npm install
    • npm install 명령을 실행하여 package.json에 정의된 Node.js 의존성들을 설치
  5. COPY . .
    • 호스트 머신의 현재 디렉토리(프로젝트 루트)에 있는 모든 파일과 디렉토리를 컨테이너의 현재 작업 디렉토리(/app)로 복사
  6. RUN npm run build
    • npm run build 스크립트를 실행하여 애플리케이션을 빌드
  7. FROM nginx:alpine
    • 두 번째 빌드 스테이지를 시작하며, nginx:alpine 이미지를 기반으로 설정( Nginx 웹 서버가 설치된 경량화된 알파인 리눅스 이미지)
  8. COPY --from=build /app/dist /usr/share/nginx/html
    • 첫 번째 빌드 스테이지에서 생성된 dist 디렉토리를 Nginx 컨테이너의 /usr/share/nginx/html로 복사
  9. RUN rm /etc/nginx/conf.d/default.conf
    • Nginx의 기본 설정 파일(default.conf)을 삭제
  10. COPY ./nginx.conf /etc/nginx/conf.d
    • 사용자 정의 Nginx 설정 파일(nginx.conf)을 호스트에서 컨테이너의 /etc/nginx/conf.d 디렉토리로 복사
  11. EXPOSE 80
    • 컨테이너의 80 포트를 외부에 노출
  12. CMD ["nginx", "-g", "daemon off;"]
    • Nginx 서버를 포그라운드 모드(daemon off;)에서 실행하도록 설정(계속 실행 상태)

그럼 이건 12레이어인 건가?

 

빌드 스테이지

  1. 베이스 이미지 설정: node:18-alpine을 사용하여 Node.js 18 버전을 기반으로 하는 알파인 리눅스 이미지를 선택
  2. 작업 디렉토리 설정: /app 디렉토리를 작업 공간으로 설정합니다.
  3. 의존성 설치: package.json과 package-lock.json 파일을 복사한 후 npm install 명령어로 필요한 의존성을 설치
  4. 파일 복사: 프로젝트의 모든 파일을 작업 디렉토리로 복사
  5. 어플리케이션 빌드: npm run build 명령어를 실행하여 프로덕션용 어플리케이션을 빌드/ 이 과정에서 생성된 dist 디렉토리에 빌드 결과물이 저장.

프로덕션 스테이지

  1. 베이스 이미지 설정: nginx:alpine을 사용하여 Nginx 서버를 실행할 알파인 리눅스 기반의 이미지를 선택
  2. 빌드 결과 복사: 빌드 스테이지에서 생성된 dist 디렉토리를 Nginx의 웹 컨텐츠 디렉토리인 /usr/share/nginx/html로 복사
  3. Nginx 설정 파일 제거 및 복사: 기본 Nginx 설정 파일을 삭제하고, 커스텀 nginx.conf 파일을 /etc/nginx/conf.d 디렉토리에 복사
  4. 포트 노출: 80 포트를 노출시켜 외부에서 Nginx 서버에 접근할 수 있도록
  5. Nginx 실행 명령: nginx 프로세스를 포그라운드 모드(daemon off;)로 실행하여 컨테이너가 계속 실행되도록

씁... 도커어렵내..

클라우드 짱짱..