본문 바로가기

IT Book Summary/스프링 마이크로 서비스 코딩공작소

Chapter 10 마이크로서비스의 배포

빌드 및 파이프라인 구축은 실제로 마이크로서비스 아키텍처에서 핵심 부분 중 하나다.

 

코드를 빌드하고 배포하는데 사용할 메커니즘

  • 자동화 automated
    빌드와 배포 프로세스에서 사람이 개입하지 않아야 한다.
    빌드 및 머신이미지 프로비저닝, 이후 서비스의 배포 프로세스가 모두 자동화되어야 하며,
    소스 저장소에 코드를 커밋하는 동작에서 시작되어야 한다.
  • 반복성 repeatability
    빌드 배포 프로세스는 반복가능하고 동일한 작업으로 수행해야 한다.
  • 완전성 complete
    배포된 산출물 결과는 서비스를 위한 완전한 런타임 환경을 포함하는 가상머신 컨테이너 이미지 여야 한다.
  • 불변성 immutability
    서비스를 포함한 머신 이미지를 빌드하고 배포한 후 런타임 구성을 건드리거나 변경해서는 안됨.
    변경이 필요하면 소스제어 시스템에서 관리되는 스크립트에서 구성을 변경하고
    서비스와 인프라스트럭처가 빌드 프로세스를 다시 거쳐야 함.

 

최종목표인 AWS ECS에 서비스를 배포하는 방법

  1. 사용중인 메이븐 빌드 스크립트를 Travis CI 지속적 통합 및 배포용 클라우드 도구에 통합
  2. 각 서비스에 대한 불변성 도커 이미지를 생성하고 중앙저장소에 올림
  3. AWS ESC를 사용해 아마존 클라우드에 마이크로서비스를 모두 배포
  4. 서비스가 정상적으로 동작하는지 플랫폼 테스트를 수행

10.1 EagleEye 클라우드의 핵심 인프라스트럭처 설정

 

  1. ECS는 도커 클러스터를 실행하는데 필요한 모든 서버를 구성하고 설정. 
    동작상태를 모니터링하고 충돌이 발생한 서비스를 재시작.
  2. 인프라스트럭처를 아마존 RDS와 아마존 ElastiCache 서비스로 옮겨 사용.
  3. 아마존 보안그룹을 사용해 ECS 클러스터의 5555 포트만 외부접속 가능하게 설정
  4. 스프링 OAuth2 서버를 사용해 서비스를 보호.
  5. 카프카를 비롯 모든 서버가 노출한 도커포트를 통해 외부에서 서버를 공개적으로 접근할 수 없다.

 

1 - 아마존 RDS로 PostgreSQL 데이터베이스 생성

아마존 RDS에 일단 개발용으로 접근가능한 데이터베이스를 만든다.

아마존 디비 접속정보를 담고있는 스프링 클라우드 컨피그 서버의 새 애플리케이션 프로파일을 깃에 추가

(서비스이름)-aws-dev.yml

 

2 - 아마존에 레디스 클러스터 구축

레디스 클러스터를 설정하기 위해 아마존 ElastiCache 서비스 사용.

클러스터가 생성되면 클러스터에서 사용되는 엔드포인트를 보여주는 상세페이지로 이동.

라이선싱 서비스만 레디스 사용.

 

3 - ECS 클러스터 생성

아마존 ECS 클러스터의 설정은 도커 컨테이너를 호스팅할 아마존 머신을 프로비저닝 한다.

AWS 콘솔에서 Elastic Containner Service 링크 -> 왼쪽메뉴의 클러스터 링크 -> 클러스터 생성 버튼 

클러스터 생성 화면에서 도커 클러드터를 호스팅하는데 사용할 EC2 인스턴스의 크기를 정함.

 

1. 클러스터 이름  2. 클러스터를 실행할 아마본 EC2 가상머신 크기 

3. 클러스터에서 실행될 인스턴스 개수  4. 각 노드에 할당될 EBS 디스크 공간

EC2 클러스터 접근에 필요한 VPC 서브넷 선택

일반적으로 VPC의 모든 서브넷 선택해 클러스터를 사용할 수 있게한다.

