[メモ]初心者がコンテナを触ってみる - (2)Dockerイメージの取得・操作

# はじめに
お疲れ様です。yuki_inkです。

初心者がコンテナを触ってみるシリーズ2回目です。
モチベはまだある。

# やったこと
- Docker Hubアカウントの作成
- イメージの検索
- Docker Hubからイメージのダウンロード
- イメージの内容の確認
- イメージの削除
- イメージのタグ設定
- Docker Hubへのイメージのアップロード


## Docker Hubアカウントの作成

[Docker Hub](https://hub.docker.com/)のページにアクセスし、サインアップ。
なんかCAPTCHAの判定めっちゃ厳しかった。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/970e5285-643c-799d-73f2-2eb9839f3d7a.png)
プランはPersonalでヨシ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/1d1c7f34-d152-18a1-c3e7-cfbe06322035.png)
サインアップページで指定したメールアドレスに確認メールが届くので、メール上のリンクをポチって登録完了。



## イメージの検索
Docker Hubの画面上部の検索バーでDockerイメージを検索できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/c2d452f2-d90e-528d-da52-a78cb174f2d9.png)

`docker search [検索キーワード]`コマンドで、コマンドラインでも検索できる。
```
$ docker search nginx
NAME                        DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
nginx                       Official build of Nginx.                        18687     [OK]
unit                        Official build of NGINX Unit: Universal Web …   6         [OK]
nginxproxy/nginx-proxy      Automated Nginx reverse proxy for docker con…   90
nginxproxy/acme-companion   Automated ACME SSL certificate generation fo…   116
～以下略～
```
画面上での検索結果と一致。

コマンドのオプションや出力の見方は公式ドキュメントを参照。

https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/search/

## Docker Hubからイメージのダウンロード
`docker image pull [イメージ名]`コマンドでイメージをダウンロードできる。

