AWS ec2 + react + nginx + jenkins + docker 배포

청포도봉봉이·2023년 12월 20일
1

AWS

목록 보기
14/14
post-thumbnail

개요

사실 배포 서버에 배포한지는 꽤 되었지만 이제야 작성한다...
mini-blog-front의 화면이 어느정도 나타나있고 실제 화면를 보고 싶어서 배포하게 되었다.

AWS EC2서버에 jenkins를 이미 설치 및 플로그인 세팅이 된 환경에서 글을 작성한다.

관련 내용이 필요하다면 아래 링크 시리즈를 참고하면 될거 같다.
https://velog.io/@pak4184/series/AWS

프로젝트 아키텍처는 아래 그림과 같이 구현했다.

Github webhook 연동


일단 jenkins와 front repository를 연동하기 위해선 Github webook을 연동해야 한다.

front repository의 main브랜치의 push 또는 merge 되었다면 jenkins로 신호를 주는 역할을 합니다.

Github webhook 연동

Github webhook을 생성할 repository의 settings에 가셔서 좌측 메뉴의 Webhooks를 클릭합니다. 그리고 Add webhook을 클릭합니다.

Payload URL: http://EC2-ipv4주소:8000/github-webhook/
Content type: application/json
Secret: 공란
Which events would you like to trigger this webhook?: Just the push event.
Active: 체크

위와 같이 세팅해주면 된다.

Jenkins 세팅


Creditials 등록

jenkins의 Credentials에 front-end gitHub 계정을 등록해줍니다.

global을 클릭합니다. 없다면 새롭게 만드시면 됩니다.

우측 상단의 Add Creditials 클릭

Kind: Username with password
Scope: (Jenkins, nodes...)
Username: Github 계정 ID
Password: Github 계정 ID
ID: jenkins에서 등록한 Creditials을 구분하는 ID (작성해도 되고 안하면 자동 생성)
Description: 설명

이렇게 입력하고 Create 버튼을 클릭해줍니다.

이와 똑같은 방법으로 Docker Hub 계정도 추가해주었습니다.

이런식으로 여러개를 생성해놓고 사용 중입니다.

jenkins project 세팅

이제 jenkins에 빌드가 될 project를 세팅해보도록 하겠습니다.

Item 생성

새로운 Item 클릭

Freestyle project로 생성해줍니다.

Configuration

생성한 프로젝트의 Configuration으로 이동해줍니다.

소스 코드 관리

우선 GitHub project 체크박스를 클릭하여 본인 repository 주소를 입력해줍니다.

소스 코드 관리에서 Git을 선택 후

본인 Repository URL을 입력해주고 Creditials에서 등록한 github 계정을 선택해줍니다.

Branches to build에선 Github Webhook이 감지될 브랜치를 작성해줍니다.

Webhook이 정상적으로 작동할 수 있도록 위와 같이 선택해줍니다.

빌드 환경

Docker Image로 빌드 후 Image를 Docker Hub에 업로드 할거기 때문에 미리 등록해놨던 Docker Hub 계정을 Creditials에서 가져와 사용할 준비를 해줍니다.

Build Steps에서 Execute shellSend files or execute commands over SSH 를 선택하여 추가해줍니다.

Execute shell에선 jenkins로 빌드 후 Docker Image로 만들고 Docker Hub에 push하는 작업을 진행합니다.

Dockerfile 작성

따라서 Image로 빌드하기 전 프로젝트에 Dockerfile을 작성해야 Dockerfile의 내용을 바탕으로 Image를 만들어줍니다.

Dockerfile은 루트 디렉토리에 작성해주면 됩니다.

# build stage
FROM node:18 as build-stage
WORKDIR /app
COPY package*.json ./

# Yarn is already installed
RUN yarn install
COPY . .
RUN yarn build

# production stage
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html

# copy the custom nginx configuration file
COPY nginx.conf /etc/nginx/nginx.conf

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

위 스크립트를 설명하자면

이 스크립트는 Node.js 앱을 빌드하고, 그 결과를 Nginx 웹 서버에 제공하는 Docker 이미지를 만든다. 이 스크립트는 두 단계로 나뉘어 있다.

첫 번째 단계(build stage)에서는 Node.js 앱을 빌드한다.

  • node:18이라는 Docker 이미지를 기반으로 새로운 빌드 환경을 만든다.
  • 작업 디렉토리를 /app으로 설정하고, package*.json 파일들을 작업 디렉토리로 복사한다.
  • 그 다음에 yarn install 명령어를 실행해서 필요한 패키지들을 설치한다.
  • 앱의 모든 파일들을 작업 디렉토리로 복사한 다음,
  • yarn build 명령어를 실행해서 앱을 빌드한다.

두 번째 단계(production stage)에서는 Nginx 웹 서버를 설정하고, 첫 번째 단계에서 빌드한 앱을 웹 서버에 추가한다.

  • nginx:stable-alpine이라는 Docker 이미지를 기반으로 새로운 프로덕션 환경을 만든다.
  • 첫 번째 단계에서 빌드한 앱을 /usr/share/nginx/html 디렉토리로 복사한다.
  • 그리고 커스텀 Nginx 설정 파일을 /etc/nginx/nginx.conf 위치로 복사한다.
  • 웹 서버를 외부에서 접근할 수 있도록 8080 포트를 열어준다.
  • 마지막으로 nginx -g "daemon off;" 명령어를 실행해서 Nginx 웹 서버를 시작한다.

위 설명에서 node:18이 있는데 이 부분은 본인 node 버전에 맞게 작성을 해야한다.

ngingx.conf 작성

