docker触ってみたかったので最小構成のflaskアプリケーションをローカル(mac)で作成して,

docker-composeして,

vagrant上のubuntuに投げてみた.

content

ローカルでflask applicationを作成する

とりあえず簡単なアプリを作っていきま.

準備

$ mkdir Project && cd Project
$ mkdir flask_app && mkdir nginx
$ python -m venv env && source env/bin/activate
(env)$ pip install flask uwsgi
(env)$ pip freeze > flask_app/requirements.txt
(env)$ touch flask_app/app.py flask_app/conf.ini nginx/nginx.conf
(env)$ tree .
.
├── env
├── flask_app
│   ├── app.py
│   ├── requirements.txt
│   └── conf.ini
└── nginx
    └── nginx.conf

ディレクトリ構成はこんな感じ.

app.py

from flask import Flask

app = Flask(__name__)


@app.route('/')
def index():
    return "<h1>Hello from Flask</h1>"


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

一応確認で,

(env)$ cd flask_app
(env)$ python app.py

サーバーを立てて, ローカルホスト にアクセスして,

Hello from Flask

が表示されていることを確認.

uWSGI用のconf.iniを書く

本筋とそれるのでこの辺はざっくり.

[uwsgi]
; module: app.py -> app
module = app:app

processes = 4
threads = 2

master = true

; socket
socket = :8080
chmod-socket = 660

; LOG
logto = ./app.log

vacuum = true
die-on-term = true

走らせるアプリを指定しつつ, ソケットの吐き出し先に8080ポートを指定しておく.

Nginx用のnginx.confを書く

server {
    listen 80;

    location / {
        include uwsgi_params;
        uwsgi_pass flask_app:8080;
    }
}

よくあるやつ.

uwsgi用のconf.iniでソケットの吐き出し先を8080にしているので, flask_app(コンテナ名)の8080を読みに行くように書く.

Dockerfileを書く

Dockerでは,

  • FROM で 元となるイメージ
  • RUN でコンテナ作成時の実行コマンド
  • CMD でコンテナ起動時の実行コマンド

を書いていく.

各コンテナ毎にDockerfileが必要なので, 今回は

flask_appディレクトリと, nginxディレクトリにそれぞれDockerfileを用意する

flask_app/Dockerfile

FROM python:3.7.2-stretch
WORKDIR /flask_app
COPY . /flask_app
RUN pip install -r requirements.txt
CMD ["uwsgi", "--ini", "conf.ini"]
  • 元イメージをPython3.7.2
  • WORKDIRではコンテナ内の作業パスを指定
  • COPYの項目では, (Dockerfileから見た)カレントディレクトリのファイルをそのままコンテナの/flask_appにコピー
  • コンテナ作成時にrequirements.txtにある必要なモジュールを取得
  • 起動コマンドは uwsgi –ini conf.ini

nginx/Dockerfile

FROM nginx
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/

nginxのデフォルトの設定ファイルを削除し, 自分で書いたnginx.confを設置する.

docker-composeする

今回はコンテナが2つあるので, これらを連携するべくdocker-composeを利用する.

(env)$ cd /path/to/Project
(env)$ touch docker-compose.yml

docker-compose.yml

version: "3.7"

services:
  flask_app:
    build: ./flask_app
    container_name: flask_app
    restart: always
    expose:
      - 8080

  nginx:
    build: ./nginx
    container_name: nginx
    restart: always
    ports:
      - "80:80"
  1. (外部から)80へのアクセスを, nginxのport80へ繋ぐ (ports: 80:80, 左がホスト, 右がnginx)
  2. nginxがport80をlistenして, flask_appコンテナの8080を読みに行く
  3. flask_appコンテナでは8080ポートを開放(expose)して, uwsgiのconf.iniによりソケットを8080に吐き出す

という流れがちゃんと行えるようにdocker-compose.ymlを書く.

走らせてみる

(env)$ docker-compose build --up

ローカルホスト にアクセスすると, flask_appのページが表示される.

Vagrantで立ち上げたUbuntuに持っていく

