Next.js EC2 — Docker, ENV

Dev Raccoon
11 min readApr 3, 2020

--

지난 글에서 프로젝트 생성과 배포를 위한 EC2, Travis CI, CodeDeploy 설정을 했습니다. 이번엔 EC2에서 프로젝트가 실행된 환경을 Docker와 NGINX를 이용해 구성해보겠습니다.

Docker와 NGINX는 저도 이제 막 공부를 시작했기 때문에 직접 설명을 하면 오히려 이 글을 읽는 분들에게 잘못된 정보를 드릴 수 있어 제가 공부하면서 찾아본 글의 링크를 걸어두겠습니다.

초보를 위한 도커 안내서 — 도커란 무엇인가?

넌 뭐니 NGINX?

nginx의 이해와 활용

생활코딩 NGINX

들어가기에 앞서 해당 프로젝트에서 사용할 부분만 간략하게 언급하자면
Dockerfile을 이용해 예제 프로젝트를 도커 이미지로 만듭니다.
그리고 컨테이너에서 해당 이미지를 실행시키는데 여기서 사용하는 툴이 docker-compose 입니다.

우선 두 개의 폴더를 만들겠습니다.
deploy는 S3에서 가져온 프로젝트를 받을 공간입니다.
docker-image는 도커 실행 파일들과 배포 관련 파일들이 위치할 공간입니다.

deploy 폴더에 프로젝트 레포지토리를 복사합니다.

도커를 설치하고 docker 명령어에 사용자 권한을 부여합니다.
도커 설치를 확인하기 위해 docker images 명령어를 실행했을 때 위와 같은 에러가 뜬다면 EC2를 종료하고 다시 실행합니다.

mkdir deploy docker-imagecd deploygit clone https://github.com/YOUR_REPOSITORY.gitcd ../docker-imagecurl -fsSL https://get.docker.com/ | sudo sh // docker 설치sudo usermod -aG docker ubuntu // 사용자 권한 부여docker images// Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.40/images/json: dial unix /var/run/docker.sock: connect: permission deniedexit // ec2 종료

이제 도커 이미지를 만들기 위해 Dockerfile을 만들텐데 여기서 중요한 설정이 필요합니다. 보통 프로젝트를 하면 공개되면 안되는 암호나 프로젝트 환경에 따라 다르게 필요한 변수를 설정하기 위해 .env 파일을 사용하게 됩니다. 하지만 travis로 빌드 후 s3에서 가져온 프로젝트에는 .env 파일이 존재하지 않습니다. 애초에 github에 올라가지도 않았기 때문에 travis에서는 .env가 없이 빌드했기 때문입니다.

때문에 도커 컨테이너에서 실행하는 프로젝트를 위해 env 설정을 해줘야하는데
여러가지 방법이 있지만 저는 가장 이해하기 쉽고 간편해보이는 방법인 Dockerfile에서 했습니다.

// Dockerfile
FROM node:10.14
MAINTAINER USER_NAME<EMIAL_ADDRESS@gmail.com>VOLUME /deploy/next-appENV NAME raccoon
ENV SECRET_KEY abcd1234
COPY ./start-server.sh /usr/local/bin
RUN ln -s /usr/local/bin/start-server.sh /start-server.sh
CMD ["start-server.sh"]
// start-server.sh
#!/bin/bash

cd /deploy/next-app
yarn install
yarn build && yarn start
chmod +x ./start-server.shdocker build -t next-app-image .docker images

여기서 빌드를 하면 Dockerfile을 사용하게 되는데 추후에 환경 변수를 제거하거나 추가할 일이 생긴다면 Dockerfile을 변경하고 해당 이미지를 다시 만들어주셔야 합니다.

생성된 이미지를 실행시키기 위해 docker-compose를 설치하겠습니다.

// install docker-compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-composedocker-compose version

설치까지 확인하셨으면 이제 프로젝트 실행을 위한 파일을 만들어줍니다.
docker-compose 파일로 실행시킬 이미지를 지정하고
deploy.sh 에서 컨테이너를 백그라운드에서 실행시키기 위해 -d 옵션을 붙여줍니다.

// docker-compose.yml
version: '2'

services:
next-app:
image: next-app-image
volumes:
- /home/ubuntu/deploy/next-app:/deploy/next-app
ports:
- "3000:3000"
// deploy.sh
docker-compose up -d
chmod +x ./deploy.sh./deploy.shdocker ps

컨테이너가 잘 동작을 하더라도 3000번 포트에서 동작을 하고 있기 때문에 웹에서는 확인이 불가능합니다.
확인을 위해선 ec2에서 3000번 포트를 열어주거나 NGINX 설정을 해줘야 합니다.
포트는 ec2 보안 그룹에서 간단하게 설정할 수 있지만 공부가 목적이므로 NGINX를 설치하겠습니다. 아주 간단한 설정으로 포트를 우회할 수 있습니다.

sudo apt-get update && sudo apt-get install nginxsudo vim /etc/nginx/site-available/next-appserver {
listen 80;
server_name EC2_IPv4_Public_IP;
location / {
proxy_pass http://127.0.0.1:3000;
}
}
sudo ln -fs /etc/nginx/sites-available/next-app /etc/nginx/sites-enabled/sudo nginx -t && sudo service nginx restart

