Docker入門メモ　Dockerfile作成からコンテナ起動するまで

# 目的

- Dockerとは何か、入門程度の知識を得る。
- Dockerfileの作成からDockerイメージ、コンテナを作成、起動する方法を知る。

# 背景

最近GitHub Actionsでworkflowを作る機会が多く、workflowでDockerコンテナを利用したテストを導入する方法を知りたいと思っていた。
しかし、そもそもDockerを触ったことがなかったため、多少のにわか知識よりも、経験が一番大事だと思ったのでやってみた。

# Docker概要

アプリケーションを開発（developing）、移動（shipping）、実行（running）するためのオープンなプラットフォームです。
様々なサービスで利用されており、今やスタンダードな技術です。

https://docs.docker.com/get-started/overview/

今回入門するにあたり、下記投稿の内容が大変参考になりました。
詳しく解説されており、大変有益な記事です。入門する方にはお勧めいたします。
投稿者様に感謝いたします。

https://qiita.com/gold-kou/items/44860fbda1a34a001fc1

# Docker Hub概要

Docker社が提供する、コンテナイメージを検索し、チーム内で共有するためのサービスです。
コンテナを作成するためのOSイメージなどもここから提供されます。

https://docs.docker.com/docker-hub/


# 全体像
こんな感じの全体像、操作を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38724/9c73bf43-4bcf-367d-57b0-1d0c9fc6af4c.png)

# 前提環境

os: macOS Monterey 12.5
machine: MacBook Air(Retina, 13-inch, 2018)
cpu: 1.6GHz デュアルコアIntel Core i5

```
% brew --version
Homebrew 3.5.10-60-g98999cc
```

# 内容

pingコマンドを実行できるコンテナ環境を構築しお試しします。

## 環境構築
まずはDockerをインストールします。
前提環境が異なる方は公式サイトにて環境に合わせたインストール方法を参照願います。
```
% brew install --cask docker
（省略）
% brew list --version | grep docker
docker 4.11.1,84025
```

## Dockerfile作成
Dockerイメージを作成するための入力となるDockerfileを作成します。
場所は任意で構いません。私は`/Users/xxx/Documents/docker`に作成しました。
```dockerfile:Dockerfile
# FROMはベースとなるコンテナのOSイメージを指定
FROM ubuntu:latest

# RUNは指定されたコマンドを実行
# pingを実行できるようにするため、apt-getの最新化とpingのインストールを指定
RUN apt-get update && apt-get install -y \
	iputils-ping

# CMDはコンテナ起動時に実行されるコマンド
# 起動後に対話形式で操作がしたかったためbashを起動
CMD ["/bin/bash"]
```

:::note warn
コマンド実行（CMD ["〜〜"]）はDockerfile内で1つしか指定できません。
別投稿でsshdを立ち上げた後、コマンド操作したいためCMD ["/bin/bash"]入れたところssh接続できなくてハマり散らかしました。
https://docs.docker.jp/engine/reference/builder.html#cmd
```
CMD 命令は Dockerfile 中で１度しか使えません。
複数の CMD 命令があれば、最後の CMD のみ有効です。
```
:::

コマンドについてもっと詳しく知りたい方は下記サイトを参照してみてください。

https://docs.docker.com/engine/reference/builder/

https://docs.docker.jp/engine/reference/builder.html?highlight=dockerfile%20from#dockerfile

## Dockerイメージ作成
作成したDockerfileを入力にDockerイメージを作成します。
Dockerfileがあるディレクトリにて`docker build`コマンドを実行します。
```
% docker build . -t example:latest
[+] Building 0.1s (6/6) FINISHED                                                
 => [internal] load build definition from Dockerfile                       0.0s
 => => transferring dockerfile: 36B                                        0.0s
 => [internal] load .dockerignore                                          0.0s
 => => transferring context: 2B                                            0.0s
 => [internal] load metadata for docker.io/library/ubuntu:latest           0.0s
 => [1/2] FROM docker.io/library/ubuntu:latest                             0.0s
 => CACHED [2/2] RUN apt-get update && apt-get install -y  iputils-ping    0.0s
 => exporting to image                                                     0.0s
 => => exporting layers                                                    0.0s
 => => writing image sha256:e61c485e49c9ebb67028faa88a6afd48952e44ba83903  0.0s
 => => naming to docker.io/library/example:latest                          0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
```

`-t`はイメージの名称とタグ名称を指定するオプションです。
name:tagの形式で指定します。

```:docker buildヘルプ（抜粋）
% docker build --help

Usage:  docker build [OPTIONS] PATH | URL | -

Build an image from a Dockerfile

Options:
  -t, --tag list                Name and optionally a tag in the
                                'name:tag' format
```

イメージの作成に成功するとイメージ一覧に掲載されます。
```
% docker image ls
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
example      latest    e61c485e49c9   6 hours ago   115MB
```

