【docker】dockerのキワミ


## はじめに

この記事では数年で飽きるほどコマンドを使ってみて「実際にこのコマンド重要だよね」とか「このコマンドはあまり使わない。。かも」など、いろんな体験を交えて必要なコマンドを書いていく記事です。

## まずは準備体操

### プロセスチェック

コンテナのプロセスをチェックするコマンドです。

``` bash
docker ps
```

単純に`ps`しても良いのですが、実際には`-a`の方をよく使うかなと思います。

```bash
docker ps -a
```

### レジストリからイメージを取得

nginxのイメージを取得するコマンドです。

``` bash
docker pull nginx
```

pullするときはタグを指定してpullすることが多いです。これはDockerfileでも同様です。

### 保存されているイメージ一覧を表示

保存されているイメージの一覧を取得します。

```bash
docker images
```

### dockerイメージからコンテナを起動

ポート80番でnginxを起動するコマンドです。

```bash
docker run -p 80:80 -d --rm --name nginx_web nginx
```

オプションがたくさんついていますが、以下のような意味があります。

- `-p`
  - ポートを指定する
- `-d`
  - コンテナをバックグラウンドで実行し、コンテナIDを表示
- `--rm`
  - コンテナ終了時にコンテナを削除する
- `--name`
  - コンテナ起動時にコンテナに名前をつける

### ボリュームマウントをして起動する場合

`--volume`をつけるとホストのストレージボリュームを関連付けます。

```bash
docker run -d --volume "$(pwd)":/usr/share/nginx/html -p 80:80 --rm --name nginx_web nginx
```

### コンテナからイメージを作成

起動中のコンテナからイメージを作成します。コンテナからイメージを作成しておくと
万が一Dockerfileを消失してしまった場合でもコンテナの情報をもとにDockerfileを再構成できます。

```bash
docker commit nginx_web oreno
```

### コンテナに対してコマンドを実行

指定したコンテナに対してコマンドを実行します。コンテナの後ろに実行するコマンドを入力します。下記の例では `sh`を実行しています。

```bash
docker exec -it nginx_web sh
```

### メタデータを見る

イメージおよびまたはコンテナがどのような構成になっているかを参照するコマンドです。

イメージを見る場合

```bash
docker inspect nginx
```

コンテナを見る場合

```bash
docker inspect nginx_web
```

### コンテナのログを表示 (Log)

コンテナで発生したログを参照するコマンドです。コンテナのデバッグでお世話になります。

``` bash
docker logs nginx_web
```

### dockerコンテナを停止

指定されたコンテナを停止するコマンドです。

```bash
docker stop nginx_web
```

### コンテナを削除する

コンテナIDを指定してコンテナを削除します。

```bash
docker rm {コンテナID}
```

### イメージを削除する

イメージIDを指定してイメージを削除します。

```bash
docker rmi {イメージID}
```

## ここからが本番

実際にはこうじゃね？って話を書いていきます。
もちろん、dockerコマンドは使いようです。

### (たぶんこう)レジストリからイメージを取得

pullするときはタグもしくはダイジェストを指定します。そうでないと何を持ってきたかわかりません。

なお、`latest`タグについては何を持ってきているのかを把握できていれば問題ないと思います。
たとえば、ご自分で管理しているAmazon ECRにある最新のイメージを常に`latest`と名付けており、イメージの修正を担当している場合は`latest`でも問題ありません。

タグで指定する場合

```bash
docker pull nginx:latest
```

ダイジェストで指定する場合

```bash
docker pull nginx@sha256:81be38025439476d1b7303cb575df80e419fd1b3be4a639f3b3e51cf95720c7b
```

別の観点ではありますが、昨今ではさまざまなアーキテクチャの端末が流通しています。

すべてのdocker buildを特定のコンピュート基盤で統一している。つまりはCI/CDの工程で統一できているのであれば問題ありませんが、そうでないことがよくあります。

つまり、統一されていないのでビルドしてプッシュしたイメージがアーキテクチャレベルで異なる場合が発生するということです。よって、正常に動作しない可能性があります。

### （たぶんこう）保存されているイメージ一覧を表示

何も指定せずに実行すると下記のように出力されると思います。

```bash
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
```

思うに`IMAGE ID`はイメージ削除などには使えるIDなので情報量がゼロとは言いませんが、常に見るものかというと見ないと思います。

また、仮に見る必要があったとしてどういうときに使うか想像するとあまり利用用途は浮かばないと思います。とくに端末に保存されているイメージを削除するときは`IMAGE ID`を意識する必要はありません。※理由は後で説明します。

ではどうしたら良いか。必要な部分だけを表示するようにします。
下記の例ではCSV形式で`docker images`を表示します。

```bash
docker images --digests --format='{{.ID}},{{.Repository}},{{.Tag}},{{.Digest}},{{.Size}}'
```

出力結果

```text
451bf5358040,nginx,<none>,sha256:18deb42e6d79c664b3fc231d60a44c8b017b0a61ecd288fab431b5ca63696481,182MB
81be38025439,nginx,1,sha256:565211f0ec2c97f4118c0c1b6be7f1c7775c0b3d44c2bb72bd32983a5696aa6a,192MB
81be38025439,nginx,1,sha256:86e53c4c16a6a276b204b0fd3a8143d86547c967dc8258b3d47c3a21bb68d3c6,192MB
81be38025439,nginx,latest,sha256:565211f0ec2c97f4118c0c1b6be7f1c7775c0b3d44c2bb72bd32983a5696aa6a,192MB
81be38025439,nginx,latest,sha256:86e53c4c16a6a276b204b0fd3a8143d86547c967dc8258b3d47c3a21bb68d3c6,192MB
```

