dockerコマンド

## 目的
dockerをなんとなく使っていた状態から、その仕組みやお作法をきちんと理解した上で使えるよになりたいと思い記事にしてみました。これまでdockerコマンドやDockerfileについてよくわからないまま使っていました。ちゃんとdockerコマンドやDockerHubについて理解するとともに、Dockerfileやdocker-compose.yml を学んでいくのがよさそうかなと思ってます。

### Dockerとは
軽量なコンテナ型アプリケーション実行環境

### Dockerの特徴
- Docker社が開発  
- コンテナ型仮想環境（Dockerエンジン＋APP）軽量、高速起動停止  
- 仮想マシンと対比される（Hypervisor＋ゲストOS＋APP）  
（仮想化ソフトウェアの代表的なものにVM WareやVirtual Boxがある）  
- 誰でも同じ環境が素早く作れる（バージョン違いなどの差異が生まれない）  
- 基本的にはLinux環境で動いており、ホストOSのカーネルを共有している（カーネルは常に１つ）  
- 隔離された実行環境（コンテナ）にすぎない
- 作成した環境を配布できる
- コンテナを破棄して作り直すことが容易である 

### Dockerイメージ
- オブジェクト指向に例えるとクラスに相当
- Dockerイメージを格納しておくことのできるDockerリポジトリの仕組みがある（Docker Hub）  
　例「Apacheがインストールされたイメージ」「MySQLがインストールされたイメージ」  
- Docker HubはDockerリポジトリであり、プライベートに使うことも、パブリックで公開して使うこともできる。  
- 有志の人が便利だと考えて作られたイメージが多種多様既に登録されている  
- Dockerファイルを使ってビルドできる（$docker build -t ImegeName .）  
- 自分で作成したコンテナをDockerイメージとして出力することやDockerHubに登録することもできる。  

### Dockerイメージの実体
- Dockerコンテナの実行に必要なファイルやメタ情報の集合体  
- 抽象的なレイヤの積み重ね（レイヤには親子関係がある）  
- 複数のイメージレイヤーが集まって１つのイメージが出来上がっている。  
（利用者からは１つのイメージにしか見えない）  

### Docker Hub
Docker Hub は、Docker社が管理公開しているレジストリ、つまり入れ物である。
そこには、コンテナを構築するためのイメージが置かれている。  
gitで言うところのGit Hub に相当する。Git Hubにはソースコードを入れることが多いが、docker Hubにはイメージを入れておき共有することができる。  
誰でもアカウントを作成してログインしたら使うことができる。  

### Docker コマンド（イメージの取得）
dockerコマンドの種類やオプションは多数存在し、必要に応じて調べて覚えていくのがよい。 ここでは、Linuxディストリビューションの中の１つでもあるubuntsイメージを例にDockerHubから取得してコンテナ起動までの流れで記載する。  

- $docker search ubuntu

DockerHub上でubuntuイメージを検索する。  
ubuntuにも多くの種類のイメージが公開されており、その中から欲しいものを選んで取得する  

- $docker image pull ubuntu

DocckerHubからubuntuのイメージを取得する。  
（tagを指定しなければデフォルトで:latestタグが使用され最新版を取得する）  

- $docker images

ローカルに保存されているDockerイメージの一覧を表示する -a オプションをつけて実行すると、イメージを構成する各レイヤーのイメージも細かく一覧で表示されるようである。  

### Docker コマンド（コンテナの作成と実行）
- $docker run ubuntu
- $docker run -it centos

イメージからコンテナを生成して起動までを行う。  
オプションが何も指定されていない場合はコンテナ起動後すぐに終了する。  
（-itオプションは後述）

--name [コンテナ名] も追加してコンテナ名を指定することもできるが、  
もし指定しなければdockerによって勝手に名前がつけられるようである。  
コンテナ名を変更したければ  
- $docker rename [現在コンテナ名] [新コンテナ名]  
で変更することができた。  

ローカルにイメージが存在しなければdockerがDockerHubからpullして  
自動でダウンロードしてくれる。
たとえばhttpdイメージをrunコマンドで指定すると  
```
Unable to find image 'httpd:latest' locally
latest: Pulling from library/httpd
```
このようにpullしていることが確認できる。  

