DockerでFlask+Apache環境を作成するではDocker Composeを利用してFlask+Apacheの環境を作成したが、今回はその環境にMySQLコンテナを追加してFalskアプリからデータベースにアクセスしてみる。
環境
Docker Desktop(Windows10 Pro)。
ファイル構成
│ .dockerignoe
│ .env
│ docker-compose.yml
│ Dockerfile
│ requirements.txt
│
├─app
│ └─sample
│ │ app.wsgi
│ │ __init__.py
│ │ config.py
│ │ database.py
│ └ models.py
│
│─conf
│ app.conf
world.sql
Dockerfileの作成
Docker Hubにある公式CentOSイメージのcentos:centos8をベースにイメージを作成する。DockerでFlask+Apache環境を作成するで作成したDockerfileにさらにMySQLクライアントとPythonライブラリのインストールを追加する。
FROM centos:centos8
# コンテナ側のルート直下に作業ディレクトリ(work)を作り移動する
WORKDIR /work
# パッケージのインストールなど
# CentOS8 EOLのためdnfコマンドがエラーになるのでリポジトリ変更で対応(2022.2.13変更)
RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-Linux-* \
&& dnf -y update \
&& dnf group install -y "Development Tools" \
&& dnf install -y openssh-server \
openssh-clients \
mysql \
mysql-devel \
httpd \
httpd-tools \
httpd-devel \
python38 \
python38-devel \
python38-mod_wsgi \
langpacks-ja \
&& cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
&& dnf clean all
# タイムゾーン、ロケール設定
ENV TZ="Asia/Tokyo" \
LANG="ja_JP.UTF-8" \
LANGUAGE="ja_JP:ja" \
LC_ALL="ja_JP.UTF-8"
# FlaskなどPythonライブラリのインストール
COPY requirements.txt ./
RUN pip3 install --no-cache-dir -r requirements.txt
# SSH設定
# rootでのログインを許可
# ポートを22から20022に変更
# rootのパスワードをpasswordに設定
# ssh-keygenでホスト鍵を作成しておかないとSSHの起動に失敗する
RUN /usr/bin/ssh-keygen -A \
&& sed -ri 's/^#PermitRootLogin yes/PermitRootLogin yes/' /etc/ssh/sshd_config \
&& sed -ri 's/^#Port 22/Port 20022/' /etc/ssh/sshd_config \
&& echo 'root:password' | chpasswd
EXPOSE 80
EXPOSE 20022
# SSHとApacheを起動
CMD ["sh","-c","/usr/sbin/sshd && /usr/sbin/httpd -D FOREGROUND"]
インストールするPythonライブラリなどはrequirements.txtに記述しておく。
flask mysqlclient SQLAlchemy Flask-SQLAlchemy
docker-compse.ymlの作成
DockerでFlask+Apache環境を作成するで作成したdocker-compose.ymlにMySQLコンテナを追加する。コンテナのイメージはDocker Hubにある公式のMySQLのイメージ(mysql:8.0)を使う。このイメージではmysqlに説明があるようにMySQLのrootパスワードなどを環境変数で設定できるようになっている。docker-compose.ymlではこの環境変数の設定も行う。具体的な環境変数の値の設定は後述の.envファイルで行う。MySQLデータベースのデータを格納する場所は、mysql_dataというフォルダをホストに作成してマウントすることでコンテナが停止してもデータが残るようにしておく。
version: "3"
services:
mysqldb:
image: mysql:8.0
container_name: mysqldb
hostname: mysqldb
environment:
MYSQL_ROOT_PASSWORD:
MYSQL_DATABASE:
MYSQL_USER:
MYSQL_PASSWORD:
MYSQL_ROOT_HOST: localhost # rootでの接続をloalhostからに限定
TZ: 'Asia/Tokyo' # タイムゾーン設定
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
volumes: # ホスト:コンテナ:ro
- .\mysql_data:/var/lib/mysql # MySQLデータベース保管場所
- .\init:/docker-entrypoint-initdb.d:ro # このディレクトリにあるsh/sqlファイルがコンテナup時に自動実行される
flask:
build:
context: .
dockerfile: Dockerfile
container_name: flask
hostname: flask
environment:
MYSQL_DATABASE:
MYSQL_USER:
MYSQL_PASSWORD:
volumes:
- .\app:/var/www/app
- .\conf/app.conf:/etc/httpd/conf.d/app.conf
ports:
- "20022:20022"
- "80:80"
初期データベースの準備
公式のMySQLのイメージでは、コンテナの/docker-entrypoint-initdb.dに拡張子shやsqlのファイルを配置しておくと、コンテナの初期起動時に自動実行される。今回はここに初期データベースのsqlを配置しておく。初期データベースとしては、Other MySQL DocumentationにあるMySQLのサンプルデータベースのworld database(zip)を使う。ダウンロードしたファイルを解凍するとworld.sqlがある。initというフォルダをdocker-compose.ymlがあるフォルダ配下に作成し、このファイルを配置しておく。initはdoker-compose.ymlでコンテナの/docker-entrypoint-initdb.dにマウントされている。
環境変数ファイルの準備
MySQLの環境変数を.envで設定する。
## MySQL設定 # rootパスワード MYSQL_ROOT_PASSWORD=rootpass # 初期データベース MYSQL_DATABASE=world # 作成されるユーザー名 MYSQL_USER=flaskuser # 作成されるユーザーのパスワード MYSQL_PASSWORD=test
.dockerignoreの配置
このままだとMySQLのデータなどコンテナ作成時に余計なファイルなどが転送されてしまうので、.dockerignoreを作成して転送されないようにする。
app conf mysql_data init
動作確認
FlaskでMySQLデータベースを使う
コンテナの動作確認ができたので、ApacheでFlaskを使えるようにしてFlaskアプリのファイルをコンテナ上の/var/www/app/sampleに配置する。まずはmod_wsgiの設定をする。DockerでFlask+Apache環境を作成すると同様にapp.confとapp.wsgiを配置する。
続いてMySQLデータベースにアクセスするFlaskアプリを作成する。datavase.py、config.py、models.py、__init__.pyを作成してホストのsampleフォルダに配置する。
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def init_db(app):
db.init_app(app)
import os
class SystemConfig:
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'mysql+mysqldb://{user}:{passwd}@{host}:{port}/{dbname}?charset=utf8'.format(**{
'user': os.getenv('MYSQL_USER'),
'passwd': os.getenv('MYSQL_PASSWORD'),
'host': 'mysqldb',
'port': 3306,
'dbname': os.getenv('MYSQL_DATABASE')
})
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = False
Config = SystemConfig
worldデータベースのcityテーブルのSQLAlchemyモデルを作成する。
from sample.database import db
class City(db.Model):
__tablename__ = 'city'
ID = db.Column(db.Integer, primary_key=True, autoincrement=True)
Name = db.Column(db.String(35), nullable=False, default='')
CountryCode = db.Column(db.String(3), nullable=False, default='', index=True)
District = db.Column(db.String(20), nullable=False, default='')
Population = db.Column(db.Integer, nullable=False, default=0)
Flaskアプリの処理を記述した__init__.pyを作成する。cityテーブルから日本の都市名-都道府県名の一覧を取得して表示する。
from flask import Flask
from sample.database import init_db, db
from sample.models import City
def create_app():
app = Flask(__name__)
app.config.from_object('sample.config.Config')
init_db(app)
@app.route('/')
def index():
res = db.session.query(
City.Name,
City.District
).order_by(
City.Name
).filter(
City.CountryCode == 'JPN'
).all()
# Name-Districtの文字列のlistを作成
name_district = ['-'.join(r) for r in res]
return '< br>'.join(name_district)
return app
ブラウザでlocalhost/sampleにアクセスすると以下のようにcityテーブルから取得したデータが表示される。

0 件のコメント:
コメントを投稿