주울을 실행하기 때문에 모든 트래픽이 5555포트로만 통과하게 구성.

외부의 모든 인바운드 트래픽 허용 (0.0.0.0/0)

 

컨데이너 IAM Role  생성.

 


10.2 인프라스트럭처를 넘어: EagleEye 배포

수동으로 배포하는 것은 실제 권장하지 않으나 이 과정을 통해 매커니즘을 이해할 수 있다.

 

1 - EC2에 EagleEye 서비스 수동으로 배포

수동으로 배포하기위해서는 ECS 명령줄 클라이언트 (amazon-ecs-cli)를 사용한다.

설치 후 ecs-cli 런타인 환경 구성

  1. 아마존 자격증명으로 ECS 클라이언트 구성
  2. 작업할 리전을 선택
  3. ECS 클라이언트가 작업할 기본 ECS 클러스터를 정의
  4. ecs-cli configure 명령어로 수행

    ecs-cli configure profile --profile-name default \
                                           --access-key $AWS_ACCESS_KEY \
                                           --secret-key $AWS_SECRET_KEY \
    ecs-cli configure --cluster spmia-tmx-dev \
                               --default-lauch-type EC2 \
                               --region ap-northeast-2 \
                               --config-name default

메이븐 스크립트는 빌드 및 배포 파이프라인에 사용되기 위해 빌드 이름을 설정해야 한다.

$BUILD_NAME 환경변수는 빌드 스크립트에 의해 생성된 도커 이미지에 태그를 지정하는데 사용.

루트 디렉터리에서 명령어 실행

export BUILD-NAME=TestManualBuild

mvn clean package docker:build

이 명령은 프로젝트 루트 디렉터리에 있는 부모 POM을 사용해 메이븐 빌드를 실행한다.

메이븐 코드실행이 완료되면 도커이미지를 ECS 인스턴스에 배포 할 수 있다.

 

도커컴포즈 파일을 사용해 컨테이너를 배포

./travis_scripts/deploy_to_docker_hub.sh
ecs-cli compose --file docker/aws-dev/docker-compose.yml up

ecs_cli ps  명령어로 서비스 실행 여부와 IP 주소를 알아낼 수 있다.

 

외부로 열려있는 5555포트 컨테이너만 빼고 나머지 6개는 외부와 차단되어 띄워졌다.

 


10.3 빌드 및 배포 파이프라인 아키텍처

각 컴포넌트는 수동으로 수행하던 작업을 자동화 한다.

  1. 개발자는 서비스 코드를 소스 저장소에 커밋
  2. 빌드 및 배포엔진은 소스코드 저장소의 변경사항을 모니터링. 코드 커밋히 코드를 저장소에서 가져와 빌드 스크립트 진행
  3. 코드를 컴파일하고 단위 테스트와 통합 테스트를 실행 후 실행가능한 산출물로 컴파일.
  4. 실행가능한 JAR 파일을 빌드한 후 마이크로서비스가 배포된 머신 이미지를 굽는다.
    가상머진 이미지나 컨테이너를 생성하고 서비스를 설치.
    CI/CD 프로세스를 사용해 마이크로서비스와 서비스용 런타임 엔진, 머신 이미지 전부를
    하나의 상호의존단위로 배포하고 개발팀이 관리
  5. 새 환경에 배포전 실행 이미지에 대해 플랫폼 테스트를 수행해 정작 작동하는지 확인후 머신이미지 사용.
  6. 서비스를 상위환경으로 승격하면 하위환경에서 사용한 것과 동일한 머신이미지로 시작.
    서버의 불변성을 보장한다.

마이크로서비스와 클라우드 기반 애플리케이션 개발 패턴의 핵심

  • 지속적 통합/지속적 전달 CI/CD
  • 코드형 인프라스트럭처 
  • 불변서버

 


10.4 실제 빌드 및 배포 파이프라인

