nginx+docker으로 무중단 배포 설정

참고한 싸이트
쿠크캬캬 갓의 블로그

nginx 설치

brew install nginx

설치경로 확인

nginx -t

무중단 배포 로직

  1. 3000포트는 a컨테이너를 3001포트는 b컨테이너를 바라본다.
  2. nginx 는 리버스 프록시로 9090포트를 3000또는 30001 으로 연결시켜준다.
  3. a컨테이너가 배포중이였다면 b컨테이너를 띄운다.
  4. nginx의 9090포트가 바라보는 포트를 바꿔준다.
  5. nginx 리로드
  6. a컨테이터 down

1. 리버스 프록시할 포트파일 작성

nginx가 설치된 경로에 conf.d 폴더 생성
conf.d에 service-url.inc 파일을 생성후

set $service_url http://127.0.0.1:3000;

을 입력
이후 .sh 에서 현재 시작하는 컨테이너의 포트로 갈아끼워줌(3001포트가 시작하면 3000=>3001으로 바뀜)
sed s/""/""/ 명령어 참고

2. 버츄얼 호스트 설정

nginx가 설치된 경로이 sites-available폴더를 생성
해당 폴더에 kuke.conf 생성후 작성


server {
        listen 9090 default_server;
  		// 1번에서 작성한 파일을 불러온다.
        include /usr/local/etc/nginx/conf.d/service-url.inc;
        server_name     ...;
        charset         utf-8;

        location / {
          		//9090포트가 패스할 url 1번에서 작성한 파일의 변수를 프록시패스로 설정
                proxy_pass      $service_url;
                proxy_set_header        X-Real-Ip $remote_addr;
                proxy_set_header        x-Forwarded-For $proxy_add_x_forwarded_$
                proxy_set_header        Host $host;
        }
}

4. nginx.conf 에 버츄얼 호스트 include

http {
    ...
    # virtual host configs
    include /usr/local/etc/nginx/sites-available/*;
    include /usr/local/etc/nginx/conf.d/*.conf;
    ...
}

3. 도커파일 작성 (프로젝트 루트디렉토리)

// 베이스 이미지는 Node
FROM node:alpine
// 포트는 3000번
ENV PORT 3000

RUN apk --no-cache add tzdata && \
        cp /usr/share/zoneinfo/Asia/Seoul /etc/localtime && \
        echo "Asia/Seoul" > /etc/timezone
// 워킹 디렉토리 설정(이 경로에서 다음 명령어를 진행)
WORKDIR /usr/src/app
// 워킹 디렉토리에 패키지제이선 카피
COPY package*.json ./
// 인스톨 진행
RUN npm install
// 루트 디렉토리를 컨테이너로 카피
COPY ./ ./
// ENV환경을 프로덕션을 설정
ENV NODE_ENV production
// 빌드
RUN npm run build
// 스타트
CMD ["npm", "run", "start"]

CMD ["npm", "run", "start"] 는
아래 스크립트를 실행

    "start": "next start -p 8080",

4. docker-compose a/b파일 작성(루트 디렉토리)

docker-compose.a.yml 작성

version: "3"
services:
  // 서비스 명
  kuke:
  	// 루트 디렉토리의 dockerfile을 실행
    build: .
    ports:
      - 3000:8080

docker-compose.b.yml 작성

version: "3"
services:
   // 서비스 명
  kuke:
  	// 루트 디렉토리의 dockerfile을 실행
    build: .
    ports:
      - 3001:8080

5. .sh파일 작성(프로젝트 디렉토리에 ./scirpts 폴더안에 작성)

아래 파일을 작성시 nginx의 설치경로에 따라 service-url.inc의 경로를 잡아주어야한다
(설지방법 환경에따라 nginx의 경로가 달라진다)

# 실행 중인 도커 컴포즈 확인
EXIST_A=$(sudo docker-compose -p kukemeet-a -f docker-compose.a.yml ps | grep Up)

if [ -z "${EXIST_A}" ] # -z는 문자열 길이가 0이면 true. A가 실행 중이지 않다는 의미.
then
        # B가 실행 중인 경우
        START_CONTAINER=a
        TERMINATE_CONTAINER=b
        START_PORT=3000
        TERMINATE_PORT=3001
else
        # A가 실행 중인 경우
        START_CONTAINER=b
        TERMINATE_CONTAINER=a
        START_PORT=3001
        TERMINATE_PORT=3000
fi

echo "kukemeet-${START_CONTAINER} up"

# 실행해야하는 컨테이너 docker-compose로 실행. -p는 docker-compose 프로젝트에 이름을 부여
# -f는 docker-compose파일 경로를 지정
sudo docker-compose -p kukemeet-${START_CONTAINER} -f docker-compose.${START_CONTAINER}.yml up -d --build

sleep 5 # 실행되었으면 5초 대기

echo "next start!"
echo "change nginx server port"

# sed 명령어를 이용해서 아까 지정해줬던 service-url.inc의 url값을 변경해줍니다.
# sed -i "s/기존문자열/변경할문자열" 파일경로 입니다.
# 종료되는 포트를 새로 시작되는 포트로 값을 변경해줍니다.  
# -i.bak 는 백업파일을 만들겠다는 의미입니다.(그래야 변경값이 저장됨)
sudo sed -i.bak "s/${TERMINATE_PORT}/${START_PORT}/" /usr/local/etc/nginx/conf.d/service-url.inc

echo "${TERMINATE_PORT} and  ${START_PORT}"
# 새로운 포트로 nextjs 앱이 구동 되고, nginx의 포트를 변경해주었다면, nginx를 재시작해줍니다.
echo "nginx reload.."
sudo nginx -s reload

# 기존에 실행 중이었던 docker-compose는 종료시켜줍니다.
echo "kukemeet-${TERMINATE_CONTAINER} down"
sudo docker-compose -p kukemeet-${TERMINATE_CONTAINER} -f docker-compose.${TERMINATE_CONTAINER}.yml down
echo "success deployment"

6. 실행

서버실행

nginx 

bash 실행

./scripts/dev.sh

좋은 웹페이지 즐겨찾기