そういえば[前回](https://qiita.com/yuki_ink/items/1fc12d019cd33929d46b)も、PCにDockerをインストールした後、`docker image pull nginx`でNginxのイメージを取得してコンテナ立てたなぁと、今更ながら思い出す。
あれはDocker Hubからイメージを取得していたんですね。

>docker pull のイメージは Docker Hub から取得するのがデフォルトです。 取得するレジストリの場所は、手動で指定可能です。 例えば、ローカルにレジストリをセットアップしておけば、そちらを指定してイメージを取得できます。

https://docs.docker.jp/engine/reference/commandline/pull.html#id12

`docker image ls`コマンドで取得したイメージの一覧を表示する。
前回やったときにNginxのイメージは取得していたので、`docker image ls nignx --digests`で以下のように表示される。
※`docker image ls [リポジトリ名]`で、指定したリポジトリに出力を限定できる。
※`--digests`オプションでイメージのダイジェストを表示。

```
$ docker image ls nginx --digests
REPOSITORY    TAG       DIGEST                                                                    IMAGE ID       CREATED       SIZE
nginx         latest    sha256:593dac25b7733ffb7afe1a72649a43e574778bf025ad60514ef40f6b5d606247   eb4a57159180   11 days ago   187MB
```

この状態で`docker image pull nginx`を実行。
```
$ docker image pull nginx
Using default tag: latest
latest: Pulling from library/nginx
Digest: sha256:593dac25b7733ffb7afe1a72649a43e574778bf025ad60514ef40f6b5d606247
Status: Image is up to date for nginx:latest
docker.io/library/nginx:latest
```
Docker Hub上に更新版があればそれをダウンロードして、ローカルのイメージを更新してくれるようだが、今回はすでにローカルのイメージが最新だった。
1週間前にダウンロードしたばかりだしなあ。。

:::note info
[イメージ名] = [リポジトリ名] + [タグ名]
[タグ名]を省略すると、「latest」のイメージが取得される
※`docker image pull nginx`と`docker image pull nginx:latest`は同じ意味になる

参考：[Docker初心者がイメージとリポジトリの違いが分からなくて混乱したこと](https://qiita.com/zaki_taka4/items/9d330556542c665b011c)
:::

リポジトリ/レジストリ/イメージ/タグの概念図は以下が分かりやすかった。

https://www.ogis-ri.co.jp/otc/hiroba/technical/docker/part3.html


## イメージの内容の確認
`docker image inspect [イメージ名]`コマンドで、イメージの詳細情報を確認できる。
イメージIDや作成日、OS、Dockerのバージョン、CPUのアーキテクチャなどが分かる。
<details><summary>コマンドの出力結果はかなり長いので折りたたむ。</summary>

```
$ docker image inspect nginx
[
    {
        "Id": "sha256:eb4a57159180767450cb8426e6367f11b999653d8f185b5e3b78a9ca30c2c31d",
        "RepoTags": [
            "nginx:latest"
        ],
        "RepoDigests": [
            "nginx@sha256:593dac25b7733ffb7afe1a72649a43e574778bf025ad60514ef40f6b5d606247"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2023-06-14T07:16:35.543292113Z",
        "Container": "20a63bb857cabbde744d031c670a18470ddff9bc46c712bc3eaecbea49df55f8",
        "ContainerConfig": {
            "Hostname": "20a63bb857ca",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.25.1",
                "NJS_VERSION=0.7.12",
                "PKG_RELEASE=1~bookworm"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"nginx\" \"-g\" \"daemon off;\"]"
            ],
            "Image": "sha256:88c36fc25777ef22f947c314610b2852daaa20bdc25b10b7b4cad93d20b46ef7",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {
                "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
            },
            "StopSignal": "SIGQUIT"
        },
        "DockerVersion": "20.10.23",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.25.1",
                "NJS_VERSION=0.7.12",
                "PKG_RELEASE=1~bookworm"
            ],
            "Cmd": [
                "nginx",
                "-g",
                "daemon off;"
            ],
            "Image": "sha256:88c36fc25777ef22f947c314610b2852daaa20bdc25b10b7b4cad93d20b46ef7",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {
                "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
            },
            "StopSignal": "SIGQUIT"
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 186854870,
        "VirtualSize": 186854870,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/4461900a2deb70a9539f4738a6bf5a677e5eb6271555498915f6974ceae620fb/diff:/var/lib/docker/overlay2/2a885ecae7789b14fe952080573530f20bdbea86db29fa8208d3ca0fe6896c28/diff:/var/lib/docker/overlay2/167b574dde1fb180c02450a4785b606ece4b4cf695a7bd5a504a63eb82eac405/diff:/var/lib/docker/overlay2/d6f1073591a995357b8c4afd9d9500eb142c5f3d2799eb609eb270cad5b38990/diff:/var/lib/docker/overlay2/a174bca077ed55e6b6fb68e02a3ce086a4111c3adce9fe90d0af44b1a00d4035/diff:/var/lib/docker/overlay2/d0c3cbf125e31a09651a53a717c804b3a468b368db75ca251c6bb04296e28882/diff",
                "MergedDir": "/var/lib/docker/overlay2/81d7641a81cadbc15e6dbca64fb06e1b7350669fa6fecc3ed29eb4680ce269c0/merged",
                "UpperDir": "/var/lib/docker/overlay2/81d7641a81cadbc15e6dbca64fb06e1b7350669fa6fecc3ed29eb4680ce269c0/diff",
                "WorkDir": "/var/lib/docker/overlay2/81d7641a81cadbc15e6dbca64fb06e1b7350669fa6fecc3ed29eb4680ce269c0/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:ac4d164fef90ff58466b67e23deb79a47b5abd30af9ebf1735b57da6e4af1323",
                "sha256:a8311013964725a288e00b53cfcf67d9303c4b3bc2ad7475cfc3b25867580ace",
                "sha256:4ca29ffc4a01ee651811c21b457cea0f2f5d5b0270d258208391a17998675a79",
                "sha256:bf8b62fb2f13ed1f2da4fd11f8136180c3284e88af95d7f00d21c8064f99f3b1",
                "sha256:7757099e19d2d8f2e1c09c9076524f912de42e6c76bc8a082ff178d74b5f54a6",
                "sha256:12a568acc014fad0d74cfa5509c6f55e80db2afb199ad5c1bdff05e2b6d1e5c7",
                "sha256:9e96226c58e7d2ab330522f49a51eb25037d4f89bfc53fa2c10b910184fa6b78"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]
```
</details>

## イメージの削除
`docker image rm [イメージ名]`コマンドで、ローカルのイメージを削除できる。
Docker導入時に取得した「hello-world」を削除する。

```
$ docker image ls
REPOSITORY    TAG       IMAGE ID       CREATED       SIZE
nginx         latest    eb4a57159180   12 days ago   187MB
hello-world   latest    9c7a54a9a43c   7 weeks ago   13.3kB

$ docker image rm hello-world
Untagged: hello-world:latest
Untagged: hello-world@sha256:c2e23624975516c7e27b1b25be3682a8c6c4c0cea011b791ce98aa423b5040a0
Deleted: sha256:9c7a54a9a43cca047013b82af109fe963fde787f63f9e016fdc3384500c2823d
Deleted: sha256:01bb4fce3eb1b56b05adf99504dafd31907a5aadac736e36b27595c8b92f07f1
```
消えた！
```
$ docker image ls
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        latest    eb4a57159180   12 days ago   187MB
```

## イメージのタグ設定
Docker Hubにイメージをアップロードして終わろ～と思っていたら、
>まず、アップロードしたDockerイメージに決まったフォーマットでタグを付けてあげる必要があります。
`docker tag イメージID DockerHubユーザ名/任意のイメージ名`でタグをつけてあげます。

とのこと。

https://www.kabegiwablog.com/entry/2018/07/18/140000

既存のNginxのイメージに対して、以下の情報を付与する。
- ユーザ名：`yukiink`　※Docker Hubのユーザ名と一緒にする
- イメージ名：`webserver`
- バージョン：`1.0`　⇒タグに入れる
```
$ docker image tag nginx yukiink/webserver:1.0
```
`docker image ls`でタグ設定を確認する。
```
$ docker image ls
REPOSITORY          TAG       IMAGE ID       CREATED       SIZE
nginx               latest    eb4a57159180   12 days ago   187MB
yukiink/webserver   1.0       eb4a57159180   12 days ago   187MB
```
タグを付与したイメージ（yukiink/webserver:1.0）と元のイメージ（nginx:latest）のIMAGE IDが同じ！（eb4a57159180）
両者の実体が同じであることを意味しているらしい。
※イメージに別名を付けただけで、イメージ自体をコピーしたりリネームしたりしたわけではない。

## Docker Hubへのイメージのアップロード
Docker Hubに、先ほどタグ付けしたイメージ（yukiink/webserver:1.0）をアップロードする。

まずはコマンドラインでDocker Hubにログインする。
```
$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: yukiink  ##ユーザ名を入力する
Password:  ##パスワードを入力する
Login Succeeded
```
オプションを利用して、`docker login -u (ユーザ名) -p (パスワード)`のコマンド一発でも入れるらしい。

`docker image push [イメージ名]`コマンドで、イメージをDocker Hubにアップロードする。
```
$ docker image push yukiink/webserver:1.0
The push refers to repository [docker.io/yukiink/webserver]
9e96226c58e7: Mounted from library/nginx
12a568acc014: Mounted from library/nginx
7757099e19d2: Mounted from library/nginx
bf8b62fb2f13: Mounted from library/nginx
4ca29ffc4a01: Mounted from library/nginx
a83110139647: Mounted from library/nginx
ac4d164fef90: Mounted from library/nginx
1.0: digest: sha256:d2b2f2980e9ccc570e5726b56b54580f23a018b7b7314c9eaff7e5e479c78657 size: 1778
```
完了。
ブラウザからDocker Hubを確認すると、`yukiink/webserver`のリポジトリが表示されている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/a2a4112d-42c1-d6f7-6471-0494c5a468e9.png)
リポジトリの中を確認すると、`1.0`のタグを持つイメージが表示されている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/3c1d1ffb-4d4b-548c-6353-2ba592c07952.png)

Docker Hubからログアウトして終了！
```
$ docker logout
Removing login credentials for https://index.docker.io/v1/
```

# 終わりに
今回はDockerイメージを操作するコマンドをいくつか触ってみました。
なるほど、こうやってイメージをリポジトリにアップするのね。。

次回はコンテナを実際に立ててみたり消してみたり、そんなライフサイクル関連のコマンドを触ってみようと思います。