Docker基礎まとめ

一通り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を使って環境構築を行う流れは以下の通り。

  1. イメージを用意する(大抵Dockerfileを使う)
  2. イメージからコンテナを作成し、起動する(複数のコンテナを扱う場合はDocker Composeを使う)
  3. コンテナに対して何かしらの操作を行う

イメージ

イメージとは

イメージとはコンテナの元となるもの。 イメージを使う時は、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

RUNLinuxのコマンドを実行する命令でレイヤーを作る。RUNによって必要なパッケージをインストールしたり、ファイルを作成したりしてイメージをカスタマイズできる。

RUN [Linuxコマンド]

# &&でコマンドをつなげることができ、\で改行できる
RUN [Linuxコマンド] && [Linuxコマンド] \
    [Linuxコマンド]

Dockerfileを作っていく段階ではRUNを細かく分けてキャッシュを利用し、実際にDockerfileを使ってイメージを作るときはなるべくRUNをまとめてイメージの容量を減らすようにする。

CMD

CMDはコンテナを起動した時にデフォルトで実行されるコマンドを指定する命令で、レイヤーを作る。

CMD [コマンド]

COPY

COPYはホストのファイルをコンテナ内にコピーする命令で、レイヤーを作る。

COPY [ホストのファイル] [コンテナ内のコピー先のディレクトリ]

ADD

ADDCOPY同様、ホストのファイルをコンテナ内にコピーする命令でレイヤーを作る。

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

ENTRYPOINTCMDと似ていてデフォルトのコマンドを指定する命令。

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=[コンテナ内のディレクトリ] [コンテナ名]

typevolumeも指定できる。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と同じ階層に書いたvolumesservices内のvolumesとは異なり、ボリュームを作成する項目。 volume createと同じ。

volumes: 
    [ボリューム名]

イメージをビルドする

Docker Composeでイメージをビルドするときはdocker compose buildを実行する。これはビルドだけ行うのでコンテナは作られない。

docker compose build

# キャッシュを使いたくない場合
docker compose build --no-cache

イメージをビルドし、コンテナを作成して起動する

イメージのビルドから、コンテナの作成・起動まで行いたい時はdocker compose upを実行する。 docker compose updocker builddocker 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が優先して実行される。

参考

米国AI開発者がゼロから教えるDocker講座

クイックスタート

実践Docker