시작하기 앞서

이 글은 2편으로 나뉘어져 있습니다. Travis CI, AWS CodeDeploy, Docker 로 배포 자동화 및 무중단 배포 환경 구축하기 - (1)을 진행하시지 않으셨다면 먼저 진행하고 그 다음에 읽어주세요

Travis CI, AWS CodeDeploy, Docker 로 배포 자동화 및 무중단 배포 환경 구축하기 - (1) 편 링크

https://velog.io/@jeff0720/Travis-CI-AWS-CodeDeploy-Docker-%EB%A1%9C-%EB%B0%B0%ED%8F%AC-%EC%9E%90%EB%8F%99%ED%99%94-%EB%B0%8F-%EB%AC%B4%EC%A4%91%EB%8B%A8-%EB%B0%B0%ED%8F%AC-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0

배포를 위한 리눅스 서버 사전작업

Travis CI와 AWS를 연동하기 앞서 배포를 위해 사전 작업을 진행할 예정입니다.

왜냐하면 AWS CodeDeploy에 역할은 배포된 소스코드를 다운로드 받아 EC2에 저장하고 EC2 서버에 있는 배포 쉘 스크립트를 실행하기 때문입니다. 해당 단계에서는 배포 쉘 스크립트에 단계별로 들어갈 작업들을 하나 하나 해보면서 진행하려고 하기 때문입니다.

순서는 다음과 같습니다.

첫 번째, 도커를 설치하고 도커를 사용해 깃헙에서 다운로드 받은 소스코드를 실행하겠습니다.
두 번째, nginx를 설치하고 nginx와 리눅스 서버를 연동하겠습니다.
세 번째, 무중단 배포를 위한 스크립트를 만들고 적용해 서버를 실행하겠습니다.

node-koa-server 소스코드 클론

먼저, mkdir deploy 라는 명령어로 deploy 라는 디렉터리를 /home/ubuntu/deploy 에 생성한 후 deploy 디렉터리로 이동해 줍니다.

이제 아래 명령어를 터미널에 입력해 node-koa-server 소스코드를 클론 합니다.

git clone https://github.com/jeffchoi72/node-koa-server.git

도커 설치

해당 리눅스 서버에 도커를 설치하겠습니다.

다음과 같은 명령어를 터미널에 입력해 주세요

curl -fsSL https://get.docker.com/ | sudo sh

sudo 없이 docker를 사용하려면 다음과 같은 명령어를 입력해 주세요 해당 명령어는 docker 그룹에 ubuntu 라는 사용자 계정을 추가한다는 의미입니다.

sudo usermod -aG docker ubuntu

배포에 사용할 Dockerefile ( 도커 이미지 ) 만들기

이제 docker로 저희가 클론 받은 소스코드를 실행하겠습니다.

먼저, 리눅스 서버에 docker-image 라는 디렉터리를 생성하신 다음 docker-image 디렉터리로 이동해 주세요

스크린샷 2019-01-26 오후 9.53.11.png

그 후 Dockerfile을 만들어 node.js 환경으로 구성된 도커 이미지를 만들겠습니다.

Dockerfile 이라는 파일을 만들어 아래 내용을 파일에 적어주고 저장해 주세요

# node 10.14 버전을 사용하겠다는 의미
FROM    node:10.14

# 해당 이미지를 만든 사용자의 정보
MAINTAINER JeffChoi <dev.jeffchoi@gmail.com>

# 도커 컨테이너 호스트와 공유할 디렉터리 지정
VOLUME /deploy/node-koa-server

# 도커 이미지를 실행할시 실행될 스크립트
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/node-koa-server
yarn install
yarn prod

참고로 해당 쉘 스크립트는 현재 호스트 서버에서 실행되는게 아닌 도커 컨테이너 호스트에서 실행될 쉘 스크립트 입니다. 그 후 해당 스크립트를 실행할 수 있게 아래 명령어로 실행 권한을 추가해줍니다.

chmod +x ./start-server.sh

그런 다음 아래 명령어를 통해 도커 이미지를 생성해 주세요

docker build -t node-koa-server-docker-image .

그 후 아래 명령어로 도커 이미지가 생성되었는지 확인하겠습니다.

docker images

배포에 사용할 Docker Compose ( 도커 컨테이너 실행 설정 파일 ) 만들기

Docker Compose 라는 툴로 저희가 방금 만든 도커 이미지를 실행하겠습니다.

