-
TIL-2024.07.01 - TIPS - React + Docker + Nginx + Git Action> 기초/도와줘요! 2024. 7. 1. 23:45
작업 내용
- React 애플리케이션을 Docker (dockerfile)와 Nginx (nginx.conf)를 사용해 컨테이너화하고, GitHub Actions로 CI/CD 파이프라인 (deploy.yml)을 구축하여 AWS EC2에 배포하는 방법
Docker (dockerfile)
# Node.js 환경에서 빌드 FROM node:12.1.0 AS build # 컨테이너 내부 작업 디렉토리 설정 WORKDIR /app # app dependencies # 컨테이너 내부로 package.json 파일들을 복사 COPY package.json ./ # package.json 및 package-lock.json 파일에 명시된 의존성 패키지들을 설치 RUN yarn install # 호스트 머신의 현재 디렉토리 파일들을 컨테이너 내부로 전부 복사 COPY . . # npm build RUN yarn build # 프로덕션 환경 설정 FROM nginx:stable-alpine # Nginx 설정 파일 복사 COPY nginx.conf /etc/nginx/nginx.conf # 이전 빌드 단계에서 빌드한 결과물을 /usr/share/nginx/html 으로 복사 COPY --from=build /app/dist /usr/share/nginx/html # custom 설정파일을 컨테이너 내부로 복사 COPY ./nginx.conf /etc/nginx # 컨테이너의 80번 포트를 열어줌 EXPOSE 80 # ENTRYPOINT로 nginx 서버를 실행하고 백그라운드로 동작하도록 함 ENTRYPOINT ["nginx", "-g", "daemon off;"]
dockerfile 작업에 대한 설명
- FROM node:12.1.0 AS build: Node.js 12.1.0 버전을 기반으로 한 build stage를 정의합니다. 이 스테이지에서는 애플리케이션을 빌드하기 위한 Node.js 환경을 설정합니다.
- WORKDIR /app: 컨테이너 내부의 작업 디렉토리를 /app으로 설정합니다. 모든 후속 명령은 이 디렉토리에서 실행됩니다.
- COPY package.json ./: 호스트의 package.json 파일을 컨테이너의 현재 작업 디렉토리(/app)로 복사합니다. 이는 종속성을 설치하기 위해 필요합니다.
- RUN yarn install: yarn install 명령을 사용하여 package.json 및 package-lock.json에 명시된 종속성을 설치합니다. 이 단계는 애플리케이션의 필요한 패키지를 모두 설치하는 역할을 합니다.
- COPY . .: 현재 디렉토리의 모든 파일을 컨테이너의 /app 디렉토리로 복사합니다. 이는 애플리케이션 코드와 모든 추가 리소스를 포함합니다.
- RUN yarn build: 애플리케이션을 빌드합니다. 이는 개발 환경에서 소스 코드를 번들링하고 정적 파일을 생성하는 단계입니다.
- FROM nginx:stable-alpine: 두 번째 스테이지에서는 Nginx의 Alpine Linux 기반의 안정적인(stable) 버전을 기본 이미지로 설정합니다. 이는 최종적으로 실행할 서버 환경을 정의합니다.
- COPY nginx.conf /etc/nginx/nginx.conf: 호스트의 nginx.conf 파일을 Nginx 컨테이너 내의 /etc/nginx/nginx.conf 경로로 복사합니다. 이 설정 파일은 Nginx 웹 서버의 설정을 커스터마이즈하는 데 사용됩니다.
- COPY --from=build /app/dist /usr/share/nginx/html: 앞서 build 스테이지에서 생성한 빌드 결과물을 Nginx의 기본 문서 루트(/usr/share/nginx/html)로 복사합니다. 이는 Nginx가 정적 파일을 서빙할 위치를 설정합니다.
- COPY ./nginx.conf /etc/nginx: 호스트의 추가적인 Nginx 설정 파일을 Nginx 컨테이너 내의 /etc/nginx 경로로 복사합니다. 이는 커스텀 설정을 더욱 확장하여 적용하는 데 사용됩니다.
- EXPOSE 80: 컨테이너가 80번 포트를 열도록 설정합니다. 이는 외부에서 HTTP 요청을 받아들일 수 있도록 합니다.
- ENTRYPOINT ["nginx", "-g", "daemon off;"]: 컨테이너가 시작될 때 Nginx 웹 서버를 실행하도록 설정합니다. -g "daemon off;"는 Nginx가 백그라운드에서 동작하지 않고, 전후에 블록킹 방식으로 실행되도록 설정합니다.
Nginx (nginx.conf)
# 기본적인 http 설정 http { include /etc/nginx/mime.types; # MIME 타입 설정 파일을 포함합니다. 이 파일에는 파일 확장자와 MIME 타입 간의 매핑이 정의되어 있습니다. default_type application/octet-stream; # MIME 타입이 지정되지 않은 경우 사용할 기본 MIME 타입을 설정합니다. # 로그 파일 설정 log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; # 로그 형식을 정의합니다. 주요 요소는 클라이언트 IP, 사용자 이름, 접근 시간, HTTP 요청, 응답 상태 코드 등입니다. access_log /var/log/nginx/access.log main; # 접근 로그 파일 경로와 정의된 로그 형식을 설정하여 접근 이벤트를 기록합니다. error_log /var/log/nginx/error.log error; # 오류 로그 파일 경로를 설정하여 서버 오류를 기록합니다. # 서버 블록 server { listen 80; # HTTP 요청을 수신할 포트 번호를 설정합니다. 여기서는 80 포트(기본 HTTP 포트)를 사용합니다. server_name localhost; # 서버의 도메인 이름을 설정합니다. 여기서는 localhost로 설정되어 있습니다. # 루트 디렉터리 설정 root /usr/share/nginx/html; # HTTP 요청의 기본 디렉터리를 설정합니다. 클라이언트가 요청한 파일을 찾을 때 이 디렉터리에서 검색합니다. index index.html; # 기본 문서 파일 이름을 설정합니다. 여기서는 index.html을 기본으로 사용합니다. # 기본적인 라우팅 설정 location / { try_files $uri $uri/ /index.html; # 파일이나 디렉터리가 없는 경우 index.html 파일을 반환하도록 설정합니다. } } } # 기본적인 이벤트 설정 events { worker_connections 1024; # 각 워커 프로세스가 처리할 수 있는 최대 동시 연결 수를 설정합니다. 워커 프로세스는 클라이언트의 요청을 처리하는 Nginx의 작업 단위입니다. }
nginx.conf 작업에 대한 설명
- include /etc/nginx/mime.types;: 파일 확장자와 MIME 타입 간의 매핑을 포함한 MIME 타입 설정 파일을 포함합니다. 이는 Nginx가 정확한 MIME 타입을 클라이언트에게 제공하기 위해 필요합니다.
- default_type application/octet-stream;: MIME 타입이 지정되지 않은 경우 사용할 기본 MIME 타입을 설정합니다. application/octet-stream은 이진 데이터를 나타내는 일반적인 MIME 타입입니다.
- log_format main '...';: 로그 파일에 기록할 로그 형식을 정의합니다. 이는 접근 로그(access log)와 오류 로그(error log)에 사용됩니다.
- access_log /var/log/nginx/access.log main;: 접근 로그 파일 경로와 정의된 로그 형식을 설정하여 클라이언트의 접근 이벤트를 기록합니다.
- error_log /var/log/nginx/error.log error;: 오류 로그 파일 경로를 설정하여 서버에서 발생한 오류를 기록합니다.
- listen 80;: HTTP 요청을 수신할 포트 번호를 설정합니다. 여기서는 80 포트로 설정하여 HTTP 요청을 처리합니다.
- server_name localhost;: 서버의 도메인 이름을 설정합니다. 이 설정은 요청된 호스트명과 일치하는 경우 해당 서버 블록을 사용합니다.
- root /usr/share/nginx/html;: HTTP 요청의 기본 디렉터리를 설정합니다. 클라이언트가 요청한 파일을 이 디렉터리에서 찾습니다.
- index index.html;: 기본 문서 파일 이름을 설정합니다. 클라이언트가 요청한 디렉터리에서 인덱스 파일을 찾을 때 사용됩니다.
- try_files $uri $uri/ /index.html;: 요청된 파일이나 디렉터리가 없는 경우 index.html 파일을 반환하도록 설정합니다.
- worker_connections 1024;: 각 워커 프로세스가 처리할 수 있는 최대 동시 연결 수를 설정합니다. 이 값은 시스템의 리소스와 서버의 처리 능력에 따라 조정됩니다.
Github Action Pipeline (deploy.yml)
# 워크플로우 이름 정의 name: MyApp_FE # 워크플로우 트리거 설정: develop 브랜치로의 push와 수동 트리거(workflow_dispatch)로 실행됨 on: push: branches: - develop workflow_dispatch: # 환경 변수 설정 (AWS 비밀 키 파일, 호스트, 사용자) env: AWS_PEM_FILE: ${{ secrets.PEM }} # AWS 인스턴스에 접근하기 위한 PEM 파일의 내용을 시크릿으로부터 가져옵니다. AWS_USER: ${{ secrets.USER }} # AWS 인스턴스 접속에 사용될 사용자 이름을 시크릿으로부터 가져옵니다. AWS_HOST: ${{ secrets.HOST }} # AWS 인스턴스의 호스트 주소를 시크릿으로부터 가져옵니다. # 빌드 작업 정의 jobs: build: runs-on: ubuntu-latest # 최신 우분투 이미지를 사용하여 작업 실행 steps: # 코드 체크아웃 - name: Get code uses: actions/checkout@v3 # GitHub Action을 사용하여 코드를 현재 작업 환경으로 체크아웃합니다. # 빌드 타임스탬프 설정 - name: Set build timestamp id: vars run: echo "BUILD_TIMESTAMP=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV # 빌드를 위한 타임스탬프를 생성하고 환경 변수에 저장합니다. # 도커 이미지 빌드 - name: Build Docker Image run: | docker build -t myapp_fe:${{ env.BUILD_TIMESTAMP }} . # 도커 이미지를 빌드하고 타임스탬프를 태그로 사용하여 이미지를 생성합니다. # 도커 이미지를 TAR 파일로 저장 - name: Save Docker Image to TAR run: | docker save myapp_fe:${{ env.BUILD_TIMESTAMP }} -o myapp_fe.tar # 빌드된 도커 이미지를 TAR 파일로 저장합니다. # 도커 이미지 아티팩트 업로드 - name: Upload Docker Image Artifact uses: actions/upload-artifact@v4 with: name: myapp_fe_tar path: myapp_fe.tar # 빌드된 도커 이미지 TAR 파일을 아티팩트로 업로드합니다. # 배포 작업 정의 deploy: runs-on: ubuntu-latest # 최신 우분투 이미지를 사용하여 작업 실행 needs: build # 이 작업은 빌드 작업이 완료된 후 실행됨 steps: # SSH 키 설정 - name: Set up SSH key run: | echo -n "$AWS_PEM_FILE" > $HOME/private_key.pem # AWS 인스턴스에 접속하기 위해 SSH 키를 설정하고 홈 디렉토리에 저장합니다. chmod 400 $HOME/private_key.pem # SSH 키 파일의 권한을 설정하여 보안을 강화합니다. # 도커 이미지 아티팩트 다운로드 - name: Download Docker Image Artifact uses: actions/download-artifact@v4 with: name: myapp_fe_tar path: . # 빌드된 도커 이미지 TAR 파일을 현재 디렉토리로 다운로드합니다. # EC2로 빌드 업로드 - name: Transfer Docker Image to EC2 run: | scp -v -o StrictHostKeyChecking=no -i $HOME/private_key.pem myapp_fe.tar $AWS_USER@$AWS_HOST:/home/$AWS_USER/myapp # SSH를 사용하여 EC2 인스턴스로 도커 이미지를 전송합니다. # EC2에서 도커 이미지 로드 및 컨테이너 실행 - name: Load Docker Image on EC2 and Run Container run: | ssh -i $HOME/private_key.pem $AWS_USER@$AWS_HOST << 'EOF' docker load -i /home/$AWS_USER/myapp/myapp_fe.tar # EC2 인스턴스에 도커 이미지를 로드합니다. if [ "$(docker ps -a -q -f name=myapp_fe)" ]; then # 도커 컨테이너가 이미 실행 중인 경우, 중지하고 삭제합니다. docker stop myapp_fe docker rm myapp_fe -f fi LATEST_IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}} {{.CreatedAt}}" | grep 'myapp_fe' | sort -k2 -r | head -n 1 | awk '{print $1}') # 가장 최신 버전의 도커 이미지를 확인합니다. docker run -d -p 80:80 --name myapp_fe $LATEST_IMAGE # 새로운 도커 컨테이너를 실행합니다. exit EOF # SSH 키 정리 - name: Clean up SSH key run: | rm $HOME/private_key.pem # 사용한 SSH 키를 삭제하여 보안을 강화합니다.
deploy.yml 작업에 대한 설명
- name: MyApp_FE: 워크플로우의 이름을 정의합니다. GitHub Actions 대시보드에서 식별할 수 있는 이름입니다.
- on: 워크플로우가 언제 실행될지를 결정하는 트리거 설정입니다. push는 develop 브랜치에 푸시될 때, workflow_dispatch는 수동으로 실행할 때 트리거됩니다.
- env: 환경 변수 설정 섹션입니다. 여기서는 AWS 인스턴스 접근에 필요한 PEM 파일, 호스트 주소, 사용자 이름을 시크릿으로부터 가져와 설정합니다.
- jobs: 워크플로우의 각 작업을 정의하는 섹션입니다.
- build: Node.js 애플리케이션을 빌드하는 작업입니다.
- runs-on: ubuntu-latest: 최신 버전의 Ubuntu 이미지를 사용하여 작업을 실행합니다.
- steps: 작업의 각 단계를 정의합니다.
- Get code: GitHub Actions을 사용하여 현재 작업 환경으로 코드를 체크아웃합니다.
- Set build timestamp: 현재 빌드를 위한 타임스탬프를 생성하고 환경 변수에 저장합니다.
- Build Docker Image: Docker를 사용하여 애플리케이션의 Docker 이미지를 빌드합니다.
- Save Docker Image to TAR: 빌드된 Docker 이미지를 TAR 파일로 저장합니다.
- Upload Docker Image Artifact: 빌드된 Docker 이미지 TAR 파일을 GitHub Artifact로 업로드합니다.
- deploy: 빌드된 Docker 이미지를 EC2 인스턴스로 전송하고 실행하는 작업입니다.
- runs-on: ubuntu-latest: 최신 버전의 Ubuntu 이미지를 사용하여 작업을 실행합니다.
- needs: build: 이 작업은 build 작업이 완료된 후에만 실행됩니다.
- steps: 작업의 각 단계를 정의합니다.
- Set up SSH key: AWS 인스턴스에 접속하기 위해 SSH 키를 설정하고 보안을 강화합니다.
- Download Docker Image Artifact: 빌드된 Docker 이미지 TAR 파일을 다운로드합니다.
- Transfer Docker Image to EC2: SSH를 사용하여 Docker 이미지를 EC2 인스턴스로 전송합니다.
- build: Node.js 애플리케이션을 빌드하는 작업입니다.
'> 기초 > 도와줘요!' 카테고리의 다른 글
TIL-2024.07.04 - TIPS - 다중 commit 하나로 합치기 (0) 2024.07.04 TIL-2024.04.14 - TIPS - Map() sort 방법 (value 먼저 key 다음) (0) 2024.04.14 TIL-2024.02.16 - Tips - .sort() 와 .sort((a,b) => a-b)) 차이 (0) 2024.02.16 001_JS_Object 타입에서 원하는 값 찾고 바꾸기 (0) 2022.06.20