# NginX를 활용한 Docker 무중단 배포

- Author: @baealex
- Published: 2021-09-26
- Updated: 2021-09-26
- Source: http://blex.me/@baealex/nginx%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-docker-%EB%AC%B4%EC%A4%91%EB%8B%A8-%EB%B0%B0%ED%8F%AC
- Tags: 도커, 엔진엑스, 배포

---

단일 서버에서 도커를 이용해 서비스를 운영중이다. 백앤드 컨테이너는 배포시 별다른 문제가 없었으나 프론트엔드 컨테이너는 재실행시 실제 구동까지 텀이 길어서, 배포 후 일정 시간 502가 리턴되는 문제가 있었다. 이 문제를 `NginX`를 활용하여 해결하고자 한다.

#### NginX

제목에서 작성한 것 처럼 현재 웹 서버로 `NginX`를 활용하고 있다. `NginX`의 `upsteam`을 활용하여 메인 서버는 사실상 중단됐지만 중단되지 않은 것처럼 동작하도록 구현할 것이다.

###### upsteam이란?

`upstream`은 다른 서버로 요청(proxy)을 보낼때 어떤식으로 처리할지 정의한다. 많은 경우 다수의 서버에서 분산처리를 위해서 사용한다.

```bash
upstream <NAME> {
    ip_hash; // <not require>
    least_conn; // <not require>
    server <HOST>:<PORT> <...options>;
    ...
    keepalive <number>; // <not require>
}
```

기본적인 형태는 위와 같다. `ip_hash`는 같은 ip에서 온 요청은 같은 서버가 처리할 수 있도록 설정할 수 있는 명령이다. `least_conn`는 로드밸런싱에 사용되는 명령이다. 요청이 가장 적은 서버로 요청을 보내도록 한다. `keepalive`는 요청의 연결을 유지하는 옵션으로 성능 최적화를 위해 주로 사용된다.

주로 사용되는 `server`의 옵션은 다음과 같다.

- weight=`number`
  - 요청을 보낼때 이 서버는 `number` 만큼의 가중치를 가진다. (기본값 = 1)
- max_fails=`number`
  - 이 서버가 `number` 만큼 요청이 실패하면 중단된 것으로 간주한다. (기본값 = 1)
- fail_timeout=`time` (ex > `3s`)
  - 이 서버가 중단된 경우 `time` 만큼 요청을 보내지 않는다. (기본값 = 10s)

전체 옵션이 궁금하시다면 [공식문서](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#server)를 참고하세요.

필자는 위 기능을 이용해 로컬호스트에 백업 컨테이너를 띄우고 메인 컨테이너를 재빌드하여 띄운 후 백업 컨테이너를 중단시키는 방식으로 무중단 배포를 구현하고자 한다. (환경변수 등을 활용하여 백업 컨테이너를 잠시 띄우는게 아니라 그린 블루 배포처럼 번갈아 가면서 운영하는 방식이 좀 더 효율적이라 생각된다.)

```nginx
upstream feserver {
    server localhost:3000;
    server localhost:3001;
}

upstream beserver {
    server localhost:8000;
    server localhost:8001;
}
```

서버 옵션도 기본값으로 충분하며 다른 명령은 필요하지 않으므로 위와같이 심플하게 작성하였다. 이후 위 `upstream`을 서버에 아래와 같이 지정할 수 있다.

```nginx
server {
    ...
    location / {
        proxy_pass http://feserver;
    }
}
```

#### Docker

우선 백업 컨테이너를 구동시키기 위해서 `docker-compose.bak.yml` 파일을 생성하였다. 여기서 중요한 점은 실제 컨테이너에서 사용하는 포트와 다른 포트로 지정해 주어야 한다는 것이다. 위 `NginX`에서 설정한 것 처럼 실제 컨테이너는 `3000`, `8000` 포트를 백업 컨테이너는 `3001`, `8001` 포트를 사용한다.

###### 백업 컨테이너 구동 및 중단

```bash
docker-compose -p ${DOCKER_APP_NAME}_bak -f docker-compose.bak.yml up -d --build
```

위 명령어로 백업 컨테이너를 구동시키자. 기존 컨테이너와 이름이 중복되지 않도록 `-p` 옵션을 주었다.

```bash
docker-compose -p ${DOCKER_APP_NAME}_bak -f docker-compose.bak.yml down
```

이후 위 명령어로 백업 컨테이너를 중단시키자.

```bash
docker-compose -p ${DOCKER_APP_NAME}_bak -f docker-compose.bak.yml up -d --build

sleep 10

docker-compose up -d --build

sleep 10

docker-compose -p ${DOCKER_APP_NAME}_bak -f docker-compose.bak.yml down
```

필자는 위와같이 스크립트를 작성하여 사용중이다.
