著者は、 Write forDOnationsプログラムの一環として寄付を受け取るためにTechEducationFundを選択しました。

序章

Docker は、管理者がコンテナーを使用してアプリケーションを作成、管理、デプロイ、および複製できるようにするオープンソースアプリケーションです。 コンテナは、アプリケーションがオペレーティングシステムレベルで実行するために必要な依存関係を格納するパッケージと考えることができます。 これは、Dockerを使用してデプロイされた各アプリケーションが独自の環境に存在し、その要件が個別に処理されることを意味します。

Flask は、Python上に構築されたWebマイクロフレームワークです。 実行に特定のツールやプラグインを必要としないため、マイクロフレームワークと呼ばれます。 Flaskフレームワークは軽量で柔軟性がありながら高度に構造化されているため、Pythonで記述された小さなWebアプリで特に人気があります。

Dockerを使用してFlaskアプリケーションをデプロイすると、最小限の再構成で異なるサーバー間でアプリケーションを複製できます。

このチュートリアルでは、Flaskアプリケーションを作成し、Dockerを使用してデプロイします。 このチュートリアルでは、デプロイ後にアプリケーションを更新する方法についても説明します。

前提条件

このチュートリアルに従うには、次のものが必要です。

ステップ1—Flaskアプリケーションのセットアップ

開始するには、Flaskアプリケーションを保持するディレクトリ構造を作成します。 このチュートリアルでは、/var/wwwTestAppというディレクトリを作成しますが、コマンドを変更して任意の名前を付けることができます。

  1. sudo mkdir /var/www/TestApp

新しく作成されたTestAppディレクトリに移動します。

  1. cd /var/www/TestApp

次に、Flaskアプリケーションの基本フォルダー構造を作成します。

  1. sudo mkdir -p app/static app/templates

-pフラグは、mkdirがディレクトリと存在しないすべての親ディレクトリを作成することを示します。 この場合、mkdirは、staticおよびtemplatesディレクトリを作成する過程でapp親ディレクトリを作成します。

appディレクトリには、ビューブループリントなど、Flaskアプリケーションに関連するすべてのファイルが含まれます。 Views は、アプリケーションへのリクエストに応答するために作成するコードです。 ブループリントは、アプリケーションコンポーネントを作成し、アプリケーション内または複数のアプリケーション間で共通のパターンをサポートします。

staticディレクトリは、画像、CSS、JavaScriptファイルなどのアセットが存在する場所です。 templatesディレクトリは、プロジェクトのHTMLテンプレートを配置する場所です。

基本フォルダー構造が完成したので、Flaskアプリケーションの実行に必要なファイルを作成する必要があります。 まず、nanoまたは任意のテキストエディタを使用して、appディレクトリ内に__init__.pyファイルを作成します。 このファイルは、appディレクトリがパッケージであり、そのように扱われる必要があることをPythonインタープリターに通知します。

次のコマンドを実行してファイルを作成します。

  1. sudo nano app/__init__.py

Pythonのパッケージを使用すると、モジュールを論理的な名前空間または階層にグループ化できます。 このアプローチにより、コードを特定の機能を実行する個別の管理可能なブロックに分割できます。

次に、Flaskインスタンスを作成するコードを__init__.pyに追加し、このファイルの保存後に作成するviews.pyファイルからロジックをインポートします。 次のコードを新しいファイルに追加します。

/var/www/TestApp/app/__init__.py
from flask import Flask
app = Flask(__name__)
from app import views

そのコードを追加したら、ファイルを保存して閉じます。 Ctrl+X,を押し、プロンプトが表示されたらYEnterを押すと、ファイルを保存して閉じることができます。

__init__.pyファイルを作成したら、appディレクトリにviews.pyファイルを作成する準備が整います。 このファイルには、ほとんどのアプリケーションロジックが含まれています。

  1. sudo nano app/views.py

次に、views.pyファイルにコードを追加します。 このコードは、hello world!文字列をWebページにアクセスするユーザーに返します。

/var/www/TestApp/app/views.py
from app import app

@app.route('/')
def home():
   return "hello world!"

