안녕하세요. soover입니다.
이전 글 [무중단 배포 환경 구축하기] - 2. AWS IAM 설정 에 이어서 배포 대상이 되는 서버를 구축해보겠습니다.
지금부터는 내용이 조금 길어질 수 있습니다..😂
하지만 내용은 그리 어렵지 않으니 차근차근 해나가봅시다 :)
우선 우리가 목표로 하는 배포 흐름을 살펴보겠습니다.
운영 중인 서버 a-1, a-2 인스턴스가 있고, 여기에 ELB를 연동하여 사용자의 유입을 각각 a-1과 a-2로 분배하는 구조가 있다고 가정합시다. 무중단 배포의 시나리오는 다음과 같이 이루어집니다.
기존 A그룹과 동일한 조건으로 B그룹을 생성합니다. (인스턴스 개수, 서버 환경 동일)
B그룹에 포함된 인스턴스에 변경된 소스를 반영합니다. (CodeDeploy Agent가 작업 수행)
세팅이 완료된 B그룹을 ELB에 연결합니다. (이 시점에서는 A그룹과 B그룹이 함께 ELB에 연결되어 있기 때문에 ELB에서 트래픽을 할당하는 인스턴스 개수는 총 4개)
ELB에 연결된 B그룹에 배포 상 문제가 없으면 A그룹의 연결은 해제 및 삭제 처리 됩니다.
배포 후에는 사용자 유입을 B그룹의 b-1, b-2 인스턴스가 감당하게 됩니다.
위 시나리오와 같은 배포 방식을 Blue-Green 유형이라고 합니다.
배포 전략에는 다양한 방법들이 존재하고, 주어진 환경과 상황 조건에 따른 장단점을 판단하여 적절한 방법으로 선택하게 됩니다.
EC2에 필요한 작업을 먼저 살펴보면,
배포 대상이 되는 서버(인스턴스)를 생성합니다.
Docker를 통해 Flask로 간단한 API 서버를 구축 및 실행합니다. (for 식별값 확인)
S3와 CodeDeploy에 연동 가능하도록 CodeDeploy Agent를 설치합니다.
Auto Scaling Group을 통해 실제 배포 정책에 사용될 AMI 이미지를 생성합니다.
EC2 서비스 콘솔에서 [인스턴스] - [인스턴스 시작] 버튼을 클릭합니다.
간단한 테스트 서버를 만들 계획이므로 OS는 Ubuntu 20.04 LTS, 인스턴스 유형은 t2.micro로 선택하고, 나머지는 default 값을 선택하여 인스턴스를 하나 생성했습니다.
Python의 웹프레임워크 중 Flask를 사용해 간단한 API 서버를 만들겠습니다.
먼저 방금 생성한 EC2로 진입하여 Python 가상환경을 만든 후, Flask 라이브러리를 설치해줍니다.
$ pwd
/home/ubuntu/test
# 가상환경 생성
$ python3 -m venv .venv
# 가상환경 활성화
$ source .venv/bin/active
# pip 최신 버전 업데이트
(.venv) $ python -m pip install --upgrade pip
# Flask 설치
(.venv) $ pip install Flask
그리고 app.py
파일을 만들어 다음 코드를 입력합니다.
### app.py
from flask import Flask, jsonify
import uuid
version = "v1.0"
unique_id = uuid.uuid4()
app = Flask(__name__)
@app.route('/')
def hello():
return jsonify({"version": version, "id": unique_id}), 200
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)
python app.py
명령으로 서버를 실행하여 해당 서버 주소의 5000 포트로 접근을 해보면, 현재 서버가 제공하는 id와 version을 확인할 수가 있습니다.
id 값은 식별을 위해 유일한 값을 줄 수 있도록 하였습니다.
여기서 잠깐.. 배포 흐름을 생각해보면 업데이트 된 소스를 S3로 부터 가져와 반영 해야하고, 이때 Flask 서버에 재실행 명령이 필요합니다.
여러가지 방법이 있겠지만 우리는 Docker를 이용해 보도록 하겠습니다. 정말 간단합니다??
- 개발 환경에 따라 Docker의 사용 유무가 달라집니다.
- 제약이 없다면 건너뛰셔도 무방합니다 :)
- Docker 설치의 경우, 공식문서에 자세히 나와있으니 참고 바랍니다.
- OS 환경에 맞춰 Ubuntu 설치 문서를 참고해주세요.
Docker 설치 후, User 모드에서 docker 명령어에 대한 권한이 부여되지 않아 실행에 문제가 생길 수 있습니다.
그럴땐 아래 명령으로 해당 사용자에게 docker 명령어 권한을 부여해줍니다.
$ sudo usermod -a -G docker $USER
앞서 만든 코드를 컨테이너로 실해하기 위해선 먼저 Dockerfile로 이미지를 만들어주어야 합니다.
아래와 같이 파일을 작성해봅시다.
### Dockerfile
# pull official base image
FROM python:3.8-alpine
# set work directory
WORKDIR /usr/src/app
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# install dependencies
RUN python3 -m pip install --upgrade pip
RUN pip install Flask
# copy app.py
COPY app.py /usr/src/app/
CMD python3 app.py
공식 python 이미지를 가져와 필요한 환경 세팅을 하고, 소스를 복사하여 서버를 실행한다는 내용입니다.
본 시리즈에서는 Docker와 관련된 자세한 내용은 주제에 벗어나므로 생략하겠습니다.
Dockerfile을 이미지로 빌드하면 다음 화면을 볼 수 있습니다.
$ ls -al
total 20
drwxrwxr-x 3 ubuntu ubuntu 4096 Jul 21 09:10 .
drwxr-xr-x 5 ubuntu ubuntu 4096 Jul 21 09:10 ..
drwxrwxr-x 6 ubuntu ubuntu 4096 Jul 20 10:45 .venv
-rw-rw-r-- 1 ubuntu ubuntu 323 Jul 21 08:50 Dockerfile
-rw-rw-r-- 1 ubuntu ubuntu 282 Jul 20 11:20 app.py
# 이미지 빌드
$ docker build --tag deploy-test .
# 이미지 확인
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
deploy-test latest 094abde73094 3 minutes ago 47.9MB
python 3.8-alpine 5e8816ee5207 3 weeks ago 43.3MB
그리고 빌드한 이미지로 컨테이너를 올리면, 이전에 python 명령으로 실행한 것과 같은 결과를 얻을 수 있습니다.
# 컨테이너 실행
$ docker run -d -p 5000:5000 --restart always --name deploy-test deploy-test
# 컨테이너 상태 확인
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
acf3496afbbe deploy-test "/bin/sh -c 'python3…" 8 seconds ago Up 7 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp deploy-test
당연히 새로운 형태의 서버를 실행했기 때문에 id
값은 달라지겠죠?
추가로 docker run
명령을 실행할 때 사용한 옵션을 설명드리면,
컨테이너는 격리된 공간에 생성된 녀석이기 때문에 해당 인스턴스의 IP 주소로 컨테이너에 접근 하기 위해선 포트포워딩이 필요합니다. 그렇기 때문에 -p 5000:5000
으로 포트포워딩을 설정하였습니다.
또한, ASG을 통해 인스턴스 생성 시에 컨테이너 구동이 가능하도록 --restart always
옵션을 주고, --name deploy-test
로 컨테이너 명을, 마지막 입력값으로 앞서 만들어 놓은 이미지 명을 주었습니다.
CodeDeploy에 의해 작업을 부여받기 위해선 CodeDeploy Agent가 있어야 합니다.
AWS 공식 문석를 참고하면 금방 설치가 가능합니다!
CodeDeploy Agent 설치하기
모든 세팅이 완료 되었으니 Auto Scaling Group에서 사용 가능하도록 AMI 이미지를 만들어야 합니다.
EC2 콘솔창에서 인스턴스를 우클릭하여 [이미지 및 템플릿] - [이미지 생성] 을 선택합니다.
그리고 '이미지 생성' 화면으로 전환되면 이미지 이름 을 입력 후, [이미지 생성] 버튼을 클릭합니다.
서버 세팅이 완료된 AMI 이미지가 만들어 졌습니다!
ELB 생성은 AMI를 만드는 과정보다 더 쉽습니다.
콘솔창에서 [로드밸런서] - [Load Balancer 생성] 을 선택하고, Classic Load Balancer로 시작합니다.
Load Balancer 이름 을 입력하고, 앞서 EC2에서 설정한 웹서버 포트에 맞추어 5000 포트로 들어오는 트래픽을 그대로 EC2의 5000 포트로 보내주도록 리스너를 설정합니다.
그리고 로드밸런서에서 5000포트로 접근할 수 있도록 포트를 열어주어 ELB를 생성합니다.
ELB 준비 끝..!
이제 마지막 단계입니다.
준비된 AMI와 ELB를 ASG에 연동하여 서버를 생성해봅시다.
ASG(Auto Scaling Group) 기능을 활성화하기 위해선 ASG의 작업명세서 역할을 하는 시작 구성(Launch Configurations) 파트를 먼저 작성해주어야 합니다.
콘솔창의 Auto Scaling 영역에서 [시작 구성] - [시작 구성 생성] 버튼을 클릭하면,
아래와 같은 양식의 화면이 나오게 됩니다.
deploy-test-lc
deploy-test-ami
t2.micro
를 사용하겠습니다.ec2-deploy-test-role
기본 값(8GiB)
으로 선택하겠습니다.deploy-test-sg
위와 같은 구성으로 [시작 구성 생성] 버튼을 클릭하여 완료합니다.
생성된 시작 구성을 가지고 이제 진짜 마지막으로 오토스케일링 기능을 활성화 하도록 합시다.
먼저 [Auto Scaling Groups] - [Auto Scaling 그룹 생성] 으로 이동합니다.
1단계 - 시작 템플릿 또는 구성 선택 에서 오토스케일링 이름(deploy-test-asg
)을 입력하고, 앞서 만들었던 시작 구성(deploy-test-lc
)을 선택합니다.
2단계 - 설정 구성 에서는 사용될 VPC 와 Subnet 을 선택해줍니다.
3단계 - 고급 옵션 구성 에서 ASG로부터 생성되는 EC2 인스턴스를 ELB에 연결할지 결정합니다. 생성해 둔 ELB가 있으므로 기존 로드 밸런서에 연결 을 선택하고, ELB 유형에 따라 Classic Load Balancer에서 선택 을 선택하여 이전에 생성한 ELB를 찾아 지정해줍니다. deploy-test-lb
4단계 - 그룹 크기 및 조정 정책 구성 에서는 그룹 크기(개수)를 지정할 수 있습니다. 원하는 용량과 최소 용량을 2, 최대 용량을 4로 구성하겠습니다.
조정 정책 부분은 오토스케일링의 핵심 기능이긴 하지만, 본 시리즈에서는 다루지 않겠습니다.
나머지 단계들은 기본 값으로 설정하여 완료하면,
아래와 같이 오토스케일링이 생성된 걸을 확인할 수 있습니다.
그리고 오토스케일링이 생성됨과 동시에 연결된 EC2 인스턴스 2개가 생성되었습니다.
ELB를 확인해보면 오토스케일링에 의해 생성된 EC2 인스턴스가 ELB에도 연결된 것을 확인할 수가 있습니다.
그말인즉슨, 각 EC2 인스턴스에 API 서버가 구현되어서 ELB의 5000번 포트로 접근을 하면 id 와 version 정보를 나타내주겠죠?
(와~!) 실제로 ELB의 5000 포트로 접근하니 각 인스턴스 마다 정보를 보내주는 것을 확인할 수 있습니다.
지금까지 서비스 환경을 구축하는 내용을 알아보았습니다.
어려운 내용은 없어기에 금방 세팅 하셨으리라 생각합니다.
다음 글에서는 [무중단 배포 환경 구축하기] - 4. Jenkins 설정 및 Gitlab 연동 을 다루면서 배포 설정을 시작해보도록 하겠습니다.
감사합니다.