2018.11.06 - Deploy(4) - AWS Elastic Beanstalk

3 분 소요

Elastic Beanstalk Docs

Elastic Beanstalk

Elastic Beanstalk 소개

aws Elastic Beanstalk를 사용하면 로컬 서버에서 웹 어플리케이션을 개발, 배포, 관리하는 것과 달리 작성한 코드를 업로드하기만 하면 자동으로 로드 밸런싱 애플리케이션 상태 모니터링 등 배포와 관리를 자동으로 처리할 수 있다.

한마디로 말해 AWS에서 사용하는 다양한 서비스들을 묶어주는 역할을 한다.

elasticbeanstalk

아래의 과정을 통해 Elastic Beanstalk를 설치하고 생성해보자.

  • eb cli 설치
$ pip install awsebcli

설치 후에 requirement.txt에 추가해준다. requirement.txt폴더에 추가할 때 영문순으로 정렬하는 습관을 들이도록하자. 나중에 찾을 때 고생한다.

Iam 생성

AWS에서 EB(Elasticbeanstalk)용 Iam을 하나 더 만들어 준다.

  • 사용자 추가(ex: EBUser)
  • 기존 정책 연결
    provies full access to AWS Elastic
    
  • eb 생성
$ eb init --profile eb

Elastic Beanstalk를 시작하는데 실행하는 키 값이 .aws에 있는 [eb]값을 가져와 실행한다.

Dockerfile에 있는 RUN 1번이 image layer의 1번이다. 따라서 작업 처리 속도를 올려주기 위해 최대한 최적화를 해준다.(RUN을 최대한 줄여 쓰기) 그리고 반복 되는 작업들을 Dockerfile.base를 만들어 따로 관리해준다. 왜냐하면 매번 실행때마다 반복해서 설치할 필요가 없기 때문. 주로 바뀌는 부분을 Dockerfile에 두고 관리한다.

$ docker build -t eb-docker:base -f Dockerfile.base .

docker login

docker에 접속하기 위해 login을 해줘야한다. 명령어는 다음과 같고 옵션들이 있다.

$ docker login [OPTION] [SERVER]
Name, Shorthand Description
–password, –p Password
–password-stdin Take the password from stdin
–username, -u Username

docker hub에 push

docker hub에는 전체 이미지를 올리는 것이 아니다. 한개의 프라이빗 이미지만을 올릴 수 있다. 베이스 이미지만을 올리고 작업한다. 소스코드와 시크릿키가 있는 파일을 올리면 개인정보가 유출 될 수 있다. 따라서 dockerfile.base의 내용만 올려준다.

먼저 생성된 docker image와 docker hub를 이어주어야 한다.

docker tag <REPOSITORY>:<TAG> <docker hub ID>/<docker hub REPO>:<TAG>

용량이 작을 수록 배포의 시간이 줄어든다. 따라서 최대한 docker image의 용량을 줄이도록 최적화를 시켜야한다.

우리가 만든 docker image를 docker hub에 업로드한다. git push랑 비슷하다고 생각하면 된다. 명령어는 다음과 같다.

$ docker push <dockerhub Username>/<docker image>:<image Tag>

Dockerfile에서 맨위에 FROM에 mongkyo/eb-docker:base로 바꿔준다.

eb deploy와 deploy.sh

docker hub에 push를 한 후에 eb deploy를 실행한다. eb deploy명령어는 Elastic Beanstalk를 이용해서 deploy하는 명령어이다. 이 명령어는 Staged(git add가 되어있는)상태에 있는 파일들만 읽어와서 deploy해준다. 따라서 git add 명령어를 실행하고 나서 아래의 명령어를 실행해준다.

$ eb deploy --profile [credentials Key Name]

이 명령어에서 --profile [credentials Key Name]은 우리가 설정해놓은 .aws폴더안의 credentials파일에 들어있는 key를 지정해서 사용해준다는 것을 의미한다.

위의 명령어를 통해서 deploy를 할 경우에 문제가 발생하는데, .gitignore에 들어있는 파일들은 commit이 되지 않기 때문에 직접 git add -f [폴더 or 파일] 명령어를 사용해서 Staged해줘야 한다. 하지만 이렇게 강제적으로 올리는 파일들은 기본적으로 git에 추가가되면 안되는 내용들이 있기때문에 deploy를 실행하고 바로 git reset HEAD [폴더 or 파일]명령어로 빼줘야한다. 이 과정을 코드로 옮기면 다음과 같다