関数の上の@app.route行は、デコレータと呼ばれます。 デコレータは、Flaskで広く使用されているPython言語の規則です。 それらの目的は、それらの直後の関数を変更することです。 この場合、デコレータは、どのURLがhome()関数をトリガーするかをFlaskに通知します。 home関数によって返されるhello worldテキストは、ブラウザのユーザーに表示されます。

views.pyファイルを配置したら、uwsgi.iniファイルを作成する準備が整います。 このファイルには、アプリケーションのuWSGI構成が含まれます。 uWSGIは、プロトコルとアプリケーションサーバーの両方であるNginxの展開オプションです。 アプリケーションサーバーは、uWSGI、FastCGI、およびHTTPプロトコルを提供できます。

このファイルを作成するには、次のコマンドを実行します。

  1. sudo nano uwsgi.ini

次に、次のコンテンツをファイルに追加して、uWSGIサーバーを構成します。

/var/www/TestApp/uwsgi.ini
[uwsgi]
module = main
callable = app
master = true

このコードは、Flaskアプリケーションが提供されるモジュールを定義します。 この場合、これはmain.pyファイルであり、ここではmainと呼ばれます。 callableオプションは、メインアプリケーションによってエクスポートされたappインスタンスを使用するようにuWSGIに指示します。 masterオプションを使用すると、アプリケーションを実行し続けることができるため、アプリケーション全体をリロードする場合でもダウンタイムはほとんどありません。

次に、アプリケーションへのエントリポイントであるmain.pyファイルを作成します。 エントリポイントは、アプリケーションとの対話方法についてuWSGIに指示します。

  1. sudo nano main.py

次に、以下をコピーしてファイルに貼り付けます。 これにより、以前に作成されたアプリケーションパッケージからappという名前のFlaskインスタンスがインポートされます。

/var/www/TestApp/main.py
from app import app

最後に、requirements.txtファイルを作成して、pipパッケージマネージャーがDockerデプロイメントにインストールする依存関係を指定します。

  1. sudo nano requirements.txt

次の行を追加して、Flaskを依存関係として追加します。

/var/www/TestApp/requirements.txt
Flask>=2.0.2

インストールするFlaskのバージョンを指定します。 このチュートリアルの執筆時点では、2.0.2が最新のFlaskバージョンであり、>=2.0.2を指定すると、バージョン2.0.2以降を確実に入手できます。 このチュートリアルでは基本的なテストアプリを作成しているため、Flaskの将来の更新によって構文が古くなる可能性は低くなりますが、安全でありながらマイナーな更新を受け取りたい場合は、そうでないことを指定できます。 Flask>=2.0.2,<3.0のようなものを指定して、将来のメジャーバージョンをインストールしたい。 更新を確認するには、 Flask の公式Webサイト、またはFlaskライブラリのPythonPackageIndexのランディングページを参照してください。

ファイルを保存して閉じます。 これでFlaskアプリケーションが正常にセットアップされ、Dockerをセットアップする準備が整いました。

ステップ2—Dockerをセットアップする

このステップでは、Dockerfilestart.shの2つのファイルを作成して、Dockerデプロイメントを作成します。 Dockerfileは、イメージのアセンブルに使用されるコマンドを含むテキストドキュメントです。 start.shファイルは、イメージを構築し、Dockerfileからコンテナーを作成するシェルスクリプトです。

まず、Dockerfileを作成します。

  1. sudo nano Dockerfile

次に、必要な構成をDockerfileに追加します。 これらのコマンドは、イメージの構築方法と、含まれる追加の要件を指定します。

/ var / www / TestApp / Dockerfile
FROM tiangolo/uwsgi-nginx-flask:python3.8-alpine
RUN apk --update add bash nano
ENV STATIC_URL /static
ENV STATIC_PATH /var/www/app/static
COPY ./requirements.txt /var/www/requirements.txt
RUN pip install -r /var/www/requirements.txt

この例では、Dockerイメージは、DockerHubにある既存のイメージtiangolo/uwsgi-nginx-flaskから構築されます。 この特定のDockerイメージは、さまざまなPythonバージョンとOSイメージをサポートしているため、他のイメージよりも優れています。