그리고 nginx 설정 파일을 복사하기 때문에 nginx 파일을 작성해보자.

nginx파일은 루트 디렉토리에 nginx.conf 파일을 작성해주면 된다.

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       8080;  # 프로젝트가 실행될 포트 번호
        server_name  localhost;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
            try_files $uri $uri/ /index.html;  # 리액트 라우팅을 위한 설정
        }
    }
}

위 설정 파일은 Nginx 웹 서버의 작동 방식을 정의하는데, 아래와 같이 해석될 수 있다.

  1. events 섹션:

    • worker_connections 1024;: 하나의 worker 프로세스가 동시에 처리할 수 있는 연결 수를 1024로 설정한다.
  2. http 섹션:

    • include mime.types;: MIME 타입 파일을 포함시킨다. 이 파일은 클라이언트에게 전송되는 파일의 종류를 알려준다.
    • default_type application/octet-stream;: 알려지지 않은 파일 타입에 대한 기본 MIME 타입을 설정한다.
    • sendfile on;: sendfile을 활성화해서 정적 파일을 더 빠르게 전송할 수 있게 한다.
    • keepalive_timeout 65;: keep-alive 연결의 timeout을 65초로 설정한다.
  3. server 섹션:

    • listen 8080;: 웹 서버가 8080 포트에서 요청을 수신하도록 한다.
    • server_name localhost;: 서버의 이름을 localhost로 설정한다.
  4. location / 섹션:

    • root /usr/share/nginx/html;: 웹 서버의 루트 디렉토리를 /usr/share/nginx/html로 설정한다.
    • index index.html index.htm;: 웹 서버가 요청받을 때 우선적으로 찾는 파일을 index.html이나 index.htm으로 설정한다.
    • try_files $uri $uri/ /index.html;: 사용자로부터 요청받은 URI가 파일이나 디렉토리로 존재하지 않는 경우, /index.html 파일로 요청을 리디렉트한다. 이 설정은 SPA(Single Page Application)에서 라우팅을 처리하기 위해 필요하다.

Build Steps

Dockerfilenginx 파일 작성이 완료되었다면 빌드가 완료된 후 실행할 script를 작성해준다.

echo docker login
docker login -u ${DOCKER_USER} -p ${DOCKER_PASSWORD} docker.io

echo docker image build
docker build -t pak0426/toy-mini-blog-front:latest .

echo docker image push
docker push pak0426/toy-mini-blog-front:latest

# 기존 도커 이미지 삭제
no_tag_image_ids=$(docker images -f "dangling=true" -q)

if [ -z "$no_tag_image_ids" ]; then
  echo "삭제할 이미지가 없습니다."
else
  # 각 이미지 ID에 대해 순회하며 삭제하기
  for image_id in $no_tag_image_ids; do
    docker rmi $image_id
    echo "이미지 $image_id 삭제 완료"
  done
fi

위 파일은
1. 도커허브 로그인
2. 도커 이미지로 빌드
3. 도커 이미지 push
의 과정이다.

Send files or execute commands over SSH

Send files or execute commands over SSH에서 스크립트를 작성해주는 이유는 CI서버(통합 서버)에서 빌드 작업이 완료된 후 CD서버(배포서버)에서 실행할 스크립트를 보내주는 역할을 한다.

CI서버EC2 인스턴스CD서버EC2인스턴스의 연결 방법은
Jenkins 빌드, DockerHub push 후 배포 서버에서 application 실행 방법
링크를 참고하면 된다.

# 이미지 이름과 태그
IMAGE_NAME="pak0426/toy-mini-blog-front"
TAG="latest"

# 새로운 이미지 pull
docker pull $IMAGE_NAME:$TAG

# 기존 컨테이너 stop 및 remove
docker stop toy-mini-blog-front
docker rm toy-mini-blog-front

# 새로운 이미지로 컨테이너 시작
docker run -d --name toy-mini-blog-front -p 80:8080 $IMAGE_NAME:$TAG

# 기존 도커 이미지 삭제
no_tag_image_ids=$(docker images -f "dangling=true" -q)

if [ -z "$no_tag_image_ids" ]; then
  echo "삭제할 이미지가 없습니다."
else
  # 각 이미지 ID에 대해 순회하며 삭제하기
  for image_id in $no_tag_image_ids; do
    docker rmi $image_id
    echo "이미지 $image_id 삭제 완료"
  done
fi

docker run -d --name toy-mini-blog-front -p 80:8080에서 추가 설명하자면

  • docker run: Docker 이미지를 기반으로 새로운 컨테이너를 생성하고 실행하는 명령어이다.

  • -d: 이 옵션은 컨테이너를 백그라운드에서 실행하고, 컨테이너 ID를 출력하도록 설정하는 것이다.

  • --name toy-mini-blog-front: 이 옵션은 생성되는 컨테이너의 이름을 toy-mini-blog-front로 지정하는 것이다.

  • -p 80:8080: 이 옵션은 호스트의 80 포트와 컨테이너의 8080 포트를 연결하도록 설정하는 것이야. 이렇게 하면, 호스트 머신에서 80 포트로 들어오는 트래픽이 컨테이너의 8080 포트로 전달되게 된다. 즉 클라이언트는 80포트로 접근 가능하다.

  • $IMAGE_NAME:$TAG: 이 부분은 실행하려는 Docker 이미지의 이름과 태그를 나타내는 부분이다. $IMAGE_NAME$TAG는 환경 변수이며, 이 명령어가 실행되는 환경에 따라 다른 값을 가질 수 있다.

위와 같은 과정들로 세팅하였다면 저장을 해주면 된다.

profile
서버 백엔드 개발자

0개의 댓글