0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Docker Compose を使用してPythonモジュールを作成

Posted at

Docker Compose を使用して大きなシステムの中のPythonのモジュールの1つを作成する必要ができたので、勉強 and 備忘録のために本記事を作成いたしました。

目的

  • 大きなシステムをチーム開発する際に、システムをモジュール分割し、互いに疎な開発を進めたい
  • Docker Compose を使用することでモジュールごとにコンテナを立ち上げ、システムを開発したい
  • 本記事は、そんな数あるモジュール + コンテナのうちの一つの開発環境を整えた際の備忘録

Dockerとは

Dockerの目的

チームでシステム開発を行う際に問題となるのは、開発環境の違いである。例えば、AさんはWindows、BさんはMacOSで開発を行っている場合に、AさんがWindows環境で開発したシステムをBさんのMacOSで動かすのは手間がかかるケースが多い。Dockerは、Dockerコンテナと呼ばれるアプリケーションの実行環境を各環境に構築し、コンテナ内でアプリケーションを実行することで、このような環境の違いに影響されることなく、アプリを開発、実行することができる。

Dockerコンテナを立てる手順

コンテナは以下の手順で構築することができる。

  1. Dockerfileを作成(自身で作成 or 公開されているものを使用)
  2. Dockerfile から Dockerイメージを作成
    docker build -t my-app-image .
  3. Dockerイメージを使用してコンテナを起動
    docker run my-app-image

それぞれについて軽く解説。詳しい使い方までは触れない。

Dockerfile

Dockerfile とは、Dockerイメージを構成するテキストデータであり、Dockerイメージを作成するための設計図である。以下のように、ベースとなるイメージ、依存関係、作業ディレクトリ、コンテナ起動時の実行コマンドなどを記載。

# Pythonベースのイメージを使用
FROM python:3.8

# 作業ディレクトリを設定
WORKDIR /app

# 依存関係をインストールするためのファイルをコピー
COPY requirements.txt .

# 依存関係をインストール
RUN pip install -r requirements.txt

# アプリケーションのソースコードをコピー
COPY . .

# コンテナ起動時に実行するコマンド
CMD ["python", "app.py"]

Dockerイメージ

  • 役割:実際のソフトウェアが動作するために必要なファイルや設定をパッケージ化したもの。Dockerfile(設計図)に従って作成された完成品 と考えられる。「実行可能なソフトウェアのパッケージ」
  • 状態:イメージは実行されていない「スナップショット」のようなもので、読み取り専用
  • 内容:OS、アプリケーション、ライブラリ、依存関係などを含んでおり、これをもとにコンテナが動作

Dockerコンテナ

  • 役割:Dockerコンテナは、Dockerイメージを元に実行される動的な実行環境
  • 状態:コンテナは実行中のプロセスで、読み書き可能です。実行中にファイルシステムに変更が加えられたり、コンテナ内のデータを変更が可能。コンテナの変更はコンテナ内に保存されるが、イメージには反映されない

それぞれの比較(By GPT-4o)

image.png

Docker Compose

巨大なシステムを構築する際は、モジュールごとに機能を開発することが多い。例えばチャットボットのアプリは大雑把に、以下のように機能分割することができる。

  • テキストの入出力やフロントエンドを担当するモジュール
  • 入力されたテキストから出力テキストをバックエンドで出力するモジュール

このようなモジュールは必要なライブラリも異なるし、複数人で開発している際は担当を分けることもある。このような場合に、それぞれ異なるDockerイメージを作成して開発を進めることになる。

実際にチャットボットアプリを起動する際に、全てのモジュールのコンテナを起動して、相互で通信を行うことになるが、このようなコンテナの同時立ち上げやコンテナ同士の振る舞いなどを定義・実行するのがDocker Composeの役割である。

使い方の流れ

  1. モジュールごとにDockerfileを作成
  2. docker-compose.yml といったyml形式のファイルを用意し、モジュールごとの設定を記述
  3. docker compose up -d を実行して全てのコンテナを一斉起動

つまりチーム開発において、Docker Composeで起動できるPythonモジュールを作成する際は、以下の手順が必要になる。

  1. Pythonモジュールを作成
  2. モジュールが実行可能なDockerイメージの設計図であるDockerfileを作成(ここで requirements.lock などを読み込んでライブラリ等を揃える)
  3. docker-compose.yml ファイルに上記のDockerfileの起動を記載
  4. docker compose up -d コマンドで作成したモジュールが起動することを確認

実際に環境構築

これらの基礎知識を踏まえて実際にDockerを使用したPythonモジュールの環境構築に取り組んでみる。ディレクトリ構造は以下のものを想定。

project-root/
│
├── app/
│   ├── app.py
│   └── __init__.py  # (必要に応じて)
│
├── requirements.lock
├── Dockerfile
└── docker-compose.yml

app.pyは以下の通り。

# app.py
import numpy as np
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return "Hello, World from Docker!"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

requirements.lockは以下の通り。

numpy
flask

Dockerfileの作成

以下のようにdockerfileを作成

# ベースイメージを指定
FROM python:3.12

# 作業ディレクトリを設定
WORKDIR /app

# requirements.txtをコンテナにコピー
COPY requirements.lock .

# 依存関係をインストール
RUN pip install --no-cache-dir -r requirements.lock

# アプリケーションのソースコードをコピー
COPY app/ ./app

# コンテナ起動時の実行コマンド
CMD ["python", "app/app.py"]

それぞれが意味していることを説明していく。

ベースイメージの指定