우선, 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-compose

docker-compose version

그런 다음 docker-compose.yml 이라는 파일을 만든 후 아래와 같은 내용을 저장해 주세요

version: '2'

services:
  node-koa-server:
     image: node-koa-server-docker-image
     volumes:
          - /home/ubuntu/deploy/node-koa-server:/deploy/node-koa-server
     ports:
          - "3000:3000"

이제 docker-compose로 우리가 만든 이미지를 실행해 줍시다. 아래와 같은 명령어를 터미널에 입력해 주세요

docker-compose up -d

그런 다음 실행되고 있는지 docker ps 명령어로 확인 해 주세요
스크린샷 2019-01-26 오후 10.39.45.png

nginx 설치 및 도커로 실행되고 있는 node.js 서버 포트 연동

다음과 같은 명령어를 통해 nginx를 설치해 주세요

sudo apt-get update && sudo apt-get install nginx

sudo service nginx status 명령어로 nginx가 실행되고 있는지 확인해 주세요 만약 실행이 안된다면 sudo service nginx start 명령어를 터미널에 입력해 주시면 됩니다.

이제 /etc/nginx/sites-available 디렉터리로 이동해 프록시 설정을 진행하겠습니다.

node-koa-server 라는 파일을 만들어 아래와 같은 내용을 넣어주세요

server {
        listen 80;
        server_name 서버 아이피; # 세미콜론 붙여주셔야 합니다.
        location / {
                proxy_pass http://127.0.0.1:3000;
        }
}

그런 다음 아래 명령어로 /etc/nginx/sites-enabled 디렉터리에 node-koa-server 파일을 링크해주겠습니다.

sudo ln -fs /etc/nginx/sites-available/node-koa-server /etc/nginx/sites-enabled/

그 후 nginx 문법이 잘못된거 없나 sudo nginx -t 명령어로 확인 하신 후 이상이 없다면 sudo service nginx restart 명령어로 nginx를 재시작 해주세요

그런 다음 웹 브라우저로 자신이 작업하고 있는 서버 주소로 접속해 보세요 아래와 같은 화면이 뜨면 성공입니다.

스크린샷 2019-01-26 오후 11.00.36.png

무중단 배포 적용하기

제가 진행할 무중단 배포 원리는 간단합니다. 저희가 만들 배포 스크립트에서는 3001번으로 서버가 실행되고 있다면 3002번 포트로 새롭게 업데이트된 소스코드를 실행한 서버를 실행하고 실행이 다 되었다면 3001번 포트의 서버를 종료하는 방식입니다. 또한 이것을 가능하게 하기 위해서는 nginx는 각각 3001번 포트와 3002번 포트를 주시하면서 로드 밸런싱을 해줘야 합니다.

자 그럼 시작하겠습니다.

다시 /home/ubuntu/docker-image 디렉터리로 이동한 후 docker-compose.blue.yml 파일과 docker-compose.green.yml 파일을 만들어 주세요

docker-compose.blue.yml에 들어갈 내용은 다음과 같습니다.

version: '2'

services:
  node-koa-server:
     image: node-koa-server-docker-image
     volumes:
          - /home/ubuntu/deploy/node-koa-server:/deploy/node-koa-server
     ports:
          - "3001:3000"

docker-compose.green.yml에 들어갈 내용은 다음과 같습니다.

version: '2'

services:
  node-koa-server:
     image: node-koa-server-docker-image
     volumes:
          - /home/ubuntu/deploy/node-koa-server:/deploy/node-koa-server
     ports:
          - "3002:3000"

docker-compose.blue.yml과 docker-compose.green.yml 파일에 차이점은 호스트에 바인딩될 포트가 서로 다르다라는 것 밖에 없습니다.

그리고 기존에 있었던 docker-compose.yml 파일은 이제 필요없으니 삭제해 주세요

이제 무중단 배포 스크립트를 만들겠습니다.

deploy.sh 라는 파일을 만들어 주신 후 아래 내용을 넣어주세요

#!/bin/bash

DOCKER_APP_NAME=node-koa-server

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

그 후 chmod +x ./deploy.sh 명령어로 deploy.sh에 실행할 수 있는 권한을 추가해 줍니다.

이제 nginx가 3001번과 3002번을 로드 밸런싱 해주도록 설정하겠습니다.