最初の2行は、アプリケーションを実行し、bashコマンドプロセッサとnanoテキストエディタをインストールするために使用する親イメージを指定します。 また、GitHub、GitLab、Bitbucketなどのバージョン管理ホスティングサービスにプルおよびプッシュするためのgitクライアントもインストールします。 ENV STATIC_URL /staticは、このDockerイメージに固有の環境変数です。 画像、CSSファイル、JavaScriptファイルなどのすべてのアセットが提供される静的フォルダーを定義します。

最後の2行は、requirements.txtファイルをコンテナーにコピーして実行できるようにし、requirements.txtファイルを解析して指定された依存関係をインストールします。

構成を追加したら、ファイルを保存して閉じます。

Dockerfileを配置すると、Dockerコンテナーをビルドするstart.shスクリプトを作成する準備がほぼ整います。 start.shスクリプトを作成する前に、まず、構成で使用するポートが開いていることを確認してください。 ポートが空いているかどうかを確認するには、次のコマンドを実行します。

  1. sudo nc localhost 56733 < /dev/null; echo $?

上記のコマンドの出力が1の場合、ポートは空いていて使用可能です。 それ以外の場合は、start.sh構成ファイルで使用する別のポートを選択する必要があります。

使用する開いているポートを見つけたら、start.shスクリプトを作成します。

sudo nano start.sh

start.shスクリプトは、Dockerfileからイメージを構築し、結果のDockerイメージからコンテナーを作成するシェルスクリプトです。 新しいファイルに構成を追加します。

/var/www/TestApp/start.sh
#!/bin/bash
app="docker.test"
docker build -t ${app} .
docker run -d -p 56733:80 \
  --name=${app} \
  -v $PWD:/app ${app}

最初の行はシバンと呼ばれます。 これがbashファイルであり、コマンドとして実行されることを指定します。 次の行は、画像とコンテナに付ける名前を指定し、appという名前の変数として保存します。 次の行は、現在のディレクトリにあるDockerfileからイメージをビルドするようにDockerに指示します。 これにより、この例ではdocker.testというイメージが作成されます。

最後の3行は、ポート56733で公開されるdocker.testという名前の新しいコンテナーを作成します。 最後に、現在のディレクトリをコンテナの/var/wwwディレクトリにリンクします。

-dフラグを使用して、デーモンモードで、またはバックグラウンドプロセスとしてコンテナを起動します。 -pフラグを含めて、サーバーのポートをDockerコンテナーの特定のポートにバインドします。 この場合、ポート56733をDockerコンテナーのポート80にバインドしています。 -vフラグは、コンテナーにマウントするDockerボリュームを指定します。この場合、プロジェクトディレクトリ全体をDockerコンテナーの/var/wwwフォルダーにマウントします。

構成を追加したら、ファイルを保存して閉じます。

start.shスクリプトを実行して、Dockerイメージを作成し、結果のイメージからコンテナーを構築します。

  1. sudo bash start.sh

スクリプトの実行が終了したら、次のコマンドを使用して、実行中のすべてのコンテナーを一覧表示します。

  1. sudo docker ps

コンテナを示す出力が表示されます。

Output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 58b05508f4dd docker.test "/entrypoint.sh /sta…" 12 seconds ago Up 3 seconds 443/tcp, 0.0.0.0:56733->80/tcp docker.test

docker.testコンテナが実行されていることがわかります。 実行されたので、ブラウザの指定されたポートのIPアドレスにアクセスします:http://ip-address:56733

次のようなページが表示されます。

the home page

このステップでは、FlaskアプリケーションをDockerに正常にデプロイしました。 次に、テンプレートを使用してコンテンツをユーザーに表示します。

ステップ3—テンプレートファイルを提供する

テンプレートは、アプリケーションにアクセスするユーザーに静的および動的コンテンツを表示するファイルです。 このステップでは、アプリケーションのホームページを作成するためのHTMLテンプレートを作成します。

app/templatesディレクトリにhome.htmlファイルを作成することから始めます。

  1. sudo nano app/templates/home.html

テンプレートのコードを追加します。 このコードは、タイトルといくつかのテキストを含むHTML5ページを作成します。

/var/www/TestApp/app/templates/home.html

<!doctype html>

<html lang="en-us">   
  <head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title>Welcome home</title>
  </head>
  
  <body>
    <h1>Home Page</h1>
    <p>This is the home page of our application.</p>
  </body> 
