도커
프로젝트 생성
deploy_eb_docker
프로젝트를 생성한다.
$ mkdir deploy_eb_docker
$ cd deploy_eb_docker
$ pyenv virtualenv 3.5.2
$ pyenv local deploy_eb_docker
$ pip install django
$ django-admin startproject eb
$ mv eb django_app
$ pip freeze > requirements.txt
$ cp ~/deploy_ec2/.gitignore .
$ git init
# pycharm setting : 인터프리터, 소스설정
.conf-secret
폴더와 settings_common.json
, settings_local.json
파일을 생성하여 설정 키를 분리한다.
{
"django": {
"secret_key": "..."
}
}
settings.py
에 기본 설정을 한다.
# settings.py
import json
import os
DEBUG = True
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
ROOT_DIR = os.path.dirname(BASE_DIR)
CONF_DIR = os.path.join(ROOT_DIR, '.conf-secret')
CONF_FILE_COMMON = os.path.join(CONF_DIR, 'settings_common.json')
if DEBUG:
CONF_FILE = os.path.join(CONF_DIR, 'settings_local.json')
else:
CONF_FILE = os.path.join(CONF_DIR, 'settings_deploy.json')
config_common = json.loads(open(CONF_FILE_COMMON).read())
config = json.loads(open(CONF_FILE).read())
for key, key_dict in config_common.items():
if not config.get(key):
config[key] = {}
for inner_key, inner_key_dict in key_dict.items():
config[key][inner_key] = inner_key_dict
SECRET_KEY = config['django']['secret_key']
ALLOWED_HOSTS = []
eb
폴더 이름을 config
로 변경
# settings.py
"""
Django settings for 'WPS Deploy ElasticBeanstalk with Docker' project.
"""
# eb. > config.으로 변경
ROOT_URLCONF = 'config.urls'
WSGI_APPLICATION = 'config.wsgi.application'
# manage.py
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
# wsgi.py
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
TIP : Github에 푸시한 후, 커밋내용에서 설정 키들이 빠져있는지 꼭 확인한다.
도커 설정
간단한 실습
$ cd deploy_eb_docker
$ docker version
$ docker images
# 우분투 이미지가 없으면 설치
# docker pull ubuntu:16.04
# 우분투 이미지를 이용해 컨테이너가 열림
$ docker run --rm -it ubuntu:16.04 /bin/bash
# 서버세팅 진행
$ apt-get update
# 서버에서는 가상환경 사용할 필요가 없다.
$ apt-get install python3
$ apt-get install python3-pip
$ apt-get install nginx
# 장고 프로젝트 생성
$ cd /srv/
$ mkdir app
$ pip3 install django
$ pip3 install uwsgi
$ django-admin startproject eb
$ l
app/ eb/
$ cd eb/
$ python3 manage.py runserver
# 컨테이너 종료하면 작업내용이 사라진다.
$ exit
# 다시 접속하면 작업한 것들이 없다.
$ docker run --rm -it ubuntu:16.04 /bin/bash
Dockerfile 작성
FROM ubuntu:16.04
MAINTAINER dev@xyz.com
RUN apt-get -y update
RUN apt-get -y install python3
RUN apt-get -y install python3-pip
RUN apt-get -y install nginx
WORKDIR /srv
RUN mkdir app
WORKDIR /srv/app
$ Docker build -t eb .
# 설치 완료 후
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
eb latest 8e026adc20cd 8 seconds ago 510 MB
$ docker run --rm -it eb /bin/bash
$ root@29d752729486:/srv/app$ pip3 list
pip (8.1.1)
setuptools (20.7.0)
wheel (0.29.0)
Dockerfiles
내용이 바뀔때 마다, 패키지가 다시 설치되는 문제가 있다. 이를 해결하기 위해 _Dockerfile_base
를 만들어 분리한다.
FROM ubuntu:16.04
MAINTAINER dev@xyz.com
RUN apt-get -y update
RUN apt-get -y install python3
RUN apt-get -y install python3-pip
RUN apt-get -y install nginx
$ docker build -t eb-base . -f Dockerfile_base
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
eb latest 8e026adc20cd 12 minutes ago 510 MB
eb-base latest fef68ca2aa6b 12 minutes ago 510 MB
_Dockerfile_base
이미지를 사용하도록 Dockerfile
도 수정한다.
FROM eb-base
MAINTAINER dev@xyz.com
WORKDIR /srv
RUN mkdir app
WORKDIR /srv/app
$ Docker build -t eb .
# 기존에 Dockerfiles로 빌드했던 것이, none으로 사라짐
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
eb latest 284ce9f44402 12 seconds ago 510 MB
<none> <none> 8e026adc20cd 14 minutes ago 510 MB
# none은 삭제해준다.
$ docker rmi 8e026adc20cd
Dockerfile
에 pip 패키지 추가
FROM eb-base
MAINTAINER dev@xyz.com
COPY . /srv/app
WORKDIR /srv/app
RUN pip3 install -r requirements.txt
RUN pip3 install uwsgi
$ Docker build -t eb .
Removing intermediate container ae170aa08f73
$ docker run --rm -it eb /bin/bash
root@d54499949d68:/srv/app$ l
Dockerfile _Dockerfile_base django_app/ requirements.txt
root@d54499949d68:/srv/app$ pip3 list
Django (1.10.6)
pip (8.1.1)
setuptools (20.7.0)
uWSGI (2.0.14)
wheel (0.29.0)
Dockerfile
에 Django 서버실행 코드 추가
FROM eb-base
MAINTAINER dev@xyz.com
COPY . /srv/app
WORKDIR /srv/app
RUN pip3 install -r requirements.txt
RUN pip3 install uwsgi
WORKDIR /srv/app/django_app
CMD ["python3", "manage.py", "runserver", "0:8080"]
$ Docker build -t eb .
# local의 4567포트를 Docker의 8080 포트와 연결
$ docker run -p 4567:8080 eb
Tip : 이미지 삭제
$ docker stop $(docker ps -a -q)
# Delete all docker containers
$ docker rm $(docker ps -a -q)
# Delete all docker images
$ docker rmi $(docker images -q)
# Delete name docker images force
$ docker rmi -f $(docker images --filter "dangling=true" -q)
Tip : Dokcer 자동완성
$ brew search docker
$ brew install docker-completion
uWsgi 설정
.conf
에 uwsgi-app.ini
파일을 작성한다.
[uwsgi]
chdir = /srv/app/django_app
module = config.wsgi:application
;가상환경을 사용하지 않으므로 삭제
;home = /home/ubuntu/.pyenv/versions/deploy_ec2
;uid = www-data
;gid = www-data
socket = /tmp/app.sock
chmod-socket = 666
;chown-socket = www-data:www-data
enable-threads = ture
master = true
vacuum = true
pidfile = /tmp/app.pid
logger = file:/tmp/uwsgi.log
logger = internalservererror file:/tmp/uwsgi500.log
Dockfile
에 uwsgi 설정을 연결
FROM eb-base
MAINTAINER dev@xyz.com
COPY . /srv/app
WORKDIR /srv/app
RUN pip3 install -r requirements.txt
RUN pip3 install uwsgi
COPY .conf/uwsgi-app.ini /etc/uwsgi/sites/app.ini
$ Docker build -t eb .
$ docker run --rm -it -p 4040:8080 eb
root@17abe9e49232:/srv/app$ uwsgi --http :8080 --chdir /srv/app/django_app/ -w config.wsgi
Dockerfile 분리
uwsgi와 nginx를 계속 설치해 오래 걸리니 분리한다.
_Dockerfile_base
파일을 수정한다.
FROM ubuntu:16.04
MAINTAINER dev@xyz.com
RUN apt-get -y update
RUN apt-get -y install python3
RUN apt-get -y install python3-pip
RUN apt-get -y install nginx
RUN pip3 install django
RUN pip3 install uwsgi
$ docker build -t eb-base . -f _Dockerfile_base
Dockerfile
파일도 수정한다.
FROM eb-base
MAINTAINER dev@xyz.com
COPY . /srv/app
WORKDIR /srv/app
COPY .conf-secret/uwsgi-app.ini /etc/uwsgi/sites/app.ini
$ Docker build -t eb .
$ docker run --rm -it -p 4040:8080 eb
root@17abe9e49232:/srv/app$ uwsgi --http :8080 --chdir /srv/app/django_app/ -w config.wsgi
root@b087c675ad47:/srv/app$ uwsgi --http :8080 -i /etc/uwsgi/sites/app.ini
.gitignore
파일에 Dockerfile 추가한다.
$ vi .gitignore
_Dockerfile*
로그를 확인해본다.
# 새로운 터미널에서 접속
$ docker ps
$ docker exec -it b087c675ad47 /bin/bash
root@b087c675ad47:/srv/app$ cd /tmp/
root@b087c675ad47:/tmp$ cat uwsgi.log
# 새로고침 후 다시 확인
root@b087c675ad47:/tmp$ cat uwsgi.log
nginx 설정
.conf
에 nginx.conf
파일을 작성한다.
user root;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
server_names_hash_bucket_size 512;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
#mail {
# # See sample authentication script at:
# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
# # auth_http localhost/auth.php;
# # pop3_capabilities "TOP" "USER";
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
# server {
# listen localhost:110;
# protocol pop3;
# proxy on;
# }
#
# server {
# listen localhost:143;
# protocol imap;
# proxy on;
# }
#}
.conf
에 nginx-app.conf
파일을 작성한다.
server {
listen 4040;
server_name localhost ec2-13-124-39-197.ap-northeast-2.compute.amazonaws.com ec2.devlim.net devlim.net;
charset utf-8;
client_max_body_size 128M;
location / {
uwsgi_pass unix:///tmp/app.sock;
include uwsgi_params;
}
}
Dockerfile
FROM eb-base
MAINTAINER dev@xyz.com
COPY . /srv/app
WORKDIR /srv/app
COPY .conf/uwsgi-app.ini /etc/uwsgi/sites/app.ini
COPY .conf/nginx.conf /etc/nginx/nginx.conf
COPY .conf/nginx-app.conf /etc/nginx/sites-available/app.conf
RUN ln -s /etc/nginx/sites-available/app.conf /etc/nginx/sites-enabled/app.conf
$ docker build -t eb .
$ docker run --rm -it -p 5050:4040 eb
root@b620284a56e1:/etc/nginx$ nginx
root@b620284a56e1:/etc/nginx$ uwsgi --ini /etc/uwsgi/sites/app.ini
supervisor
uwsgi와 nginx중 프로세스가 하나라도 죽으면 안되니, supervisor를 사용한다. 우리가 지정한 프로그램이 죽으면 다시 실행해준다.
# nginx.conf
# 데몬이 아니라 프롬프트에서 작동할 수 있도록 한다.
daemon off;
supervisor-app.conf
생성하여 작성한다.
[program:uwsgi]
command = uwsgi --ini /etc/uwsgi/sites/app.ini
[program:nginx]
command = nginx
_Dockerfile_base
수정
FROM ubuntu:16.04
MAINTAINER dev@xyz.com
RUN apt-get -y update
RUN apt-get -y install python3
RUN apt-get -y install python3-pip
RUN apt-get -y install nginx
RUN apt-get -y install supervisor
RUN pip3 install django
RUN pip3 install uwsgi
$ docker build -t eb-base . -f _Dockerfile_base
Dockerfile
수정
FROM eb-base
MAINTAINER dev@xyz.com
COPY . /srv/app
WORKDIR /srv/app
COPY .conf/uwsgi-app.ini /etc/uwsgi/sites/app.ini
COPY .conf/nginx.conf /etc/nginx/nginx.conf
COPY .conf/nginx-app.conf /etc/nginx/sites-available/app.conf
COPY .conf/supervisor-app.conf /etc/supervisor/conf.d/
RUN ln -s /etc/nginx/sites-available/app.conf /etc/nginx/sites-enabled/app.conf
EXPOSE 4040
CMD supervisord -n
$ docker build -t eb .
$ docker run --rm -it -p 5050:4040 eb
Dockerfile 통합
하나의 Dockerfile
로 실행되도록 합친다.
# _Dockerfile_base에서 ubuntu로 변경
FROM ubuntu:16.04
MAINTAINER dev@xyz.com
COPY . /srv/app
WORKDIR /srv/app
RUN apt-get -y update
RUN apt-get -y install python3
RUN apt-get -y install python3-pip
RUN apt-get -y install nginx
RUN apt-get -y install supervisor
# requirements 파일을 이용해 장고 설치
RUN pip3 install -r requirements.txt
RUN pip3 install uwsgi
COPY .conf/uwsgi-app.ini /etc/uwsgi/sites/app.ini
COPY .conf/nginx.conf /etc/nginx/nginx.conf
COPY .conf/nginx-app.conf /etc/nginx/sites-available/app.conf
COPY .conf/supervisor-app.conf /etc/supervisor/conf.d/
RUN ln -s /etc/nginx/sites-available/app.conf /etc/nginx/sites-enabled/app.conf
EXPOSE 4040
CMD supervisord -n
$ docker build -t eb .
$ docker run --rm -it -p 5050:4040 eb
EB
개념
- 엘라스틱 빈이 도커를 자동으로 관리
- 애플리케이션은 프로젝트 단위를 의미
- CLI 이용
$ cd deploy_eb_docker
$ pip install awsebcli
$ eb init
(default is 3): 10
Enter Application Name
(default is "deploy_eb_docker"):
ERROR: Elastic Beanstalk could not find any platforms. Ensure you have the necessary permissions to access Elastic Beanstalk.
권한 에러가 나므로 IAM에 가서 권한을 준다.
User > 유저선택 > Add permissions > Attach existing > elasticbeanstalkFullAccess 체크
해서 권한을 추가한다.
$ eb init
(default is 3): 10
Enter Application Name
(default is "deploy_eb_docker"): WPS deploy EB with Docker
Select a platform version.
1) Docker 1.12.6
2) Docker 1.11.2
3) Docker 1.9.1
(default is 1):
Do you want to set up SSH for your instances?
(Y/n): y
Select a keypair.
1) wps-deploy
2) wps-deploy-reivew
3) [ Create new KeyPair ]
(default is 2): 1
프로젝트를 확인하면 .elasticbeanstalk
폴더가 생긴다.
$ eb create
Enter Environment Name
(default is WPSdeployEBwithDocker-dev): wps-eb
Enter DNS CNAME prefix
(default is wps-eb):
Select a load balancer type
1) classic
2) application
(default is 1):
2.0+ Platforms require a service role. We will attempt to create one for you. You can specify your own role using the --service-role option.
Type "view" to see the policy, or just press ENTER to continue:
# ...
ERROR: Create environment operation is complete, but with errors. For more information, see troubleshooting documentation.
AWS elasticbeanstalk 대시보드에 접속하면 한 개가 생성된 것을 확인할 수 있다.
Dockerfile.aws.json
파일을 생성하고 작성한다.
{
"AWSEBDockerrunVersion": 2,
"volumes": [
{
"name": "wps-eb",
"host": {
"sourcePath": "var/app/current/django_app"
}
}
],
"containerDefinitions": [
{
"name": "wps-eb",
"essential": true,
"memory": 512,
"portMappings": [
{
"hostPort": 80,
"containerPort": 4040
}
]
}
]
}
$ git commit -m "Your message"
# 커밋된 파일만 배포하므로 eb deploy 전에
# 변경사항을 먼저 commit
$ eb deploy # = scp -i -r
# ...
$ eb open
AWS EB Dashboard에 서버가 생성된 것을 확인한 후 실행해보면, Internal Server Error 발생한다.
에러를 확인하기 위해 다음과 같이 한다.
$ eb logs
# 위의 로그가 너무 길어 보기 힘드니,
# ssh 접속해서 로그 확인
$ eb ssh
[ec2-user@ip-172-31-5-219 ~]$ cd /var/log
[ec2-user@ip-172-31-5-219 log]$ ls
[ec2-user@ip-172-31-5-219 log]$ vi eb-activity.log
# 위의 방법도 보기 힘드니,
# eb 도커 이미지를 실행해 확인
[ec2-user@ip-172-31-5-219 log]$ sudo docker exec -it `sudo docker ps --no-trunc -q | head -n 1` /bin/bash
root@261c6c40d5f0:/srv/app$ cd /tmp/
root@261c6c40d5f0:/tmp$ vi uwsgi.log
FileNotFoundError: [Errno 2] No such file or directory: '/srv/app/.conf-secret/settings_common.json'
.gitignore
파일에 관리되고 있어 .conf-secret
파일을 찾지 못해 에러가 발생한다. 해결하기 위해 .ebignore
파일을 만든다. .ebignore
파일에 있는 파일은 .gitignore
에 있어도 무시하게된다.
!.conf-secret/
다시 실행해본다.
$ git commit -m ".ebignore 추가"
$ eb deploy
$ eb open
allowd 호스트를 찾을 수 없다는 에러가 발생하면, 수정하여 다시 배포한다. 정상 작동하는 것을 확인 할 수 있다.