파이프라인을 구현하는데 사용할 다양한 기술

  1. 깃허브
    클라우드 기반 소스제어 저장소
  2. Travis CI
    깃허브와 밀접하게 통합된 빌드엔진
  3. 메이븐/스포티파이 도커 플러그인
    메이븐에서 도커 빌드를 만든다.
  4. 도커
  5. 도커 허브
    도커이미지를 생성 후 고유 태그를 붙여 중앙 저장소에 올린다.
  6. 파이썬
    실제환경에서 API 소비자처럼 동작하는 완전한 블랙박스 테스트를 수행한다.
  7. 아마존 ECS

10.5 깃허브와 Travis CI에서 서비스 빌드

먼저 깃허브와 Travice CI, 도커허브 계정을 설정한다.

 

처음 모든 서비스를 단일 빌드 스크립트를 통해 아마존 클라우드에 전체 환경을 올리고 

개별 서비스마다 빌드 스크립트를 관리해 독립된 개별 저장소를 사용해 마이크로 서비스를 설정해야 한다.

 


10.6 Travis CI에서 서비스 빌드

수동 배포시 단계

로컬 머신에서 명령중창에 메이븐 스크립트 실행 

-> 빌드후 도커이미지로 패키징해 로컬에서 실행되는 도커 저장소에 저장

-> 로컬 도커 저장소에 새로 생성된 도커이미지를 docker-compose 실행. 

 

빌드 및 배포를 위해 .travis.yml 파일이 수행하는 상세단계

 

.travis.yml 파일 빌드의 구조

 

language: java --핵심 런타임 구성정보 설정
jdk:
- oraclejdk8
cache:
  directories:
  - "$HOME/.m2"
sudo: required
services:
- docker
notifications: --핵심 런타임 구성정보 설정
  email:
  - carnell28@gmail.com
  on_success: always
  on_failure: always
branches:
  only:
  - master
env: --핵심 런타임 구성정보 설정
  global:
  - secure: E6WqUsvNBaznI6xiaDLzBVLr7pKGqR3 ...
  - secure: j97NlFyjfMEA1CDh1uPXpksrp7udS57 ...
  - secure: km8ABs12DHC1juDJ1W6W1ekvo8E1pNx ...
  - secure: KOnFu91uxkxVpIgztouC6pHYYQBlbki ...
  - secure: IMo6+b8kxTXhavolsJQDwWPm5rKZfad ...
before_install: --필요한 명령줄 도구를 빌드 전 설치
- gem install travis -v 1.8.5 --no-rdoc --no-ri
- sudo curl -k -o /usr/local/bin/ecs-cli https://s3.amazonaws.com/amazon-ecs-cli/ecs-cli-linux-amd64-latest
- sudo chmod +x /usr/local/bin/ecs-cli
- export BUILD_NAME=chapter10-$TRAVIS_BRANCH-$(date -u "+%Y%m%d%H%M%S")-$TRAVIS_BUILD_NUMBER
- export CONTAINER_IP=54.215.193.139
- export PLATFORM_TEST_NAME="chapter10-platform-tests"
script:
- sh travis_scripts/tag_build.sh --빌드이름으로 소스에 태그 다는 셸스크립트
- sh travis_scripts/build_services.sh --메이븐을 사용해 서버와 로컬 도커이미지 빌드
- sh travis_scripts/deploy_to_docker_hub.sh --도커이미지를 도커서브에 올림
- sh travis_scripts/deploy_to_amazon_ecs.sh --아마존 ECS 컨테이너에서 서비스 시작
- sh travis_scripts/trigger_platform_tests.sh --빌드된 서비스에 대해 플랫폼 테스트를 실행하는 Travis 빌드 시작

 

1 - 핵심 빌드 런타임 구성

 

language: java
jdk:
- oraclejdk8
--주요 런타임 환경으로 자바와 JDK8 사용 지정
cache:
directories:
- "$HOME/.m2"
--빌드간 메이븐 리렉터리를 캐시하고 재사용 지정
sudo: required
--빌드가 실행되는 가상머신에서 sudo 액서스의 허용여부를 지정
services:
- docker
notifications:
email:
- carnell28@gmail.com
on_success: always
on_failure: always
--빌드 성공/실패를 알리는 이메일 주소를 구성
branches:
only:
- master
--마스터 브랜치에 커밋이 발생할 때만 빌드하도록 지정
env: --스크립트에 사용할 보안 환경변수 설정
global:

