Dockerがよくわからないので再入門した
Dockerについてわからなくなったり忘れたりすることが多いので、自分用の備忘メモをまとめることにした。
あくまで自分用の再入門メモなので、入門者向けにわかりやすくまとめたとかではない。
Dockerについて
Dockerとコンテナ
- Dockerはコンテナ管理ツール
- DockerはBuild、Ship、Runの思想で作られている
- Build: コンテナイメージの作成
- Ship: イメージの配布
- Run: イメージを元にコンテナを実行
- コンテナは隔離されたアプリケーション実行環境
- Dockerはクライアントサーバ型のアーキテクチャ
docker
コマンドはクライアントが提供- サーバ側ではDockerデーモン(dockerd)が起動している
- クライアントはDocker API(WebAPI)を使ってDockerデーモンに処理依頼をする
Build、Ship、Runの思想がJava仮想マシンっぽい。
公式ドキュメントと日本語訳プロジェクトが充実しているので、詳しく知りたいときはこれを読む。
コンテナと仮想マシンの違い
- 仮想マシン
- ホストOS・ハイパーバイザの上でゲストOSとアプリケーションが実行される
- 1台の物理マシン上で複数のOSを動作させる
- コンテナ
- ホストOSの機能(Linuxカーネル)によってプロセスが隔離されて実行される
- コンテナ自体にはOSは含まれない
コンテナを使うメリット
- 可搬性のある実行環境が手に入る
- 異なるマシン上での挙動の再現性が高い
- 仮想マシンに比べて軽量
- 開発者ごとに独立した開発環境が作りやすい
- 数多くの関連サービスやツールと連携できる
開発環境がコンテナになると幸せなことは多いと思うし、実際幸せになった。
DockerはLinux依存的な話
- DockerはLinuxカーネルが無いと動かない
- コンテナ環境はcgroups、namespaces、overlayfsといったLinux機能で実現されるため
- namespacesはシステムリソースの分離を行っている
- cgroups(コントロールグループ)はCPUやメモリなどのシステムリソースの割り当てを行っている
- Docker Desktopでは仮想マシン上でLinuxカーネル(moby linuxというらしい)を動かしてる
- Intel Mac版ではHyperKit、M1以降だとVirtualizationフレームワークで仮想化してるらしい
- Windows版はHyper-Vという仮想化ソフトウェアを使ってる
- WindowsではWSL2にLinuxカーネルが搭載されたので、Docker DesktopなしでDockerが動く
正直このあたりは全然自信がない。
とりあえず大事そうなのは、DockerはLinux無しでは動かないこと。
あと、Docker Desktop上でCentOSのベースイメージを指定してコンテナを実行しても、実際にCentOSが動くわけではない。あくまでベースイメージに含まれるCentOS相当のディレクトリ構成や実行コマンドによってCentOSっぽく動作するだけで、実際のOSの機能はDocker Desktop上のLinuxカーネルの互換性によって使えている。
イメージはレイヤ構造
- コンテナイメージはベースイメージからの変更差分が重なったレイヤ構造になっている
- 後述するDockerfileの1命令(ビルドステップ)ごとに変更差分が発生する
- レイヤ単位にビルドキャッシュが作られる
- 変更差分が同じビルドステップはスキップされる
- Dockerfileの
RUN
命令を&&
で繋ぐのはレイヤを減らしたいから - コンテナ実行時もレイヤ構造は維持される
- イメージのレイヤ群は読み取り専用になり、新たに読み書き可能なレイヤが上積みされる
- コンテナ実行中に作成/削除されたファイルは読み書き可能レイヤに変更差分が積まれる
- 単一イメージから複数コンテナを生成しても、読み取り専用レイヤのファイル実体は共通なので軽量
- テキストだとイメージしにくいのでこの記事など図式化されているものを参照するとわかりやすい
OCIランタイム
- 隔離されたコンテナ環境を作るのはDockerデーモンではなくOCIランタイム(低レベルランタイム)
- OCIランタイムがcgroupsやnamespacesなどLinuxカーネルの機能を使ってコンテナ環境を作る
docker
コマンド -> Dockerデーモン -> OCIランタイム -> Linuxカーネル のイメージ- Dockerは高レベルランタイムに相当する
- OCIはOpen Container Initiativeによって定められた仕様
- OCIの実装はrunc、gVisor、Kata Containersなど色々
- ほとんどの人は意識せずruncを使ってるらしい
- runcは元々Dockerに組み込まれていたが、現在は分離されている
- runcについて説明されたスライド
複数コンテナの実行
- Docker Composeを使用することで複数コンテナを定義してまとめて実行できる
- Composeではコンテナやネットワーク、ボリュームをまとめて『サービス』という概念で扱う
docker-compose.yml
ファイルにアプリケーション構成を定義する- 1つの設定ファイルは1つのプロジェクト名を持つ
- Composeのネットワーク機能により、コンテナ間はサービス名を指定して通信できる
- 例によってだいたい公式マニュアルに書いてある
アプリケーションサーバとDBサーバなど、複数のコンテナを連動させたい時はCompose使った方が楽。
使い方関連
Dockerfile
コンテナイメージを作る手順書がDockerfile
命令 | 説明 |
---|---|
FROM | ベースイメージを指定する |
RUN | イメージ作成時に実行するコマンドを指定する |
WORKDIR | 作業ディレクトリを指定する |
COPY | ファイルやディレクトリをコピーする |
ADD | ファイルやディレクトリをコピーする |
ENTRYPOINT | コンテナ実行時の実行コマンドを指定する |
CMD | コンテナ実行時の実行コマンドを指定する |
VOLUME | コンテナ実行時に匿名ボリュームを作る |
ENV | 環境変数を設定する |
RUN
は\
で複数行に分割して書くとよい- だいたい
apt-get
してパッケージインストールする用に使う
- だいたい
WORKDIR
はRUN mkdir hoge && cd hoge
だと考えるとよいADD
とCOPY
ADD
よりCOPY
の方が単機能で明確なのでCOPY
使用を推奨(公式もそう言ってる)ADD
だとコピー元をリモート資源にできたり、圧縮ファイルが自動解凍されたりして怖い
ENTRYPOINT
とCMD
ENTRYPOINT
とCMD
はDockerfileで1度だけ指定できるENTRYPOINT
とCMD
が両方書かれた場合、CMD
はENTRYPOINT
のコマンド引数になるCMD
はコンテナ実行時のコマンド引数で上書きができる
VOLUME
は難しいので公式とかこの記事を読むFROM
を複数指定することで、中間生成物をパージして最終成果物のイメージを軽量化するマルチステージビルドという手法がある
これどう使えばいいの?的な疑問はほとんど公式のベストプラクティスに書いてある。
コマンド
- Dockerコマンドは操作対象ごとにサブコマンドが用意されている
- よく使う操作対象
docker image
docker container
docker network
docker volume
docker compose
create
,rm
,prume
,ls
あたりは共通して使えることが多い- 互換性維持のために旧コマンドも一応使える
- 新:
docker image ls
- 旧:
docker images
- 新:
コマンドはたくさんあるので使用頻度高そうなものだけ載せておく。
イメージ
コマンド | 説明 |
---|---|
docker image build | Dockerfileからイメージをビルドする |
docker image ls | イメージ一覧を表示する |
docker image prune | 使用していないイメージを削除する |
docker image pull | イメージをレジストリから取得する |
docker image push | イメージをレジストリに送信する |
docker image rm | イメージを削除する |
docker image save | イメージをtarアーカイブに保存する |
-f
でDockerfileを指定できる。デフォルトはカレントのDockerfile
--no-cache
でビルドキャッシュを使わずに構築する--platform
でプラットフォームが指定できる--tag
または-t
でタグとイメージ名を付与できる
コンテナ
コマンド | 説明 |
---|---|
docker container run | 新しいコンテナを作成して実行する |
docker container exec | 実行中のコンテナ内でコマンドを実行する |
docker container ls | コンテナ一覧を表示する |
docker container start | 停止中のコンテナを実行する |
docker container stop | 実行中のコンテナを停止する |
docker container rm | コンテナを削除する |
docker container prune | 停止中の全コンテナを削除する |
docker container cp | ローカルとコンテナ内でファイルをコピー |
docker container attach | ローカルの標準入出力に実行中コンテナを接続 |
docker container logs | コンテナのログを取得 |
run
のオプション--name
任意のコンテナ名を付けられる--rm
コンテナ終了時にコンテナを自動で削除-it
コンテナ内でbashシェルを作成する(コンテナ内で動き回れる)-i
がインタラクティブ、-t
が疑似TTYを意味する
-v
ボリュームのマウントを指定する
Compose
コマンド | 説明 |
---|---|
docker compose build | サービスの構築(イメージのビルド) |
docker compose up | サービスを作成し実行する |
docker compose down | サービスを停止して削除する |
docker compose run | サービスを1回限りのコマンドとして実行する |
docker compose exec | 実行中のサービス内でコマンドを実行する |
docker compose logs | コンテナのログを表示する |
-f
オプションでdocker-compose.yml
以外の設定ファイルを指定できる(複数指定可)down
は停止だけでなくコンテナやネットワークの削除をしてくれる、便利run
の実行後にコンテナを削除したい場合は--rm
オプションを付ける
その他
- Dockerはオブジェクトの削除に対して慎重な指針で作られているため、不要物の削除は明示的に行う必要がある
- 詳しくはドキュメントを参照すればよいが、基本的には
prune
コマンドを使う prune
は使われていないオブジェクトを削除するだけで、すべてのオブジェクトが消えるわけではない
- 詳しくはドキュメントを参照すればよいが、基本的には
参考文献
ちょっと箇条書きにまとめようかな、くらいの気持ちで始めたら結構長くなってしまった。
ネットワークやボリュームについても調べたかったが、世界が広がりすぎて大変そうだったので別の機会に勉強し直すとする。