-
Notifications
You must be signed in to change notification settings - Fork 2
CD 파이프라인 설계 및 인프라 구축
yu-yj215 edited this page Dec 1, 2024
·
1 revision
주제 요약
- 본 문서는 Ask-It 프로젝트의 개발 환경 배포를 위한 CD 파이프라인 설계와 구현 과정을 설명합니다.
- 주된 목표는 자동화된 배포 과정을 구축하여, 코드 변경 시 최소한의 수작업으로 서버에 반영되도록 하는 것입니다.
- 프로젝트 규모가 커지면서 수작업으로 배포를 관리하는 방식의 효율성이 떨어지고, 배포 과정에서 실수가 발생할 가능성이 증가했습니다.
- 효율적이고 신뢰성 있는 배포 환경을 구축하기 위해, GitHub Actions를 사용한 CI/CD 파이프라인을 설계하고자 했습니다.
- 요구사항:
- 정적 파일 업로드: 클라이언트 빌드 결과물을 오브젝트 스토리지에 업로드.
- 백엔드 배포 자동화: 코드 변경 사항을 서버에 적용하고, 애플리케이션을 재시작.
도구 선택
-
GitHub Actions:
- Git 이벤트 기반으로 동작하며, 다른 CI/CD 도구와 비교해 GitHub와의 통합성이 뛰어남.
- 커뮤니티와 공식 플러그인의 풍부한 생태계를 활용 가능.
-
pm2:
- Node.js 애플리케이션의 프로세스 관리 및 재시작에 유용.
- 클러스터 모드 및 환경 변수 관리 기능 제공.
-
AWS CLI 및 NCP Object Storage:
- 정적 파일을 효율적으로 관리하기 위해 오브젝트 스토리지 활용.
-
Node.js 및 패키지 설치:
- GitHub Actions 워크플로에서 Node.js와 pnpm을 설치하고, 프로젝트의 종속성을 설치.
-
클라이언트 빌드 및 정적 파일 업로드:
- apps/client 디렉토리에서 정적 파일을 빌드하고, AWS CLI를 이용해 NCP Object Storage로 업로드.
-
백엔드 배포 및 프로세스 관리:
- pm2를 사용해 기존 프로세스를 종료하고 새로운 프로세스를 실행.
- 환경 변수는 .env 파일로 설정.
-
오브젝트 스토리지와의 통합:
- 정적 파일이 배포 후 퍼블릭하게 접근 가능하도록 설정.
ncp는 aws와 다르게 pem이 접속 키가 아닙니다. pem은 단순히 root계정의 비밀번호를 받는용도이기 때문에 들어가서 공개키 설정을 해주어야합니다.
그래서 다음과 같은 과정을 진행했습니다.
admin이라는 sudo그룹 계정을 만들고 root로그인을 차단한 후에 admin계정에 공개키를 등록한 과정입니다.
이후에는 개인키를 깃허브 시크릿에 업데이트해서 배포스크립트를 완성했습니다.
vi secure-server-setup.sh
chmod +x secure-server-setup.sh
sudo ./secure-server-setup.sh
exit
ssh -i '개인키 파일 경로' admin@your-server-ip#!/bin/bash
set -e
# 변수 설정
NEW_ADMIN="admin"
SSH_DIR="/home/$NEW_ADMIN/.ssh"
AUTHORIZED_KEYS="$SSH_DIR/authorized_keys"
PUBLIC_KEY="ssh-rsa 공개키내용 공개키이름"
# 1. 새 사용자 계정 생성
echo "Creating a new admin user: $NEW_ADMIN"
useradd -m -s /bin/bash $NEW_ADMIN
# 2. sudo 권한 부여
echo "Adding $NEW_ADMIN to sudo group"
usermod -aG sudo $NEW_ADMIN
# 3. SSH 키 인증 설정
echo "Setting up SSH key authentication for $NEW_ADMIN"
mkdir -p $SSH_DIR
echo "$PUBLIC_KEY" > $AUTHORIZED_KEYS
chmod 700 $SSH_DIR
chmod 600 $AUTHORIZED_KEYS
chown -R $NEW_ADMIN:$NEW_ADMIN $SSH_DIR
# 4. SSH 설정 파일 수정
SSH_CONFIG="/etc/ssh/sshd_config"
echo "Configuring SSH settings"
if ! grep -q "^PermitRootLogin" $SSH_CONFIG; then
echo "PermitRootLogin no" >> $SSH_CONFIG
else
sed -i 's/^PermitRootLogin.*/PermitRootLogin no/' $SSH_CONFIG
fi
if ! grep -q "^PasswordAuthentication" $SSH_CONFIG; then
echo "PasswordAuthentication no" >> $SSH_CONFIG
else
sed -i 's/^PasswordAuthentication.*/PasswordAuthentication no/' $SSH_CONFIG
fi
# 5. SSH 데몬 재시작
echo "Restarting SSH service"
systemctl restart sshd
echo "Setup complete. You can now log in as $NEW_ADMIN using your SSH key."name: Deploy to Development Server
on:
push:
branches:
- main # main 브랜치에 변경 사항이 푸시될 때만 실행
jobs:
deploy:
runs-on: ubuntu-latest
steps:
# 1. Node.js 및 pnpm 설치
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '18' # 원하는 Node.js 버전으로 설정
- name: Install pnpm
run: npm install -g pnpm
# 2. Repository Checkout
- name: Checkout repository
uses: actions/checkout@v2
# 3. Build Project
- name: Install dependencies and build project
run: |
pnpm install
cd apps/client
pnpm run build
# 4. Upload static files to Object Storage
- name: Upload to Object Storage
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: "kr-standard" # 리전 설정
run: |
# AWS CLI 설치 확인 및 설정
sudo apt-get update && sudo apt-get install -y awscli
# 빌드된 정적 파일을 오브젝트 스토리지로 업로드
aws --endpoint-url=https://kr.object.ncloudstorage.com s3 sync ./apps/client/dist s3://ask-it-static/dist --acl public-read
# 5. Deploy Code and Start Server
- name: Deploy to Development Server
uses: appleboy/[email protected]
with:
host: ${{ secrets.WEB_SERVER_IP }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.NCP_SERVER_RSA_PRIVATE_KEY }}
script: |
# NVM 설정 로드
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
# 전역 패키지 설치
npm install -g pnpm
npm install -g pm2
# 프로젝트 디렉토리 이동 및 최신 코드 가져오기
cd ~/web07-Ask-It
git pull origin main
pnpm install
# 서버 디렉토리로 이동하여 환경 변수 설정
cd apps/server
echo "DATABASE_URL=${{ secrets.DEV_DATABASE_URL }}" > .env
echo "JWT_ACCESS_SECRET=${{ secrets.JWT_ACCESS_SECRET }}" >> .env
echo "AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}" >> .env
echo "AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> .env
# pm2로 기존 프로세스 종료 및 새 프로세스 시작
pm2 stop ask-it || true
pm2 delete ask-it || true
pnpx prisma generate
pnpx prisma migrate deploy
pnpm build
pm2 start pnpm --name "ask-it" -- run start:prod-
문제 상황: NVM이 SSH로 접속 시 자동으로 로드되지 않아 pnpm과 같은 명령어를 인식하지 못함.
-
원인:
- SSH 세션에서 NVM 환경 변수가 기본적으로 로드되지 않음.
- NVM은 쉘 초기화 스크립트(.bashrc 또는 .zshrc)에 설정되는데, GitHub Actions와 같은 비인터랙티브 SSH 환경에서는 이 초기화가 실행되지 않음.
- 결과적으로 pnpm, node 등의 NVM을 통해 설치된 도구가 사용 불가능.
-
해결 방법:
-
배포 스크립트에서 명시적으로 NVM 관련 환경 변수를 설정하고 초기화 스크립트를 실행하도록 수정.
-
추가된 명령어:
export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
-
-
원인:
-
문제 상황: 오브젝트 스토리지 업로드 시 퍼미션 문제로 파일 접근이 제한됨.
-
원인:
- AWS CLI를 사용하여 정적 파일을 업로드했으나, 업로드된 파일의 기본 퍼미션 설정이 **비공개(Private)**로 되어 있었음.
- 기본적으로 오브젝트 스토리지에 업로드된 파일은 접근 권한이 제한되며, 별도로 퍼미션 설정을 하지 않으면 외부에서 접근 불가능.
- 이로 인해 배포된 클라이언트 정적 파일이 퍼블릭 URL을 통해 제공되지 않음.
-
해결 방법:
-
업로드 시 ACL(Access Control List) 옵션을 추가하여 파일을 퍼블릭 읽기 가능(public-read) 상태로 설정.
-
수정된 명령어:
aws --endpoint-url=https://kr.object.ncloudstorage.com s3 sync ./apps/client/dist s3://ask-it-static/dist --acl public-read
-
-
원인:
-
자동화 구축 성과:
- GitHub Actions를 활용하여 코드 푸시 후 자동 배포를 실현.
-
효율성 개선:
- 정적 파일 관리가 간편해졌고, 수작업으로 인한 오류를 방지.
-
향후 개선점:
- 다중 환경(개발/테스트/운영)을 위한 추가적인 환경 구성 필요.
- 로깅 및 모니터링 도구 통합.
-
클라이언트와 서버 배포 분리:
- 모노레포 환경 특성을 고려하여, 클라이언트와 서버의 배포 프로세스를 분리.
- GitHub Actions의 label 기능을 활용하여 레이블별 워크플로 트리거:
- 클라이언트 관련 작업: client 레이블.
- 서버 관련 작업: server 레이블.