Dockerの魅力はローカルで作ったイメージをそのまま実環境に持っていけることだと理解しているので(そうだよね?),

とりあえずVagrantでUbuntuを立ち上げて移植してみる

とりあGithubで共有(割愛)

1. VagrantでUbuntuを立ち上げる

Vagrantが未導入なら以下の2つをいれる(普通にec2とかgce使ってもいいけど).

特に設定はないので, インストールだけすればおけ.

$ mkdir Vag && cd Vag
$ vagrant box add trusty64 https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box
$ vagrant init trusty64
# Vagrantfile ->  config.vm.network "private_network"のコメントアウトを解除して, ipをメモっておく. 今回は 192.168.33.10
$ vagrant up
$ vagrant ssh

ubuntuに接続された.

2. dockerとdocker-composeのインストール

まずは, dockerとdocker-composeをインストール

$ curl -fsSL get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose

でインストールが完了.

$ sudo docker -V
$ sudo docker-compose

でインストールが正常にできているか確認.

※自分の場合はお試しでdocker runとかいじってたらバージョンの関係でエラーを吐かれたので,

$ sudo apt-get remove docker-ce && sudo apt-get install -y docker-ce=18.06.1~ce~3-0~ubuntu

をして解消した.

3. docker-composeでアプリケーションの起動

まずは, git clone等でローカルで作ったファイル等を取ってくる.

その上で,

$ cd <dirname>
$ sudo docker-compose up --build

で, 192.168.33.10 にアクセスしてみるとflask_applicationのページに繋がった!

すげぇ!

ctrl-cで閉じれるけど, 実環境だとデーモン化したいはずなので

$ sudo docker-compose up -d

でデーモン化し, 終了は

$ sudo docker ps  # CONTAINER IDを把握
$ sudo docker kill <CONTAINER ID>

とするか, めんどければ

$ docker ps -aq | xargs rm -f

としてコンテナ全部消し去ってもOK.

Docker hubでimageを共有

先程の例では,

ローカル環境で作成したアプリをDockerfile毎共有することで実環境(というかVagrant)上でもスムーズにアプリを起動したが,

imageを共有できるDocker hubもあるとのことなのでそちらも試してみる

まずは, Docker Hub でアカウントを作成して,

$ docker login  # 必要な情報を入力
Login Succeeded

Docker Hubにpushするイメージは,

<username>/hogeでなきゃいけないらしいので, docker-compose.ymlを修正してイメージ名を指定しておく.

version: "3.7"

services:
  flask_app:
    build: ./flask_app
    image: <username>/flask_app
    container_name: flask_app
    restart: always
    environment:
      - APP_NAME=MyFlaskApp
    expose:
      - 8080

  nginx:
    build: ./nginx
    image: <username>/nginx
    container_name: nginx
    restart: always
    ports:
      - "80:80"

image名を書き換えたので, 再Buildしてpushする.

(env)$ docker-compose build
(env)$ docker push <usename>/flask_app
(env)$ docker push <usename>/nginx

これでpushできた.

Docker Hub に行くと, リポジトリが追加されているはず.

Vagrantに移動して,

$ sudo docker pull <username>/flask_app
$ sudo docker pull <username>/nginx

でイメージを取得できた.

$ sudo docker run -d <username>/flask_app
$ sudo docker run -d <username>/nginx

で無事起動できた.

けど, アクセスできない.

コンテナ名がdocker-compose.ymlに書いた内容と異なるので, 設定が反映できてないっぽい.

引き数で指定して再実行してみる.

$ sudo docker run -d --expose=8080 --restart=always --name flask_app <username>/flask_app
$ sudo docker run -d -p=80:80 --restart=always --name nginx <username>/nginx

またダメ.

おとなしくdocker-compose.ymlを準備したら上手く行った.

という感じで, どちらにせよdocker-compose.ymlを共有する必要があるくさいので, サーバーにdockerいれて起動ってするならGithubリポジトリを共有してしまったほうが良い気がする(というかdocker hubでどうこうするメリットが浮かばない)