「データサイエンティストたちよ。フォースを感じるのだ。」ーDockerFileを理解し、書けるようになるー
Dockerはすべてのデータサイエンティストの心強い味方です。いつもDockerとともにいることを感じていればどんなデータ分析も怖くない!
ということで、今回はDockerのインストールを完了してから、どんな感じでデータサイエンティストはDockerを使えばいいのか?を解説していきます。
より具体的にはどのようにDockerFileを書いたらいいのかを説明していきます。
Dockerは、データサイエンティストがデータ分析環境を構築するために非常に役立つツールです。それ自体がデータ分析の主要な技術ではありませんが、データサイエンスプロジェクトにおけるエラーを回避しながら、再現性を高めたり、効率的に前のデータ分析環境を使いまわすことで、今よりもテンポよくデータ分析を行うことができるようになります。
Dockerってぶっちゃけデータサイエンティストに必要なの?
データサイエンティストにとってのDockerとはすなわち、データ分析環境です。データ分析環境と聞いて「?」と思っている方も多いのではないでしょうか?
多くの方々はデータ分析を行う環境はJupyter notebookやVisual studio codeをローカルPCにインストールしてそこでPythonを使っているのではないかと思います。
データ分析環境といったときに、上記のようなJupyter notebookやVisual studio codeのように分析を行うアプリケーションやIDE環境をどれにするのか?も立派な環境構築の設定項目の一つです。さらにはPythonと一口に言っても最新版のPythonを使うのか、プロジェクトに合わせてちょっと前のバージョンのPythonを利用するのかも設定の一つです。さらに利用するライブラリーをどれにするのか?利用するライブラリーのバージョンはどうするのか?など実はあまり意識はこれまでしてこなかったかもしれませんが、いろいろデータ分析を行うためには環境構築が必要なのです。
「意識せずこれまでできてたのに、なんでそんなこと気にする必要があるの?」
そう思った方もいらっしゃるかと思います。確かにその通りです。しかし、データ分析も例えばビジネスで行っていくと例えばあなたのコードはあなたの分析環境では問題なく動くのに、どういうわけか仲間の環境だと動かないという問題が生じたりします。また、仮にあなたがパソコンを買い替えたとしてこれまでと同じ分析環境を新しいパソコンに構築する必要がありますが、実際それって手動でやるのはかなりの手間だったりします。
こうした課題や問題に対していくつか方法はありますが、Dockerを利用するというのが解決策の一つだったりします。なぜならDockerはこうした分析環境の仕様を決めて定義書として書いておくことで、必要な時にその定義書に基づいて仮想的なデータ分析環境を作り出すことができるからです。こうした定義書のことをDockerでは「DockerFile」と呼びます。そしてこのDockerFileの定義書に基づいて実際に環境を構築するときに立ち上げるファイルを「Dockerイメージ」といいます。
Dockerが面白いのは、DockerFileという名の定義書を自分で書く以外に他の人が書いた定義書を利用して環境を構築することができるという点です。
つまり、「あぁ~こんなデータ分析環境があったらいいんだけど、自分でDockerFile書くのはめんどくさいな。サクッと環境構築したいんだけど」なんて思ったときに他の人が書いた定義書を利用することでほんの数行で自分のほしい環境を構築することができるのです。また、他の人が書いている定義書をテンプレートのように利用して、そこから自分の定義を書き足して作るということも可能です。
この記事では、データ分析環境を構築するための仕様を定義する
「DockerFile」の書き方や意味について解説をします。
DockerFileに入る前にコンテナ環境の開始と終了のおさらい
本題に入る前に、まずコンテナ環境を開始し、終了する方法についておさらいしましょう。コンテナってなんだっけ?という部分についてはいろいろな方が解説しているのでここでは詳しく解説しませんが、データサイエンティストが自分のパソコン上で構築する文脈においてコンテナとは、「自身のローカルPCに生み出すちっちゃなPC」のようなものだと考えてください。
コンテナで生み出すちっちゃなPCは自分のローカルPCのハードウェアとOSは共有しますが、どんなアプリケーションを入れていくかとかは母体となるローカルPCとは独立してインストール・管理できるため、データ分析専用の環境をもつちっちゃなPCをローカルPC上につくれる、という雰囲気で覚えておくとよいです。
さてここでのミッションは、新しい環境でデータ分析を始めるためのコンテナ環境を構築することです。最初のステップは、Dockerfileに基づいて定義された環境を起動することです。これは docker run コマンドで実行されます。
docker run コマンドに --entrypoint /bin/sh オプションを追加すると、その環境内でシェルを即座に使用できるようになります。このオプションは、Dockerfile内でEntrypointを設定している場合でも有効です。
docker run -it --rm --entrypoint /bin/sh {IMAGE NAME}
コンテナ環境を /bin/sh を指定せずに起動した場合でも、起動した後に別途docker exec を使用してその環境に入ることができます。
docker exec -it {my-container_id} /bin/bash
/bin/sh はBourne Shellを使用するためのもので、多くのLinux OSでデフォルトのシェルとして設定されています。別のシェルを使用したい場合は、引数を変更することで対応できます。ただし、使用したいシェルは事前にインストールしておく必要があります。以下はDockerコンテナで利用可能なシェルの代表例です。
Dockerコンテナで利用可能なシェル
Dockerコンテナ内で使用できるシェルは複数ありますが、それはベースとなるDockerイメージやオペレーティングシステムに依存します。
Unix系シェル
/bin/sh : Bourne Shell
/bin/bash : Bash
/bin/zsh : Z Shell
/bin/ksh : Korn Shell
Windows系シェル
cmd.exe : コマンドライン
powershell.exe : PowerShell
その他のシェル
fish : Friendly Interactive Shell
ash : Almquist Shell
Dockerイメージにどのシェルがインストールされているか確認する方法
公式イメージのドキュメントを確認する
他の人が書いたDockerイメージをベースに使う場合、そのDockerイメージの公式ドキュメントに記載されている情報を確認することでシェルを確認することができます。以下のようなコマンドを使用する
実際にコンテナ内に入って確認することも可能です。例えば以下のようなコマンドを実行します。これにより、コンテナ内でシェルの存在を確認できます。
docker run --rm -it <IMAGE NAME> --entrypoint /bin/sh -c "which bash"
docker run を実行する際に --rm オプションを指定した場合、exit コマンドを実行するとコンテナインスタンスは削除されます。
コンテナを終了する方法
コンテナ内での操作が終わったら、シェル内で exit コマンドを使用することでコンテナを停止できます。
exit
停止したコンテナを再起動する方法
停止したコンテナインスタンスを再起動する必要がある場合があります。その場合は、docker start と docker exec を使用して再起動できます。
# REBOOT
docker start <CONTAINER ID/ CONTAINER NAME>
# REBOOT AND CREATE A NEW SHELL SESSION ALTOGETHER
docker start -i <CONTAINER ID/ CONTAINER NAME> /bin/sh
# USE SHELL
docker exec -it <CONTAIN ID/ CONTAINER NAME> /bin/sh
コンテナインスタンスを継承して新しいコンテナを作成する方法
すでに立ち上げている別のコンテナを受け継ぐ形で新たなコンテナを立ち上げることもできます。
docker commit <CONTAINER ID/ CONTAINER NAME> <NEW IMAGE NAME>
DockerFileの書き方
さて、復習も終わったところでここからは本題のDockerfileの書き方を学んでいきます。Dockerfileは、さまざまな役割を持つ「命令」で構成されています。そのため、命令ごとにその意味を理解していくことでDockerFile全体を理解することができるようになります。
各命令の解説を順に行っていきます。
FROM
FROM は、カスタムイメージを作成するためのベースイメージを指定するために使用されます。ベースイメージとは、先に述べたようにほかの人が書いた定義書のことです。この定義書をベースにして自分の定義書を書くからベースイメージと呼ぶわけですね。
ベースイメージはDocker Hubで見つけることができ、次のように自分のDockerFileでは記載をします。
FROM {BASE-IMAGE-NAME}:{VERSION}
RUN
RUN は、コンテナ環境内で必要なものをインストールするために使用される命令です。その使い方を説明するために、ほとんどの場合に必要となるエディタをインストールしてみましょう。以下では、コンテナ環境で利用するエディタソフトとして「VIM」をインストールしておくような定義をしています。
# update the package lists & install Vim editor
RUN apt-get update && apt-get install -y vim
ENTRYPOINT
ENTRYPOINT は、コンテナ構築コマンドが実行される際にコンテナ内部で自動的に実行するコマンドを指定する命令です。CMD も似た機能を持つコマンドですが、docker run コマンドのオプションで置き換えることができるのに対し、ENTRYPOINT に指定したコマンドは確実に実行されるという違いがあります。
ENTRYPOINT を使用して異なるスクリプトファイルを実行する方法
ENTRYPOINTに直接コマンドを書かずにスクリプトファイルをENTRYPOINTでは指定することもできます。スクリプトファイルを指定することで長めのコマンドを実行したい場合などはDockerFileの可読性を高めることができます。以下はその例です。
Step 1: 独自のスクリプトを作成し、ファイルとして保存
この例では、start.sh というスクリプトファイルを作成します。このスクリプトには、Pythonファイルを実行するコマンドを記述します。これらのファイルは、Dockerfile と同じディレクトリに保存してください。
#!/bin/sh
# start.sh
echo "Starting application..."
python app.py
Step 2: Pythonファイルを作成する
app.py という名前のPythonファイルを作成します。このファイルでは、「Hello world」を出力します。
# app.py
print('Hellow world')
Step 3: Dockerfileを作成する
DockerfileにENTRYPOINT命令を含めます。
# base image
FROM python:3.12.5
# set working directory in the container environment
WORKDIR /usr/src/app
# copy files in the host directory to the container directory
COPY . .
# ENTRYPOINT to execute sh command
ENTRYPOINT ["sh", "start.sh"]
Step 4: 作成したDockerfileに基づきDockerイメージをビルドし、実行する
# Build
docker build -t {CONTAINER IMAGE NAME}.
# run the image
docker run {CONTAINER IMAGE NAME}
コンテナ実行が成功すれば、ターミナル上に次のようなメッセージが確認できるはずです。
Starting application...
Hello world
CMD
CMDはDockerイメージを実行した際に自動的に実行されるデフォルトコマンドを指定する命令です。CMDは一つで、二つ以上書いても最後の一つのみが実行されるだけになります。以下はCMDコマンドの例です。
CMD ["echo", "Hello-World"]Dockerfileの例
JSON形式で記述された最初の引数はコマンドを表し、2つ目の引数はそのコマンドへの変数として扱われます。echo はシェルコマンドで、2つ目の引数を出力します。
Docker Fimeの例
# base image
FROM python:3.12.5
# meta information
LABEL description="This is a simple Dockerfile example"
# environment variables
ENV VAR Hello-World
# working directory
WORKDIR /usr/src/app
# app install
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# commands when activate this container
CMD ["echo", "Hello-World"]
CMDとENTRYPOINTの違いに注意
前述の通り、ENTRYPOINT は確実に実行されるのに対し、CMD は事前に定義した後でdocker run コマンドで置き換えることもできます。
例1: CMDの場合
CMD ["echo", "Hello-World"] を記述している状態で docker run <DOCKER IMAGE> ls を実行すると、ls コマンドが実行されます。
例2: ENTRYPOINTの場合
ENTRYPOINT ["echo", "Hello-World"] を設定している状態で docker run <DOCKER IMAGE> ls を実行すると、ls は echo コマンドの引数として渡されます。つまり、echo ls が実行され、結果として「ls」というテキストが出力されます。
COPY
COPY コマンドは、ホストマシン上の現在のディレクトリ内のすべての内容をコンテナのディレクトリにコピーします。
COPY {host directory path} {container direcotry path}
COPY . . と記述すると、Dockerfileが保存されているホスト側のディレクトリが、コンテナ内の WORKDIR に設定されたディレクトリにコピーされます。
例えば、WORKDIR /usr/src/app を設定している場合、ホスト上のすべてのファイルとディレクトリが /usr/src/app にコピーされます。
WORKDIR を設定していない場合、コンテナ環境内のルートディレクトリ (/) が使用されます。
複数のファイルをコピーする場合
以下のように指定することで対応できます。
COPY file1.txt file2.txt /path/in/container/
file1.txt と file2.txt がコンテナ内の /path/in/container/ ディレクトリにコピーされます。
コンテナ内のディレクトリパスは、ホスト側の現在のディレクトリからの相対パス、または絶対パスで設定できます。
コンテナディレクトリを指定しない場合、エラーが発生します。
コンテナ内にディレクトリが見つからない場合
コンテナ内に指定したディレクトリが存在しない場合、同じ名前のディレクトリが自動的に作成され、ホスト側の内容がコピーされます。
コンテナOSのデフォルトディレクトリと名前が重複する場合
コンテナOSで既に使用されているディレクトリ名を指定した場合、競合が発生する可能性があります。この競合を回避するために、以下の方法を検討しましょう。
重複する名前を避ける
.dockerignore を使用して不要なファイルをホストからコピーしないようにする
デフォルトディレクトリを上書きしないよう注意する
Linuxベースのコンテナで一般的なディレクトリ構造
以下は、Linuxベースのコンテナで一般的なディレクトリ構造です。このような名前のディレクトリを避けることで、不要な競合を回避できます。
/ (ルートディレクトリ):すべてのファイルとディレクトリの起点。
/bin: 基本的なユーザーコマンド (例: ls, cat, cp など) を含むディレクトリ。システム起動に必要なコマンドが配置されています。
/boot: ブートローダーやカーネルイメージを配置するディレクトリ。ただし、標準的なコンテナでは通常存在しません。
/dev: デバイスファイルを配置するディレクトリ。コンテナ内ではデバイスファイルがここにマウントされます。
/etc: システムの設定ファイルが配置されるディレクトリ。コンテナ内の設定ファイルもここに配置されます。
/home: ユーザーホームディレクトリを配置するディレクトリ。通常は空で、ユーザーアカウントに応じてホームディレクトリが作成されます。
/lib, /lib64: システムライブラリが配置されるディレクトリ。アプリケーションが依存するライブラリがここにあります。
/media, /mnt: 一時的なマウントポイントとして使用されるディレクトリ。コンテナでは通常使用されません。
/opt: オプションのアプリケーションソフトウェアがインストールされる場所。
/root: ルートユーザーのホームディレクトリ。
/sbin: システム管理用コマンドが配置されるディレクトリ。
/srv: サーバーサービスが提供するデータが配置されるディレクトリ。一般的なコンテナではあまり使用されません。
/tmp: 一時ファイルを配置するディレクトリ。通常、アプリケーションが生成する一時データが保存されます。
/usr: ユーザー関連のプログラム、ライブラリ、データが配置されるディレクトリ。
/usr/bin : ユーザーコマンド
/usr/lib : ライブラリ
/var: ログファイル、メールスプール、データベースなどの可変データが保存されるディレクトリ。
/var/log : ログファイル
/var/lib : アプリケーションデータ
VOLUME
コンテナ環境を起動した場合、コンテナ内に保存したデータはコンテナを停止すると失われます。しかし、コンテナ内で編集したデータを停止後も保持したい場合、“ボリューム” と呼ばれる特別なストレージ空間を作成し、そこにデータを保存することでデータを永続化できます。
この機能を実現するには、ボリュームを指定します。
Docker の VOLUME 指令は、コンテナとホストマシン間でデータを共有するためにも利用できる機能です。
言い換えると、コンテナ停止時にデータが失われないようにするだけでなく、複数のコンテナ間でデータを共有することも可能にします。
使用方法
ボリュームを定義する方法には2つあります:
1. Dockerfile 内で定義する方法
Dockerfile でボリュームを指定することで、コンテナのビルド時に自動的にボリュームが作成されます。
2. docker コマンドを使用してボリュームを作成・バインドする方法
特定のコンテナに紐づけられないボリュームを作成し、その後 docker コマンドで特定のコンテナにバインドすることが可能です。
Dockerfile に定義する例
VOLUME /data
この設定により、コンテナが起動された際に、/data ディレクトリがボリュームとして扱われ、コンテナ外からアクセスできるようになります。
VOLUME /data で指定された /data ディレクトリは、コンテナ内でルートディレクトリ (/) の直下に作成されます。なお、この設定は、WORKDIR の設定とは無関係です。
Docker コマンドで定義する方法
docker volume create コマンドを使用して、特定のコンテナインスタンスに紐付けられないボリュームを作成できます。
このボリュームは Docker ホストで管理され、複数のコンテナ間で共有することが可能です。
docker volume create {VOLUME NAME}
docker volume create コマンドを使用すると、特定のコンテナインスタンスに紐付けられていないボリュームを作成できます。
このボリュームは Docker ホストで管理され、複数のコンテナ間で共有することが可能です。
docker run -it --rm -v my_volume:/path/in/container my_image
ボリューム名 my_volume はボリューム自体を指し、/path/in/container はコンテナ内でのマウントポイントを指します。指定したディレクトリがコンテナ内に存在しない場合、Docker はボリュームをマウントする際に自動的にそのディレクトリを作成します。
つまり、コンテナ内に /data ディレクトリが存在しなくても、ボリュームを指定すると Docker が自動的に作成するため、Dockerfile で明示的にディレクトリを作成する必要はありません。ただし、アプリケーションがそのディレクトリを設定ファイルやスクリプトで必要とする場合は、事前に作成しておくことが推奨されます。
一方で、指定したディレクトリがすでに存在する場合、そのディレクトリがボリュームのマウントポイントとして使用されます。そのディレクトリに既存のデータがある場合、それはボリュームの一部として扱われます
Dockerfile の VOLUME 指令を使用して特定のコンテナに紐付いたボリュームを作成する場合は、特に注意が必要です。--rm オプションを付けてコンテナを実行し、終了した後に同じイメージで新しいコンテナを作成した場合、ボリューム内のデータは保持されません。これは、ボリュームの新しいインスタンスが毎回作成され、元のボリュームインスタンスが使用されないためです。そのため、同じコンテナインスタンスを停止して再起動する場合はボリュームデータにアクセスできますが、コンテナインスタンス自体を削除した場合(例:docker run コマンドで --rm オプションを使用して終了した場合)、データへのアクセスは失われます。
したがって、複数のインスタンスやコンテナ間でボリュームデータを共有したい場合は、docker volume create {ボリューム名} を使用してボリュームを作成することが推奨されます。これにより、個々のコンテナインスタンスのライフサイクルを超えてボリューム内のデータが保持されます。
ボリュームにホストからデータを追加する方法
docker volume create で作成したボリュームにホストからファイルを追加する方法はいくつかあります。以下はその手順です:
1: 一時的なコンテナを使用してデータを追加する
一時的なコンテナを作成して、ボリュームを使用してデータを追加することができます。
docker run -it --rm -v my_volume:/data alpine sh
my_volume はボリュームの名前です。
/data はボリュームがマウントされるコンテナ内のパスです。
alpine は sh シェルを含むベースイメージです。
コンテナ内のファイルをボリュームにマウントされたディレクトリにコピーすることで、これらのファイルがボリュームに保存されることを保証します。
cp /path/to/your/files/* /data/
/path/to/your/files/ はホスト側のファイルパスです。
/data/ はボリュームがマウントされるパスです。
2: Bind-Mountを使用してデータを追加する
もう一つの方法は、Bind-Mountを使用することです。これは、ホストマシンの特定のディレクトリをコンテナ内のディレクトリにマウントする方法です。この方法を使用すると、ホストとコンテナの間で同じディレクトリを共有でき、変更が双方に反映されます。
ホストでディレクトリを準備する:
ホストマシンで共有したいディレクトリを作成します。例えば、/path/to/host-dir にディレクトリを作成します。コンテナを起動する際にBind-Mountを指定する:
docker run コマンドで -v オプションを使用してBind-Mountを設定します。
以下でホストでディレクトリを作成し、その中にファイルを入れます
mkdir -p /path/on/host cp /path/to/your/files/* /path/on/host/
次のコマンドでコンテナを起動し、バインドマウントを行うことができます。
docker run -it --rm -v /path/on/host:/data my_image
/path/on/host はホストディレクトリです。
/data はコンテナ内でマウントされるディレクトリです。
my_image はイメージ名を指します
マウントオプション以外に-v optionを利用する方法もあります。
docker run -it --mount type=bind,source="$(pwd)"/src,target=/{WORKDIR_NAME}/src --entrypoint /bin/sh
この場合、WORKDIR を指定する際には注意が必要です。ホスト側に「Volume_share_test」というフォルダがある場合でも、コンテナ側では「app」という名前に変わる点に留意してください。
コンテナ内でのデータ編集
コンテナ内で /path/in/container にデータを保存すると、そのデータはホストの /path/to/host-dir にも保存されます。逆に、ホスト側での変更もコンテナ内に反映されます。
ホストとコンテナの変更における競合
ホストとコンテナで同じディレクトリやファイルを共有するためにBind-Mountを使用する場合、両方の環境で行われた変更が競合することがあります。以下はその影響と考慮点です。
即時反映
Bind-Mountはホストとコンテナ間でリアルタイムで同期されます。つまり、ホスト側でファイルが変更されると、コンテナ内の対応するファイルも即座に更新されます。同様に、コンテナ内での変更もホストに即時に反映されます。
上書きとデータ損失
ホストとコンテナで同じファイルに異なる変更を加えた場合、最も最近の変更がファイルに反映され、以前の変更は上書きされます。この結果、データ損失が発生する可能性があります。すべての変更が保持されるわけではありません。
編集競合
両方の環境で同時に編集を行うと、ファイルの整合性が損なわれる可能性があります。特に、複数のプロセスやユーザーが同時にファイルにアクセスしている場合、競合が発生する可能性があります。
特定のケース例
例えば、ホスト側で「file.txt」を変更し、同時にコンテナ内でも「file.txt」を変更した場合、最後に行われた変更が優先されます。元々の変更は失われます。また、ホスト側でファイルを削除すると、コンテナ内でもそのファイルは削除されますし、その逆も同様です。
競合の軽減策
変更管理: 同じファイルに対して複数の編集が予想される場合、変更管理戦略を策定します。例えば、特定のプロセスにファイル編集を制限したり、変更管理ツール(Gitなど)を使用することが考えられます。
バックアップ: 定期的に重要なデータをバックアップし、データ損失のリスクを減らします。
適切なマウント: 競合を避けるために、異なるディレクトリやファイルをマウントすることを検討します。例えば、アプリケーションデータをボリュームで管理し、設定ファイルやスクリプトをBind-Mountで扱うことができます。
ファイルロック: 一部のアプリケーションやシステムではファイルロック機構を使用して同時編集を防止します。ただし、すべてのシステムやツールがこれをサポートしているわけではありません。
EXPOSE
EXPOSE コマンドは、Dockerfile内でコンテナが外部に公開するポート番号を宣言します。例えば、コンテナ内でJupyterノートブック環境を実行し、ホストのブラウザからアクセスしたい場合、アクセス用のポートを指定する必要があります。
EXPOSE は、他のコンテナやサービスに対して、コンテナ内のアプリケーションがリッスンしているポート番号を通知する役割を果たします。例えば、Webアプリケーションがコンテナ内でポート8080を使用している場合、Dockerfileには EXPOSE 8080 と記述します。
また、EXPOSE で公開されたポートは、docker-compose.yml で定義されたサービス間の通信にも使用できます。
実行時のポート公開
EXPOSE はポートを宣言するだけであり、実際にそのポートを外部からアクセス可能にするためには、docker run コマンドを使ってポートをマッピングする必要があります。EXPOSE は主にドキュメントの役割を持ち、Dockerfileを確認することでどのポートが使用されているかを把握するのに役立ちます。この情報は、複数のチームやユーザーが同じDockerfileを使用する場合に特に有用です。
ホストポートとコンテナポートをマッピングするには、以下のように -p オプションを使用します。
docker run -p 8080:8080 my_image
ホストのポート8080はコンテナのポート8080にマッピングされ、外部からアクセスできるようになります。
ポート指定のフォーマット:
単一ポート: EXPOSE 8080
複数ポート: 複数のポートを公開する場合は、複数の EXPOSE コマンドを指定します。
EXPOSE 8080 EXPOSE 443
ポートとプロトコル: 特定の通信のプロトコルを使用することもできます。デフォルトではTCPだけでなくUDPも利用することが可能です。
EXPOSE 8080/tcp EXPOSE 53/udp
ENV
コンテナ内で使用する環境変数を設定できます。例えば、データベース接続情報や操作モードなどを環境変数として指定することで、コンテナ環境がそのデータベースを使用できるようになります。また、同じイメージを使用しながら、実行時に異なる設定を提供することも可能です。これにより、開発環境と本番環境で異なる設定を使用する際に便利です。環境変数を使用することで、イメージをより柔軟で再利用可能にできます。環境変数を変更することで、コンテナの動作を変更できます。
使用方法:
Dockerfileで指定する方法
ENV をDockerfileに記述することで、イメージがビルドされる際に環境変数を設定できます。
ENV VAR Hello-World
実行時に上書きする方法
docker run コマンドの -e オプションを使用することで、コンテナを起動する際に環境変数を上書きできます。
ENV VAR Hello-World と ENV VAR=Hello-World の違い
これらは似ているように見えますが、Dockerfile内での動作は少し異なります。
ENV VAR Hello-World: 複数の環境変数を一度に設定する柔軟な方法です。
ENV VAR=Hello-World: 1つの変数だけを設定するより明示的な方法です。
ENV VAR Hello-World は、変数 VAR に Hello-World を設定します。この記法を使うと、複数の環境変数を一度に設定できます。
ENV VAR1 Hello-World VAR2 Another-Value
これらは次のように解釈されます:
VAR1=Hello-World
VAR2=Another-Value
ENV VAR1=Hello-World: これは、変数 VAR1 に Hello-World を設定します。= 記号を使用することで、単一の環境変数を定義できます。
WORKDIR
これは、コンテナ内で作業ディレクトリを設定するための命令です。このディレクトリに対して、すべての後続の命令(RUN、CMD、ENTRYPOINT、COPY、ADDなど)が実行されます。指定されたディレクトリが存在しない場合は、自動的に作成されます。WORKDIR で指定されたディレクトリは、コンテナ環境を起動してシェルに入ったときの初期のルートディレクトリ(/)とは異なります。
WORKDIR /usr/src/app
例えば、WORKDIR /usr/src/app を設定すると、すべての後続の命令(RUN、CMD、COPY など)は /usr/src/app ディレクトリ内で実行されます。コンテナ起動時に実行されるコマンド(CMD や ENTRYPOINT で指定されたコマンドなど)も、WORKDIR で指定されたディレクトリ内で実行されます。
また、
これはコンテナシェルを起動したときの初期ディレクトリにもなります。例えば、docker run -it <image_name> /bin/bash でコンテナシェルに入ると、初期ディレクトリは /(ルートディレクトリ)になります。しかし、WORKDIR が設定されている場合は、そのディレクトリが初期ディレクトリとなります。この設定は、インタラクティブシェル(-it オプション)でコンテナを起動する場合にも適用されます。
LABEL
LABEL は、イメージやコンテナに関する情報(例えば、バージョン、メンテナー、プロジェクト名、ライセンス情報など)を記録するために使用します。Docker Hub やプライベートリポジトリでイメージを検索する際、LABEL に基づいてイメージをフィルタリングやタグ付けすることができます。さらに、CI/CD パイプラインや運用スクリプトで、特定のラベルを持つイメージやコンテナに対して特定のアクションを実行することができます。
補足(おまけ):echoコマンド
echo コマンドは、シェル(ターミナル)やスクリプトでテキストや変数の内容を表示するための基本的なコマンドです。主に、文字列や変数の値を確認したり、それらを他のコマンドに渡すために使用されます。
echo "Hello, World!"
主な用途:
文字列の出力: echo の後に文字列を入力すると、その文字列が入力した通りに出力されます。 例: echo "This is a test." → This is a test. と表示されます。
変数の値を確認: echo を使って、環境変数やシェル変数の値を表示できます。 例: echo $HOME → ユーザーのホームディレクトリへのパスが表示されます。
ファイルや他のコマンドに渡す: echo の出力をリダイレクト (> または >>) して、ファイルに書き込むことができます。 例: echo "Hello, File!" > hello.txt → hello.txt というファイルが作成され、その中に "Hello, File!" が書き込まれます。 また、パイプ (|) を使用して、出力を他のコマンドに渡すこともできます。 例: echo "hello" | grep "h" → grep が "h" を含む行を検索するため、hello と出力されます。
環境変数の表示: echo を使って環境変数を表示することもできます。
VAR="Hello, World!"
echo $VAR
オプション:
-n: 改行を加えずに出力します。
echo -n "Hello" echo "World"
-e: バックスラッシュ(\)で始まる特殊文字を解釈します(例:\n は改行を意味します)。
echo -e "Hello\nWorld"