pullとcreateとstartを通して実行してくれるようなのでrunを使えば  
爆速でコンテナを使えるようにできるというわけである。

注意としては、docker run の実行のたびにコンテナが新規作成されるということである。実行の度にコンテナが増え続けるので作りすぎに注意が必要である。  

- $docker run -it ubuntu

-iと-tのオプションをあわせて-itと指定できるが、これを指定することで  
起動したコンテナにログインすることができる。  
但し、exitをしてしまうとログアウトすると同時にコンテナも終了してしまう。  
この場合、Ctrl+PのあとQを押すと、コンテナを起動したままの状態でログアウトできる。これをデタッチといいバックグラウンドで動作している状態である。  

$docker ps -a
で確認してみると、STATUSが Up となっておりExitedされてないことが確認できる。  

- $docker attach [コンテナID]

デタッチしたコンテナのIDを指定して上記を実行すると、再びコンテナに接続することができる。  

コンテナに接続している状態で  
#exit を実行して  
$docker ps -a　で確認してみると、STATUS がExitedとなっており、ログアウトと同時にコンテナが終了したことを確認できる。  

$docker run -it ubuntu /bin/bash  
シェルを指定することもできる。  

### phpが動くコンテナを作成しechoしてみる
$docker run php php -r 'echo 11*22;'  
242

### Docker コマンド（コンテナの起動・停止）
コンテナを作成する別な方法として  

- $docker create -it --name konta ubuntu  

これによりイメージからコンテナを作成するところまでができる。  
$docker ps -a   
で確認するとSTATUSがCreatedになっていて起動まではされてないことがわかる。  

次のstartコマンドを実行してもすぐにExitしてしまわないように、  
createの時に-itを指定しておく。  

- $docker start konta

生成されているコンテナを起動する。  
なにもオプション指定がされてない場合には、$docker run -d と同様バックグラウンドで実行される  
-a オプションを付けると-dオプション無しと同じ動作になり、コマンドプロンプト#が表示されるが、tty接続されていないため何もコマンドは入力できない。（Ctrl+Cで終了するしかない）  

- $docker stop konta

起動しているコンテナを停止する。  

$docker ps -a  
でSTATUSを確認するとExitになっていることが確認できる。  

### Docker コマンド（コンテナに接続）
- $docker exec -it konta /bin/bash  
- $docker exec konta /bin/ls -la  

起動中のコンテナに接続して、コンテナ内でコマンドを実行できるようになる。  
上記の場合はbashを起動しているのでbash上でコマンドを実行できる。  
後者は、コンテナ内でls -la を実行したのち、すぐにコンテナを終了する。  

### Docker オプション（-i、-t）
```
- -i は --interactiveと同じであり、コンテナの標準入力をDockerホストの標準入力と接続する。
- -t は --ttyと同じであり、コンテナ内で疑似的な仮想端末を割り当て、Dockerホストの標準出力と接続する。
```
※上記はあるサイトからの引用

要するに、  
-i はコンテナ側からの出力をコンテナの外側へ出せるようにするものであり  
-t は外側からの入力をコンテナ内部へと入力できるようにさせるようなものと考えた。  

なので、コンテナに接続してコンテナ上でコマンド操作するといったように、  
対話型コマンドを実現させたい場合には、両方をまとめて -it を指定する。  

### Docker コマンド（run と execの相違）
docker run コマンドは、コンテナを生成し、かつ、起動までも行うようである。  
（createとstartを一発で実行するようなものである）  
docker exec コマンドは、既に起動中であるコンテナに接続してコンテナ内でコマンドを実行させたい場合に使う。  なのでexecの場合には、コンテナが起動されている必要がある。  

### Docker コマンド（cp）
コンテナ内にファイルをコピーする。  
コンテナは起動中でも停止中でもコピーできるようである。  

- $docker run -d -p 8080:80 httpd

httpdイメージを使ってコンテナをバックグラウンドで起動しておく。  

-pオプションは外部ポートとコンテナ内部のポートを接続するオプションである。  
外部から8080ポートでアクセスすると、コンテナ内の80ポートに接続できるというものである。  