TravisCI는 자격 증명 보호하기 위해 암호화된 환경변수를 추가할 수 있는 기능을 제공

다음의 환경변수를 만들고 암호화 

DOCKER_USERNAME 도커허브 사용자

DOCKER_PASSWORD 도커허브 패스워드

AWS_ACCESS_KEY 아마존 액세스 키

AWS_SECRET_KEY 아마존 시크릿 키

GITHUB_TOKEN 깃허브 접근 토큰

 

trivis 도구가 설치되면 다음 명령어로 암호화된 환경변수를 .travis.yml 파일의 env.global 섹션에 추가함.

travis encrypt DOCKER_USERNAME=seomrandomname --add env.global

 

env.gloval 섹션에 secure 프로퍼티 태그와 긴 테스트 문자열이 표시

env:
  global:
  - secure: E6WqUsvNBaznI6xiaDLzBVLr7pKGqR3u ...
  - secure: j97NlFyjfMEA1CDh1uPXpksrp7udS57/ ...
  - secure: km8ABs12DHC1juDJ1W6W1ekvo8E1pNxy ...
  - secure: KOnFu91uxkxVpIgztouC6pHYYQBlbkif ...
  - secure: IMo6+b8kxTXhavolsJQDwWPm5rKZfadU ...
--Travis암호화 도구는 암호와된 환경변수의 이름을 표시하지 않음.

 

2 - 사전 빌드 도구 설치

빌드엔진은 빌드 프로세스에서 사용하는 다른 여러 도구를 한데 묶는 '글루코드' 스크립팅이 대부분.

travis 와 ecs-cli 명령중 도구를 먼저 설치

 

before_install:
- gem install travis -v 1.8.5 --no-rdoc --no-ri
--travis 명령줄 도구 설치
- sudo curl -k -o /usr/local/bin/ecs-cli https://s3.amazonaws.com/amazon-ecs-cli/ecs-cli-linux-amd64-latest
--아마존 ECS 클라이언트 설치
- sudo chmod +x /usr/local/bin/ecs-cli
--아마존 ECS 클라이언트에 실행할 수 있도록 권한 변경
- export BUILD_NAME=chapter10-$TRAVIS_BRANCH-$(date -u "+%Y%m%d%H%M%S")-$TRAVIS_BUILD_NUMBER
- export CONTAINER_IP=54.215.193.139
- export PLATFORM_TEST_NAME="chapter10-platform-tests"
--빌드 프로세스에서 사용될 환경변수 설정

BUILD_NAME 고유 빌드이름 생성. 도터 이미지에 태그 지정에 사용

CONTAINER_ID 도커 컨테이너가 실행될 아마존 ECS의 가상머신 IP주소. 플랫폼 테스트를 실행할 다른 Travis CI 작업에 전달

PLATFORM_TEST_NAME 실행중인 빌드작업의 이름.

 

 

3 - 빌드 실행

사전 빌드 구성과 의존성 설치 완료 후 

빌드를 실행하기 위해 Travis의 script 프로퍼티를 사용한다.

 

명령을 주요 단계로 나누어 각 셸 스크립트로 캡슐화 하고 

Travis가 이 셸스크립트를 실행하게 한다.

 

4 - 소스제어 코드에 태그달기

 

tag_build.sh

echo "Tagging build with $BUILD_NAME"
export TARGET_URL="https://api.github.com/repos/carnellj/spmia-chapter10/releases?access_token=$GITHUB_TOKEN"
#깃허브 릴리스 API의 엔드포인트
body="{ 
  \"tag_name\": \"$BUILD_NAME\",
  \"target_commitish\": \"master\",
  \"name\": \"$BUILD_NAME\",
  \"body\": \"Release of version $BUILD_NAME\",
  \"draft\": true,
  \"prerelease\": true
}"
#REST 호출의 바디

curl -k -X POST \
  -H "Content-Type: application/json" \
  -d "$body" \
  $TARGET_URL
#curl을 사용해 빌드를 시작하는 서비스를 호출

 

5 - 마이크로서비스 빌드와 도커이미지 생성

 