</html>

テンプレートを追加したら、ファイルを保存して閉じます。

次に、app/views.pyファイルを変更して、新しく作成されたファイルを提供します。

  1. sudo nano app/views.py

まず、ファイルの先頭に次の行を追加して、Flaskからrender_templateメソッドをインポートします。 このメソッドは、HTMLファイルを解析して、ユーザーにWebページをレンダリングします。

/var/www/TestApp/app/views.py
from flask import render_template
...

ファイルの最後に、テンプレートファイルをレンダリングするための新しいルートも追加します。 このコードは、ユーザーがアプリケーションの/templateルートにアクセスするたびに、home.htmlファイルのコンテンツが提供されることを指定します。

/var/www/TestApp/app/views.py
...

@app.route('/template')
def template():
    return render_template('home.html')

更新されたapp/views.pyファイルは次のようになります。

/var/www/TestApp/app/views.py
from flask import render_template
from app import app 

@app.route('/')
def home():
    return "Hello world!"

@app.route('/template')
def template():
    return render_template('home.html')

完了したら、ファイルを保存して閉じます。

これらの変更を有効にするには、Dockerコンテナを停止して再起動する必要があります。 次のコマンドを実行して、コンテナを再構築します。

  1. sudo docker stop docker.test && sudo docker start docker.test

http://your-ip-address:56733/templateでアプリケーションにアクセスして、提供されている新しいテンプレートを確認してください。

homepage

これで、アプリケーションの訪問者にサービスを提供するDockerテンプレートファイルを作成しました。 次のステップでは、Dockerコンテナを再起動しなくても、アプリケーションに加えた変更をどのように有効にできるかを確認します。

ステップ4—アプリケーションを更新する

新しい要件のインストール、Dockerコンテナーの更新、HTMLとロジックの変更など、アプリケーションに変更を加える必要がある場合があります。 このセクションでは、Dockerコンテナーを再起動せずにこれらの変更を行うようにtouch-reloadを構成します。

Python autoreloading は、ファイルシステム全体の変更を監視し、変更を検出するとアプリケーションを更新します。 自動リロードは、リソースをすぐに消費する可能性があるため、本番環境では推奨されません。 このステップでは、touch-reloadを使用して特定のファイルへの変更を監視し、ファイルが更新または置換されたときにリロードします。

これを実装するには、uwsgi.iniファイルを開くことから始めます。

  1. sudo nano uwsgi.ini

次に、強調表示された行をファイルの最後に追加します。

/var/www/TestApp/uwsgi.ini
module = main
callable = app
master = true
touch-reload = /app/uwsgi.ini

これは、アプリケーション全体のリロードをトリガーするように変更されるファイルを指定します。 変更を加えたら、ファイルを保存して閉じます。

これを実証するために、アプリケーションに小さな変更を加えます。 app/views.pyファイルを開くことから始めます。

  1. sudo nano app/views.py

home関数によって返された文字列を置き換えます。

/var/www/TestApp/app/views.py
from flask import render_template
from app import app

@app.route('/')
def home():
    return "<b>There has been a change</b>"

@app.route('/template')
def template():
    return render_template('home.html')

変更を加えたら、ファイルを保存して閉じます。

次に、アプリケーションのホームページをhttp://ip-address:56733で開くと、変更が反映されていないことがわかります。 これは、リロードの条件がuwsgi.iniファイルへの変更であるためです。 アプリケーションをリロードするには、touchを使用して条件をアクティブにします。

  1. sudo touch uwsgi.ini

アプリケーションのホームページをブラウザに再度ロードします。 アプリケーションに変更が組み込まれていることがわかります。

Homepage Updated

この手順では、touch-reload条件を設定して、変更を加えた後にアプリケーションを更新します。

結論

このチュートリアルでは、Flaskアプリケーションを作成してDockerコンテナーにデプロイしました。 また、touch-reloadを構成して、コンテナーを再起動せずにアプリケーションを更新しました。

Docker上の新しいアプリケーションを使用すると、簡単にスケーリングできるようになります。 Dockerの使用の詳細については、Dockerの公式ドキュメントを確認してください。