はじめに
Dockerやコンテナについてふわっと理解できているくらいで、どんなことが便利なのか?実際にはどのように使用するのか?が分かっていなかったので今回学習してみました。
自分なりにわかりやすくまとめたのでこれからDockerを学習する方の参考になればいいなと思っています。
コンテナの特徴
コンテナはコンテナ内のプロセスがすべて終了した際にExitされる。
Dockerfileとは
イメージをカスタマイズするために使う。
dockerhubに存在するイメージは最低限の機能しか入っておらず、カスタマイズが必要。
外に持ち出せるのはイメージのため、コンテナではなくイメージをカスタマイズする。
FROMエリア
元となるdockerイメージを指定できる。
# FROM {元となるdockerイメージ名}
FROM ubuntu:20.04
RUNエリア
コンテナ起動時にシェルで実行したいコマンドを指定できる。
FROM ubuntu:20.04
# RUN {任意のコマンド}
RUN apt update
RUN apt install -y curl
COPYエリア
ホストマシンの任意のファイルやディレクトリをコンテナにコピーできる。
イメージビルド時にコピーされるため、ビルド後に元ファイルを操作しても影響はない。
FROM ubuntu:20.04
RUN apt update
RUN apt install -y curl
# COPY {元ファイルのパス} {コンテナ内のパス}
COPY ./hello.txt /app/
CMDエリア
コンテナ実行時のデフォルトコマンドを設定できる。
Dockerfileで1度のみ使える。複数ある場合最後のCMDのみ有効になる。
FROM ubuntu:20.04
RUN apt update
RUN apt install -y curl
COPY ./hello.txt /app/
# CMD ["実行ファイル", "パラメータ1", "パラメータ2"]
CMD ["ls", "-a"]
ENVエリア
環境変数を設定できる。1度に複数個の環境変数を設定することも可能。
イメージ作成時とコンテナ実行時に利用する変数を作成。
コンテナの中で環境変数によって処理を動的に変更するときなどに有効。
FROM ubuntu:20.04
RUN apt update
RUN apt install -y curl
COPY ./hello.txt /app/
# ENV {キー1} = {値1} {キー2} = {値2}
ENV hello="Hello World"
ENV hoge=HOGEHOGE # スペースが入っていなければ""は必要なし
CMD ["bash"]
root@d2195c998190:/# echo $hello
Hello World
ARGエリア
イメージ作成時に利用する変数を作成。
Dockerfileの中でのみ使いたい変数などを設定する際に有効。
FROM ubuntu:20.04
RUN apt update
RUN apt install -y curl
COPY ./hello.txt /app/
ENV hello="Hello World"
ENV hoge=HOGEHOGE
# ARG {キー1} = {デフォルト値}
ARG message # デフォルト値無しでも問題なし
CMD ["cat", "message.txt"]
docker image build --build-arg message="Hello Message" .
docker container run -it {ビルドされたイメージ名}
Hello Message
WORKDIRエリア
RUNやCMDなどの作業ディレクトリを指定できる。
(未指定の場合、"/"が作業ディレクトリになっている)
FROM ubuntu:20.04
# WORKDIR {ディレクトリパス}
RUN echo "" > 1.txt
WORKDIR /app/my_dir
RUN echo "" > 2.txt
WORKDIR ..
RUN echo "" > 3.txt
CMD ["bash"]
root@17e3129684cf:/app# ls
3.txt my_dir
root@17e3129684cf:/app# cd my_dir
root@17e3129684cf:/app/my_dir# ls
2.txt
root@17e3129684cf:/app/my_dir# cd ../..
root@17e3129684cf:/# ls
1.txt app bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
ビルドコンテキストとは
ビルドに必要なファイル群をDockerデーモンに送信するディレクトリ(の範囲)のこと。
DockerfileのCOPYやADDで参照できるのはコンテキスト内のファイルのみ。
docker image build -f docker/Dockerfile .
上のコマンドでは-fオプションでDockerfileの場所を、.でビルドに必要なファイルの送信範囲をビルドコンテキストとして伝えている。
.dockerignoreとは
.dockerignoreファイルに記載したものはビルドコンテキストから除外できる。
クレデンシャルな情報や重たいファイルを記載する。
イメージレイヤーとは
イメージの変更差分がレイヤーとして保存される。
Dockerfileで実行したものが1行ずつ保存される感じ。
FROM ubuntu:20.04
RUN apt update
RUN apt install -y curl
COPY ./hello.txt /app/
CMD ["ls", "-a"]
上の例だと5つのレイヤーができる。
イメージレイヤーで意識すること
レイヤーは少ないほうがイメージレイヤーの容量が小さくなる。
FROM ubuntu:20.04
RUN apt update
RUN apt install -y curl
COPY ./hello.txt /app/
CMD ["ls", "-a"]
↓
FROM ubuntu:20.04
# RUNをまとめて1行にした
RUN apt update && apt install -y curl
COPY ./hello.txt /app/
CMD ["ls", "-a"]
多くのソフトウェアをインストールするような状況ではレイヤーを細かく分けた方が良かったりする。
開発初期でインストールするソフトウェアが多かったり、ほかにもインストールが必要になるものがあるときはレイヤーを細かく分け、最終的にひとまとめにして容量を減らすのがいいかも。
マルチステージビルドとは
1つのDockerfileでステージごとの環境を分離し、最終イメージには必要なファイルだけを含められる。
FROM gcc:12.2.0 AS compiler
WORKDIR /app
COPY ./hello.c .
RUN gcc hello.c
FROM ubuntu:20.04
WORKDIR /app
COPY --from=compiler /app/a.out .
CMD ["./a.out"]
上の例だと、C言語のソースコードをコンパイルするためにgccを入れたcompiler環境、コンパイルされたファイルを実行するための環境に分かれている。最終イメージには実行環境のみ含まれる。
マルチステージビルドの利点
- dockerイメージには実行環境のみ含まれ、その他環境は含まれないためイメージサイズが削減できる
- 開発・本番環境を1つのDockerfileで管理できる
データの永続化
ボリュームとは
Dockerが管理しているデータ領域。コンテナとは分離したもののためコンテナが削除されても消えない。
# ボリューム作成
docker volume create my-volume
# ボリュームを紐づけてコンテナ起動
docker container run -v my-volume:/app ubuntu
各コンテナからアクセスすることでデータの読み書きが可能。
例として、my-volumeを/appにマウントしたcontainer-1とcontainer-2がある場合
# /appにファイル作成
root@d7145dbaeccc:/app# echo "Hello World" > hello.txt
# /appにcontainer-1で作成されたhello.txtが存在する
root@d7145dbaeccc:/app# ls
hello.txt
バインドマウントとは
ホストマシンの任意のディレクトリとコンテナ内の任意のディレクトリを同期させる。
指定には任意のディレクトリの絶対パスが必要。
動作はボリュームと同じ
ボリュームとバインドマウントの使い分け
ホスト側の状況に依存しないよう、基本的にはボリュームの使用が推奨されている。
ホストの環境に依存したり、ホストからのデータアクセスが必要な場合はバインドマウントが有効。
コンテナのポート制御
コンテナはPORTをホストと接続しないとアクセスできない。
ホストが外部に公開しているポート番号とコンテナのポート番号を紐づけてあげることで初めて外部から接続することが可能になる。
Dockerネットワークとは
通信が必要なコンテナのみのネットワークを作り、その中での通信を簡単にしたり、ネットワーク間の通信を防いだりできる。
ブリッジネットワークとは
複数のコンテナ間の通信を橋渡しする。
ブリッジネットワークでつながれているコンテナ以外は通信できない。
ブリッジネットワークを何も指定せずコンテナを作成した場合、「bridge」というブリッジネットワークに接続される。
コンテナ間を通信させる
ブリッジネットワーク「my-net」を作成して2つのコンテナを接続する。
# ブリッジネットワーク作成
docker network create my-net
# コンテナ1作成
docker container run -itd --name my-nginx --network my-net nginx
#コンテナ2作成(Dockerfileから作成)
# FROM ubuntu:22.04 RUN apt update && apt install -y iputils-ping curl
docker image build -t my-ubuntu .
docker container run -itd --name my-ubuntu --network my-net my-ubuntu
コンテナのIPアドレスを確認する。
docker network inspect my-net
-- 略 --
"Containers": {
"873a55b9c6ffe5f01baf33de49fd34c801f6a665f17b241536e80dae5b91e933": {
"Name": "my-nginx",
"EndpointID": "f50531376f8b972d7dc94fcbbf0bffc2d87c2832077602bd138392c931f42060",
"MacAddress": "ba:2b:7f:fb:bd:2b",
"IPv4Address": "172.18.0.2/16", ←IPアドレス
"IPv6Address": ""
},
"dcea08b8c833efb85973d3fd8adeb2d88e08edb3e1955d54df4d1e540bd55c70": {
"Name": "my-ubuntu",
"EndpointID": "d293248b3e9d3bea97b2a858c1c09330fb14a5dd9e2ea5e385b0799085105fb4",
"MacAddress": "1a:00:b6:4c:05:1c",
"IPv4Address": "172.18.0.3/16", ←IPアドレス
"IPv6Address": ""
}
},
-- 略 --
curlコマンドでHTTPリクエストを送る。
docker container exec -it my-ubuntu bash
# my-ubuntuのbash
root@bf05057366a3:/# curl http://172.18.0.2
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
-- 略 --
ウェブページのリソースが返ってきたため通信ができた。
ブリッジネットワーク内の名前解決
自身で作成したブリッジネットワークでは、コンテナ名を指定するだけでコンテナ間の通信ができる。
docker container exec -it my-ubuntu bash
# my-ubuntuのbash
root@bf05057366a3:/# curl http://my-nginx
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
-- 略 --
Docker Composeとは
コンテナの作成やブリッジネットワーク、ボリュームの作成のために実行するdockerコマンドを1つのコマンド実行で環境が作成できるようになる機能。
docker-compose.ymlファイルに環境を作成するためのコマンドを記載し、docker compose upコマンドで実行できる。
version: '3.9'
services:
api:
build: ./api
ports:
- 8080:8080
docker compose up
上記のように実行すると、apiディレクトリに存在するDockerfileがビルドされ、ポート8080に紐づけられた状態のコンテナが作成される。専用のブリッジネットワークも作成される。
# 以下を実行した結果と同一
docker image build -t api-img ./api
docker container run --name api -p 8080:8080 api-img
単語メモ
デフォルトコマンド
コンテナ起動時に何も指定されていない場合に1度だけ実行されるコマンド。
-itオプション
-iでコンテナの標準入力をホストOSに接続したまま保持する。
標準入力:ターミナルからコンテナに対して文字を入力するためのパイプラインのようなもの。
-tでコンテナに疑似ターミナル(TTY)を割り当てる。
TTY:改行コードの変換やコンテナからの出力をターミナル上に表示してくれる。
bash
シェルの一種。
シェル:OS(カーネル)に対して指示する際に自然言語を機械語に直してくれる機能。
macのターミナルやwindowsのコマンドプロンプトはシェルを実行するアプリケーション。
ターミナルでコマンド実行 → シェルが機械語に翻訳 → OS(カーネル)が処理を実行
デタッチドモード / フォアグランドモード
デタッチドモード
バックグラウンドでコンテナを動かせるモード。
-dオプションで実行できる。
常駐する必要があったり、コンテナを起動したうえで別のコマンドを実行したいときなどに便利。
フォアグランドモード
何も指定しなかったらこのモードになる。
デバッグや一時的なスクリプト実行などで便利。
ポート
接続先のアプリケーションを一意に特定するためのもの。
クライアントからアプリケーションに接続するためには、IPアドレスでサーバーを特定し、ポート番号でアプリケーションを特定する必要がある。
新旧Dockerコマンド
| 旧コマンド | 新コマンド | 用途 |
|---|---|---|
| docker pull | docker image pull | イメージをダウンロード |
| docker images | docker image ls | ローカルに存在するイメージ一覧を表示 |
| docker rmi | docker image rm | ローカルに存在するイメージを削除 |
| docker run | docker container run | イメージからコンテナを作成し起動 |
| docker ps | docker container ls | ローカルに存在するコンテナ一覧を表示 |
| docker rm | docker container rm | 停止したコンテナを削除 |
旧コマンドは短いが、新コマンドの方が何に対しての操作かわかりやすい。
また、今後のメンテナンスは新コマンドに対して行われる想定のため、新コマンドに慣れていくのがいい。
コマンド一覧
| コマンド | 用途 |
|---|---|
| docker image pull {イメージ名} | イメージをダウンロード |
| docker image ls | ローカルに存在するイメージ一覧を表示 |
| docker image rm {イメージ名} | ローカルに存在するイメージを削除 |
| docker image inspect {イメージ名} | イメージの詳細情報を表示 |
| docker image build {ディレクトリパス} | Dockerfileからイメージを作成 |
| docker image history {イメージ名} | イメージレイヤーを表示 |
| docker container run {イメージ名} | イメージからコンテナを作成し起動 |
| docker container run {イメージ名} {実行したいコマンド名} | コンテナを起動して任意のコマンドを実行 |
| docker container exec {コンテナ名} {実行したいコマンド名} | Up状態のコンテナに任意のコマンドを実行 |
| docker container ls | コンテナ一覧を表示 -aオプション:起動していないコンテナも表示 |
| docker container stop {コンテナ名} | コンテナを停止 |
| docker container restart {コンテナ名} | コンテナを再起動 |
| docker container logs {コンテナ名} | コンテナのログを表示 |
| docker container rm {コンテナ名} | 停止したコンテナを削除 |
| docker container prune | Up状態以外のコンテナを一括削除 |
| docker container attach {コンテナ名} | デタッチドモードのコンテナに接続 |
| docker volume create {ボリューム名} | ボリューム領域を新規作成 |
| docker volume ls | ボリューム領域一覧を表示 |
| docker volume inspect {ボリューム名} | 指定したボリューム領域の詳細情報を表示 |
| docker volume rm {ボリューム名} | 指定したボリューム領域を削除 |
| docker network ls | ネットワークの一覧を表示 |
| docker network inspect {ネットワーク名} | ネットワークの詳細情報を表示 |
| docker network create {ネットワーク名} | ネットワークを新規作成 |
| docker network rm {ネットワーク名} | 指定したネットワークを削除 |
| docker compose up | docker-compose.ymlファイルを実行 |
| docker compose down | docker compose upで起動したネットワークとコンテナを停止 |
オプション一覧
| オプション | 使用例 | 用途 |
|---|---|---|
| -it | docker container run -it {イメージ名} | 標準入力をOpenにし、疑似TTYを割り当てる |
| -t | docker image build -t {イメージ名:タグ名} {ディレクトリパス} | イメージに任意の名前・タグ名を付ける |
| --name | docker container run --name {イメージ名} {任意の名前} | コンテナに任意の名前を付ける |
| --rm | docker container run --rm {イメージ名} {実行したいコマンド} | コマンド実行後削除 |
| --build-arg | docker image build --build-arg {ARGで宣言した変数名}={値} | ビルド時に変数の値を設定 |
| --network | docker container run --network {ネットワーク名} {イメージ名} | 任意のネットワークを紐づける |
| --target | docker image build --target {ステージ名} | 任意のステージでイメージ作成 |
| --build | docker compose up --build | イメージを再作成 |
| -f | docker container rm -f {コンテナ名} | コマンドを強制実行 |
| -f | docker image build -f {ディレクトリパス} | Dockerfileを指定 |
| -d | docker container run -it -d {イメージ名} | デタッチドモードでコンテナ起動 |
| -y | apt install -y {パッケージ名} | 質問に対して自動でYesを選択 |
| -v | docker container run -v {Vol名 or ホスト絶対パス}:{コンテナ内絶対パス} {イメージ名} | ボリューム or ホストマシンの任意のディレクトリに接続 |
| -p | docker container run -p {ホスト側のポート}:{コンテナ側のポート} {イメージ名} | ホスト側のポートをコンテナのポートに紐づける |