任意のファイル （TESTと記載された）test.htmlを用意しておく。  
$docker ps でhttpdコンテナが起動中であることを確認し、  
$docker exec -it httpd /bin/bash でDocumentRootが  
/usr/local/apache2/htdocs  
であることを確認しておく。  

```
$docker cp test.html httpd:/usr/local/apache2/htdocs
```
コピー先は[コンテナ名]:[格納ディレクトリのパス]で指定する。  

ブラウザで  
http://localhost:8080/test.html  
を表示させると TEST という文字が表示されるこたことが確認できた。  

cpだけでもまだまだ奥が深いので、別の機会に試してみようと思う。  

### Docker コマンド（rename）
コンテナを作成する際、--name でコンテナ名を指定しないと、自動的に名前が付けられるようである。  
それをあとから変更するためには、rename コマンドを使う。  

- $docker rename elegant_dhawan httpd

変な名前elegant_dhawanが付けられてしまったが、あとからhttpdに変更した場合のコマンドである  


### Docker コマンド（build）
これは、Dockerfileを使ってDockerイメージを生成するためのコマンドである。  
ちょうどmakeコマンドのMakefileに相当するようなものだ。  
Dockerfileについては別の記事に記載する。  

### Docker コマンド（commit）
既存のコンテナに対して、いろいろと手を加えて（コンテナ内にファイルを入れたりアプリを入れたりして）自分独自のコンテナへと更新させることができる。  
しかし、そのコンテナを削除してしまうと、せっかく作ったオリジナルなコンテナを再度作り直さなければならない。  
そこで、自分で作ったコンテナをイメージとして保存しておくことができる。  
（そのイメージをDockerHubにアップロードすることも可能だ）  

- $docker commit httpd kontaimg

これは、httpdという名前のコンテナをkontaimgという名前のイメージとして保存するという意味だ。  
$docker images  
で確認するとイメージが出来上がっていることが確認できる。  

これにより、kontaimgイメージさえあれば、コンテナを作り直すこともできるし複製もできる。  

### Docker コマンド（diff）
コンテナ内で変更があった情報の一覧を出力してくれるようだ。  

- $docker diff httpd

例えば、初期のコンテナの状態から  
$docker cp test.html httpd:/usr/local/apache2/htdocs  
このようにファイルをコンテナ内にコピーしたのち、diffを実行してみたら、  
```
C /usr
C /usr/local
C /usr/local/apache2
C /usr/local/apache2/htdocs
A /usr/local/apache2/htdocs/test.html
```
このように表示される。  

CはChange（変更）  
AはAdd（追加）  
を意味するのだと思う。（Dは削除かな）  

A /usr/local/apache2/htdocs/test.html  
上記の通り追加されていることが確認できた。

### Docker コマンド（info）
Dockerクライアントとサーバーの細かな情報が表示される。  

- $docker info

サーバーにおいては、稼働中コンテナ数、停止中コンテナ数、イメージ数など。  

```
Client:
 Context:    default
 Debug Mode: false
 Plugins:
  app: Docker App (Docker Inc., v0.9.1-beta3)
  buildx: Build with BuildKit (Docker Inc., v0.5.1-docker)
  scan: Docker Scan (Docker Inc., v0.5.0)

Server:
 Containers: 11
  Running: 1
  Paused: 0
  Stopped: 10
 Images: 31
 Server Version: 20.10.2
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 1
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 269548fa27e0089a8b8278fc4fc781d7f65a939b
 runc version: ff819c7e9184c13b7c2607fe6c30ae19403a7aff
 init version: de40ad0
 Security Options:
  seccomp
   Profile: default
 Kernel Version: 4.19.128-microsoft-standard
 Operating System: Docker Desktop
 OSType: linux
 Architecture: x86_64
 CPUs: 4
 Total Memory: 12.45GiB
 Name: docker-desktop
 ID: A3AZ:FLYN:SXFK:7KIM:QMDV:JVMX:HCX5:FLDS:QRND:TYTF:ZQWK:KGQA
 Docker Root Dir: /var/lib/docker
 Debug Mode: true
  File Descriptors: 46
  Goroutines: 48
  System Time: 2021-01-21T01:37:27.1105279Z
  EventsListeners: 2
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false
```

