よく使うDockerコマンドまとめ

# この記事について
この記事は、

- 開発時に私個人がよく使うdockerコマンド
- 開発時に気になったdockerコマンドの細かい挙動
- コンテナを支えるネットワーク・ボリュームといった裏の仕組み

だけに絞って書き残したものです。
「よく使うコマンドだけ手っ取り早く知りたい」「コンテナという概念は知っている状態から、もっとdockerシステムについての理解を深めたい」という人には役立つかもしれません。

注：「コンテナについての一からの解説が欲しい」「dockerコマンドにはどういう機能があるのかを網羅的に知りたい」という方のニーズは満たせていません。

## 使用する環境・バージョン
- Mac OS Mojave 10.14.5
- Docker version 19.03.8

# Containers
## コンテナの新規作成・起動
`docker run`は指定したイメージから新しくコンテナを作成・起動するコマンドです。

ただし、コンテナの元になるイメージ(`Dockerfile`の`FROM`命令で指定されたもの)がローカルにまだインストールされていない場合、DockerデーモンがそのコンテナイメージをDocker Hub（Docker社が運営するPaaS型のDocker Registry）から自動でダウンロードし、イメージからコンテナを起動します。
この挙動から、`docker run`は「`docker pull`→`docker create`→`docker start`」と同じ動作であると言えます。
参考：[さわって理解するDocker入門 第1回 Dockerのイメージ・コンテナ管理の仕組み](https://www.ogis-ri.co.jp/otc/hiroba/technical/docker/part1.html)

コマンドオプションについては以下の通りです。

- `-p XXXX:YYYY` : localhost:XXXXをコンテナポートYYYYにリダイレクト
- `-d` : デタッチモード(コンテナ内に入らずに、バックグラウンドで作動させる)での起動

```bash
$ docker run -p 80:3000 -d <起動したいイメージ名>
```

ここで注意したいのは、`docker run`コマンドは「イメージからの新規作成」であるという点です。
そのため、`docker run ImageA`というコマンドを二回叩くと、　ImageAを使用したコンテナが2つできることになります。

```bash
# 1回目のdocker run
$ docker run -p 80:8080 -d ImageA
$ docker ps
CONTAINER ID        IMAGE                                         COMMAND                  CREATED             STATUS                        PORTS                  NAMES
dd1e156a0d6a        ImageA                  "go run main.go"         39 seconds ago      Up 38 seconds                 0.0.0.0:80->8080/tcp   cool_buck
$ docker stop dd1e156a0d6a

# 2回目のdocker run
$ docker run -p 80:8080 -d ImageA
$ docker ps
CONTAINER ID        IMAGE                                         COMMAND                  CREATED             STATUS
55f3cccb4b33        ImageA                  "go run main.go"         3 seconds ago       Up 2 seconds                  0.0.0.0:80->8080/tcp   jolly_pasteur
# さっきと違うコンテナIDのものが立ち上がってることが確認できる
$ docker stop 55f3cccb4b33

# 存在するコンテナ一覧の確認
$ docker ps -a
CONTAINER ID        IMAGE                                         COMMAND                  CREATED             STATUS                        PORTS                  NAMES
55f3cccb4b33        ImageA                  "go run main.go"         3 seconds ago       Exited (2) 4 minutes ago                     jolly_pasteur
dd1e156a0d6a        ImageA                  "go run main.go"         7 minutes ago       Exited (2) 6 minutes ago                     cool_buck
# ImageAを元にしたコンテナが2つ立ち上がってることが確認できる
```
そのため、「既に存在するコンテナを起動させる」という場合は、次の`docker start`コマンドを使用する必要があります。

## 指定コンテナの起動
既に存在する停止中コンテナを起動したい場合は、`docker start`を使います。
コンテナの指定は、コンテナIDかコンテナ名を使います。

```bash
$ docker start <container ID>
# または
$ docker start <container Name>
```
備考: コンテナIDやコンテナ名を知りたい場合は、後述する`docker ps`コマンドを使います。

## コンテナの停止
ある特定のdockerコンテナを停止させるには、`docker stop`を使います。

```bash
$ docker stop <container ID>
# または
$ docker stop <container Name>
```
備考: コンテナIDやコンテナ名を知りたい場合は、後述する`docker ps`コマンドを使います。

## コンテナ一覧の確認
`docker ps`コマンドで、現在稼働中のコンテナ一覧が確認できます。

```bash
CONTAINER ID        IMAGE                                         COMMAND                  CREATED             STATUS                        PORTS               NAMES
55f3cccb4b33        ImageA                  "go run main.go"         3 seconds ago       Up 2 seconds                  0.0.0.0:80->8080/tcp   jolly_pasteur
```

停止中のコンテナまで含めた全てのコンテナを確認したい場合は、オプション`-a`をつけます。

```bash
$ docker ps -a
CONTAINER ID        IMAGE                                         COMMAND                  CREATED             STATUS                        PORTS               NAMES
55f3cccb4b33        ImageA                  "go run main.go"         3 seconds ago       Up 2 seconds                  0.0.0.0:80->8080/tcp   jolly_pasteur
dd1e156a0d6a        ImageA                  "go run main.go"         7 minutes ago       Exited (2) 6 minutes ago                     cool_buck
```
これら2つのコマンドで、以下のことが確認できる。

- CONTAINER ID : コンテナID
- IMAGE : そのコンテナの元となったイメージ
- COMMAND : コンテナ起動時にコンテナ中で実行されたコマンド(`Dockerfile`の`CMD`命令にあたる)
- CREATED : 作成日時
- STATUS : 起動中か、起動中でないなら停止した日時
- PORTS : ホストポートとコンテナポートの接続状態
- NAMES : コンテナ名

## 削除
`docker rm`コマンドで、指定されたIDのコンテナを削除できます。
コンテナを削除しても、そのコンテナの元となったイメージが残ることに注意してください。

```bash
$ docker rm <docker ID>
<docker ID>
# または
$ docker rm <docker Name>
<docker Name>
```

削除対象コンテナを複数指定すると、それらの一括削除が可能です。

```bash
$ docker rm <docker ID 1> <docker ID 2>
<docker ID 1>
<docker ID 2>
```
起動していないコンテナを一括削除したい場合は、`docker container prune`で可能です。

```bash
$ docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
# 以下削除処理
```
参考：[dockerでいらないimage,container,networkを一括削除する](https://qiita.com/mom0tomo/items/911b92cc18871f52a2a0)
参考：[Dockerのあれこれを断捨離する](https://qiita.com/ksato9700/items/b0075dc54dfffc64b999#コンテナの断捨離)

## ログの出力
dockerアプリで出たログを出力して見るには、`docker logs`コマンドを使います。
これはコンテナ停止中でもログ取得が可能です。

```bash
$ docker logs <container ID>
# または
$ docker logs <container Name>
```

## docker内部に入る
docker内に実際に入ってコマンドを実行したいという場合は、以下のコマンドを実行します。

```bash
$ docker exec -it <container Name> /bin/bash
# 以下、コンテナ内部
root@<container ID>:/#
```
このように、このコマンドを使うと、ルートユーザーとしてログインすることになります。

## コンテナ情報の確認
### コンテナ情報一覧の取得
指定コンテナに関する全ての情報を取得するには、`docker inspect`コマンドを利用します。

```bash
$ docker inspect <container ID>
```
しかし、如何せんこれでは全ての情報が一気に出力されるので、そこから自分の知りたい情報だけを探すのが大変です。そのため、知りたい情報だけをピンポイント出力するオプションをつけるのが一般的です。

### コンテナに割り振られたIPアドレスの取得
```bash
$ docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container ID>
172.18.0.6
```

### コンテナに割り振られたMACアドレスの取得
```bash
$ docker inspect --format='{{range .NetworkSettings.Networks}}{{.MacAddress}}{{end}}' <container ID>
02:42:ac:12:00:06
```

### コンテナ内で設定された環境変数の取得
```bash
$ docker inspect --format='{{range .Config.Env}}{{println .}}{{end}}' <container ID>
MYSQL_ROOT_USER=root
MYSQL_ROOT_PASSWORD=pass
MYSQL_DATABASE=sampledb
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
GOSU_VERSION=1.12
MYSQL_MAJOR=5.7
MYSQL_VERSION=5.7.30-1debian10
```

参考:[Docker-docs-ja公式ドキュメント inspect](http://docs.docker.jp/engine/reference/commandline/inspect.html)
参考:[[Docker]docker inspcetコマンドでコンテナの情報を確認する](https://qiita.com/toshihirock/items/b2180607d2b12c292890)

# docker-compose
`docker-compose.yml`に記述した設定を元にコンテナ群を起動したい場合は、以下の`docker-compose`コマンドを使います。

## コンテナ群の起動
以下のコマンドで、カレントディレクトリにある`docker-compose.yml`に沿ったコンテナ群が起動できます。

```bash
$ docker-compose up
Starting app_service1     ... done
Starting app_service2     ... done
# 以下コンテナログが流れる
```
オプションをつけない状態では、デオフォルトでフォアグラウンドモードで起動され、以降ターミナルにコンテナログが流れてきます。

バックグラウンドで起動したい場合は、オプション`-d`をつければOKです。

```bash
$ docker-compose up -d
Starting app_service1     ... done
Starting app_service2     ... done
$ 
# バックグランド起動だと同ターミナルで引き続きコマンドラインの使用が可能
```

また初回起動時には、これらのコンテナ群を繋ぐユーザ定義・ブリッジ・ネットワーク(app_default)も自動で作成されます。
(ネットワークについての詳細は後述)

## コンテナ群の停止
フォアグラウンドモードでの起動だった場合は、ターミナルで`Ctrl+C`を押すだけです。
バックグラウンドモードの場合は、`docker-compose stop`コマンドを使います。

```bash
$ docker-compose stop
Stopping app_service1     ... done
Stopping app_service2     ... done
$ 
```

## イメージの再ビルド
コンテナアプリのソースコードを変えた場合は、もう一度コンテナをビルドしないと、現存するコンテナにソース変更が反映されません。
そのため、ソースコードの変更をコンテナに反映させるためには、`docker-compose build`コマンドを使って再ビルドしてから起動という手順をたどる必要があります。

```bash
$ docker-compose build
# 以下ビルド処理の様子がログで流れる
$ docker-compose up
```

特定の一個のサービスだけbuildしたいなら、`docker-compose build <サービス名>`でサービスを指定すればOKです(サービス名はdocker-compose.ymlに記述したものです)。

## 削除
`docker-compose.yml`から作成したコンテナ群+ネットワークの削除は以下のコマンドで可能です。

```bash
$ docker-compose down
Removing app_service1 ... done
Removing app_service2 ... done
Removing network app_default
```
ただし、使用されていたイメージやボリュームは削除されないので、それも消したい場合は別途作業が必要です。

# Images
## 既存のDockerfileからイメージを作成する
`docker build`はDockerfileからimageを作成するコマンドです。
Dockerfileがあるディレクトリで実行すれば、`-t`オプションでつけたタグ名のイメージが作成されます。

```bash
# 最後の.はカレントディレクトリを意味するドットなので必要
$ docker build -t ImageA .
$ docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
ImageA   latest              6c97772719d3        17 seconds ago      919MB
(以下略)
```

## 一覧の確認
`docker images`で、現在存在するイメージを確認できます。

```bash
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ImageA   latest              6c97772719d3        17 seconds ago      919MB
```
このコマンドで確認できる項目は以下の通り。

- REPOSITORY : イメージ名
- TAG : タグ名
- IMAGE ID : イメージのID
- CREATED : 作成日時
- SIZE : メモリ容量

## repository・tagの追加
今あるイメージにリポジトリ・タグ名を新しく追加するためには以下のコマンドを使います。
(作った後も、<現repository>:<現tag>は残ります)

```bash
$ docker tag <現repository>:<現tag> <新repository>:<新tag>
```

## レジストリにpush
dockerレジストリにログインしている状態で以下のコマンドを実行することで、レジストリへのdockerイメージ登録ができます。

```bash
$ docker push <pushしたいイメージのrepository>:<pushしたいイメージのtag>
```
レジストリへのログイン方法は後述。

## 削除
`docker rmi`コマンドで、指定されたIDのイメージを削除できます。

```bash
$ docker rmi <image ID>
Deleted: sha256:bf756fb1ae65adf866bd8c456593cd24beb6a0a061dedf42b26a993176745f6b
Deleted: sha256:9c27e219663c25e0f28493790cc0b88bc973ba3b1686355f221c38a36978ac63
```
現在存在しているコンテナに使われていないイメージを一括削除したい場合は、`docker image prune`コマンドを使います。

```bash
$ docker image prune
WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N] y
# 以下削除処理
```

# Registries
Dockerレジストリとは、dockerイメージの公開・保存・配布を行うサービスのことです。
(例)Docker Hub, ECRなど

## リポジトリにログイン
```bash
$ docker login --username <your-user-name> --password <your-password> <loginURL>
```

## リポジトリからログアウト
```bash
$ docker logout <loginURL>
```

# Networks
## dockerのネットワーク概要
コンテナを単独で起動している分では、dockerのネットワークの仕組みがどうなっているのかはあまり意識しないことが多いでしょう。
ここでは、コマンドを紹介する前に、そもそもdockerネットワークがどういうものなのかを確認します。

まず、dockerインストール時にすでに存在するデフォルトネットワークについて説明します。
![docker-compose-03-03-1536x1024.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/add2f818-1c9f-a015-ab4f-a28695d22b44.png)
上図引用：[Docker Compose入門 (3) ～ネットワークの理解を深める～](https://knowledge.sakura.ad.jp/23899/)

### none
このネットワークを使うように指定されたコンテナには、外部のネットワークに繋ぐインターフェースが一切設置されません。
もちろんコンテナホストのPCと繋がるインターフェースも設置されないので、用途としてはネットワーク接続を必要としない開発環境を用意するときでしょう。

### host
この設定では、コンテナとホストがネットワークインターフェースを共有するものです。なので、コンテナのeth0とホストのeth0がそのまま繋がります。
これを利用すると、コンテナがホストマシンと同じIPアドレスを持つようになります。

### bridge
この設定では、ホストの任意のポートをコンテナのポートにマップすることで、コンテナ外部のネットワークに接続します。
例えば、先ほど紹介した`docker run -p 80:3000`というコマンドは、bridgeで「コンテナの3000番ポートをホストの80番ポートに繋ぐ」という設定をしていることになります。

コンテナーホスト間のポートマッピングは、ホストマシンのLinuxカーネル内部に作られるイーサネット・ブリッジによって行われています(この仮想ブリッジにはdocker0という名前がついています)。
![l_docker29-001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/c82c172f-81e2-30cf-1937-5b34ee830878.jpeg)
上図引用：[第29回 Docker Networkingの基礎知識　標準的なネットワークを理解する (4/5)](https://www.itmedia.co.jp/enterprise/articles/1609/21/news001.html)

コンテナ内部とdocker0仮想ブリッジは、veth(Virtual Ethernet Tunnel)によって接続されています。vethペアのうち、コンテナ側のインターフェースは、コンテナ内ではeth0として振る舞います。残ったホスト側の方は、docker0ブリッジにつながるインターフェースとなります。
docker0ブリッジには、ホストマシンのeth0にも繋がっています。

そのため、コンテナから外部への通信は、docker0ブリッジを経由し、そこでブリッジが提供するNAT機能を用いることで行うことになります。

ただし、このbridgeネットワークには名前解決機能がありません。
例えば、bridgeネットワークに同時に`container1`と`container2`というコンテナ2つが接続されているときに、`container1`から`container2`に向けて通信するためには、宛先に`container2`という名前を使うことができず、`container2`コンテナに付与されたプライベートIPアドレスをわざわざ調べてそれを使う必要があるということです。
コンテナに付与されるプライベートIPは、起動ごとにdockerが空いているIPを割り振るため不定です。そのため、コンテナ間通信に生のIPアドレスとそのまま使うのは避けるべきです。
そのため、同時に起動している他のコンテナと通信したいという場合は、次に挙げるdocker-conposeを利用したネットワークを利用します。

参考：[Docker-docs-ja公式ドキュメント Docker0 ブリッジのカスタマイズ](http://docs.docker.jp/engine/userguide/networking/default_network/custom-docker0.html)
参考：[Dockerのネットワークの仕組み](http://sagantaf.hatenablog.com/entry/2019/12/18/234553)
参考：[Docker の基本学習 ~ Docker のネットワーク](https://qiita.com/Arturias/items/b538e6bbf05dd3364397)
参考：[Docker network 概論](https://qiita.com/TsutomuNakamura/items/ed046ee21caca4a2ffd9)

### docker-composeで作成されるネットワーク
![docker-compose-03-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/7609dafa-89c6-24a7-35ed-a718e66ebfac.png)
上図引用：[Docker Compose入門 (3) ～ネットワークの理解を深める～](https://knowledge.sakura.ad.jp/23899/)

`docker-compose.yml`からコンテナを起動させた場合には、このようなユーザ定義・ブリッジ・ネットワークがデフォルトで作成されます。
仕組みとしては、上で挙げたbridgeネットワークと同じです。違いとしては、これにはDNS設定がされるので、bridgeネットワークでは不可能だったコンテナ間名での名前解決ができます。
参考：[Docker入門（第五回）〜コンテナ間通信〜](https://knowledge.sakura.ad.jp/16082/)

## 一覧確認
`docker network ls`コマンドで現在存在するネットワーク設定一覧を確認できます。

``` bash
$ docker network ls
NETWORK ID          NAME                        DRIVER              SCOPE
af74802186be        bridge                      bridge              local
a26bb8a73819        app_default                 bridge              local
c987a5c599df        host                        host                local
551c3f676ee0        none                        null                local
```
デフォルトネットワーク3つと、`docker-compose.yml`からできたユーザ定義・ブリッジ・ネットワークが1つ確認できました。
このコマンドで、以下のことがわかります。

- NETWORK ID: ネットワークID
- NAME: ネットワークの名前
- DRIVER: 元となったドライバ
- SCOPE: ネットワークのスコープ

## ネットワークの状態の確認
コンテナと同様に、`inspect`コマンドでネットワークの詳細設定を確認することができます。

```bash
$ docker network inspect <network Name>
```

## 削除
特定のネットワークを削除は、`docker network rm <name>`で可能です。

```bash
$ docker network rm <network Name>
```

# Volumes
## 一覧確認
`docker volume ls`でボリューム一覧が観れる。

``` bash
$ docker volume ls
DRIVER              VOLUME NAME
local               app_db-volume
local               app_redis-volume
```

## ボリュームの状態の確認
コンテナ・ネットワークと同様に、`inspect`コマンドで詳細設定を確認することができます。

```bash
$ docker volume inspect <volume name>
[
    {
        "CreatedAt": "2020-06-20T16:44:05Z",
        "Driver": "local",
        "Labels": {
            "com.docker.compose.project": "app",
            "com.docker.compose.version": "1.23.2",
            "com.docker.compose.volume": "db-volume"
        },
        "Mountpoint": "/var/lib/docker/volumes/app_db-volume/_data",
        "Name": "app_db-volume",
        "Options": null,
        "Scope": "local"
    }
]
```

## 削除
特定のボリュームを削除するためには、`docker volume rm <name>`で可能。

```bash
$ docker volume rm <volume Name>
```

どこのコンテナにもアタッチされていないボリュームを一括削除するには、`docker volume prune`でできます。

```bash
$ docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
# 以下削除処理
```