cd /etc/nginx/sites-available 명령어로 /etc/nginx/sites-available 디렉터리로 이동하세요

그 후 node-koa-server 를 아래 내용과 같이 수정해 줍니다.

# Load Balancing
upstream node-koa-server {
  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://node-koa-server;
  }
}

그런 다음 아래 명령어들을 실행하세요

sudo ln -fs /etc/nginx/sites-available/node-koa-server /etc/nginx/sites-enabled/ &&
sudo nginx -t && sudo service nginx restart

자 테스트로 /home/ubuntu/docker-image로 이동하셔서 ./deploy.sh를 실행하세요 그런 다음 웹 브라우저로 계속 새로고침해서 접속이 안되나 확인해 보세요 아마 잘될겁니다!

Travis CI 배포 설정

이제 모든 준비가 끝났습니다. 정말 많은 작업들을 진행했네요 이제 Travis CI가 어떻게 배포를 진행해줄지 행동을 정의해 주겠습니다.

AWS CodeDeploy 배포 그룹 생성

Travis CI가 사용할 AWS 배포그룹을 만들겠습니다.

AWS 대시보드에서 CodeDeploy를 검색하신 후 아래와 같은 페이지에서 애플리케이션 생성을 누릅니다.

스크린샷 2019-01-26 오후 11.52.27.png

그런 다음 애플리케이션 이름을 입력해 준 후 애플리케이션을 생성해 줍니다.

스크린샷 2019-01-26 오후 11.46.45.png

그러고 나서 애플리케이션 리스트가 보이면 클릭해 배포 그룹을 생성해 줍니다.

스크린샷 2019-01-26 오후 11.53.38.png

다음과 같이 정보들을 입력해 배포 그룹을 생성합니다.

스크린샷 2019-01-26 오후 11.54.41.png

스크린샷 2019-01-26 오후 11.55.08.png

스크린샷 2019-01-26 오후 11.55.55.png

.travis.yml에 deploy 추가하기

Travis CI는 테스트와 빌드가 끝난 후 스스로 배포를 못하기 때문에 타 플랫폼 ( heroku, aws )으로 배포할 수 있게 지원해 줍니다. 타 플랫폼으로 배포할 수 있게 행동을 정의해주는것 역시 .travis.yml에서 설정합니다. 배포 행동을 정의해주는 것은 deploy 라는 key 이름으로 존재합니다.

.travis.yml을 아래와 같이 수정합니다.

language: node_js
node_js:
  - "10.14"
before_install:
  - npm install -g yarn
branches:
  only:
    - master
before_deploy: # 배포하기전 하는 작업들
  - rm -rf node_modules # travis가 설치한 node_moduels를 삭제
  - zip -r node-koa-server * # node-koa-server 라는 이름으로 zip 파일 생성
  - mkdir -p deploy # deploy 라는 디렉터리를 만듬
  - mv node-koa-server.zip deploy/node-koa-server.zip # deploy 디렉터리로 node-koa-server.zip 파일을 이동
deploy: # 배포
  - provider: s3 # AWS S3를 의미
    access_key_id: $AWS_ACCESS_KEY # Travis repo settings에 설정된 값
    secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
    bucket: jeffchoi-ci-cd-tutorial # S3에 생성한 버킷
    region: ap-northeast-2
    skip_cleanup: true 
    local_dir: deploy # deploy 디렉터리에 있는 파일을 s3로 업로드 하겠다는 의미
    wait-until-deployed: true
    on:
      repo: jeffchoi72/node-koa-server #Github 주소
      branch: master
  - provider: codedeploy # AWS CodeDeploy를 의미
    access_key_id: $AWS_ACCESS_KEY # Travis repo settings에 설정된 값
    secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
    bucket: jeffchoi-ci-cd-tutorial # AWS CodeDeploy가 다운로드 받은 버킷
    key: node-koa-server.zip # 해당 버킷에 저장되어 있는 파일 이름
    bundle_type: zip # 버킷에 저장되어 있는 파일의 확장자
    application: ci-cd-tutorial-code-deploy-service # AWS 배포 애플리케이션
    deployment_group: ci-cd-deploy-grop # AWS 배포 애플리케이션에 만들어져 있는 배포 그룹
    region: ap-northeast-2
    wait-until-deployed: true
    on:
      repo: jeffchoi72/node-koa-server
      branch: master