FROM python:3.12
  • これは、Dockerイメージのベースイメージを指定するための行である。このようにしてPythonのベースイメージを指定することで、PythonインタープリタやPythonを動かすために必要な基本的なライブラリが含まれている
  • ベースイメージを指定することで新しいコンテナをこのイメージ上に作り、Pythonアプリをその上で動作させることができる

作業ディレクトリの設定

WORKDIR /app
  • 作成したばかりのコンテナはなんのファイルやディレクトリも含まないまっさらなファイル空間である
  • WORKDIR {作業ディレクトリ} とすることで作業ディレクトリを指定することができる。Docker を起動しているホストマシンの空間とコンテナ内の空間は異なるので、仮にホストマシン上に app というディレクトリが存在しても関係ない
  • もしホストとコンテナのディレクトリを関連付けたい場合はコンテナの方からホストマシンの対象ディレクトリをマウントする必要がある

requirements.lockをコンテナにコピー

COPY requirements.lock .
  • ホストマシン(Dockerコマンドを走らせているローカル環境)のカレントディレクトリにある requirements.lockをコンテナの作業ディレクトリ /appにコピーするコマンド
  • ホストマシン内のファイルは何もしない状態では使用できず、このようにしてコンテナにコピーをすることで初めて使用可能

依存関係のインストール

RUN pip install --no-cache-dir -r requirements.lock
  • RUNはDockerイメージのビルド中にコンテナ内でコマンドを実行するツール
  • pip install --no-cache-dir -r requirements.lockrequirements.lockに記載されているライブラリをインストールするコマンド
  • --no-cache-dirを使用することでダウンロードしたパッケージのキャッシュを保存してサイズが増加するのを防止

アプリケーションのソースコードコピー

COPY app/ ./app
  • ホストマシン上のディレクトリapp/の中の全てのディレクトリをコンテナの作業ディレクトリ/appの中に/app/appとしてコピー
  • このコマンドを使用することによってアプリのソースコードがコピーされる
  • 逆にこのコマンドを使用しないとソースコードがない空のコンテナになってしまう

コンテナ起動時の実行コマンド

CMD ["python", "app/app.py"]
  • CMDはコンテナが起動した際に実行されるデフォルトのコマンド
  • このコマンドにより先ほどワーキングディレクトリにコピーしたappディレクトリの中のapp.pyを実行
  • CMDはイメージのビルド時ではなく、コンテナの実行時に起動するものであることに注意

Dockerコンテナの起動

これらの条件化でDockerコンテナを起動してみる。まずはイメージのビルドを以下のコマンドで行う。

docker build -t flask-app .

-t flask-app . の部分は、カレントディレクトリ.にあるDockerfileという名称のファイルを読み込みflask-appというタグをつけるというオプションである。

ここでイメージが起動しているかどうかはdocker imagesコマンドで確認できる。ビルドが成功していれば、以下のように出力される。

REPOSITORY                                 TAG       IMAGE ID       CREATED        SIZE
flask-app                                  latest    09acf5d77c98   2 hours ago    1.09GB

続いて、Dockerイメージからコンテナを起動する。コンテナの起動は以下のコマンドで実行できる。

docker run -d -p 5001:5000 flask-app
  • -dは「デタッチドモード(detached mode)」を意味し、コンテナがバックグラウンドで実行されるため、このコマンドを入力したターミナルが操作可能な状態なまま残る
  • -p 5001:5000はポートマッピングを指定するオプションであり、5001は外部からアクセスするポート、5000はコンテナ内でコンテナがリッスンするポート
  • ホストマシンのポート5001http://localhost:5001のようにアクセスするとコンテナ内のアプリのポート5000にマッピングされflask-appにアクセス可能
  • このようになっている理由は、このプログラムを試していた際、ホストマシンのポート5000が別のプロセスで埋まっていたため

この状態で、http://localhost:5001/をブラウザで開いてHello Dockerという文字列が表示されればコンテナの起動に成功していることがわかる。

Docker compose を使用してコンテナを起動

これまで作成してきたDockerfileをDocker composeを使用して起動する。実際の開発では、今回作成したDockerfileに加え、他のチームメンバーが開発したDockerfileもこのDocker composeで同時に起動されることになる。先ほどのproject-root直下に以下のdocker-compose.ymlファイルを作成。

services:
  flask-app:
    build: .
    ports:
      - "5001:5000"
    environment:
      - FLASK_ENV=development
  # app2:
  #   build: .
  #   ports:
  #     - "5002:5003"
  #   environment:
  #     - FLASK_ENV=development

上記は、flask-appというタグをつけて、先ほど作成した Dockerコンテナ + flaskのPythonアプリを起動するための設定ファイルである。つまり、docker build -t flask-app .というコマンドとdocker run -d -p 5001:5000 flask-appという2つのコマンドを上記ファイルでは、一括で実行可能。

  • Services:複数のコンテナ(サービス)を定義する場所
  • flask-app:1つ目のコンテナの名称
  • build:.:カレントディレクトリからflask-appのDockerfileを探索してそれに従いbuild
  • ports:ポート番号の指定
  • app2:今回は作成していない2つめのサービス。ポート番号を変えているので、flask-appと同時に別々のポートからリクエストを受け付けることが可能

このファイルを以下のコマンドにより、読み込み実行。

docker-compose up --build

docker-compose upコマンドは、サービスをビルドし、起動するコマンド。--build をつけることで、イメージの再ビルドを矯正。新しいコードの変更や、Dockerfileの更新があった場合は、必ずこのオプションをつける必要がある。

-d オプションを付けることでバックグラウンド実行が可能になり、--no-cache でキャッシュを無視して再ビルドも可能。

参考サイト

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?