Dockerとは:コンテナ型仮想化技術
- コンテナ型仮想化技術:Dockerは、従来の仮想マシンよりも軽量で効率的なコンテナを用いて仮想化(パソコンの中に仮想パソコンを起動する)を実現
- Dockerのコンセプトは、アプリケーションを開発、テスト、デプロイする過程をより効率的かつ一貫性のあるものにすること。これにより、環境の違いによって発生する問題(「うちのマシンでは動くけど、他のマシンでは動かない」というような問題)を大幅に減少させることができる。
Dockerイメージ
- アプリケーションの設計図:Dockerイメージは、アプリケーションとその実行に必要なすべてのファイル、ライブラリ、依存関係、環境設定を含む静的なファイル
- レイヤー化された構造:イメージは複数のレイヤーから成り立っており、これによりイメージの再利用、共有、更新が容易
Dockerコンテナ
- 実行可能なインスタンス:Dockerコンテナは、Dockerイメージから生成された実行時の環境。コンテナはイメージを基にして起動し、アプリケーションを実行するための隔離された環境を提供する。
- 軽量かつ柔軟性:コンテナは軽量で、必要に応じて簡単に起動、停止、移動、削除が可能。
Tag:Imageのversion
- tag名を何も指定しないと 自動的に「latest」タグが使用される
- image名とタグ名を : で区切って、下記のように表記される。
nginx:latest
nginx:1.14-perl
Dockerの概念に関して詳しくは下記参照
https://qiita.com/etaroid/items/b1024c7d200a75b992fc
Dockerfile
アプリケーションをDocker化して起動したい時に作成する。
Dockerイメージを作成するためのテキストファイル(レシピ)。
pythonのflaskアプリケーションを例に記載
Flask アプリケーションの外部化:host=’0.0.0.0’
docker化するということは、dockerコンテナという独自の環境に対して、外部からアクセスできるようにしてアプリケーションを検証するということなので、アプリケーションを外部に開放しないといけない。実行ファイルにhost='0.0.0.0'
を指定する。
host='0.0.0.0'
を指定しない場合、アプリケーションは外部からの接続を受け付けず、127.0.0.1
(localhost)からのみアクセス可能
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, Docker!'
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
Dockerfileの作成
Dockerfileは、Dockerイメージの設計図。DockerfileがないとDockerを起動できない。
# 基本イメージとしてPythonを使用
FROM python:3.8-slim
# 作業ディレクトリを設定
WORKDIR /app
# 必要なファイルをコンテナにコピー
COPY . /app
# 必要なパッケージをインストール
RUN pip install -r requirements.txt
# アプリケーションの実行コマンド
# コンテナが起動する時に、app.pyを実行することを意味する。
CMD ["python", "app.py"]
WORKDIR
WORKDIR
ディレクティブは、コンテナ内での作業ディレクトリ(カレントディレクトリ)を設定する。すべての後続の命令は、このディレクトリを基準に実行される。
COPY
COPY
コマンドは、ホストマシンからファイルやディレクトリをコンテナ内にコピーする<source>
はホストマシン上のファイルまたはディレクトリのパスであり、<destination>
はコンテナ内のパス。<destination>
はWORKDIR
で指定したディレクトリを基準とする。
COPY <source> <destination>
例えば、下記のflaskアプリケーションがあったとして、実行ファイル(ここではroutes.py)がapp/配下にある場合は、app/ディレクトリ内の全てのファイルとサブディレクトリを、コンテナ内にコピーする。
COPY app/ /app/
COPYの相対パスと絶対パス記述に関して
Dockerfile内でパスを指定する際に、「/」を先頭につけるかどうかで、相対パスと絶対パスが区別される。
copy先のディレクトリの手前に「/」をつけなければ相対パス、「/」をつければ絶対パスで指定することを表す。
app/
:WORKDIR
に設定されているディレクトリに対する相対パス。WORKDIR
は設定しない場合は、コンテナのルートディレクトリになる。
/app/
:コンテナのルートディレクトリからの絶対パス。
ややこしくなってきたが、ローカル環境にあるflaskアプリケーションの実行ファイルがapp/配下にあって、それをdockerコンテナのapp/に再現したい場合は
1)WORKDIRを設定しない場合
コンテナのルートディレクトリがデフォルトの作業ディレクトリになる。
WORKDIR
が設定されていない場合、COPY app/ /app/
と COPY app/ app/
は実質的に同じ操作を意味する。どちらの命令も、ホストの app/
ディレクトリをコンテナの /app/
ディレクトリにコピーする。
Dockerは必要なディレクトリを自動的に作成するので、app/
ディレクトリが存在しない場合でもエラーは発生しない。相対パスでCOPYを指定した時に、workdirを設定していないと、そもそもapp/ディレクトリがないので、copy先のディレクトリが作成されてないよというエラーが出そうな気がするが、そこはよしなに対応してくれる。
COPY app/ /app/ #コンテナのルートディレクトリからの絶対パスで指定
COPY app/ app/ #相対パス。WORKDIRを設定していないのでルートディレクトリからのパスになる
2)WORKDIRを設定する場合
workdirを/appと記載した場合
絶対パスで指定する場合は、workdirを設定しない場合と同じで、もちろん変更はない。
一方で相対パスで指定する場合は、カレントディレクトリが/appなので、「.」と設定する。
WORKDIR /app
COPY app/ /app/ #コンテナのルートディレクトリからの絶対パスで指定
COPY app/ . #相対パス。/appに作成したいので、カレントディレクトリ「.」
ちなみにWORKDIR
を /test
に設定した場合、COPY
コマンドでファイルをコピーするときにも WORKDIR
の値を考慮してコピー先のパスを指定する必要がある。まず、ないと思うが。
WORKDIR /test
COPY app/ /test/
となる。仮にこのdockerfileで実行した場合、ホストの下記のファイル構成は
app/
app.py
static/
style.css
Dockerコンテナ内では
/test/
app.py
static/
style.css
となる。
requirements.txt
先ほどのcopyの続きだが、下記のようなflaskアプリケーションのフォルダ構成の場合、app/配下をdockerコンテナのapp/配下にコピーした場合、requirements.txtはapp/配下にないので、当然コピーされない。
なので、別途コピーする必要がある。
ローカルのフォルダ構成と同じにする場合には、下記で絶対パスのルートディレクトリ「/」を記載
COPY requirements.txt /
# 使用するPythonのベースイメージ
FROM python:3.10-slim
# 作業ディレクトリを設定
WORKDIR /app
# 依存関係をインストール
COPY requirements.txt /
RUN pip install --no-cache-dir -r requirements.txt
# アプリケーションのコードをコピー
COPY app/ /app/
# コンテナ内で実行するコマンド
CMD ["python3", "routes.py"]
-r
フラグ: “requirements file”(要件ファイル)を意味し、pip
に対して与えられたファイルからパッケージ名のリストを読み込み、それらをインストールするよう指示--no-cache-dir
オプション:requirements.txtにリストされたパッケージをキャッシュなしでインストールする。dirはdirectoryの略。
pip
を使ってPythonのライブラリをインストールする時、通常はダウンロードしたライブラリをキャッシュとして保存する。Dockerのイメージを作るときには、キャッシュがイメージの中にも保存されてしまい、イメージのサイズが大きくなってしまう。
--no-cache-dir
オプションを使ってキャッシュを無効にすると、ライブラリはインストールされますが、キャッシュとして保存されないないため、イメージのサイズが小さくなる。
ただし、メリットばかりではなく、キャッシュを無効にすると、pipは毎回必要なパッケージをインターネットからダウンロードしなければならず、それがDockerコンテナビルド時間の増加につながる。
Flaskとその他必要なライブラリを記載したrequirements.txt
を作成する。
flask==1.1.2
requests>=2.24.0
numpy
-uオプション:バッファリング無効
バッファリング
- バッファリングは、データを一時的に格納するプロセス
- Pythonでは、デフォルトで標準出力(print文などによる出力)は「バッファリング」される。つまり、実際に画面に表示されるまで一定量のデータが溜まるか、または出力バッファがフラッシュされる(空にされる)まで、出力が保留されます。
リアルタイムでpythonのログを出力するには、このバッファリングを無効にする必要があり、そのためには、Python スクリプトを -u
オプションをつけて実行する必要がある。
CMD ["python", "-u", "script.py"]
-u
オプションの -u
は、特に略称ではなく、単なるオプションのフラグ。Pythonの公式ドキュメントでは、-u
は単に “unbuffered binary stdout and stderr”(バッファリングされないバイナリ形式のstdoutおよびstderr)の意味で使用されている。
Docker イメージのビルド
Dockerfileを使用してDockerイメージをビルド。
現在のディレクトリ(.
)にあるDockerfileを使用して、flask-app
という名前のイメージを作成する場合
- -t オプションは「tag」の略で、ビルドされるイメージに名前(タグ)を付けるために使用される
- flask-appは、イメージに付ける名前。この名前は任意で、後でイメージを識別しやすくするために使う。例えば、アプリケーションの名前やバージョンなど、意味のある名前を付けるのが一般的
- ドット . は、Dockerfileがあるディレクトリ。この場合、現在の作業ディレクトリ(コマンドを実行しているディレクトリ)。Dockerfile が別のディレクトリにある場合、そのディレクトリのパスを指定する必要あり。
docker build -t flask-app .
Docker コンテナの実行
ビルドされたイメージからコンテナを起動する。
- 8080番ポートをローカルマシンの5000番ポートにマッピングして、flask-appイメージからコンテナを起動する。これにより、http://localhost:8080 でFlaskアプリケーションにアクセスできるようになる。
docker run -p 8080:5000 flask-app
環境変数を指定するとき
これで、Dockerコンテナをビルドして実行して、サイトにアクセスできるようになる。
ただし、これだと、毎回portマッピングや環境変数をdocker runのオプションコマンドで指定しないといけないので手間。というわけで、docker-compose.ymlという概念が登場する。
docker-compose.ymlは絶対ないと、Dockerを起動できないというわけではないが、docker操作を効率化するためのもの
docker-compose.yml
version: '3'
services:
web:
build: .
image: flask-app
ports:
- "8080:5000"
environment:
- FLASK_ENV=development
- OPENAI_API_KEY=${OPENAI_API_KEY}
volumes:
- ./app:/app
version: '3'
: これはdocker-compose.yml
ファイルのバージョンを指定。バージョン3はDocker Composeの特定のバージョンでサポートされる機能セットを持っている。services
: このセクションでは、管理するサービス(コンテナ)を定義する。サービスは、実行するコンテナのこと。web
: 定義されたサービスの名前。この例では “web” という名前のサービスになっているが、これはFlaskアプリケーションを実行するコンテナになるbuild: .
: これはDocker Composeに、カレントディレクトリ(.
)を使用してコンテナイメージをビルドするよう指示。docker build -t flask-app . コマンドの最後につけている部分を指す。ports
: port mapping。ホストマシンの8080ポートをコンテナの5000ポートにマッピングすることを意味environment
: 環境変数をコンテナに設定。この例では、FLASK_ENV
をdevelopment
に設定しているので、Flaskが開発モードで実行されることを意味する。また、OPENAI_API_KEY
は環境変数から読み取られ、コンテナ内の環境変数として設定されます。volumes
: ホストマシンとコンテナ間でファイルシステムのマウントを設定。この例では、ホストマシンのカレントディレクトリ内のapp
ディレクトリをコンテナ内の/app
にマウントしている。ホストマシン上でapp
ディレクトリ内のPython関数(またはその他のファイル)を編集すると、それらの変更がすぐにコンテナ内のファイルにも反映される。コンテナが動いている間にファイルを変更した場合、その変更はコンテナ内で実行されているアプリケーションにも直ちに影響を与える。
複数のDockerコンテナ間で通信したい場合は、external:trueを設定する。
Dockerによる自動イメージ名生成の仕組み
image
キーに関して
docker-compose.yml
ファイルにimage
キーを記載しなくてもdocker-compose up
を実行することは可能。この場合、Docker Composeは自動的にイメージ名を生成し、ビルドされたイメージに割り当てる。image
キーが指定されていない場合、Docker Composeはデフォルトの命名規則に従ってイメージ名を生成する。
<ディレクトリ名>-<サービス名>
<ディレクトリ名>
は docker-compose.yml
ファイルが存在するディレクトリの名前
<サービス名>
は docker-compose.yml
ファイル内の services
セクションで定義されているサービスの名前。加えて、Docker Composeはイメージに自動的にタグ latest
を付ける。
たとえば、docker-compose.yml
ファイルが myproject
ディレクトリにある場合には、Docker Composeは myproject-web
という名前のイメージを自動的に生成し、タグ latest
を付ける。これにより、ビルドされたイメージは myproject-web:latest
として識別される。特定のイメージ名を指定する必要がある場合は、image
キーを使って名前を明示的に設定する。
Dockerコマンド
docker-compose.ymlファイルを作成すると、docker-composeコマンドを使ってDockerを操作(ビルド・実行・停止・削除)できるようになる。
ビルド(Build)
docker-compose build
docker-compose.yml
に定義されたサービスのイメージをビルドする。これにより、指定されたDockerfileに基づいて各サービスのDockerイメージが作成される。
実行(Up / Run)
docker-compose.yml
ファイルに定義されたすべてのサービス(コンテナ)を起動する場合
docker-compose up
指定されたサービス(コンテナ)を個別に起動し、任意のコマンドを実行する場合
SERVICE:実行するサービス名
docker-compose run [options] SERVICE [COMMAND] [ARGS...]
実行時に強制ビルド:up —build
docker-compose up
コマンドは通常、ビルドされたイメージがない場合には新規ビルドを実行する。既にビルドされたイメージがある場合、再ビルドせずにコンテナを起動する。ビルドを強制的に行いたい場合は、--build
オプションを使用する。
docker-compose up --build
ログ(logs)
ログのリアルタイム表示:-f(followの略)
特定のサービスのログを見たい場合は、サービス名を指定する。例:docker-compose logs -f web
。
停止(Down)
docker-compose down
docker-compose up
で起動したサービスを停止し、コンテナ、ネットワークやボリュームなどのリソースも削除する。イメージは削除されない。イメージを削除したい場合は、docker-compose down
コマンドに --rmi
オプション(remove imageの略)を追加する。
イメージ削除:—rmi(remove image)
docker-compose down --rmi all #全てのイメージ削除
docker rmi [イメージ名またはイメージID] #特定のイメージ削除
個別のサービス停止(Stop)
全てのサービスを停止するときはdownだが、個別のサービスを停止したいときはstop。
stopコマンドは指定したサービスのコンテナの実行を停止させるが、コンテナを削除はしない。
docker-compose stop service_name # service_name:停止したいサービス名
コンテナ内でのコマンド実行(Exec:execute)
docker-compose exec -it service_name bash
Execはexecute(実行する)の略
-it
オプション
- インタラクティブな操作や端末(TTY)のアタッチメントを可能にするために使用される
-i
:--interactive
の略。-t
:-ttyの略。仮想端末(TTY)- 既に実行中のコンテナに対して、インタラクティブなシェルを起動するには、
docker exec
コマンドに-it
オプションを使用する
docker exec
ではコンテナ名またはIDを使用し、docker-compose exec
ではサービス名を使用する
docker exec -it my_container bash #コンテナ名 or コンテナID
docker-compose exec my_service bash #サービス名
bash
- コンテナ内で実行するコマンドを指定している
- すべてのコンテナに
bash
がインストールされているわけではありません。特に軽量なイメージでは、bash
の代わりにsh
(シェル)や他のコマンドラインインターフェースが使われることがある
コンテナ一覧表示:ps(process statusの略)
docker ps
現在実行中のコンテナの一覧を表示する。これにより、システム上でどのDockerコンテナが稼働しているかを簡単に確認できる。
以下のような情報を含む表を出力する:
- CONTAINER ID:コンテナの一意のID。
- IMAGE:コンテナを作成するのに使用されたイメージ。
- COMMAND:コンテナ起動時に実行されたコマンド。
- CREATED:コンテナが作成されてからの経過時間。
- STATUS:コンテナの状態(実行中、停止中、一時停止中など)。
- PORTS:コンテナが開放しているポートと、それに対応するホストマシンのポート。
- NAMES:コンテナの名前。
コメント