일반적으로 저희가 접근하는 주소는 80번 포트입니다. 80번 포트의 접속할 경우 3000번 포트를 연결해줍니다.

이제 ec2 아이피에 접속해 보시면 프로젝트가 실행되고 있는 걸 확인하실 수 있습니다.

하지만 이렇게만 할 경우 프로젝트를 수정하고 다시 배포할 경우 반영이 되지 않습니다. 이를 위해 필요한게 무중단 배포입니다.

무중단 배포는 두가지 포트(3001, 3002)를 이용해서 하나의 포트는 프로젝트를 실행하고 새로 배포를 할 경우 다른 포트에서 프로젝트를 실행시키고 NGINX를 이용해 포트를 연결하는 방식입니다.

// docker-compose.blue.yml
version: '2'

services:
next-app:
image: next-app-image
volumes:
- /home/ubuntu/deploy/next-app:/deploy/next-app
ports:
- "3001:3000"
// docker-compose.green.yml
version: '2'

services:
next-app:
image: next-app-image
volumes:
- /home/ubuntu/deploy/next-app:/deploy/next-app
ports:
- "3002:3000"
// deploy.sh
#!/bin/bash

DOCKER_APP_NAME=next-app

EXIST_BLUE=$(docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml ps | grep Up)

if [ -z "$EXIST_BLUE" ]; then
echo "blue up"
docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml up -d

sleep 10

docker-compose -p ${DOCKER_APP_NAME}-green -f docker-compose.green.yml down
else
echo "green up"
docker-compose -p ${DOCKER_APP_NAME}-green -f docker-compose.green.yml up -d

sleep 10

docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml down
fi

기존 docker-compose.yml 파일로 프로젝트를 실행하던 방법과 달리 두가지 파일로 포트를 나눠 프로젝트를 실행하고 있습니다.

// /etc/nginx/site-available
# Load Balancing
upstream next-app {
least_conn;
server 127.0.0.1:3001 weight=5 max_fails=3 fail_timeout=10s;
server 127.0.0.1:3002 weight=10 max_fails=3 fail_timeout=10s;
}
server {
listen 80;
server_name 서버 아이피;
location / {
proxy_pass http://next-app;
}
}
sudo ln -fs /etc/nginx/sites-available/next-app /etc/nginx/sites-enabled/sudo nginx -t && sudo service nginx restart

두 개의 포트를 연결하기 위해 NGINX도 다시 설정을 하고 재실행 시켜줍니다.

여기까지 하셨으면 프로젝트를 수정하고 다시 배포해봅니다.
수정사항이 변경되었으면 완성입니다.

만약 개발 환경과 실제 서비스 환경이 나눠서 필요할 때 저 같은 경우 지금까지의 과정과 똑같이 하나의 인스턴스를 더 생성한 후 travis.yml 에서 새로운 브랜치와 배포 환경을 추가하고 Dockerfile에서 다른 변수를 넣어서 실행하려고 생각하고 있습니다.

제 글을 보시고 프로젝트를 진행하시다 보면 어디선가 막히는 부분이 있을 수도 있습니다.
만약 에러가 난다면 가장 먼저 의심을 해봐야 할 건 제 글입니다.
EC2에서 도커를 실행시키는 방법은 이미 많은 분들이 글을 쓰셨기 때문에 그 글과 비교해보시는 걸 추천합니다.
저도 공부를 하면서 많은 에러를 경험했는데 해결하는데 가장 오래걸렸던 에러는

The overall deployment failed because too many individual instances failed deployment, too few healthy instances are available for deployment, or some instances in your deployment group are experiencing problems.

Codedeploy에서 실패하는 이 에러입니다.

이 외에도 다른 에러를 경험하셨을 경우 순서를 잘 생각해보시길 바랍니다.
저의 경우 github에 푸시가 제대로 되었고, Travis에서 빌드도 성공했습니다. 그 후 S3 확인 결과 zip 파일이 업로드 된 것도 확인할 수 있었습니다. 하지만 S3에서 EC2로 zip 파일을 받아오지 못하는 현상이 계속 발생했습니다.

때문에 Travis에서는 문제가 없다고 생각을 했는데 이게 실수였습니다.
Travis에서는 업로드도 하지만 zip 파일을 받을 경로도 설정해주고 있습니다. 하지만 여기서 받을 파일의 확장자를 적어주지 않아 발생한 에러였습니다.

또한 EC2에서 역할을 업데이트한 경우 EC2에서 codedeploy-agent를 재실행하지 않아도 같은 에러가 발생한다고 하니 참고해주시길 바랍니다.

참고로 codedeploy-agent의 에러 로그도 많은 도움이 되었는데 확인은

/var/log/aws/codedeploy-agent/codedeploy-agent.log

위의 경로에서 확인하실 수 있습니다.
CodeDeploy EC2/온프레미스 배포에 대한 로그 데이터 보기

즐거운 코딩하세요.

--

--