上記の書き方はデータとして持っておく用途では有益ですが、実際には特定のdockerイメージを使って
dockerfileを作ると思います。

dockerfileの書き方について別の記事でおさらいしたいと思いますが
dockerfileのベースイメージはタグもしくは`SHA256`で始まるダイジェストで指定すると思います。
dockerイメージのダイジェストを表示する場合は下記のコマンドで表示できます。

```bash
docker images --digests --format='{{.Digest}}'
```

タグを表示する場合

```bash
docker images --format='{{.Tag}}'
```

#### Tips --filter=referenceを使って該当のイメージのみ表示

該当のイメージ名だけ取得したい場合は下記のコマンドでできます。

```bash
docker images --format='{{.Repository}}' --filter=reference='nginx'
```

特定のイメージだけピンポイントに取得した時に便利なコマンドです。
--filterを使うことで`IMAGE ID`を意識することなく、`IMAGE ID`を特定してイメージを操作できます。
これが前述の削除するイメージの`IMAGE ID`を意識する必要がない理由です。

#### Tips `<none>`となっているイメージのみ表示

中間イメージにも使われていないような不要なイメージ、Tagが`<none>`となっているものについて
表示したい場合は下記のコマンドが有効です。

```bash
docker images -f "dangling=true"
```

上記のコマンドはイメージの削除コマンドと組みわせると便利です。

### (たぶんこう)イメージを削除する

まずは基本コマンドを見てみましょう。
`docker rmi`コマンドはイメージIDを指定して特定のイメージを削除するコマンドです。

```bash
docker rmi {イメージID}
```

実際のところ、「削除対象のイメージIDを見て削除」って難しいと思うんですよね。
つまりは他のコマンドと組み合わせるのが良いのではないかなと思います。

下記のコマンドは中間イメージにも使われていないような不要なイメージ
Tagが`<none>`となっているものだけ削除するコマンドです。

```bash
docker rmi -f `docker images -f "dangling=true" -q`
```

ちなみに保存したイメージをすべて削除するときは下記のコマンドは有効です。

```bash
docker rmi -f `docker images -q`
```

### Tips `prune`と`rmi`の違い

下記のコマンドは24時間以内に使っていないイメージを削除します。

```bash
docker image prune -a --force --filter "until=24h"
```

`docker rmi`も同じイメージを削除するコマンドですが、何が違うのでしょうか。
結論を述べると削除するという文脈で言えば同じコマンドです。

ですが、pruneの場合は不要なものを削除するというところにフォーカスしてします。

### (たぶんこう)コンテナを削除する

まずは基本コマンドを見てみましょう。`docker rm`コマンドはコンテナIDを指定して特定のコンテナを削除するコマンドです。

```bash
docker rm {コンテナID}
```

実際のところ、「削除対象のコンテナIDを見て削除」というのは煩雑だと思います。

そこで`docker rm`コマンドは`docker ps`コマンドと組み合わせて利用するのがベストだと考えています。

下記の例はすべてのコンテナを削除するコマンドです。

```bash
docker rm -f $(docker ps -a -q)
```

停止済みのコンテナだけ削除したい場合は下記のコマンドが有効です。

```bash
docker rm $(docker ps -a -q --filter "status=exited")
```

削除した後に実行されているコンテナがないかを確認したいので上記のコマンドを一工夫すると下記の通りになります。

```bash
docker rm $(docker ps -a -q --filter "status=exited") && docker ps -a
```

コンテナIDではなく、コンテナ名で対応できるとやりやすいのかなと思います。

### Docker環境の掃除

まずは現状を確認します。

```bash
docker system df
```

`Images`,`Containers`,`Local Volumes`,`Build Cache`の4つの状態が表示されます。
それぞれイメージの容量、コンテナの容量、コンテナのボリューム容量、ビルド時に利用するキャッシュが表示されます。

これらの中で不要となるデータを掃除する場合は下記のコマンドを使いましょう。

```bash
docker system prune
```

## まとめ

今回は改めてDockerの使い方を振り返りました。
よくよく考えてみると`docker images`や`docker ps`などイメージやコンテナの情報を表示するコマンドをうまく使うと
他のコマンドの味も出るのかなと思うところです。

Docker環境の情報を出力してどこかに保存しておきたいなどの要件があれば、`docker images`や`docker ps`の使い方、とくにオプションを使えるようにしておきましょう。

今回はビルドコマンドについて細かくみてこなかったため、次はDockerfileの書き方と一緒に見ていきたいと思います。

## 参考

- [Docker コマンド](https://docs.docker.jp/v19.03/engine/reference/commandline/index.html)
- [docker pull](https://docs.docker.jp/engine/reference/commandline/pull.html)
- [docker images](https://docs.docker.jp/engine/reference/commandline/images.html)
- [docker inspect](https://docs.docker.jp/engine/reference/commandline/inspect.html)
- [docker run](https://docs.docker.jp/v19.03/engine/reference/commandline/run.html)

- [nginx DockerHub](https://hub.docker.com/_/nginx/tags)

## おわり