notifications:
  email:
    recipients:
      - dev.jeffchoi@gmail.com

Travis CI가 빌드와 테스트가 끝난 코드를 S3에 업로드 하고 AWS CodeDeploy 이벤트를 발생시켰을때 appspec.yml 이라는 파일로 AWS CodeDeploy가 어떻게 행동을 할 것인지 정의해 줘야합니다.

해당 프로젝트 루트 디렉터리에 appspec.yml 파일을 만들어 주세요 해당 파일에 들어갈 내용은 다음과 같습니다.

version: 0.0
os: linux
files:
  - source:  /
    destination: /home/ubuntu/deploy/node-koa-server/ # S3에서 가지고온 파일을 저장할 디렉터리 지정
hooks:
  AfterInstall: # 배포가 끝나면 아래 명령어를 실행
    - location: execute-deploy.sh
      timeout: 180

AWS CodeDeploy에서는 S3에서 코드를 받아 EC2 서버에 저장만 해줄뿐 직접 명령어 실행을 못합니다. 그렇기 때문에 루트 디렉터리 배포 스크립트를 실행할 쉘 스크립트 파일을 만들고 appspec.yml에서 해당 쉘 스크립트 파일을 실행할 수 있게 해줘야 합니다.

루트 디렉터리에 execute-deploy.sh 파일을 만들고 다음과 같이 내용을 작성합니다.

#!/bin/bash

cd /home/ubuntu/docker-image
./deploy.sh > /dev/null 2> /dev/null < /dev/null &

해당 스크립트는 배포 스크립트가 있는 곳으로 디렉터리를 이동하고 실행한다는 의미입니다.

Travis CI 환경변수 추가하기

방금 수정한 .travis.yml 파일에 $AWS_ACCESS_KEY와 $AWS_SECRET_KEY가 있는것을 볼 수 있습니다. 이 두개는 환경변수 인데요 Travis CI에서 환경변수를 설정해 줍시다.

travis-ci.org에서 해당 레파지토리로 이동해 More options -> Settings를 눌러줍니다.

스크린샷 2019-01-27 오후 6.11.01.png

아래 사진처럼 환경변수에 각각 AWS_ACCESS_KEY, AWS_SECRET_KEY를 입력해 주세요 입력 값들로는 아까 받은 csv에 있는 ACCESS_KEY와 SECRET_KEY를 넣어주시면 됩니다.

스크린샷 2019-01-27 오후 6.13.13.png

배포하기

모든 준비가 끝났습니다. 이제 수정한 소스코드를 깃헙에 푸쉬하기만 하면 됩니다!

먼저, EC2 서버에 접속하셔서 /home/ubuntu/deploy/node-koa-server 디렉터리로 이동하신 후 모든 파일들을 삭제해 주세요

그런다음 수정한 소스코드를 깃헙에 푸쉬합시다!

Travis CI가 빌드가 성공했다고 보이네요

스크린샷 2019-01-27 오후 8.20.25.png

배포 작업이 이루어졌는지 확인하기 위해 AWS CodeDeploy 웹 페이지로 이동하신 후 애플리케이션 리스트중에 사용하고 있는 애플리케이션을 클릭하신다면 다음과 같이 배포에 성공한 모습을 보실 수 있습니다.

스크린샷 2019-01-27 오후 8.22.11.png

Docker로 node.js 서버가 잘 돌아가고 있는지 확인해보겠습니다.

스크린샷 2019-01-27 오후 8.24.58.png

웹 페이지도 접속해 보세요!

스크린샷 2019-01-27 오후 8.26.00.png

직접 한번 프로젝트에 있는 코드들을 바꾸고 깃헙에 올려 소스코드가 업데이트 되었는지 확인해 보세요

확인하시면 자동 배포와 무중단 배포가 된것을 보실 수 있습니다!

마무리

Travis ci, AWS CodeDeploy, Docker 로 배포 자동화 환경 구축했습니다. 이렇게 한 번 구축해보니 쉽게 느껴지지만 정말 배포 자동화 환경을 구축 할 때는 어떻게 해야지 정말 고민한거 같습니다. 저처럼 고민하신 분들께 도움이 되었길 바라면서 글을 마치겠습니다. 긴 글 봐주셔서 감사합니다.

참고글

https://jojoldu.tistory.com/265
https://subicura.com/2017/02/10/docker-guide-for-beginners-create-image-and-deploy.html