SEワンタンの独学備忘録

IT関連の独学した内容や資格試験に対する取り組みの備忘録

【Docker】Nginx Unit(Flask)アプリをDockerコンテナで構築する

今回はDockerでNginx Unitを構築します。


環境はAWS Linux上にDockerをインストールして実行しています。

Dockerコマンドで構築する

まずは基本のコマンドで構築します。
コマンドというよりは中に入ってガチャガチャやっているので正直ダサいやり方です。

もっとスマートにできるのかもしれません。

イメージの取得

まずはDockerHubからイメージを検索するところから始めます。
適当なOSのコンテナにインストールしてもよかったですが、Nginx Unitのコンテナイメージが存在するようなのでそちらを使用します。

コマンドでの確認と、

docker search nginx

AME DESCRIPTION STARS OFFICIAL AUTOMATED
nginx/unit NGINX Unit is a dynamic web and application … 36

公式ページから確認します。

f:id:wantanBlog:20200414002443p:plain

DockerHubからバージョンを選択します。
今回はpython3を使用したいので、「1.16.0-python3.7」というバージョンを選択します。

Dockerイメージを取得してきます。

docker image pull nginx/unit:1.16.0-python3.7
コンテナの生成、起動

取得したイメージからコンテナを生成します。
今回は「unitx」という名前でコンテナを生成します。

・コンテナの生成

docker create  -p 8081:8081 --name unitx nginx/unit:1.16.0-python3.7

・コンテナの起動

docker container start unitx


普通にrunコマンドでもよかったかもしれません。

ファイルの配置

全ての操作をホスト側から実行する方法がわからなかったので、コンテナにアタッチします。

・コンテナへアタッチ(ホスト側から操作)

docker container exec -it unitx /bin/bash

・実行ディレクトリの作成(コンテナ内の操作)

実行ディレクトリの場所自体は任意の場所でOKです。今回はわざわざ作成しています。

cd /usr/local/
mkdir nginx/app -p

/usr/local/nginx」に設定ファイルを配置して、「/usr/local/nginx/app」に実行モジュールを配置します。

・ファイルコピー(ホスト側から操作)
一旦コンテナからデタッチして、ホスト側からコンテナへファイルのコピーを行います。

設定ファイル(conf.json)

{
  "listeners": {
    "*:8081": {
      "application": "flask_sample"
    }
  },

  "applications": {
    "flask_sample": {
      "type": "python",
      "path": "/usr/local/nginx/app/",
      "module": "main"
    }
  }
}

コピー実行コマンド

docker container cp conf.json unitx:/usr/local/nginx/conf.json

python実行モジュール(main.py)

from flask import Flask

application = Flask(__name__)

#default
@application.route('/')
def index():
    print('test')
    return "Hello Flask"


コピー実行コマンド

docker container cp main.py unitx:/usr/local/nginx/app/main.py
Flask実行環境の構築

妙にFlaskにこだわったせいでここが大変になりました。
Flask使用するつもりがなければ、すっ飛ばしてOKです。

Nginx Unitに設定を反映させるために設定ファイルのPUTを行うのですが、ソースにFlaskを使用している場合はそのまま実行すると以下のように実行時のFlaskインポートに失敗します

{
"error": "Failed to apply new configuration."
}

2020/04/13 15:20:07 [info] 2349#2349 "flask_sample" application started
2020/04/13 15:20:07 [alert] 2349#2349 Python failed to import module "main"
Traceback (most recent call last):
File "/usr/local/nginx/app/main.py", line 1, in
from flask import Flask
ModuleNotFoundError: No module named 'flask'
2020/04/13 15:20:07 [notice] 1#1 process 2349 exited with code 1
2020/04/13 15:20:07 [warn] 12#12 failed to start application "flask_sample"
2020/04/13 15:20:07 [alert] 12#12 failed to apply new conf

Nginx Unitの実行環境(コンテナ)にFlaskがインストールされていないためと思われます。

なのでコンテナ内でFlaskのインストールを行ってしまいます。以下、コンテナにアタッチしたコンテナ内での操作です。

・aptの最新化

apt update
apt upgrade

・python3.7の存在確認
今回はNginxUnitがpython3.7に対応しているようなのでこのバージョンが存在するか確認しておきます。
ずらーっと表示されればOK。

apt search -y python3.7-*

・python3.7インストール

apt install -y python3.7 

・pipのインストール

apt install -y python-pip python3-pip