`docker image --help`でイメージに対する操作のヘルプを確認できます。
サブコマンドに対しても`--help`を指定すれば同様にヘルプを確認可能です。

```:docker imageヘルプ
% docker image --help

Usage:  docker image COMMAND

Manage images

Commands:
  build       Build an image from a Dockerfile
  history     Show the history of an image
  import      Import the contents from a tarball to create a filesystem image
  inspect     Display detailed information on one or more images
  load        Load an image from a tar archive or STDIN
  ls          List images
  prune       Remove unused images
  pull        Pull an image or a repository from a registry
  push        Push an image or a repository to a registry
  rm          Remove one or more images
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE

Run 'docker image COMMAND --help' for more information on a command.
```

## Dockerコンテナ作成、起動
作成したDockerイメージを入力にDockerコンテナを作成、起動します。
`docker run`コマンドを実行します。
`{IMAGE ID}`の部分は前項で`docker image ls`を実行した際に表示されたIMAGE IDを指定します。
例）`docker run -it e61c485e49c9`
```
% docker run -it {IMAGE ID}
root@fb55030af5df:/# 
```

これでコンテナが起動し、コマンドを受け付けている状態となりました。

`-it`についてはちゃんと理解ができていませんが、コンテナへの入力や結果の出力が行われ、対話形式でやりとりができる状態な感じです。（適当ですみません。。。）

ヘルプを抜粋で掲載します。

```:docker runヘルプ（抜粋）
% docker run --help

Usage:  docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

Run a command in a new container

Options:
  -i, --interactive                    Keep STDIN open even if not attached
  -t, --tty                            Allocate a pseudo-TTY
```

`docker container --help`でコンテナに対する操作のヘルプを確認できます。
commitやdiff辺りは構築の時に使いそうなコマンドです。
ファイルやフォルダを追加した時などは、diffを使うと変更差分がわかったりします。（1つ後のコードブロックで例を見せます）
```:docker containerヘルプ
% docker container --help

Usage:  docker container COMMAND

Manage containers

Commands:
  attach      Attach local standard input, output, and error streams to a running container
  commit      Create a new image from a container's changes
  cp          Copy files/folders between a container and the local filesystem
  create      Create a new container
  diff        Inspect changes to files or directories on a container's filesystem
  exec        Run a command in a running container
  export      Export a container's filesystem as a tar archive
  inspect     Display detailed information on one or more containers
  kill        Kill one or more running containers
  logs        Fetch the logs of a container
  ls          List containers
  pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  prune       Remove all stopped containers
  rename      Rename a container
  restart     Restart one or more containers
  rm          Remove one or more containers
  run         Run a command in a new container
  start       Start one or more stopped containers
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop one or more running containers
  top         Display the running processes of a container
  unpause     Unpause all processes within one or more containers
  update      Update configuration of one or more containers
  wait        Block until one or more containers stop, then print their exit codes

Run 'docker container COMMAND --help' for more information on a command.
```

コンテナ内で`/new_dir`フォルダを作成した後に差分表示した場合、下記のように結果表示されます。
```
% docker container ls
CONTAINER ID   IMAGE          COMMAND       CREATED          STATUS          PORTS     NAMES
44aa1263b642   e61c485e49c9   "/bin/bash"   31 seconds ago   Up 29 seconds             peaceful_elbakyan
% docker container diff 44aa1263b642
A /new_dir
```
差分を可視化できるのは素晴らしいですね。

## 動作確認、終了
動作確認として、インストール指示したpingが使えるかを試してみます。
```
root@fb55030af5df:/# ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.092 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.057 ms
^C
--- 127.0.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1034ms
rtt min/avg/max/mdev = 0.057/0.074/0.092/0.017 ms
```
使えてますね。

コンテナを終了するときは`exit`です。
```
root@fb55030af5df:/# exit
exit
```

# 最後に
今まではPJ内でDockerを使っていても、構築したことや利用したことはなかった。
実際に体験することで、さわり程度の知識やイメージを知ることができた。

学習していて良いなと思ったところは、Dockerfileのように、インフラがコード化されていること。
様々なサイトで解説されているメリットだが、今まで手順書で解説されていたことが1テキストファイルで済むという点、テキスト情報なのでバージョン差分が視覚的にわかる点がある。これは大きなメリットだと感じた。

そして、操作していて思ったのは、コマンドのヘルプがわかりやすかったこと。
Dockerの全体像と用語の示す先が理解できれば、コマンドのヘルプを見れば大体の想像がつき操作ができる親切さがいいと思った。（Linuxコマンドと同じキーワードを利用しているところも入りやすいのかもしれない）

学習や本記事を投稿するのに時間はかかってしまったが、相応に得るものも多く、非常に有益な時間であった。