### Docker コマンド（inspect）
実行してみるとコンテナの細かい情報が表示された。  

- $docker inspect httpd

たとえば、コンテナのステータスとか、コンテナ内で設定された環境変数だとか。。
```
[
    {
        "Id": "d31a31a707ae8738daae7e3bc6578ea9b52e516aeba2d5d37a9000a6d5768c53",
        "Created": "2021-01-20T11:00:57.1970936Z",
        "Path": "httpd-foreground",
        "Args": [],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 891,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2021-01-21T01:37:22.5737225Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:683a7aad17d3baed344799b397c55a9ccbc3ddabf0d077862739585ee76d4cb3",
        "ResolvConfPath": "/var/lib/docker/containers/d31a31a707ae8738daae7e3bc6578ea9b52e516aeba2d5d37a9000a6d5768c53/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/d31a31a707ae8738daae7e3bc6578ea9b52e516aeba2d5d37a9000a6d5768c53/hostname",
        "HostsPath": "/var/lib/docker/containers/d31a31a707ae8738daae7e3bc6578ea9b52e516aeba2d5d37a9000a6d5768c53/hosts",
        "LogPath": "/var/lib/docker/containers/d31a31a707ae8738daae7e3bc6578ea9b52e516aeba2d5d37a9000a6d5768c53/d31a31a707ae8738daae7e3bc6578ea9b52e516aeba2d5d37a9000a6d5768c53-json.log",
        "Name": "/httpd",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {
                "80/tcp": [
                    {
                        "HostIp": "",
                        "HostPort": "8080"
                    }
                ]
            },
            
            (長いので中略）
            
        "Config": {
            "Hostname": "d31a31a707ae",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": true,
            "AttachStderr": true,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/apache2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "HTTPD_PREFIX=/usr/local/apache2",
                "HTTPD_VERSION=2.4.46",
                "HTTPD_SHA256=740eddf6e1c641992b22359cabc66e6325868c3c5e2e3f98faf349b61ecf41ea",
                "HTTPD_PATCHES="
            ],
            "Cmd": [
                "httpd-foreground"
            ],
            "Image": "httpd",
            "Volumes": null,
            "WorkingDir": "/usr/local/apache2",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {},
            "StopSignal": "SIGWINCH"
        },
    }
]
```

### Docker コマンド（events）
Docker内部で発生したいろいろなイベントが表示できるようだ。  

- $docker events

これを実行した状態で、あるコンテナを削除すると  

```
2021-01-22T11:03:17.486167200+09:00 container destroy 899561fad6098c31e262627a10924d2c73d3a08317a4a4c2f51ed7d29a5d34d0 (image=hoge, name=mystifying_brahmagupta)
```
このようなメッセージが表示された。  
その他にもpullやrunを実行したタイミングなど、イベントが生じた場合には  
情報をリアルタイムで表示してくれるようである。  

### Docker コマンド（history）
Dockerイメージのレイヤー情報を表示してくれる。  

- $docker history ubuntu

これを実行すると、下記のような表示がされた。  

```
IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
f643c72bc252   8 weeks ago   /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
<missing>      8 weeks ago   /bin/sh -c mkdir -p /run/systemd && echo 'do…   7B
<missing>      8 weeks ago   /bin/sh -c [ -z "$(apt-get indextargets)" ]     0B
<missing>      8 weeks ago   /bin/sh -c set -xe   && echo '#!/bin/sh' > /…   811B
<missing>      8 weeks ago   /bin/sh -c #(nop) ADD file:4f15c4475fbafb3fe…   72.9MB
```

６層から出来ているイメージであることが確認できる。上の方が新しい層のようであり、自分で層を追加したら、上に追加されることが確認できる。  


以下のDockerfileでビルドしてみる。  
```
FROM ubuntu
RUN echo "hello konta" > /tmp/konta.txt
```
$docker build --rm -t test .  

