CI(Continuous Integration):
자동적으로 중앙저장소에 통합하는 과정을 말한다 & 빌드 및 테스트 과정을 거쳐야 한다.
CD(Continuous Deployment):
코드 변경사항이 자동적으로 배포되는 과정을 말한다. 수동 승인 없이 코드가 바로 사용자에게 제공된다.
ECR(Amazon Elastic Container Registry):
ECS(Amazon Elastic Container Service):
ECS Fargate:
1) 프로젝트 설정:
Nest.js 기반의 간단한 서버 어플리케이션을 생성
2) 환경 설정 파일:
alpha 및 prod에 대한 환경 설정 파일 작성 (예: .env.alpha, .env.prod).
3)Docker 설정:
4)GitHub Actions CI/CD 설정:
.github/workflows 디렉토리 내에 각 phase(alpha, prod)에 대한 별도의 YAML 파일을 생성합니다.
각 YAML 파일에는 다음 작업이 포함되어야 합니다:
AWS IAM에서 배포에 사용할 IAM 사용자를 생성하고, 필요한 권한을 부여합니다.
GitHub Actions의 Secrets 메뉴를 사용하여 AWS 액세스 키, 비밀 키 등의 민감 정보를 저장합니다.✔️
AWS ECR에서 Docker 이미지를 저장할 레포지토리를 생성합니다.
AWS ECS에서 Fargate를 사용하여 서비스를 배포할 클러스터를 설정합니다.
문서화:
배포 파이프라인, 협업 정책, CI/CD 과정 등을 문서화하여 팀원들과 공유합니다.
루트 계정 보호: 루트 계정은 가장 높은 권한을 가진 계정입니다. 루트 계정의 액세스 키를 절대 생성하지 말고, AWS Management Console에 로그인할 때만 사용하도록 하세요. MFA(Multi-Factor Authentication)를 활성화하여 루트 계정의 보안을 강화합니다.
개별 IAM 사용자 생성:
배포나 리소스 관리에 필요한 작업을 위해 별도의 IAM 사용자를 생성합니다.
이 사용자에게는 프로젝트에서 필요한 AWS 리소스에 접근할 수 있는 권한만 부여합니다.
AWS Management Console 액세스는 옵션으로 선택할 수 있습니다. 필요하다면 Console 액세스도 부여할 수 있지만, 웹 콘솔 대신 CLI나 SDK를 주로 사용한다면 프로그래밍 방식 액세스만 선택하는 것이 좋습니다.
관리형 정책 사용:
AWS에서 제공하는 관리형 정책을 활용하여 사용자에게 필요한 권한을 부여합니다. 예를 들어, EC2 인스턴스를 관리하는 경우 AmazonEC2FullAccess와 같은 정책을 사용할 수 있습니다.
GitHub Actions의 Secrets:
IAM 사용자의 액세스 키 ID와 비밀 액세스 키는 GitHub Actions의 Secrets에 저장하여 CI/CD 과정에서 사용합니다.
비용 모니터링:
혹시나 예상치 못한 리소스 사용으로 인한 과도한 비용이 발생하는 것을 방지하기 위해 AWS 비용 알람을 설정하는 것이 좋습니다.
docker-compose까지 사용하는 이유
여러개의 도커 컨테이너를 함께 정의하고 실행하기 위한 도구
1. 다중 컨테이너 어플리케이션 관리
ex) 웹어플리케이션,DB, 캐시서버, 백그라운드 작업자등 여러 서비스가 함께 작동할 수 있다.
2. 환경 일관성: 전체 구조와 서비스 설정을 문서화하기 때문에 개발자간의 환경 차이를 최소화하고 개발, 스테이징, 프로덕션 등의 다양한 환경에서 동일한 설정으로 어플리케이션을 실행할 수 있다.
3. depends_on 옵션을 통해 서비스 간의 의존 관계와 실행 순서를 정의할 수 있다.
4. 변수 및 환경 구성: '.env'파일이나 환경 변수를 통해 설정값을 관리하도록 지원. 이를 통해 개발, 테스트, 프로덕션 등 다양한 환경에 맞게 설정값을 조정할 수 있다.
5. 네트워크 및 볼륨관리: 각 서비스간의 네트워크 연겨르 볼륨 마운트가 가능하다. (docker-compose에서 서비스간의 연결을 설정할때, 해당 서비스 이름을 도메인이름처럼 사용할 수 있다. 그래서 db를
#github actions
name: Deploy to EC2
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
# EC2 서버에 배포
- name: Deploy to EC2
uses: appleboy/ssh-action@master
with:
host: 3.39.216.163
username: ubuntu
key: ${{ secrets.SSH_PRIVATE }}
script: |
cd /home/ubuntu/cicd
git pull origin main
docker-compose -f docker-compose.prod.yml down
docker-compose -f docker-compose.prod.yml build
docker-compose -f docker-compose.prod.yml up -d
# docker-compose.prod.yml
version: '3.7'
services:
nestjs-server:
build:
context: .
dockerfile: Dockerfile
target: production
environment:
- NODE_ENV=production #파일 캐싱, 에러 메시지 감추기 로컬로 지정하려면.env파일에 NODE_ENV=production 이렇게 하면 됨
ports:
- 3000:3000
depends_on:
- db
db:
image: postgres:latest
container_name: postgres
env_file:
- .env
environment:
- POSTGRES_USER=${PROD_DB_USER}
- POSTGRES_PASSWORD=${PROD_DB_PASSWORD}
- POSTGRES_DB=${PROD_DB_NAME}
ports:
- ${PROD_DB_PORT}:${PROD_DB_PORT}
# docker-compose.alpha.yml
version: '3.7'
services:
nestjs-server:
build:
context: .
dockerfile: Dockerfile
target: development # 알파 환경에서는 개발 빌드를 사용할 수 있습니다.
environment:
- NODE_ENV=development # dev 상태로 설정 : 파일캐싱방지, 디버그를 위한 상세한 에러 메시지 보이기 등
ports:
- 3000:3000
depends_on:
- db
db:
image: postgres:latest
container_name: postgres-alpha # 컨테이너 이름을 알파 환경에 맞게 변경합니다.
env_file:
- .env # 알파 환경 설정을 포함하는 .env 파일을 사용합니다.
environment:
- POSTGRES_USER=${ALPHA_DB_USER}
- POSTGRES_PASSWORD=${ALPHA_DB_PASSWORD}
- POSTGRES_DB=${ALPHA_DB_NAME}
ports:
- ${ALPHA_DB_PORT}:${ALPHA_DB_PORT}
###################
# BUILD FOR LOCAL DEVELOPMENT
###################
# 1. 기본 이미지 설정
FROM node:18-alpine As development
# 2. 작업 디렉터리 설정
WORKDIR /usr/src/app
# 3. 앱 의존성 파일들 복사
# --chown=node:node 옵션은 파일의 소유권을 node 사용자와 그룹에 할당
COPY --chown=node:node package*.json ./
# 4. 앱 의존성 설치
# npm ci는 package-lock.json을 사용하여 정확한 버전의 패키지를 설치하는 명령어
RUN npm ci
# 5. 앱 소스 코드 복사
COPY --chown=node:node . .
# 이후에는 node 사용자로 전환
USER node
###################
# BUILD FOR PRODUCTION
###################
FROM node:18-alpine As build
WORKDIR /usr/src/app
COPY --chown=node:node package*.json ./
COPY --chown=node:node --from=development /usr/src/app/node_modules ./node_modules
COPY --chown=node:node . .
RUN npm run build
ENV NODE_ENV production
RUN npm ci --only=production && npm cache clean --force
USER node
###################
# PRODUCTION
###################
FROM node:18-alpine As production
COPY --chown=node:node --from=build /usr/src/app/node_modules ./node_modules
COPY --chown=node:node --from=build /usr/src/app/dist ./dist
CMD [ "node", "dist/main.js" ]