・Flaskのインストール

pip3 install flask
設定の反映と動作確認

環境の準備ができたら設定ファイル(conf.json)をUnitに反映させます。

・設定の反映
ソケットが配置されている場所にだけ気を付けてください。
サーバに直でインストールしたときとパスが違いました。

curl -X PUT --data-binary @/usr/local/nginx/conf.json --unix-socket /var/run/control.unit.sock http://localhost/config

以下が表示されれば成功です。

{
"success": "Reconfiguration done."
}

設定は即時反映されるので、ここまでで準備OKです。

ブラウザから接続確認を行う場合には、各種サーバによってファイアウォール、セキュリティーグループなどが接続を阻害しないように適切に設定されていることを確認します。

・疎通確認

f:id:wantanBlog:20200414005756p:plain

やった!!!確かに接続できています。

Dockerfileで構築する

コマンドでポチポチ構築したコンテナと同様のものをDockerfileでも構築してみます。
どこまで楽にできるかのチャレンジです!!

構成情報
/home/ec2-user/docker_work/unit
 ┣conf.json
 ┣main.py
 ┗unitDfile

Dockerfile以外は上記とほぼ同じですが一応内容を再掲します。
ポートだけ変えています。

設定ファイル(conf.json)

{
  "listeners": {
    "*:8082": {
      "application": "flask_sample"
    }
  },

  "applications": {
    "flask_sample": {
      "type": "python",
      "path": "/usr/local/nginx/app/",
      "module": "main"
    }
  }
}

python実行モジュール(main.py)

from flask import Flask

application = Flask(__name__)

#default
@application.route('/')
def index():
    print('test')
    return "Hello Flask"
Dockerfileの作成

・unitDfile(Dockerfile)

# ベースイメージunit取得
FROM nginx/unit:1.16.0-python3.7

# 作業ディレクトリの作成
WORKDIR /usr/local/nginx/app

# conf.jsonのコピー
COPY conf.json /docker-entrypoint.d/

# main.pyのコピー
COPY main.py /usr/local/nginx/app/

# 実行環境準備(flaskインストール)
RUN ["/bin/bash","-c","apt update"]
RUN ["/bin/bash","-c","apt -y upgrade"]
RUN ["/bin/bash","-c","apt install -y python3.7"]
RUN ["/bin/bash","-c","apt install -y python-pip python3-pip"]
RUN ["/bin/bash","-c","pip3 install flask"]

もっと賢いやり方はあるかもしれません、基本は上記のコマンド実行の流れに沿って各命令を記述しています。
ポイントは設定ファイルを「/docker-entrypoint.d/」に格納することです。

設定ファイルをPUTする方法に悩みました。スクリプトで実行する方法もありそうですが、なかなかうまくいかず・・

そこでコンテナの起動時に実行される「/usr/local/bin/docker-entrypoint.sh」の中身を確認したところを「/docker-entrypoint.d/」に存在する「*.json」ファイルをPUTする旨の記述があったのでそこに格納しました。

詳しくは実際に中身を確認してみてください。

イメージの構築とコンテナ起動

・イメージの構築

docker build -t unitim:1.0 -f unitDfile /home/ec2-user/docker_work/unit

イメージの構築時はインストールが多いので少し待ちます。

・コンテナの起動
ポート8082にしている以外は上で実施したときと同じです。

docker container run -p 8082:8082 --name devunit -d unitim:1.0

もしもうまくいかない場合にはログの確認や

docker logs devunit

コンテナ内に入ってソケットの内容を確認します。

curl --unix-socket /var/run/control.unit.sock http://localhost/
疎通確認

ブラウザから確認!!!

f:id:wantanBlog:20200415011800p:plain


やったー!できてる!!

実際には構築のためにかなり試行錯誤していますが、一度方法を確立してファイルさえ用意されていれば2コマンドで環境構築が完了してブラウザから確認できるのは楽ですね!Dockerfileによる環境構築の威力です。

DockerHubにあげておく

MongoDB同様にせっかくなので上げておきます。

・コンテナのイメージ化

docker container commit -a "wantanblog" devunit wantanblog/devunitim:1.0

・DockerHubにログイン

docker login

・DockerHubにログイン

docker image push wantanblog/devunitim:1.0


ーーーーーーーー
・ソース類
docker/sample/unit at master · wantanblog/docker · GitHub

※本記事は本書の内容に沿っているわけではありません。