一通りDockerについて学んだので、Dockerの基礎知識と疑問点をまとめました。
環境
Mac | 13.1(22C65) |
Docker | 20.10.23 |
Docker Compose | v2.15.1 |
Docker
Dockerとは
Dockerとは仮想環境を構築するためのソフトウェア。 コンテナというアプリを動作させるための箱のようなものを作って仮想環境を構築する。
仮想環境とは
仮装環境とは、物理的なハードウェア上で仮想的に作られた環境のこと。 要はコンピュータの中で全く別のコンピュータを動かすみたいなこと。
仮想化にも種類があり、Dockerはコンテナ型仮想化で、他にもホスト型仮想化やハイパーバイザー型仮想化がある。
ホスト型はホストOS(自分のPCのOS)に仮想化ソフトウェアをインストールし、その上でゲストOS(仮想化ソフトウェア上のOS)を管理する。
ハイパーバイザー型はハードウェアに仮想化ソフトウェアをインストールし、その上でゲストOSを管理する。
コンテナ型はホストOSに仮想化ソフトウェアをインストールし、ゲストOSは使わずにアプリを管理する。
Dockerの仕組み
Dockerの特徴であるコンテナの実体は、LinuxのNamespaceという機能によって分離された1つのプロセスである。
Namespaceとは1つのOSの中で隔離された空間を作るLinuxのカーネルの機能で、これを扱いやすくしたのがコンテナ。
プロセスとはOS上で実行されている1つのプログラムのこと。Linuxのコマンドを実行すると1つのプロセスが作られる。
コンテナはプロセスと変わらないので動作が早いことがメリットだが、Linuxのカーネルを利用した技術なので他のOSは使えない。
Docker Engine
Docker Engineがコンテナを乗せるDockerの土台の部分。
Docker CLI
Dockerを操作するために命令を出すのが、Docker Engineに提供されるDocker CLIである。Dockerのコマンドのこと。 Dockerはクライアント・サーバーの構成になっていて、Docker CLIはクライアントにあたる。
Docker daemon
Docker CLIから命令を受け取り、実際にコンテナやイメージを操作するのがDocker daemon。 Docker daemonはサーバーにあたる。
Dockerを使う流れ
Dockerを使って環境構築を行う流れは以下の通り。
- イメージを用意する(大抵Dockerfileを使う)
- イメージからコンテナを作成し、起動する(複数のコンテナを扱う場合はDocker Composeを使う)
- コンテナに対して何かしらの操作を行う
イメージ
イメージとは
イメージとはコンテナの元となるもの。 イメージを使う時は、Docker Hubから取得して使う方法と、Dockerfileから作成して使う方法の2種類ある。
Docker Hubから取得する
Docker Hubはイメージが置かれているインターネット上の倉庫のようなもの。Docker Hubで公開されているイメージは自由に使うことができる。
イメージを取得するにはdocker pull
を実行する。
docker pull [イメージ名]
Dockerfileから作成する
イメージをそのまま使うのではなく、カスタマイズして使いたい時はDockerfileを作成する。 Dockerfileはイメージを作るための設計図のようなもの。さまざまな命令(Instruction)を記述して作る。
Dockerfileを作ることでどんなイメージか、どんなコンテナが作られるかを明示して共有することができる。
FROM
FROM
にはベースとなるイメージを指定する命令。:
の後ろにバージョンを指定でき、latest
とすると最新のバージョンを使うことができる。
Dockerのイメージはレイヤーという層になっており、FROM
で指定したベースイメージの上にレイヤーを重ねていくことでイメージを作っていく。
FROM [Docker Hubのイメージ]
RUN
RUN
はLinuxのコマンドを実行する命令でレイヤーを作る。RUN
によって必要なパッケージをインストールしたり、ファイルを作成したりしてイメージをカスタマイズできる。
RUN [Linuxコマンド] # &&でコマンドをつなげることができ、\で改行できる RUN [Linuxコマンド] && [Linuxコマンド] \ [Linuxコマンド]
Dockerfileを作っていく段階ではRUN
を細かく分けてキャッシュを利用し、実際にDockerfileを使ってイメージを作るときはなるべくRUN
をまとめてイメージの容量を減らすようにする。
CMD
CMD
はコンテナを起動した時にデフォルトで実行されるコマンドを指定する命令で、レイヤーを作る。
CMD [コマンド]
COPY
COPY
はホストのファイルをコンテナ内にコピーする命令で、レイヤーを作る。
COPY [ホストのファイル] [コンテナ内のコピー先のディレクトリ]
ADD
ADD
はCOPY
同様、ホストのファイルをコンテナ内にコピーする命令でレイヤーを作る。
ADD [ホストのファイル] [コンテナ内のコピー先のディレクトリ]
COPY
と異なるのは、ADD
は圧縮ファイルを解凍できるので容量が大きいファイルをコピーするのに向いている。
WORKDIR
WORKDIR
は命令を実行したいディレクトリを指定する命令。WORKDIR
を指定していない場合、命令はコンテナ内のroot直下で実行される。
以下の例は、dir
に移動してファイルを作成しているように見えるが、実際はroot
直下に作成される。
RUN mkdir dir RUN cd dir RUN touch file.txt
/dir
に移動してからファイルを作成するためにWORKDIR
を使う。
RUN mkdir dir WORKDIR /dir RUN touch file.txt # mkdirは省略可 WORKDIR /dir RUN touch file.txt
ENTRYPOINT
ENTRYPOINT
はCMD
と似ていてデフォルトのコマンドを指定する命令。
ENTRYPOINT [コマンド]
CMD
と異なるのはENTRYPOINT
で指定したコマンドをdocker run
で上書きできないこと。
基本的にCMD
を使えばOK。
ENV
ENV
は環境変数を設定する命令。環境変数とはOSに設定するOS上でどこでも使える変数。
ENV [key] [value] ENV [key]=[value]
イメージをビルドする
Dockerfileを記述しただけではイメージは作られていないので、イメージを作成するdocker build
を実行する。
Dockerfileからイメージを作ることをビルドするという。
docker build .
基本的にはDockerfileがあるディレクトリに移動してdocker build .
を実行する。
複数のDockerfileを扱うときは、-f
をオプションを指定する。
docker build -f [Dockerfileが存在するディレクトリ]
イメージに名前をつけたいときは-t
を指定する。
docker build -t [イメージ名] .
イメージに名前をつけない場合、作られたイメージをdocker images
で確認すると<none>
と表示される。
ビルドコンテキスト
ビルドする時になぜDockerfileではなくDockerfileが存在するディレクトリを指定しているかというと、Dockerはビルドを行うときにDockerfileが存在するフォルダをDocker daemonに渡して、Docker daemonがフォルダとDockerfileを元にイメージを作成するからである。 このときに渡されるフォルダのことをビルドコンテキストという。
イメージの一覧を確認する
イメージの一覧を確認するにはdocker images
コマンドを実行する。
docker images
イメージを削除する
イメージを削除したいときはdocker rmi
コマンドを実行する。
docker rmi [イメージID]
イメージIDは完全なものを入力せずに、最初の何文字かで区別できるものを入力すれば削除できる。
コンテナ
コンテナとは
コンテナとは実際にアプリを動作させる環境のこと。基本的に1つのコンテナに1つのアプリケーションを動作させる。
コンテナを起動する
docker build
を実行した段階ではイメージが作成されただけで、コンテナは作られていない。
コンテナはイメージから作成し起動して使う。この操作はdocker run
で実行できる。
docker run [イメージ名]
docker run
はコンテナを作成するdocker create
とコンテナを起動するdocker start
を合わせたもの。また指定したイメージがなければdocker pull
も実行される。
コンテナには起動した時に実行されるデフォルトのコマンドが指定されており、docker run
の後ろにコマンドを指定することでデフォルトのコマンドを上書きして実行できる。
docker run [イメージ名] [デフォルトのコマンド]
docker run
にはさまざまなオプションがあり、オプションを指定して実行するのがほとんど。
docker runのオプション
docker run
コマンドには複数のオプションがある。
-it
-it
は-i
と-t
をくっつけたオプションで、2つをくっつけて指定するのが一般的。
-i
は--interactive
の省略形で、ホストからコンテナに対して標準入力ができるようにするオプション。コンテナでシェルを起動するときに必要になる。
-t
は--tty
の省略形で、出力を綺麗に表示するオプション。
--name
コンテナに名前をつけたいときは--name
を指定する。
docker run --name [コンテナ名] [イメージ名]
-rm
--rm
を指定すると、コンテナを停止させた時に自動で削除されるようになる。
1回きりのコンテナを起動するときに使うと便利。
docker run --rm [イメージ名]
-d
コンテナはフォアグラウンドかバックグラウンドのどちらかで実行する。
何も指定しないとフォアグラウンドで実行され、-d
を指定するとバックグラウンドで実行される。-d
は--detach
を省略したオプション。
# フォアグラウンドで実行する docker run [イメージ名] # バックグラウンドで実行する docker run -d [イメージ名]
フォアグラウンドもバックグラウンドもどちらもプロセス。 フォアグラウンドは見える部分で動いていて、バックグラウンドは見えない部分で動いている、
デフォルトのフォアグラウンドで実行すると、コンテナのログが表示され、コマンドの入力ができない状態になる。control
+C
で終了できるが、コンテナの状態はUp
からExited
になる。
バックグラウンドで実行すると、裏で動いているので何も表示されず、コマンドを入力できる状態になる。
-v
-v
を指定するとホストとコンテナでファイルを共有できるようになる。ファイルを共有できるようにすることをマウントするという。
--volume
の省略形。
docker run -v [ホストのディレクトリ]:[コンテナのディレクトリ] [コンテナ名]
実際にコンテナの中に作られているわけではなく、コンテナにあるように見えるだけ。
-m
-m
は-v
同様、ファイルをマウントするオプション。--mount
の省略形。
docker run -m type=bind source=[ホストのディレクトリ] destination=[コンテナ内のディレクトリ] [コンテナ名]
type
はvolume
も指定できる。volume
については後述。
-v
との違いは、指定したホストのディレクトリがなかった時にディレクトリを作成するかしないか。
-v
は作成し、-m
は作成せずエラーを出す。
-u
-u
を指定するとコンテナに対してroot権限以外でアクセスできる。。何も指定しないとコンテナにはroot権限でアクセスしてしまうので注意。
共有サーバーをシェアしたりするときに使う。
docker run -u [ユーザーID]:[グループID] [コンテナ名] # 以下のように実行もできる docker run -u $(id -u):$(id -g) [コンテナ名]
id -u
はユーザーIDを確認するコマンドで、id -g
はグループIDを確認するコマンド。
-p
コンテナとホストマシンは隔離されているため、コンテナ内のサーバーにアクセスできない。
コンテナ内のサーバーにアクセスしたいときは-p
を使ってポートを公開する。
docker run -p [ホストマシン側のポート]:[コンテナ側のポート] [イメージ名]
起動しているコンテナに対してコマンドを実行する
docker run
はコンテナを新しく作成して起動する命令だが、起動中のコンテナに対してコマンドを実行したい場合はdocker exec
を使う。
docker exec [コンテナ] [コマンド]
コンテナの一覧を確認する
コンテナの一覧を確認するにはdocker ps
を実行する。
docker ps
docker ps
は起動しているコンテナだけ表示するので全てのコンテナを表示したい場合は-a
オプションをつける。
docker ps -a
コンテナを停止する
コンテナを停止するにはdocker stop
を実行する。
docker stop [コンテナID]
コンテナを削除する
コンテナを削除するにはdocker rm
を実行する。
docker rm [コンテナID]
スペースで区切ることで、複数のコンテナを同時に削除できる。
docker rm [コンテナID] [コンテナID] [コンテナID] ...
コンテナの状態
コンテナにはいくつかの状態がある。
状態 | 意味 |
---|---|
created | コンテナが作られて起動していない状態 |
runnning | コンテナが起動している状態 |
restarting | コンテナが再起動している状態 |
removing | コンテナを削除している状態 |
paused | コンテナが一時停止している状態 |
exited | コンテナが終了している状態 |
dead | コンテナが停止に失敗している状態 |
コンテナの情報を確認する
コンテナの情報を確認するにはdocker inspect
を実行する。
docker inspect [コンテナID]
コンテナのログを見る
docker logs
を実行すると、フォアグラウンドで表示されるコンテナのログを確認できる。
docker logs [コンテナID]
ボリュームとバインドマウント
通常コンテナを削除すると、コンテナ内のファイルは削除される。 ホストとコンテナ内のファイルを共有してデータを保持する方法がボリュームとバインドマウント。
ボリューム
ボリュームは、コンテナ内のファイルをホストマシン上でDockerが管理して、コンテナが削除されてもファイルが削除されないようにする仕組み。 ファイルがどこにあるかは気にせず、データベースのデータを永続化したいときなどに使う。
ボリュームを作成する
ボリュームを作成するにはdocker volume create
を実行する。
--name
でボリューム名を設定する。
docker volume create --name [ボリューム名]
ボリュームをマウントする
docker volume create
だけではボリュームが作成されただけなので、マウントする必要がある。
マウントするにはdocker run
の-v
か-m
を指定する。
docker run -v [ボリューム名]:[コンテナ内のディレクトリ] [コンテナ名] docker run -m type=volume source=[ボリューム名] destination=[コンテナ内のディレクトリ] [コンテナ名]
ボリュームの一覧を確認する
ボリュームの一覧を確認するにはdocker volume ls
を実行する。
docker volume ls
ボリュームを削除する
ボリュームを削除するときはdocker volume rm
を実行する。
docker volume rm [ボリューム名]
バインドマウント
バインドマウントは、ホストとコンテナでファイルを共有してホストで変更したものがコンテナに反映される仕組み。 ソースコードを共有したいときなどに使う。
バインドマウントは前述のdocker run
の-v
か-m
で行う。
ネットワーク
Dockerでのネットワークは、コンテナ同士を通信するために作成する。 同じネットワークに接続したコンテナは互いに通信ができるようになる。
ネットワークには、デフォルトブリッジネットワークと、ユーザーが定義するネットワークの2種類ある。
デフォルトブリッジネットワーク
デフォルトブリッジネットワークはDockerを起動した時に自動的に生成されるネットワーク。
何も指定しないとコンテナはデフォルトブリッジネットワークに接続される。
デフォルトブリッジネットワーク内にあるコンテナ同士を通信したい場合は、docker run
の--link
を使って双方向にリンクを指定する必要がある。この方法は面倒かつ古い機能なので、コンテナ同士を通信したいときはユーザー定義ネットワークを作成する。
またデフォルトブリッジネットワーク内にあるコンテナはDocker Engine上にあるすべてのコンテナに接続できてしまう。
ユーザー定義ネットワーク
ユーザー定義ネットワークは自分で作成するネットワーク。ユーザー定義ネットワークはデフォルトブリッジネットワークより優先される。
ユーザー定義ネットワークはコンテナ同士を通信したい場合は、同じネットワークを指定するだけでよく、他のネットワークに存在するコンテナはアクセスできない隔離されたネットワークを作ることができる。
ネットワークを作成する
ネットワークを作成するにはdocker network create
を実行する。
docker network create [ネットワーク名]
コンテナをネットワークに接続する
コンテナをネットワークに接続するにはdocker run --network
を実行する。
docker run --network [ネットワーク名] [コンテナ名]
ネットワークの一覧を確認する
docker network ls
ネットワークを削除する
docker network rm [ネットワークIDまたは名前]
Docker Compose
Docker Composeとは
Docker Composeは複数のDockerのコマンドを実行するツールで、同時にコンテナを操作できる。 またDocker Composeを使えば、ネットワークも自動で作成される。
docker-compose.yml
docker-compose.ymlはDocker Composeを使うときの設定ファイル。 入れ子で設定を記述していく。
docker-compose.ymlに記述する項目
version
docker-compose.ymlの一番最初にversion
を記述してDocker Composeのバージョンを指定する。
これは決まりごとのようなもの。
version: 'バージョン'
services
services
に書いたものがそれぞれのコンテナになる。
services: [コンテナ]: [コンテナ]: ...
container_name
container_name
にはコンテナの名前を指定する。docker run
の--name
と同じ。
container_name: [コンテナ名]
build
build
にはビルドするDockerfileを指定する。
build: [Dockerfile]
複数のDockerfileを扱う場合はそれぞれのサービスで以下のように記述する。
build: dockerfile: [Dockerfile] context: [Dockerfileを含むディレクトリのパス]
image
image
にはDocker Hubから取得したいイメージを指定する。
image: [イメージ名]
ports
docker run
の-p
と同じ。
ports: - '[ホストのポート]:[コンテナのポート]'
command
docker run
で指定していたデフォルトのコマンドと同じ。
command: [コマンド]
depends_on
depends_on
は依存関係を作る項目。
後述のRails+MySQLのdocker-compose.ymlでは、webコンテナをdbコンテナに依存させるようにしたいので以下のように記述する。
services: web: depends_on: - db db:
こうすることで、dbコンテナが起動してからwebコンテナが起動され、反対に停止する時はwebコンテナが先に停止した後にdbコンテナが停止されるようになる。
volumes
services
内のvolumes
はマウントを設定する項目。
# ボリュームをマウントする volumes: - type: volume source: [ボリューム名] target: [コンテナ内のディレクトリ] # バインドマウント volumes: - type: bind source: [ホストのディレクトリ] target: [コンテナ内のディレクトリ]
stdin
docker run
の-i
と同じ。
stdin_open: true
tty
docker run
の-t
と同じ。
tty: true
environment
environment
にはコンテナ内に設定したい環境変数を指定する。
environment: [key]: [value] [key]: [value]
volumes
services
と同じ階層に書いたvolumes
はservices
内のvolumes
とは異なり、ボリュームを作成する項目。
volume create
と同じ。
volumes: [ボリューム名]
イメージをビルドする
Docker Composeでイメージをビルドするときはdocker compose build
を実行する。これはビルドだけ行うのでコンテナは作られない。
docker compose build
# キャッシュを使いたくない場合
docker compose build --no-cache
イメージをビルドし、コンテナを作成して起動する
イメージのビルドから、コンテナの作成・起動まで行いたい時はdocker compose up
を実行する。
docker compose up
はdocker build
とdocker run
を合わせたもの。
2回目以降はイメージがビルドされているのでdocker run
だけが行われる。
# フォアグラウンドで実行する docker compose up # バックグラウンドで実行する docker compose up -d
Dockerfileを更新したときは--build
を指定する。
docker compose up --build
コンテナを作成してコマンドを実行する
新しくコンテナを作成してコマンドを実行するにはdocker compose run
を実行する。
docker compose run [コンテナ] [コマンド]
起動しているコンテナに対してコマンドを実行する
起動しているコンテナに対してコマンドを実行するにはdocker compose run
を実行する。
docker compose exec [コンテナ] [コマンド]
サービスの一覧を見る
docker compose ps
停止・削除する
サービスを全て停止して、削除するにはdocker compose down
を実行する。
docker compose down
その他の操作
容量を確認する
イメージ、コンテナ、ボリュームの数や容量を確認するには、docker system df
を実行する。
docker system df
イメージ、コンテナ、ネットワークを削除する
使われていないイメージ、停止しているコンテナ、使われていないネットワークを削除するにはdocker system prune
を実行する。
容量が増えた時に一気に削除するのに便利。
docker system prune
# 使われていないボリュームも削除する
docker system prune --volumes
疑問点
Dockerとその他の仮想化ソフトウェアの違いは?
- その他の仮想化ソフトウェアはホストOS上にゲストOSを管理して、DockerはゲストOSを使わないので動作が早いこと。
- ゲストOSを使わないので、Dockerでは他のOSを使用できない。
docker build、docker compose build、docker compose build --no-cache、docker compose up --buildの違いは?
docker build
は指定のDockerfileをビルドするだけ。docker compose build
はdocker-compose.ymlで指定されているDockerfileをビルドする。コンテナは作成されない。(キャッシュがあれば使うのでDockerfileを更新しても反映されない)docker compose build --no-cache
はdocker-compose.ymlで指定されているDockerfileをキャッシュを使わずにビルドする。コンテナは作成されない。docker compose up --build
はdocker-compose.ymlの内容でイメージをビルドし、コンテナを作成・起動する。
docker-composeとdocker composeのコマンドの違いは?
docker-compose
を置き換えるために作られたのがdocker compose
なので、どちらでもいいがdocker compose
を使ったほうがいい。
DockerfileのCMDとdocker-compose.ymlのcommandの違いは?
docker-compose.ymlのcommand
が優先して実行される。