build_services.sh

echo "Building with travis commit of $BUILD_NAME ..."
mvn clean package docker:build

상위메이븐 파일을 실행하면 상위메이븐 파일은 서비스별 하위 메이블 파일을 실행

 

6 - 도커 허브에 이미지 올리기

 

deploy_to_docker_hub.sh

echo "Pushing service docker images to docker hub ...."
docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
docker push johncarnell/tmx-authentication-service:$BUILD_NAME
docker push johncarnell/tmx-licensing-service:$BUILD_NAME
docker push johncarnell/tmx-organization-service:$BUILD_NAME
docker push johncarnell/tmx-confsvr:$BUILD_NAME
docker push johncarnell/tmx-eurekasvr:$BUILD_NAME
docker push johncarnell/tmx-zuulsvr:$BUILD_NAME

스크립트를 통해 로그인하고 각 마이크로서비스 도커이미지를 도커허브저장소에 올림

 

7 - 아마존 ECS에서 서비스 시작

 

deploy_to_amazon_ecs.sh

echo "Launching $BUILD_NAME IN AMAZON ECS"
ecs-cli configure --region us-west-1 --access-key $AWS_ACCESS_KEY --secret-key $AWS_SECRET_KEY --cluster spmia-tmx-dev
ecs-cli compose --file docker/common/docker-compose.yml up
rm -rf ~/.ecs

docker-compose.yml 파일은 환경변수 $BUILD_NAME 에 포함된 빌드 이름을 사용하도록 매개변수화되어 있음.

 

8 - 플랫폼 테스트 시작

 

trigger_platform_tests.sh

echo "Beginning platform tests for build $BUILD_NAME"
travis login --org --no-interactive  --github-token $GITHUB_TOKEN
#깃허브 토큰을 사용해 Travis CI에 로그인하고 반환된 토큰을 RESULTS 변수에 저장
export RESULTS=`travis token --org`
export TARGET_URL="https://api.travis-ci.org/repo/carnellj%2F$PLATFORM_TEST_NAME/requests"
echo "Kicking off job using target url: $TARGET_URL"

body="{
\"request\": {
  \"message\": \"Initiating platform tests for build $BUILD_NAME\",
  \"branch\":\"master\",
  \"config\": {
    \"env\": {
      \"global\": [\"BUILD_NAME=$BUILD_NAME\",
                   \"CONTAINER_IP=$CONTAINER_IP\"]
                   #호출을 위한 JSON 바디를 생성. 2개값을 하위작업에 전달
    }
  }
}}"

echo "$body"

curl -s -X POST \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Travis-API-Version: 3" \
  -H "Authorization: token $RESULTS" \
  -d "$body" \
  $TARGET_URL
  #curl을 사용해 Travis CI의 REST API 호출
  #테스트 스크립트를 실행하는 부분
  #플랫폼 테스트 스크립트는 별도의 깃허브 저장소에 저장

 


10.7 빌드 및 배포 파이프라인을 마치며

데브옵스 팀이 이 작업을 지원하고 파이프라인은 독립적인 단계 (컴파일>패키징>배포>테스트)로 나뉘어

개발 팀이 자기 마이크로서비스의 빌드 스크립트를 각 단계에서 hook 할 수 있게 될것.

 

실무에서 많은 회사들이 앤서블 Ansible, 퍼펫 Puppet, 셰프 Chef 같은 프로비저닝 도구를 사용해 가상 머신이나 컨테이너 이미지에 운영체제를 설치하고 구성한다.

 

실제 빌드 및 파이프라인에서는 각 마이크로서비스는 자기 빌드 스크립트를 통해 독립적으로 ECS 컨테이너 클러스터에 배포됨.

 


  • 제대로된 빌드 및 배포 파이프라인을 구축하면 새로운 기능과 오류 수정을 몇분만에 배포 가능
  • 사람의 직접적 개입없이 자동화되어야 함.
  • 많은 스크립팅과 적절한 구성이 필요함
  • 불변 가상머신 또는 컨테이너 이미지를 제공해야함.
  • 환경별 서버구성은 서버가 설정될 때 매개변수로 전달 되어야 함