Skip to content

Github Actions를 이용한 CI CD 구축

김두종 edited this page Jan 15, 2025 · 3 revisions

시스템 아키텍처

전체 구조

docker containers

CI/CD 프로세스

  • github actions를 이용한 CI/CD의 기본 구조는 github의 workflow를 활용하는 것
  • workflow 파일을 작성하기 위해 github workflow의 기본 개념부터 학습. 학습 정리
  • 순서
    • github actions 활성화
    • workflow YAML 파일 작성
      • CI/CD가 이루어질 이벤트를 등록
        • ex) dev 브랜치가 변경될 때
    • github repository의 settings에서 필요한 secrets 등록
  • 이후 이벤트가 trigger 될 때마다 작성한 workflow가 실행된다

workflows에 dev 브랜치 push 이벤트에 대한 job 등록하기

  • dev 브랜치에 push 이벤트가 발생하면
  • github에서 ubuntu 서버를 실행시키고
  • docker in docker 컨테이너를 설치
  • 소스코드를 가져오고, yarn 설정 캐싱
  • 패키지 의존성을 설치하고, 백엔드와 프론트엔드 코드 빌드
  • Dokcer hub에 로그인하고, Dockefile들을 기반으로 백엔드와 프론트엔드 docker image 빌드 및 푸시
  • NCP 서버 인스턴스에 접속 및 docker compose 실행

[.github/deploy-dev.yml]

name: Deploy Dev in Monorepo

on:
  push:
    branches:
      - dev

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    services:
      docker:
        image: docker:20.10.7
        options: --privileged

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      
      - name: Cache Yarn dependencies
        uses: actions/cache@v3
        with:
          path: |
            **/node_modules
            ~/.yarn-cache
          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
          restore-keys: |
            ${{ runner.os }}-yarn-

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'yarn'

      - name: Install dependencies
        run: yarn install --frozen-lockfile

      - name: Build backend and frontend
        run: |
          yarn workspace backend build
          yarn workspace frontend build

      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build and push Docker images
        run: |
          # 백엔드 이미지 빌드 및 푸시
          docker build -t ${{ secrets.DOCKER_USERNAME }}/backend:latest -f packages/backend/Dockerfile .
          docker push ${{ secrets.DOCKER_USERNAME }}/backend:latest

          # 프론트엔드 이미지 빌드 및 푸시
          docker build -t ${{ secrets.DOCKER_USERNAME }}/frontend:latest -f packages/frontend/Dockerfile .
          docker push ${{ secrets.DOCKER_USERNAME }}/frontend:latest

      - name: Deploy to server
        uses: appleboy/[email protected]
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SERVER_SSH_KEY}}
          password: ${{ secrets.SERVER_PASSWORD }}
          port: ${{ secrets.SERVER_PORT }}
          script: |
            docker pull ${{ secrets.DOCKER_USERNAME }}/frontend:latest
            docker pull ${{ secrets.DOCKER_USERNAME }}/backend:latest
            docker compose down 
            docker compose up -d

CI/CD를 적용하기 위한 설정

github repositroy secrets

  • DOCKER_USERNAME: 도커 허브 아이디
  • DOCKER_PASSWORD: 도커 허브 비밀번호
  • SERVER_HOST: 서버 인스턴스 공용 IP
  • SERVER_USER: 서버 접속시 유저 정보
  • SERVER_SSH_KEY: .pem 키 파일
  • SERVER_PASSWORD: 네이버 클라우드 플랫폼 기준 서버 인스턴스의 관리자 비밀번호
  • SERVER_PORT: 22(디폴트값)

서버 인스턴스에 설치되어야할 프로그램

  • Docker
    • 도커만 설치한다면 서버의 환경과 관계없이 우리가 설정한 대로 프론트, 백엔드, nginx 서버를 띄울 수 있다.

서버 인스턴스 디렉토리 구조

  • /root
    • docker-compose.yml
    • /nginx
      • reverse-proxy.conf
      • nginx-frontend.conf
    • /configs
      • /frontend
        • .env
      • /backend
        • .env

서버 인스턴스 설정 파일들

[docker-compose.yml]

networks:
  corp:
    driver: bridge

services:
  nginx_proxy:
    image: nginx:1.27.2-alpine
    container_name: nginx_proxy
    ports:
      - '80:80'
    depends_on: #proxy가 먼저 켜지는 경우 죽어버리는 문제가 있었음. 의존성 추가
      - frontend
      - backend
    volumes:
      - ./nginx/reverse-proxy.conf:/etc/nginx/nginx.conf
    command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
    networks:
      - corp

  frontend:
    image: frontend:latest
    container_name: frontend
    env_file:
      - ./configs/frontend/.env
    environment:
      - NODE_ENV=production
    depends_on:
      - backend
    volumes:
      - ./nginx/nginx-frontend.conf:/etc/nginx/nginx.conf
    networks:
      - corp

  backend:
    image: backend:latest
    container_name: backend
    env_file:
      - ./configs/backend/.env
    environment:
      - NODE_ENV=production
    networks:
      - corp

[/nginx/reverse-proxy.conf]

user nginx;
worker_processes  auto;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    # 백엔드 upstream 설정
    upstream nest-api-server {
        server backend:3000;
    }

    # 프론트엔드 upstream 설정
    upstream static-server {
        server frontend:8080;
    }

    server {
        listen 80;
        server_name juchumjuchum.site;

        location / {
            proxy_pass         http://static-server/;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }

        location /api {
            proxy_pass         http://nest-api-server/api;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }
    }

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    keepalive_timeout  65;
    #include /etc/nginx/conf.d/*.conf;
}

[/nginx/nginx-frontend.conf]

user  nginx;
worker_processes  auto;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    
    # 백엔드 upstream 설정
    upstream nest-api-server {
        server backend:3000;
    }

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    keepalive_timeout  65;

    server {
        listen 8080;
        server_name localhost;

        root   /usr/share/nginx/html;
        index  index.html index.htm;
        
        # 웹 소캣 경로 추가
        location /socket.io {
          proxy_pass         http://nest-api-server/socket.io;
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection 'upgrade';
          proxy_set_header Host $host;
        }

        location / {
            try_files $uri $uri/ /index.html;
        }
    }
}

CI/CD 적용 과정 중 발생한 문제들

서버 연결 실패

  • deploy-dev.yml 파일에 SERVER_PASSWORD 와 관련된 설정을 명시하지 않았기 때문에 발생
  • 해결방법
    • NCP의 경우 서버 인스턴스의 관리자 비밀번호를 추가

deploy to server 실패

docker-compose 실패

  • 기존에 사용하던 docker-compose 명령어가 Compose V1에 해당하는데, 현재 서버 인스턴스에는 Compose V2가 설치되어 있기 때문에 발생
  • 해결방법
    • docker-compose 대신 docker compose 사용

deploy to server 실패2 docker-compose

성공!

deploy to server 성공

팀 빌딩

📚팀 빌딩
📝Git 전략

회의록

1주차

🤝1월 7일
🤝1월 8일
🤝1월 9일

2주차

🤝주간 계획(1월 13일)

3주차

🤝주간 계획(1월 20일)

인공지능 리팩토링 1주차

🤝주간 계획(2월 3일)

인공지능 리팩토링 2주차

🤝주간 계획(2월 10일)

개발일지

AI 리팩토링 기획안

AI 리팩토링 개발일지

성능개선

리팩토링

팀회고

학습 정리

Clone this wiki locally