Front 코드 배포
프론트에서 vue.js
작업한 내용을 웹 서버에 올리면, 검색엔진이 긁어갈 때 껍데기만 가져가게 된다. 이런 문제를 극복하기 위해 node
를 사용해 ServerSideRendering(SSR)을 한다.
우리는 SSR을 제외하고 하나의 서버에서 backend
프로젝트와 forntend
프로젝트를 배포하는 법을 실습한다.
Django 프로젝트 설정
$ mkdir deploy
$ cd deploy
$ mkdir docker-nginx-node-proxy
$ cd docker-nginx-node-proxy
$ pyenv virtualenv 3.5.2 docker-nginx-node-proxy
$ pyenv local docker-nginx-node-proxy
$ git init
$ cp ~/fastcampus/projects/django/instagram-api/.gitignore .
$ vi .gitignore
# https://www.gitignore.io/ 에서 node 내용 추가
$ pip install django
$ pip install --upgrade pip
$ pip freeze > requirements.txt
$ django-admin startproject mysite
$ mv mysite django_app
$ py .
# 인터프리터 설정
# config로 이름 변경
# settings.py
ALLOWED_HOSTS = [
"*",
]
Dockerfile 및 .conf 설정
기본 프로젝트에서 복사
스크립트
도커에서 이미지를 생성하기위해 시간이 오래걸리므로 스크립트를 작성해 자동화한다.
1. Dockerfile 생성을 위한 텍스트 설정파일 생성
.conf/docker/00_template.docker
FROM {from_image}
MAINTAINER {maintainer}
{base}
{extra}
.conf/docker/01_template.docker
COPY . /srv/app
RUN apt-get -y update && \
apt-get -y install python3 && \
apt-get -y install python3-pip && \
apt-get -y install nginx && \
apt-get -y install supervisor
WORKDIR /srv/app
RUN pip3 install -r requirements.txt && \
pip3 install uwsgi
.conf/docker/02_extra.docker
COPY .conf/uwsgi-app.ini /etc/uwsgi/sites/app.ini
COPY .conf/nginx-app.conf /etc/nginx/sites-available/app
COPY .conf/nginx.conf /etc/nginx/nginx.conf
COPY .conf/supervisor-app.conf /etc/supervisor/conf.d/
RUN ln -s /etc/nginx/sites-available/app /etc/nginx/sites-enabled/app
WORKDIR /srv/app/django_app
EXPOSE 4567
CMD ["supervisord", "-n"]
2. dockerfile을 생성하는 스크립트
build.py
import argparse
import os
# Const
import sys
MODE_BASE = 'base'
MODE_DEBUG = 'debug'
MODE_PRODUCTION = 'production'
IMAGE_BASE = 'front-base'
IMAGE_DEBUG = 'front-debug'
IMAGE_PRODUCTION = 'front'
MAINTAINER = 'dev@abc.com'
DOCKERFILE_BASE = 'Dockerfile.base'
DOCKERFILE_DEBUG = 'Dockerfile.debug'
DOCKERFILE_DOCKERHUB = 'Dockerfile'
# ArgumentParser
parser = argparse.ArgumentParser(description='Build command')
parser.add_argument('-m', '--mode', type=str, default=MODE_DEBUG)
args = parser.parse_args()
# Paths
ROOT_DIR = os.path.dirname(__file__)
CONF_DIR = os.path.join(ROOT_DIR, '.conf')
CONF_DOCKER_DIR = os.path.join(CONF_DIR, 'docker')
# Docker conf file
dockerfile_template = open(os.path.join(CONF_DOCKER_DIR, '00_template.docker')).read()
dockerfile_base = open(os.path.join(CONF_DOCKER_DIR, '01_base.docker')).read()
dockerfile_extra = open(os.path.join(CONF_DOCKER_DIR, '02_extra.docker')).read()
if args.mode == MODE_BASE:
dockerfile = dockerfile_template.format(
from_image='ubuntu:16.04',
maintainer=MAINTAINER,
base=dockerfile_base,
extra=''
)
filename = DOCKERFILE_BASE
elif args.mode == MODE_DEBUG:
dockerfile = dockerfile_template.format(
from_image=IMAGE_BASE,
maintainer=MAINTAINER,
base='',
extra=dockerfile_extra
)
filename = DOCKERFILE_DEBUG
elif args.mode == MODE_PRODUCTION:
dockerfile = dockerfile_template.format(
from_image='ubuntu:16.04',
maintainer=MAINTAINER,
base=dockerfile_base,
extra=dockerfile_extra
)
filename = DOCKERFILE_PRODUCTION
else:
sys.exit('Mode invalid')
with open(os.path.join(ROOT_DIR, filename), 'wt') as f:
f.write(dockerfile)
실행
아래와 같이 실행하면 Dockerfile
, Dockerfile.base
, Dockerfile.debug
파일이 생성된다.
$ python build.py -m=base
$ python build.py -m=debug
$ python build.py -m=production
# 정상적으로 파일이 생성된 것을 확인 후,
# Dockerfile.* 을 gitignore에 추가한다.
$ vi .gitignore
3. docker build 추가
build.py
import subprocess
# Docker conf file
# ...
if args.mode == MODE_BASE:
dockerfile = dockerfile_template.format(
# ...
)
filename = DOCKERFILE_BASE
imagename = IMAGE_BASE
elif args.mode == MODE_DEBUG:
dockerfile = dockerfile_template.format(
# ...
)
filename = DOCKERFILE_DEBUG
imagename = IMAGE_DEBUG
elif args.mode == MODE_PRODUCTION:
dockerfile = dockerfile_template.format(
# ...
)
filename = DOCKERFILE_PRODUCTION
imagename = IMAGE_PRODUCTION
else:
sys.exit('Mode invalid')
with open(os.path.join(ROOT_DIR, filename), 'wt') as f:
f.write(dockerfile)
build_command = 'docker build . -t {imagename} -f {filename}'.format(
imagename=imagename,
filename=filename
)
print('Docker build command: {}'.format(build_command))
subprocess.run(build_command, shell=True)
실행
$ python build.py -m=base
# docker 이미지 생성 확인 후
$ docker images
front-base latest a36e8597fc34 48 minutes ago 577 MB
$ python build.py -m=debug
$ docker images
front-debug latest 7562cffe5f54 47 minutes ago 577 MB
$ docker run --rm -it -p 8080:4567 front-debug
http://localhost:8080/ 접속해서 Django 페이지가 작동하는지 확인한다.
Vue.js
설치
$ cd ..
$ l
total 0
drwxr-xr-x 4 limhm staff 136B 4 6 16:53 .
drwxr-xr-x@ 14 limhm staff 476B 4 6 15:21 ..
drwxr-xr-x 15 limhm staff 510B 4 6 18:06 docker-nginx-node-proxy
$ npm install --global vue-cli
$ vue init nuxt/starter mysite
$ mv mysite front-site
$ l
total 0
drwxr-xr-x 4 limhm staff 136B 4 6 16:53 .
drwxr-xr-x@ 14 limhm staff 476B 4 6 15:21 ..
drwxr-xr-x 15 limhm staff 510B 4 6 18:06 docker-nginx-node-proxy
drwxr-xr-x 19 limhm staff 646B 4 6 17:04 front-site
$ cd front-site
# 자동으로 생성된 파일이 많은데 .gitignore 파일도 있다.
# https://www.gitignore.io/ 에서 macOS 추가
$ vi .gitignore
$ git add -A
$ git commit -m "first commit"
# remote repository에 연결
$ git push -u origin master
# https://github.com/pinstinct/front-deploy 접속하면
# 빌드 방법이 나온다.
$ npm install
$ npm run dev
# http://localhost:3000/ 에서 작동 확인
# 서버 실행
$ npm run build
$ npm start
# frontend에서 npm start까지 다 된다는 가정하에서 작업한다.
nginx reverse proxy
front 코드를 프로젝트에 추가
$ cd docker-nginx-node-proxy
$ git clone https://github.com/pinstinct/front-deploy.git front
$ vi .gitignore
# front/ 추가
$ git st
# .gitignore가 잘됐나 확인
ngnix 설정에 front server 추가
.conf/nginx-app.conf
server {
listen 4567;
server_name front.localhost;
charset utf-8;
client_max_body_size 128M;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:3000/;
proxy_redirect off;
}
gzip on;
gzip_comp_level 2;
gzip_proxied any;
gzip_min_length 1000;
gzip_disable "MSIE [1-6]\." gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
}
Dockerfile에 nodejs 설정 추가
.conf/docker/01_base2.docker
RUN apt-get -y install curl
RUN curl -sL https://deb.nodesource.com/setup_6.x | bash -
RUN apt-get -y install nodejs
.conf/docker/02_extra.docker
COPY . /srv/app
WORKDIR /srv/app/front
RUN npm install
RUN npm run build
.conf/supervisor-app.conf
[program:node]
command = npm start --prefix /srv/app/front
build.py
MODE_BASE2 = 'base2'
IMAGE_BASE2 = 'front-base2'
DOCKERFILE_BASE2 = 'Dockerfile.base2'
# Docker conf files
dockerfile_base2 = open(os.path.join(CONF_DOCKER_DIR, '01_base2.docker')).read()
# ...
elif args.mode == MODE_BASE2:
dockerfile = dockerfile_template.format(
from_image=IMAGE_BASE,
maintainer=MAINTAINER,
base=dockerfile_base2,
extra=''
)
filename = DOCKERFILE_BASE2
imagename = IMAGE_BASE2
elif args.mode == MODE_DEBUG:
dockerfile = dockerfile_template.format(
from_image=IMAGE_BASE2,
maintainer=MAINTAINER,
base='',
extra=dockerfile_extra
)
filename = DOCKERFILE_DEBUG
imagename = IMAGE_DEBUG
실행
# base는 빌드했고, 변경사항이 없으므로 다시 빌드하지 않는다.
$ python build.py -m=base2
$ python build.py -m=debug
$ docker run --rm -it -p 8080:4567 front-debug
http://localhost:8080 에서는 Django 페이지, http://front.localhost:8080/ 에서는 Vue 페이지가 정상적으로 작동하는지 확인한다.
DockerHub
이대로 진행하면 설치시간이 너무 길기 때문에 eb deploy
시, 타임아웃이 발생한다. (npm 이 설치과정이 길다.)
DockerHub 홈페이지로 이동해 가입한다. 가입 후 진행한다.
$ docker login
# 원격 저장소 형식 username/저장소이름
$ docker tag front-debug hm07/front:latest
# Dockerhub에 푸시
$ docker push hm07/front
배포가 완료되면 https://hub.docker.com/r/hm07/front/tags/에서 이미지를 확인 할 수 있다.
Dockerhub에 올린 이미지도 스크립트에 추가
build.py
프로덕션빌드하는 건 너무 오래걸리므로 Dockerhub을 이용하는 것을 기본 사양으로 한다. 그러면 나중에 eb deploy
할 때에도 Dockerfile에는 Dockerhub서버에 있는 것을 받게 되어 있다.
MODE_DOCKERHUB = 'dockerhub'
IMAGE_PRODUCTION = 'front-production'
IMAGE_DOCKERHUB = 'front'
DOCKERFILE_PRODUCTION = 'Dockerfile.production'
DOCKERFILE_DOCKERHUB = 'Dockerfile'
dockerfile_extra_dockerhub = open(os.path.join(CONF_DOCKER_DIR, '03_extra_dockerhub.docker')).read()
# ...
elif args.mode == MODE_DOCKERHUB:
dockerfile = dockerfile_template.format(
from_image='hm07/front',
maintainer=MAINTAINER,
base='',
extra=dockerfile_extra_dockerhub,
)
filename = DOCKERFILE_DOCKERHUB
imagename = IMAGE_DOCKERHUB
.conf/docker/03_extra_dockerhub.docker
WORKDIR /srv/app/django_app
EXPOSE 4567
CMD ["supervisord", "-n"]
실행
$ python build.py -m=dockerhub
$ docker run -p 8080:4567 front
http://localhost:8080 에서는 Django 페이지, http://front.localhost:8080/ 에서는 Vue 페이지가 정상적으로 작동하는지 확인한다.