```
Sending build context to Docker daemon  6.144kB
Step 1/2 : FROM ubuntu
 ---> f643c72bc252
Step 2/2 : RUN echo "hello konta" > /tmp/konta.txt
 ---> Running in a01822b4152e
Removing intermediate container a01822b4152e
 ---> c00d6ffcc62a
Successfully built c00d6ffcc62a
Successfully tagged test:latest
```

$docker history test
```
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
c00d6ffcc62a   16 seconds ago   /bin/sh -c echo "hello konta" > /tmp/konta.t…   13B
f643c72bc252   8 weeks ago      /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
<missing>      8 weeks ago      /bin/sh -c mkdir -p /run/systemd && echo 'do…   7B
<missing>      8 weeks ago      /bin/sh -c [ -z "$(apt-get indextargets)" ]     0B
<missing>      8 weeks ago      /bin/sh -c set -xe   && echo '#!/bin/sh' > /…   811B
<missing>      8 weeks ago      /bin/sh -c #(nop) ADD file:4f15c4475fbafb3fe…   72.9MB
```
上記の通り、一番上に自分が追加した層が追加されていることが確認できる。  
<missing>となってIMAGEIDが表示されないのはDockerの仕様のようである。  

### Docker コマンド（コンテナの削除とイメージの削除）
- $docker rm [コンテナID]  

これでコンテナを削除できる。  

```
$docker ps -a
CONTAINER ID   IMAGE                 COMMAND                   CREATED        STATUS                     PORTS                               NAMES
2482e87ac13d   httpd                 "httpd-foreground"        5 days ago     Exited (0) 5 days ago                                          elegant_dhawan
d31a31a707ae   httpd                 "httpd-foreground"        5 days ago     Exited (137) 4 days ago                                        httpd
07bed7ba48fe   jwilder/nginx-proxy   "/app/docker-entrypo…"    6 days ago     Exited (2) 6 days ago                                          rccpf_proxy_1
```

上記コンテナ一覧から  
2482e87ac13dこのコンテナを削除してみる。

```
$docker rm 2482e87ac13d
2482e87ac13d
```

```
$docker ps -a
CONTAINER ID   IMAGE                 COMMAND                   CREATED        STATUS                     PORTS                               NAMES
d31a31a707ae   httpd                 "httpd-foreground"        5 days ago     Exited (137) 4 days ago                                        httpd
07bed7ba48fe   jwilder/nginx-proxy   "/app/docker-entrypo…"    6 days ago     Exited (2) 6 days ago                                          rccpf_proxy_1
```

削除されたことが確認できた。  
起動中のコンテナは削除できないが、-f オプションを付けると起動中でも強制的に削除されることについても確認できた。  



- $docker rmi [イメージID]  

これでイメージを削除できる。

```
$docker images
REPOSITORY            TAG          IMAGE ID       CREATED         SIZE
envtest               latest       804910d40577   4 days ago      72.9MB
labeltest             latest       e26e53a9bcc3   4 days ago      72.9MB
test                  latest       c00d6ffcc62a   4 days ago      72.9MB
centoshttpd           latest       a559de6ce936   4 days ago      250MB
hoge                  latest       f8e58afd17c2   4 days ago      220MB
hello                 latest       cf6b541b21fc   5 days ago      5.61MB
```

上記コンテナ一覧から  
804910d40577このイメージを削除してみる。  

```
$docker rmi 804910d40577
Untagged: envtest:latest
Deleted: sha256:804910d4057780e1175623baf7532ff290d574852bfe53b945f55d7a09bafc83
```

```
$docker images
REPOSITORY            TAG          IMAGE ID       CREATED         SIZE
labeltest             latest       e26e53a9bcc3   4 days ago      72.9MB
test                  latest       c00d6ffcc62a   4 days ago      72.9MB
centoshttpd           latest       a559de6ce936   4 days ago      250MB
hoge                  latest       f8e58afd17c2   5 days ago      220MB
hello                 latest       cf6b541b21fc   5 days ago      5.61MB
```

削除されたことが確認できた。  

### -rmオプション指定 （おまけ）
何度もrunを繰り返すと docker ps -a で確認できる停止中のコンテナが量産されてしまう。これを都度 docker rm で消去するのは手間である。これを回避するために、停止した段階でrmも一緒にやってくれるのがこのオプションです。