[Docker] 우분투 12.04 에서 파이썬 웹 개발 환경 컨테이너 만들기 Computer Tip

요즘 클라우드에 갑자기 도커라는 것이 나와서
컨테이널 실어 나르느니 등의 말이 너무 많이 등장하고 있습니다.


제가 보기에는, 과거 OO 프로프그램을 하던, 컴포넌트웨어를 하던
모두 코드의 재사용을 목적으로 하는데 반해
컨테이너 자체적으로 실행가능한 작은 단위의 독립 실행 환경으로 
이해 하면 될 것 같습니다.

마치 파이썬에서 VirtualEnv가 존재하여 자체 App을 해당 Python 환경에서만 
폐쇄적으로 돌듯이 이번에는 시스템에서 마치 컨테이너에 갖힌 독립 실행 
환경이 돌아가는 형태이지요.

결국은 이 컨테이너와 마이크로 서비스 아키텍쳐가 합쳐져서
굉장한 패러다임의 변화가 올 것으로 확신합니다.

암튼 그 첫 시작으로 우분투 12.04에서 파이썬 웹 개발 환경을 컨테이너로 만들어 보려고 합니다.


1) 우분투 12.04에서 Docker 설치



리눅스 커널 3.8 이상, 그리고 AUFS 파일시스템 (아마도 read-only 기능 때문이 아닐까 하는데요)을 필요로 합니다.

# install the backported kernel
$ sudo apt-get update
$ sudo apt-get install linux-image-generic-lts-raring linux-headers-generic-lts-raring

# install the backported kernel and xorg if using Unity/Xorg
$ sudo apt-get install --install-recommends linux-generic-lts-raring xserver-xorg-lts-raring libgl1-mesa-glx-lts-raring

# reboot
$ sudo reboot

만약 /usr/lib/apt/methods/https 파일이 없으면 apt-transport-https 패키지를 설치합니다.

[ -e /usr/lib/apt/methods/https ] || {
  apt-get update
  apt-get install apt-transport-https
}

그 다음 다커 패키지를 위한 키를 가져옵니다.

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9

마지막으로 도커 설치입니다.

$ sudo sh -c "echo deb https://get.docker.com/ubuntu docker main\
> /etc/apt/sources.list.d/docker.list"
$ sudo apt-get update
$ sudo apt-get install lxc-docker

최초의 우분투 컨테이너 실행해보기

$ sudo docker run -i -t ubuntu /bin/bash
...
# exit


만약 UFW 방화벽이 커져 있으면, UFW 설정을 변경해야 한다 합니다.

$ sudo vi /etc/default/ufw

$ sudo ufw reload


2) 도커 명령

다음과 같이 docker 데몬이 켜져 있는지 확인합니다.

조커 CLI 명령행 형식

sudo docker [option] [command] [arguments]

자세한 명령은 sudo docker help 명령을 활용합니다.


3) 파이썬 WSGI 도커 컨테이너 (샌드박스) 앱 생성

$ sudo docker run -i -t -p 80:80 ubuntu /bin/bash

이전 다운받은 (최초 명령이면 도커 외부 저장소에서 따끈 따끈한 빈 우분투 컨테이너를 다운 받습니다)
우분투 박스를 실행시키는데 80 포트 서비스를 위하여 -p 80:80 옵션을 추가하였습니다.


다른 터미널에서 
$ sudo docker ps
명령으로 현재 컨테이너로 돌고 있는 것들이 보이며

$ sudo docker top xxx
명령으로 해당 컨테이너 프로세스 목록을 확인합니다.

또는 도커 터미널 자체에서 Ctrl-P와 Ctrl-Q 키를 눌러 컨테이너 바깥으로 빠져나가고,

$ sudo docker ps 
명령으로 컨테이너 id를 확인하여
$ sudo docker attach xxx
명령으로 해당 컨테이너에 다시 접속(attach) 할 수 있습니다.

지금 까지는 컨테이너를 준비한 것이구요,
다음은 해당 컨테이너 내부 (Sandbox) 에서 해당 서비스를 준비하는 과정입니다.


root@9231e29239fe:~# echo "deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -sc) main universe" >> /etc/apt/sources.list
(위의 root@ 9231e29239fe 에서 9231e29239fe는 해당 컨테이너 ID로 컨테이너 안의 쉘에서는 디폴트로 이렇게 보입니다)

root@9231e29239fe:~# apt-get update

그 다음, 필요 패키지를 설치합니다.

root@9231e29239fe:~# apt-get install -y tar \
                   git \
                   curl \
                   vim \
                   wget \
                   dialog \
                   net-tools
                   build-essential

다음은 파이썬 패키지 설치를 위한 pip 설치 입니다.

root@9231e29239fe:~# apt-get install -y python python-dev python-distribute python-pip

이전 블로그 내용에서와 같이 Flask를 이용합니다.


root@9231e29239fe:~# pip install flask


다음은 간단한 app을 위한 폴더를 만들어 봅니다.

root@9231e29239fe:~# mkdir my_application && cd my_application

root@9231e29239fe:~# vi app.py
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()

실제로는 위와 같이 직접 작성을 하지않고,
개발된 결과를 git 등으로 가져오는 작업이 됩니다.

다음으로 python 필요 패키지를 requirements.txt 에 기술해 봅니다.

root@9231e29239fe:~# vi requirements.txt
flask
cherrypy

