dockerfile 분리하기 (base, local, dev, production)
25 Oct 2018 | Docker패스트캠퍼스 웹 프로그래밍 수업을 듣고 중요한 내용을 정리했습니다.
개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
docker 기능별로 분리
Dockerfile.base
FROM python:3.6.5-slim
MAINTAINER zehye.01@gmail.com
RUN apt -y update && apt -y dist-upgrade
RUN apt -y install build-essential
RUN apt -y install nginx supervisor
# 로컬의 requirments.txt파일을 /srv에 복사 후 pip install 실행
# (build하는 환경에 requirments.txt가 있어야함!)
COPY ./requirements.txt /srv/
RUN pip install -r /srv/requirements.txt
Dockerfile.local
FROM eb-docker-study:base
MAINTAINER zehye.01@gmail.com
ENV BUILD_MODE local
ENV DJANGO_SETTGINS_MODULE config.settings.${BUILD_MODE}
COPY . /srv/project
WORKDIR /srv/project/app
CMD python manage.py runserver 0:8000
Dockerfile.dev
FROM eb-docker-study:base
MAINTAINER zehye.01@gmail.com
ENV BUILD_MODE dev
ENV DJANGO_SETTINGS_MODULE config.settings.${BUILD_MODE}
# requirements.txt를 새로 설치하는 이유는 build.py에서 build_dev를 새로 만들었는데
# requirements.txt를 만들어주는 명령어가 다르다 (requirements.txt -- dev)
# local과 production에서는 최소한의 패키지만을 설치하지만 dev에서는 최대로 설치를 하게 된다.
# 따라서 build_dev에서 만든 패키지는 base이미지에 추가가 되어야 하기 때문에 새로 COPY해줘야 한다.
COPY ./requirements.txt /srv/
RUN pip install -r /srv/requirements.txt
COPY . /srv/project
# nginx설정파일들 복사 및 enabled로 링크
RUN cp -f /srv/project/.config/${BUILD_MODE}/nginx.conf \
/etc/nginx/nginx.conf && \
cp -f /srv/project/.config/${BUILD_MODE}/nginx_app.conf \
/etc/nginx/sites-available/ && \
rm -rf /etc/nginx/sites-enabled/* && \
ln -sf /etc/nginx/sites-available/nginx_app.conf \
/etc/nginx/sites-enabled/
# supervisor설정 복사
RUN cp -f /srv/project/.config/${BUILD_MODE}/supervisor.conf \
/etc/supervisor/conf.d/
# supervisord 실행
CMD supervisord -n
nginx 설정파일들을 복사할 경우 nginx와 nginx_app의 오타가 자주 발생할 수 있는데, 잘못 작성하게 된다면 server block
에러가 뜬다. 이는 블럭에 있으면 안되는 무언가가 있는 의미로, 설정 파일 내 잘못된 것이 들어가있다고 생각하면 된다. 만약 이 외의 에러를 발견하게 된다면 docker exec로 들어가 하나씩 확인해보는게 좋다.
Dockerfile.production
FROM eb-docker-study:base
MAINTAINER zehye.01@gmail.com
ENV BUILD_MODE production
ENV DJANGO_SETTINGS_MODULE config.settings.${BUILD_MODE}
COPY . /srv/project
# Nginx 설정파일들 복사 및 enabled로 링크
RUN cp -f /srv/project/.config/${BUILD_MODE}/nginx.conf \
/etc/nginx/nginx.conf && \
cp -f /srv/project/.config/${BUILD_MODE}/nginx_app.conf \
/etc/nginx/sites-available/ && \
rm -rf /etc/nginx/sites-enabled/* && \
ln -sf /etc/nginx/sites-available/nginx_app.conf \
/etc/nginx/sites-enabled/
# supervisor설정 복사
RUN cp -f /srv/project/.config/${BUILD_MODE}/supervisor.conf \
/etc/supervisor/conf.d/
# supervisord실행
CMD supervisord -n
.config/dev/nginx.conf
user root;
daemon off;
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 64;
# 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;
# }
#}
.config/dev/nginx_app.conf
server {
# 80번 포트로부터 request를 받는다
listen 80;
# 도메인명이 'localhost'인 경우에 해당
server_name localhost;
# 인코딩 방식 지정
charset utf-8;
# request/response의 최대 사이즈 지정(기본값이 매우 작음)
client_max_body_size 128M;
# '/' (모든 URL로의 연결에 대해)
location / {
# uwsgi와의 연결을 unux소켓 (/tmp/app.sock 파일)을 사용한다
uwsgi_pass unix:///tmp/app.sock;
include uwsgi_params;
}
location /static/ {
alias /srv/project/.static/;
}
location /media/ {
alias /srv/project/.media/;
}
}
.config/dev/supervison.conf
[program:uwsgi]
command=uwsgi --ini /srv/project/.config/dev/uwsgi.ini
[program:nginx]
command=nginx
supervisor가 uwsgi를 실행하는 방법에 변화가 있다. 원래는 pipenv를 사용했지만, 파이썬 이미지 안에서 pip, 파이썬 각각 한개씩 사용하기 때문에 uwsgi라고 실행을 해준다. 그리고 맨 뒤에 socket.ini가 붙은 이유도 우리가 http와 socket을 분리하는 것은 연습용이니 바로 uwsgi.ini를 붙여줬다.
settings/wsgi/dev.py
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.dev")
application = get_wsgi_application()
settings/wsgi/production.py
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
application = get_wsgi_application()
.config/dev/uwsgi.ini
[uwsgi]
;파이썬 프로젝트로 change directory
chdir = /srv/project/app
;가상환경 경로
;home = $(VENV_PATH)
;chdir로 바꾼 파이썬 프로젝트에서 wsgi모듈의 경로(path가 아닌 파이썬 모듈 경로)
module = config.wsgi.dev:application
;socket을 사용해 연결을 주고받음
socket = /tmp/app.sock
;uWSGI가 종료되면 자동으로 소켓파일을 삭제
vacuum = true
;Log
logto = /var/log/uwsgi.log
위와 같이 settings의 wsgi를 파이썬 리팩토링을 한 후 dev와 production을 각각 바꿔주지 않으면 setdefault
로 설정해주는 내용들이 uwsgi.ini에서 쓰는 module = config.wsgi.dev:application
즉, wsgi 어플리케이션과 파이썬 어플리케이션과 연결이 될 때 어떤 내용을 쓸건지가 중요한데, 지금 uwsgi.ini에서는 dev와 연결한다고 되어있으니 settings/wsgi/dev와 연결이 되어진다.
그리고 추가적으로 .config에 production을 추가한다. production은 dev에 들어간 파일들과 내용은 같지만 supervisor.conf와 uwsgi.ini에서 dev를 production으로 바꿔주기만 하면 된다.
settings/dev.py
from .base import *
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
WSGI_APPLICATION = 'config.wsgi.dev.application'
# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/
STATIC_URL = '/static/'
settings/production.py
그러고 production의 도커 이미지를 만들고 docker run을 하기 전에 DEBUG = False와 ALLOWED_HOSTS=[‘localhost’,]설정을 해준다.
DEBUG가 False일 경우 일단 ALLOWED_HOSTS가 없다고 처리가 되기 때문에 localhost를 설정해준다.
from .base import *
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
WSGI_APPLICATION = 'config.wsgi.production.application'
# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/
STATIC_URL = '/static/'