$ git add -f .secrets/
$ eb deploy --profile eb --staged
$ git reset HEAD .secrets

이러한 과정에서 실수를 하여 잘못 commit, push를 할 수도있고 이러한 일을 반복적으로하기 귀찮기(?)때문에 위에 3개의 코드를 자동화시키는 파일을 만들어준다. 이 파일이 deploy.sh파일이다. ROOT 폴더안(Dockerfile과 같은 위치)에 deploy.sh파일을 만들어준다. 그리고 그 안에 아래의 내용들을 추가해 준다.

# deploy.sh
#!/usr/bin/env bash
git add -f .secrets/
eb  deploy --profile eb --staged
git reset HEAD .secrets/

그리고 이 파일을 읽을 수 있는 권한을 chmod 명령어를 사용해서 바꿔주고 실행시켜본다.

$ chmod 755 deploy.sh
$ ./deploy.sh

그리고 터미널에서 파일을 읽을 수 있는 권한을 준다. (권한 없이도 실행가능하다. 명령어는 sh deploy.sh)

권한을 주고 그 다음 실행시켜본다. 그럼 terminal에 다음과 같이 나타단다.

deploy.sh 실행

그리고 deploy된 웹페이지를 보기위해서 eb open명령어를 실행해주면 된다.

$ eb open

eb open 명령어 실행

Django Log

공식문서에 나와있는 예제를 입력해보자

# import the logging library
import logging

# Get an instance of a logger
logger = logging.getLogger(__name__)

def my_view(request, arg1, arg):
    ...
    if bad_mojo:
        # Log an error message
        logger.error('Something went wrong!')

handlers는 log가 들어왔을때 그 log를 어떻게 처리할지에 대한 로직을 가지고 있다. log를 기록하는 주체가 여러개일때 같은 동작을 하고싶은경우 동작만 정의하는 handler를 따로 만들어주면 된다. 이 handlers안에 file이라는 핸들러는 자신에게 어떠한 로그가 전달되면 logging.FileHandler라는 handler가 입력 되면 file형태로 기억된다. Debug level 이상의 log를 class에 입력된 handler를 통해서 filename의 경로에 입력한다는 것이다. 실제 동작하는 logger는 django 패키지에서 시작한 log의 경우에는 debug부터 기록하고 handler는 리스트로 파일을 지정한다.

log의 기록은 production의 경우에만 필요하다. dev의 경우에는 terminal에서 확인이 가능하기 때문이다. production.py에 log의 내용을 적어준다.

LOG_DIR = os.path.join(ROOT_DIR, '.log')
if not os.path.exits(LOG_DIR)
    os.makedirs(LOG_DIR, exist_ok=True)
LOGGING = {
	'version': 1,
	'handlers': {
	    'file': {
	        'class': 'logging.FileHandler',
	        'level': 'DEBUG',
	        'filename': os.path.join(LOG_DIR, 'django.log'),
	    }
	},
	'loggers': {
	    'django': {
	        'handlers': ['file'],
	        'level': 'DEBUG',
	        'propagate': True,
	    }
	}
}

.log파일은 .gitignore에 포함시킬것이므로 eb open에 포함되지 않는다. 따라서 위에서 파일의 존재유무를 확인하고 만들어주는 로직을 넣어서 eb open 이후에 파일 생성이 되게 해준다.(github에 포함시키지 않기위한 장치)

에러가 언제 쌓였는지 알기 위해서는 log에 format을 지정해준다. 그리고 RotatinFileHandler는 지정된 용량(maxBytes옵션)이 넘어가면 다른파일에 저장되게 하는 handler다.

보안 그룹 설정

어딘가에 존재하는 RDS에 Inbound로 나의 로컬 환경과 EC2를 RDS Security Group에 추가로 지정해주어야한다. 이 방법은 RDS의 인바운드 규칙 편집에 SecurityGroup for ElasticBeanstalk environment의 그룹ID를 추가해준다. 이 그룹ID를 넣으면 해당하는 보안그룹을 갖는 모든 것들에 접속 권한을 준다.

인바운드 규칙 편집

혹시 몰라서 소스에 IP주소를 일부 삭제하고 그룹 아이디도 지웠다. sg-라고 입력하면 자동완성이 나오는데 직접 입력하지말고 자동완성을 사용해서 입력하도록 하자! 오타의 위험을 줄일 수 있다.