이전에는 gunicorn이라는 WSGI 툴 을 이용하였는데 이번에는 동일한 기능의
cherrypy 를 이용해 봅니다.

root@9231e29239fe:~# pip install cherrypy

다음은 cherrypy 를 위한 server.py 코드를 넣습니다.

root@9231e29239fe:~# vi server.py
# Import your application as:
# from app import application
# Example:

from app import app

# Import CherryPy
import cherrypy

if __name__ == '__main__':

    # Mount the application
    cherrypy.tree.graft(app, "/")

    # Unsubscribe the default server
    cherrypy.server.unsubscribe()

    # Instantiate a new server object
    server = cherrypy._cpserver.Server()

    # Configure the server object
    server.socket_host = "0.0.0.0"
    server.socket_port = 80
    server.thread_pool = 30

    # For SSL Support
    # server.ssl_module            = 'pyopenssl'
    # server.ssl_certificate       = 'ssl/certificate.crt'
    # server.ssl_private_key       = 'ssl/private.key'
    # server.ssl_certificate_chain = 'ssl/bundle.crt'

    # Subscribe this server
    server.subscribe()

    # Start the server engine (Option 1 *and* 2)

    cherrypy.engine.start()
    cherrypy.engine.block()


이제는 다음과 같이 RestAPI 서버를 동작시켜 봅니다.

root@9231e29239fe:~# python server.py

백그라운드로 기동시키려면 
python server.py &
라고 해 줍니다.

마지막으로 다른 터미널에서 테스트로

라고 잘 서비스 되고 있는 것을 확인할 수 있습니다.


4) 도커 이미지 생성

이제는 위와 같이 우분투 12.04라는 빈 컨테이너에서 실제로 앱을 설치하는 것을 하였으나
그와는 달리 Dockerfile 이라는 것을 이용하여 위와 같은 역할을 하는 도커 이미지를 한번에
생성하는 방법입니다.

호스트 위치에서 

$ mkdir docker && cd docker
라고 하고

그 아래에 my_application을 만들어 아래와 같이 위에서 샘플 컨테이너에서 생성했던 파일을
그래도 생성합니다.
(실은 git나 svn 으로 소스를 가져오겠지요)

위와 같이 있는데
(이미 Dockerfile 이 있는데 그 내용은 다름과 같습니다)


$ vi Dockerfile
############################################################
# Dockerfile to build Python WSGI Application Containers
# Based on Ubuntu
############################################################

# Set the base image to Ubuntu
FROM ubuntu

# File Author / Maintainer
MAINTAINER Maintaner Name

# Add the application resources URL
RUN echo "deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -sc) main universe" >> /etc/apt/sources.list

# Update the sources list
RUN apt-get update

# Install basic applications
RUN apt-get install -y tar git curl nano wget dialog net-tools build-essential

# Install Python and Basic Python Tools
RUN apt-get install -y python python-dev python-distribute python-pip

# Copy the application folder inside the container
ADD /my_application /my_application

# Get pip to download and install requirements:
RUN pip install -r /my_application/requirements.txt

# Expose ports
EXPOSE 80

# Set the default directory where CMD will execute
WORKDIR /my_application

# Set the default command to execute    
# when creating a new container
# i.e. using CherryPy to serve the application
CMD python server.py


위에서 수동으로 설치한 것을 적어 놓은 것입니다.

그 다음 Dockerfile이 있는 곳에서 (~/docker) 호스트에서 다음 명령으로...

toor@testVM:~/docker$ sudo docker build -t my_application_img .

라고 실행시킵니다.

약 십여분의 시간이 흐른 다음 위와 같이 이미지를 성공적으로 생성했음이 나타납니다.

위와 같이 이미지가 잘 만들어 졌네요...

이미지는 항상 변하지 않는 원판 (클래스) 같은 것이구요, 실제 돌아가는 컨테이너는 사본 (인스턴스) 같은
것이라 이해하면 됩니다.

그럼 이제 컨테이너를 하나 돌려 볼까요?

toor@testVM:~/docker$ sudo docker run -name my_application_instance -p 80:80 -i -t my_application_img

후훗! 이전에 빈 컨테이너에서 해 보았던 것과 같은 python server.py 가 실행되었네요...
역시나 curl로 테스트 해보니 잘 됩니다.

참고로 도커의 이미지가 위치하는 곳은

/var/lib/docker 입니다.
 
이미지는 원판 OS와의 차이만 가지고 있기 때문에, 하단의 ubuntu (14.04 버전이었습니다)의 이미지는 
188.3 MB 밖에 안 되었고, 그 위에 build 시킨 my_application_img 는 434.7MB 이었습니다.

그리고 위의 이미지 등을 모두 합한 것은 1.2G 네요...

여기에 한 개 이상의 컨테이너가 이미지로부터 파생되어도 큰 하드 디스크를 잡아먹을 것 같지는 않습니다.

잠깐 맛보기로 보았는데,
엄청 재미있네요...


어느 분께는 도움이 되셨기를~~




덧글

  • agkdc 2015/02/04 22:15 # 답글

    iptables에서 docker0에서 forwarding되는 걸 accept만 해줘도 되는 것 같아요.
  • 지훈현서아빠 2015/02/05 09:08 #

    네~ 그렇군요. 좋은 의견 감사드립니다. ^^
댓글 입력 영역

구글애드텍스트