コンテナ型仮想化技術 Study01 / Docker基礎

#はじめに
コンテナ型仮想化技術(主にDocker, Kubernetes辺り)を中心としたお勉強のログです。主に以下の書籍を軸にしながら、色々手を動かしたり調査した時の情報を整理していきます。
[Docker/Kubernetes 実践コンテナ開発入門](https://www.amazon.co.jp/Docker-Kubernetes-%E5%AE%9F%E8%B7%B5%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E9%96%8B%E7%99%BA%E5%85%A5%E9%96%80-%E5%B1%B1%E7%94%B0-%E6%98%8E%E6%86%B2/dp/4297100339/ref=sr_1_2?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=Docker&qid=1572505388&sr=8-2)
[15Stepで習得 Dockerから入るKubernetes コンテナ開発からK8s本番運用まで](https://www.amazon.co.jp/15Step%E3%81%A7%E7%BF%92%E5%BE%97-Docker%E3%81%8B%E3%82%89%E5%85%A5%E3%82%8BKubernetes-%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E9%96%8B%E7%99%BA%E3%81%8B%E3%82%89K8s%E6%9C%AC%E7%95%AA%E9%81%8B%E7%94%A8%E3%81%BE%E3%81%A7-StepUp-%E9%81%B8%E6%9B%B8/dp/4865941614/ref=sr_1_8?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=Docker&qid=1572505388&sr=8-8)

はじめはDockerについて。

##関連記事
[コンテナ型仮想化技術 Study01 / Docker基礎](https://qiita.com/tomotagwork/items/34b4505b90b71dcfa8ca)
[コンテナ型仮想化技術 Study02 / Docker レジストリ](https://qiita.com/tomotagwork/items/bb1df5232dec5ea7adb7)
[コンテナ型仮想化技術 Study03 / Docker Compose](https://qiita.com/tomotagwork/items/af802c3e25f594cb4a8a)
[コンテナ型仮想化技術 Study04 / Minikube & kubectl簡易操作](https://qiita.com/tomotagwork/items/79527a132d343ab8d534)
[コンテナ型仮想化技術 Study05 / Pod操作](https://qiita.com/tomotagwork/items/7b16bde0529c052a9540)
[コンテナ型仮想化技術 Study06 / ReplicaSet, Deployment, Service](https://qiita.com/tomotagwork/items/2eb36f84c7f396f51e56)
[コンテナ型仮想化技術 Study06' / Kubernetesネットワーク問題判別](https://qiita.com/tomotagwork/items/f1145f3f5656a5cd51c3)
[コンテナ型仮想化技術 Study07 / ストレージ](https://qiita.com/tomotagwork/items/eacf8629bd4889f80672)
[コンテナ型仮想化技術 Study08 / Statefulset, Ingress](https://qiita.com/tomotagwork/items/3a5589031854c702fcec)
[コンテナ型仮想化技術 Study09 / Helm](https://qiita.com/tomotagwork/items/f46a26e3437c716881dc)



#参考情報

[Docker Documentation](https://docs.docker.com/)
[Docker Hub](https://hub.docker.com/)

[Linuxコンテナ(LXC)の基礎をまとめ直す](https://www.school.ctc-g.co.jp/columns/nakai/nakai41.html)
[なぜDockerではホストOSと違うOSベースのコンテナイメージが動くのか](https://qiita.com/kirikunix/items/33414240b4cacee362da)
[Docker ライフサイクル 概要図 ＆ 環境複製手順](https://qiita.com/TakahiRoyte/items/39dcf18da0ef2d1fe8b0)
[Dockerイメージの理解とコンテナのライフサイクル ](https://www.slideshare.net/zembutsu/docker-images-containers-and-lifecycle)

[Docker・Kubernetes周辺の動向を整理してみた件](https://qiita.com/mamomamo/items/e4e9e44d9f77cd72b70a)
[コンテナランタイムの動向を整理してみた件](https://qiita.com/mamomamo/items/ed5db2ab1555078f8a24)
[コンテナの標準仕様について調査してみた件](https://qiita.com/mamomamo/items/448a8edf6d4ccfc22bbd)
[dockerと称するもの](https://eng-blog.iij.ad.jp/archives/1478)
[今話題のいろいろなコンテナランタイムを比較してみた](https://medium.com/nttlabs/container-runtime-d3e25189f67a)
[Kubernetesのエコシステム ー コンテナランタイム編](https://www.kaitoy.xyz/2019/06/15/k8s-ecosystem-container-runtimes/)

[Dockerfileを既存のDockerイメージから生成する方法](https://qiita.com/iaoiui/items/bd88509dc513f7a1a8f4)
[Dockerfileを楽に作りたい（imageから自動生成したい）](https://qiita.com/RyodoTanaka/items/6f8da0749cbd0afa0ddd)

[IT業界で働く者の基礎知識となるクラウドネイティブ とは？](https://qiita.com/MahoTakara/items/7c6c89cbddfd4a8f7b44)

#環境
Dockerインストール
[oneWEX導入メモ / Ubuntu編](https://qiita.com/tomotagwork/items/bdd48adf45140b584678)

※上で作ったUbuntu環境を使うことにする

```xxx:DockerCE
vagrant@ubuntu-xenial:~$ sudo docker version
Client:
 Version:           18.09.6
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        481bc77
 Built:             Sat May  4 02:35:27 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.6
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.8
  Git commit:       481bc77
  Built:            Sat May  4 01:59:36 2019
  OS/Arch:          linux/amd64
  Experimental:     false
```


#用語の整理

最初、この辺の用語が混乱しやすい...

**Dockerコンテナ**: Dockerイメージを基にして作成される仮想環境のインスタンス。
**Dockerイメージ**: Dockerコンテナを作成するためのテンプレート。ハッシュ値によるIMAGE IDが生成されて管理されるが、一般的にはリポジトリ名+タグ名(≒バージョン)で識別される。
**Dockerリポジトリ**: 同じ内容の異なるDockerイメージ(異なるバージョン)の集合。
**Dockerレジストリ**: Dockerリポジトリを集約して管理し、ホスティング機能を提供するサービス(Docker Hub, AWS ECR など)。

補足:
"リポジトリ名"と"イメージ名"はほぼ同義的に使われていることも多い(例: example/echo)。

イメージのBuild時に、docker image build コマンドの--tagオプションで、```name:tag```という指定ができ、ここで指定したnameがリポジトリ名として表示される。
参考: [docker build](https://docs.docker.com/engine/reference/commandline/build/)


```xxx:例_Dockerイメージのリスト
vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
example/echo        0.1.0               b128bbc227f5        3 hours ago         750MB
example/echo        latest              b128bbc227f5        3 hours ago         750MB
<none>              <none>              1bab7e1d9051        5 days ago          750MB
hello-world         latest              fce289e99eb9        9 months ago        1.84kB
ibm-wex-ee          12.0.2.417          68b237b78230        11 months ago       5.17GB
golang              1.9                 ef89ef5c42a9        14 months ago       750MB
gihyodocker/echo    latest              3dbbae6eb30d        21 months ago       733MB
```

```xxx:例_Dockerコンテナのリスト
vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container ls -a
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS                    PORTS               NAMES
e90108256ea9        example/echo:latest   "go run /echo/main.go"   2 hours ago         Up 2 hours                                    test-echo
ed7b9fdea5f0        1bab7e1d9051          "go run /echo/main.go"   19 hours ago        Exited (2) 19 hours ago                       keen_khayyam
697fbfadd1bd        1bab7e1d9051          "go run /echo/main.go"   5 days ago          Exited (2) 19 hours ago                       frosty_bose
09c96d2fe2b8        gihyodocker/echo      "go run /echo/main.go"   5 days ago          Exited (2) 5 days ago                         romantic_neumann
8484e0182dd6        hello-world           "/hello"                 2 months ago        Exited (0) 5 days ago                         elastic_ramanujan
8fcc80ffdeee        hello-world           "/hello"                 3 months ago        Exited (0) 3 months ago                       recursing_hoover
```

通常、コンテナを実行する時には、docker container runというコマンドが使われますが、この時引数として指定するのは、コンテナのIDではなく**Dockerイメージ**のIDもしくはイメージ名(リポジトリ名)+タグ(バージョン)です。
例: ```docker container run example/echo:latest```
docker container runコマンドを実行すると、指定したイメージから**コンテナを作成**し、その後**開始**する、という処理が行われます(内部的にcreate + start が行われます)。

参考: [docker run](https://docs.docker.com/engine/reference/commandline/run/)

>The docker run command first creates a writeable container layer over the specified image, and then starts it using the specified command. That is, docker run is equivalent to the API /containers/create then /containers/(id)/start. A stopped container can be restarted with all its previous changes intact using docker start. See docker ps -a to view a list of all containers.

この辺りが従来のインフラ管理の考え方からすると分かりにくいのですが、動的に環境を増やしたり減らしたりというような、いわゆるクラウドちっくな利用を想定する場合、環境の作成と起動というのはセットで、不要になったら停止して破棄する、というのがベースの考え方のようです。
最初に環境を作って(create)、それを開始(start)/停止(stop)で運用を回す、という感じではないんでしょうね(こういう思考回路だと最初は違和感半端ない)。
これは、「イミュータブル・インフラストラクチャー(Immutable infrastructure)」という概念に基づくもので、クラウド環境においてはかなり重要な考え方になっているようです。


Dockerイメージを識別するのに、"example/echo:0.1.0"といったように、リポジトリ名(イメージ名) + タグ(バージョン)がよくつかわれますが、正確には、もう一つレジストリ名が修飾子として付きます。
"example/echo:0.1.0"はレジストリ名が省略された形で、デフォルトだとDockerHubが参照されることになるようです。
DockerHub以外のレジストリ(GitLab.comやローカルのレジストリサーバーなど)を使用する場合は、先頭にレジストリ名を付けて、"myregistryhost:5000/example/echo:0.1.0" といった形式で識別することになります。

参考: [docker tag](https://docs.docker.com/engine/reference/commandline/tag/)



# docker command help

```
vagrant@ubuntu-xenial:~$ docker --help

Usage:  docker [OPTIONS] COMMAND

A self-sufficient runtime for containers

Options:
      --config string      Location of client config files (default "/home/vagrant/.docker")
  -D, --debug              Enable debug mode
  -H, --host list          Daemon socket(s) to connect to
  -l, --log-level string   Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
      --tls                Use TLS; implied by --tlsverify
      --tlscacert string   Trust certs signed only by this CA (default "/home/vagrant/.docker/ca.pem")
      --tlscert string     Path to TLS certificate file (default "/home/vagrant/.docker/cert.pem")
      --tlskey string      Path to TLS key file (default "/home/vagrant/.docker/key.pem")
      --tlsverify          Use TLS and verify the remote
  -v, --version            Print version information and quit

Management Commands:
  builder     Manage builds
  config      Manage Docker configs
  container   Manage containers
  engine      Manage the docker engine
  image       Manage images
  network     Manage networks
  node        Manage Swarm nodes
  plugin      Manage plugins
  secret      Manage Docker secrets
  service     Manage services
  stack       Manage Docker stacks
  swarm       Manage Swarm
  system      Manage Docker
  trust       Manage trust on Docker images
  volume      Manage volumes

Commands:
  attach      Attach local standard input, output, and error streams to a running container
  build       Build an image from a Dockerfile
  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
  deploy      Deploy a new stack or update an existing stack
  diff        Inspect changes to files or directories on a container's filesystem
  events      Get real time events from the server
  exec        Run a command in a running container
  export      Export a container's filesystem as a tar archive
  history     Show the history of an image
  images      List images
  import      Import the contents from a tarball to create a filesystem image
  info        Display system-wide information
  inspect     Return low-level information on Docker objects
  kill        Kill one or more running containers
  load        Load an image from a tar archive or STDIN
  login       Log in to a Docker registry
  logout      Log out from a Docker registry
  logs        Fetch the logs of a container
  pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  ps          List containers
  pull        Pull an image or a repository from a registry
  push        Push an image or a repository to a registry
  rename      Rename a container
  restart     Restart one or more containers
  rm          Remove one or more containers
  rmi         Remove one or more images
  run         Run a command in a new container
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  search      Search the Docker Hub for images
  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
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
  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
  version     Show the Docker version information
  wait        Block until one or more containers stop, then print their exit codes

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

## docker image

```
vagrant@ubuntu-xenial:~$ 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 container 

```
vagrant@ubuntu-xenial:~$ 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.
```


#操作例

## 単純なコンテナの作成/実行

イメージ取得 / docker image pull

```xxx:途中経過
vagrant@ubuntu-xenial:~$ sudo docker image pull gihyodocker/echo:latest
latest: Pulling from gihyodocker/echo
723254a2c089: Extracting [=========>                                         ]  8.716MB/45.12MB
abe15a44e12f: Download complete
409a28e3cc3d: Download complete
503166935590: Downloading [=====================================>             ]  37.18MB/50.02MB
abe52c89597f: Downloading [===========>                                       ]  13.43MB/57.5MB
ce145c5cf4da: Waiting
96e333289084: Waiting
39cd5f38ffb8: Waiting
22860d04f4f1: Pulling fs layer
7528760e0a03: Waiting
```

```xxx:完了
vagrant@ubuntu-xenial:~$ sudo docker image pull gihyodocker/echo:latest
latest: Pulling from gihyodocker/echo
723254a2c089: Pull complete
abe15a44e12f: Pull complete
409a28e3cc3d: Pull complete
503166935590: Pull complete
abe52c89597f: Pull complete
ce145c5cf4da: Pull complete
96e333289084: Pull complete
39cd5f38ffb8: Pull complete
22860d04f4f1: Pull complete
7528760e0a03: Pull complete
Digest: sha256:4520b6a66d2659dea2f8be5245eafd5434c954485c6c1ac882c56927fe4cec84
Status: Downloaded newer image for gihyodocker/echo:latest
```

コンテナ作成,実行 / docker container run

```
vagrant@ubuntu-xenial:~$ sudo docker container run -t -p 9000:8080 gihyodocker/echo
2019/09/26 08:14:33 start server
```

別な端末からcurlでコンテナ上のサービスにアクセスしてみる。

```
vagrant@ubuntu-xenial:~$ curl http://localhost:9000/
Hello Docker!!
```

コンテナ状況確認 / docker container ls

```
vagrant@ubuntu-xenial:~$ sudo docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
09c96d2fe2b8        gihyodocker/echo    "go run /echo/main.go"   2 minutes ago       Up 2 minutes        0.0.0.0:9000->8080/tcp   romantic_neumann
```

```
vagrant@ubuntu-xenial:~$ sudo docker container ls -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                    PORTS                    NAMES
09c96d2fe2b8        gihyodocker/echo    "go run /echo/main.go"   5 minutes ago       Up 5 minutes              0.0.0.0:9000->8080/tcp   romantic_neumann
8484e0182dd6        hello-world         "/hello"                 2 months ago        Exited (0) 2 months ago                            elastic_ramanujan
8fcc80ffdeee        hello-world         "/hello"                 3 months ago        Exited (0) 3 months ago                            recursing_hoover
```

コンテナ停止 / docker container stop

```
vagrant@ubuntu-xenial:~$ sudo docker container stop 09c96d2fe2b8
09c96d2fe2b8
```

コンテナ状況確認

```
vagrant@ubuntu-xenial:~$ sudo docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

vagrant@ubuntu-xenial:~$ sudo docker container ls -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
09c96d2fe2b8        gihyodocker/echo    "go run /echo/main.go"   13 minutes ago      Exited (2) 29 seconds ago                       romantic_neumann
8484e0182dd6        hello-world         "/hello"                 2 months ago        Exited (0) 2 minutes ago                        elastic_ramanujan
8fcc80ffdeee        hello-world         "/hello"                 3 months ago        Exited (0) 3 months ago                         recursing_hoover
```

## Dockerイメージ作成

GO言語による簡単なWebサーバーが動くDockerイメージを作成する。
(GO言語環境が含まれているイメージをDocker Hubから取得して、それをベースにして新たなイメージを作成する)

Go言語アプリのソース

```go:main.go
package main

import (
        "fmt"
        "log"
        "net/http"
)

func main(){
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
                log.Println("received request")
                fmt.Fprintf(w, "Hello Docker!")
        })

        log.Println("start server")
        server := &http.Server{Addr: ":8080"}
        if err := server.ListenAndServe(); err != nil {
                log.Println(err)
        }
}
```

Dockerfile

```Dockerfile
FROM golang:1.9

RUN mkdir /echo
COPY main.go /echo

CMD ["go", "run", "/echo/main.go"]
```

基本、DockerfileにはDokcerイメージ作成時に実行される操作を記載しておく。
ただし、CMDに記載された内容は、このイメージからコンテナーが起動される時に実行される！(ENTRYPOINTも同様)
参考: [[docker] CMD とENTRYPOINT の違いを試してみた](https://qiita.com/hihihiroro/items/d7ceaadc9340a4dbeb8f#%E3%81%BE%E3%81%A8%E3%82%81)


Dockerイメージ作成 / docker image build

```
vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker image build -t example/echo:latest .
Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM golang:1.9
1.9: Pulling from library/golang
55cbf04beb70: Pull complete
1607093a898c: Pull complete
9a8ea045c926: Pull complete
d4eee24d4dac: Pull complete
9c35c9787a2f: Pull complete
8b376bbb244f: Pull complete
0d4eafcc732a: Pull complete
186b06a99029: Pull complete
Digest: sha256:8b5968585131604a92af02f5690713efadf029cc8dad53f79280b87a80eb1354
Status: Downloaded newer image for golang:1.9
 ---> ef89ef5c42a9
Step 2/4 : RUN mkdir /echo
 ---> Running in d250ae9c747d
Removing intermediate container d250ae9c747d
 ---> 3a640bd707fd
Step 3/4 : COPY main.go /echo
 ---> 573acfbcaf8d
Step 4/4 : CMD ["go", "run", "/echo/main.go"]
 ---> Running in 3998edcee3ce
Removing intermediate container 3998edcee3ce
 ---> 1bab7e1d9051
Successfully built 1bab7e1d9051
Successfully tagged example/echo:latest

vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
example/echo        latest              1bab7e1d9051        2 minutes ago       750MB
hello-world         latest              fce289e99eb9        8 months ago        1.84kB
ibm-wex-ee          12.0.2.417          68b237b78230        11 months ago       5.17GB
golang              1.9                 ef89ef5c42a9        14 months ago       750MB
gihyodocker/echo    latest              3dbbae6eb30d        21 months ago       733MB
```

Dockerコンテナの作成,実行 / docker container run

```xxx:実行
vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container run example/echo
2019/09/26 09:10:51 start server
```

```xxx:状況確認
vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
f509be8d7bb3        example/echo        "go run /echo/main.go"   36 seconds ago      Up 35 seconds                           musing_noyce
```

```xxx:停止
vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container stop  f509be8d7bb3
f509be8d7bb3
```

コンテナ作成 & バックグラウンドでの起動 / docker container run -d

```
vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container run -d example/echo
697fbfadd1bdb5669cbcf778d2759505a5a40a04374cb4ec2c8fe3749c312493

vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container ls -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                         PORTS               NAMES
697fbfadd1bd        example/echo        "go run /echo/main.go"   9 seconds ago       Up 8 seconds                                       frosty_bose
f509be8d7bb3        example/echo        "go run /echo/main.go"   4 minutes ago       Exited (2) 2 minutes ago                           musing_noyce
09c96d2fe2b8        gihyodocker/echo    "go run /echo/main.go"   About an hour ago   Exited (2) About an hour ago                       romantic_neumann
8484e0182dd6        hello-world         "/hello"                 2 months ago        Exited (0) About an hour ago                       elastic_ramanujan
8fcc80ffdeee        hello-world         "/hello"                 3 months ago        Exited (0) 3 months ago                            recursing_hoover
```

※docker container run は、イメージからコンテナを作成して実行するので、コンテナがどんどん増えていく！

前のコンテナ削除 / docker container rm

```
vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container rm f509be8d7bb3
f509be8d7bb3
```

docker container start/stopを使うのがいいのかと思ったのだが、docker container startだとバックグラウンドで実行するオプションが無い???!!!

```
vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container start --help

Usage:  docker container start [OPTIONS] CONTAINER [CONTAINER...]

Start one or more stopped containers

Options:
  -a, --attach               Attach STDOUT/STDERR and forward signals
      --detach-keys string   Override the key sequence for detaching a container
  -i, --interactive          Attach container's STDIN
```

...と思ったら、勝手にバックグラウンドでの起動になったっぽい。

```
vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container start 697fbfadd1bd
697fbfadd1bd

vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container ls -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                         PORTS               NAMES
697fbfadd1bd        example/echo        "go run /echo/main.go"   7 minutes ago       Up 16 seconds                                      frosty_bose
09c96d2fe2b8        gihyodocker/echo    "go run /echo/main.go"   About an hour ago   Exited (2) About an hour ago                       romantic_neumann
8484e0182dd6        hello-world         "/hello"                 2 months ago        Exited (0) About an hour ago                       elastic_ramanujan
8fcc80ffdeee        hello-world         "/hello"                 3 months ago        Exited (0) 3 months ago                            recursing_hoover
```

## ポートフォワード

作成したDockerコンテナでは、8080ポートをListenするhttpサーバー(Go言語での実装)が起動するが、そのままだと外部からアクセスできない。そのため、コンテナ上でListenしているポートとホスト側ポートをマッピングする必要がある。

ホスト側ポート:9000 とコンテナポート:8080を紐づけてみる

```
vagrant@ubuntu-xenial:~$ sudo docker container run -d -p 9000:8080 example/echo:latest
ed7b9fdea5f0956fccea31f3af98c798582191dad7aa5b7dc851fe2463e11570

vagrant@ubuntu-xenial:~$ sudo docker container ls
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                    NAMES
ed7b9fdea5f0        example/echo:latest   "go run /echo/main.go"   24 seconds ago      Up 23 seconds       0.0.0.0:9000->8080/tcp   keen_khayyam

vagrant@ubuntu-xenial:~$ netstat -an | grep 9000
tcp6       0      0 :::9000                 :::*                    LISTEN
```

Curlでアクセスしてみる。

```
vagrant@ubuntu-xenial:~$ curl http://localhost:9000
Hello Docker!
```

アクセスできるようになった。

## Dockerイメージを再度Build

main.goを編集後、再Build

```
vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker image build -t example/echo:latest .
Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM golang:1.9
 ---> ef89ef5c42a9
Step 2/4 : RUN mkdir /echo
 ---> Using cache
 ---> 3a640bd707fd
Step 3/4 : COPY main.go /echo
 ---> 24ed88e37920
Step 4/4 : CMD ["go", "run", "/echo/main.go"]
 ---> Running in 730f96c78672
Removing intermediate container 730f96c78672
 ---> b128bbc227f5
Successfully built b128bbc227f5
Successfully tagged example/echo:latest

vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
example/echo        latest              b128bbc227f5        5 seconds ago       750MB
<none>              <none>              1bab7e1d9051        5 days ago          750MB
hello-world         latest              fce289e99eb9        9 months ago        1.84kB
ibm-wex-ee          12.0.2.417          68b237b78230        11 months ago       5.17GB
golang              1.9                 ef89ef5c42a9        14 months ago       750MB
gihyodocker/echo    latest              3dbbae6eb30d        21 months ago       733MB
```

latestで新しく作ったイメージに別のタグ(バージョン)を付けて分かりやすくする。

```
vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker image tag example/echo:latest example/echo:0.1.0

vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
example/echo        0.1.0               b128bbc227f5        8 minutes ago       750MB
example/echo        latest              b128bbc227f5        8 minutes ago       750MB
<none>              <none>              1bab7e1d9051        5 days ago          750MB
hello-world         latest              fce289e99eb9        9 months ago        1.84kB
ibm-wex-ee          12.0.2.417          68b237b78230        11 months ago       5.17GB
golang              1.9                 ef89ef5c42a9        14 months ago       750MB
gihyodocker/echo    latest              3dbbae6eb30d        21 months ago       733MB
```

##名前付きコンテナ作成

※同名のコンテナをrunする場合には既存のものは削除しないといけないので、本番環境ではあまり使われないらしい

```xxx:作成_実行
vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container run -t -d --name test-echo example/echo:latest
e90108256ea94a2e36d55daf043798dbc1defce69ada25317cbc7902736b22af

vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container ls
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS               NAMES
e90108256ea9        example/echo:latest   "go run /echo/main.go"   10 seconds ago      Up 9 seconds                            test-echo
```

```xxx:停止
vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container stop test-echo
test-echo

vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container ls -a
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS                      PORTS               NAMES
e90108256ea9        example/echo:latest   "go run /echo/main.go"   3 minutes ago       Exited (2) 15 seconds ago                       test-echo
ed7b9fdea5f0        1bab7e1d9051          "go run /echo/main.go"   16 hours ago        Exited (2) 16 hours ago                         keen_khayyam
697fbfadd1bd        1bab7e1d9051          "go run /echo/main.go"   5 days ago          Exited (2) 16 hours ago                         frosty_bose
09c96d2fe2b8        gihyodocker/echo      "go run /echo/main.go"   5 days ago          Exited (2) 5 days ago                           romantic_neumann
8484e0182dd6        hello-world           "/hello"                 2 months ago        Exited (0) 5 days ago                           elastic_ramanujan
8fcc80ffdeee        hello-world           "/hello"                 3 months ago        Exited (0) 3 months ago                         recursing_hoover
```

```xxx:実行
vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container start test-echo
test-echo

vagrant@ubuntu-xenial:~/docker_test/test01$ sudo docker container ls
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS               NAMES
e90108256ea9        example/echo:latest   "go run /echo/main.go"   4 minutes ago       Up 29 seconds                           test-echo
```

##コンテナ内でのコマンド実行
docker container execコマンドで、仮想環境であるコンテナ内でコマンドを実行することができます。
参考: [docker exec](https://docs.docker.com/engine/reference/commandline/exec/)

```
vagrant@ubuntu-xenial:~$ sudo docker container ls
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS               NAMES
e90108256ea9        example/echo:latest   "go run /echo/main.go"   4 hours ago         Up 4 hours                              test-echo

vagrant@ubuntu-xenial:~$ sudo docker container exec test-echo pwd
/go
```

標準入力をオープンにする-iオプションと、仮想端末を割り当てる-tオプションをつけて、shを実行すると、sshで仮想環境にログインしたようなイメージで操作できます。

```
vagrant@ubuntu-xenial:~$ sudo docker container exec -it test-echo sh
# pwd
/go
# whoami
root
# hostname
e90108256ea9
# ls /
bin  boot  dev  echo  etc  go  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
```

## コンテナ稼働状況確認

```
vagrant@ubuntu-xenial:~$ sudo docker container stats
CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
e90108256ea9        test-echo           0.00%               5.355MiB / 17.64GiB   0.03%               5.54kB / 0B         1.14MB / 8.19kB     23
ed7b9fdea5f0        keen_khayyam        0.00%               6.902MiB / 17.64GiB   0.04%               2.77kB / 0B         8.19kB / 8.19kB     15
```

#ストレージ管理

イメージやらコンテナはホストOS上のどこに保持されるのか？
参考: 
[Manage data in Docker](https://docs.docker.com/storage/)
[About storage drivers](https://docs.docker.com/storage/storagedriver/)

物理的には、/var/lib/docker/以下が消費されるようです。
(この下のimage, containersディレクトリ辺りですね)

```
vagrant@ubuntu-xenial:/var/lib/docker$ pwd
/var/lib/docker
vagrant@ubuntu-xenial:/var/lib/docker$ sudo ls -la
合計 72
drwx--x--x  14 root root  4096 10月  2 01:21 .
drwxr-xr-x  74 root root  4096  7月 15 10:12 ..
drwx------   2 root root  4096  6月 15 10:40 builder
drwx------   4 root root  4096  6月 15 10:40 buildkit
drwx------   8 root root  4096 10月  2 02:44 containers
drwx------   3 root root  4096  6月 15 10:40 image
drwxr-x---   3 root root  4096  6月 15 10:40 network
drwx------ 125 root root 20480 10月  2 02:44 overlay2
drwx------   4 root root  4096  6月 15 10:40 plugins
drwx------   2 root root  4096 10月  2 01:21 runtimes
drwx------   2 root root  4096  6月 15 10:40 swarm
drwx------   2 root root  4096 10月  2 02:22 tmp
drwx------   2 root root  4096  6月 15 10:40 trust
drwx------   3 root root  4096  6月 17 01:14 volumes
```

以下のコマンドで、イメージ、コンテナごとに消費されるディスクのサイズを確認することができます。

```xxx:イメージのサイズ
vagrant@ubuntu-xenial:/var/lib/docker$ sudo docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
example/echo        0.1.0               b128bbc227f5        6 hours ago         750MB
example/echo        latest              b128bbc227f5        6 hours ago         750MB
<none>              <none>              1bab7e1d9051        5 days ago          750MB
hello-world         latest              fce289e99eb9        9 months ago        1.84kB
ibm-wex-ee          12.0.2.417          68b237b78230        11 months ago       5.17GB
golang              1.9                 ef89ef5c42a9        14 months ago       750MB
gihyodocker/echo    latest              3dbbae6eb30d        21 months ago       733MB
```

```xxx:コンテナのサイズ
vagrant@ubuntu-xenial:/var/lib/docker$ sudo docker container ps -a  -s
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS                    PORTS               NAMES               SIZE
e90108256ea9        example/echo:latest   "go run /echo/main.go"   5 hours ago         Up 5 hours                                    test-echo           8.4MB (virtual 758MB)
ed7b9fdea5f0        1bab7e1d9051          "go run /echo/main.go"   21 hours ago        Exited (2) 21 hours ago                       keen_khayyam        4.2MB (virtual 754MB)
697fbfadd1bd        1bab7e1d9051          "go run /echo/main.go"   5 days ago          Exited (2) 21 hours ago                       frosty_bose         12.6MB (virtual 762MB)
09c96d2fe2b8        gihyodocker/echo      "go run /echo/main.go"   5 days ago          Exited (2) 5 days ago                         romantic_neumann    4.2MB (virtual 738MB)
8484e0182dd6        hello-world           "/hello"                 2 months ago        Exited (0) 5 days ago                         elastic_ramanujan   0B (virtual 1.84kB)
8fcc80ffdeee        hello-world           "/hello"                 3 months ago        Exited (0) 3 months ago                       recursing_hoover    0B (virtual 1.84kB)
```

Dockerイメージを作成すると、イメージレイヤと呼ばれるReadOnlyのデータエリアが確保されます(ミドルウェアやアプリ稼働に必要なモジュール等を含むファイルシステムなど)。
このDockerイメージを基にコンテナが作成されると、イメージレイヤに加えてコンテナレイヤと呼ばれるRead/Write可能なエリアが追加されます。
イメージレイヤは同一Dockerイメージから作成された複数コンテナで共有され、コンテナレイヤは各コンテナごとに作成されるようです。
上の```docker container ps -s```コマンドのSIZEの欄に表示されるのは、各コンテナのコンテナレイヤ(R/W)のみのサイズで、カッコ内のvirtualで示されるのはコンテナレイヤ(R/W)+イメージレイヤ(R/O)のサイズのようです。
(virtualで示されるサイズには、複数コンテナで共有している部分も含むため、これを全部足してしまうと、実際のサイズより大きくなってしまいます。)

# コンテナの一時的な利用

コンテナ間の通信の確認や、ホストOSからは操作できないことなどがある場合、テンポラリーにテスト用のコンテナ立ち上げて利用するということがしばしばあります。そういう時によく利用されるのが、BusyBoxやAlipne Linuxと呼ばれる軽量なLinuxイメージです。

ubuntuやmysqlのイメージと比較すると、busyboxやalpineのイメージのサイズが格段に小さいのが分かります。

```
vagrant@nfsserver:~$ sudo docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
busybox             latest              b534869c81f0        8 days ago          1.22MB
ubuntu              16.04               56bab49eef2e        2 weeks ago         123MB
mysql               5.7                 1e4405fe1ea9        2 weeks ago         437MB
alpine              latest              965ea09ff2eb        7 weeks ago         5.55MB
```

## BusyBox
組み込み系のシステムでよく利用されているLinuxディストリビューションのようです。/bin/busyboxというバイナリにユーティリティを集約してサイズを縮小化を図っているようです。
必要最低限のものしか提供されておらず、パッケージマネージャーも提供されていません。そのため、これをベースに足りないパッケージを追加して環境を作るというのはあまり向いていません。
bashは提供されておらず、代わりにash(Almquist Shell)と呼ばれる軽量なシェルが提供されています。

[BusyBox](https://busybox.net/)
BusyBoxベースのDockerイメージ=> https://hub.docker.com/_/busybox

利用イメージ

```
vagrant@nfsserver:~$ sudo docker container run -it --rm busybox sh
/ #　
```

これでbusyboxのコンテナ起動して、shで接続した状態になるので、このコンテナ内での操作が可能です。exitで抜けるとコンテナ終了して破棄されます。

-i: 標準入力をオープン
-t: 仮想端末を割り当て
--rm: 終了時にコンテナ破棄

上で起動中のコンテナに別のシェルを接続する場合

```
vagrant@nfsserver:~$ sudo docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
f374592aa2f1        busybox             "sh"                54 seconds ago      Up 53 seconds                           modest_cerf

vagrant@nfsserver:~$ sudo docker container exec -it f374592aa2f1 sh
/ #
```



## Alpine Linux
Alpine Linuxも軽量なLinuxディストリビューションの一種で、busyboxをベースに利用しやすいように機能拡張がされているようです。
特徴的なのは、apkというパッケージマネージャーが提供されている点です。Ubuntuのaptとは若干コマンドのキーワード等が異なるようですが、それほど違和感なく使えそうです。
apk update: ローカルのインデックスキャッシュの更新
apk serach: 利用可能なパッケージの検索
apk add: パッケージのインストール

[Alpine Linux](https://alpinelinux.org/)
Alpine LinuxベースのDockerイメージ=> https://hub.docker.com/_/alpine

利用イメージ

```
vagrant@nfsserver:~$ sudo docker container run -it --rm alpine ash
/ # tree -?
ash: tree: not found

/ # apk update
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/community/x86_64/APKINDEX.tar.gz
v3.10.3-77-g9739986c1e [http://dl-cdn.alpinelinux.org/alpine/v3.10/main]
v3.10.3-68-ge1e42c5d6c [http://dl-cdn.alpinelinux.org/alpine/v3.10/community]
OK: 10341 distinct packages available

/ # apk search tree
tree-1.8.0-r0
lddtree-1.26-r2
samba-client-4.10.11-r0
libnl3-cli-3.4.0-r0
geany-plugins-treebrowser-1.35-r0
freeradius-3.0.20-r1
ostree-dev-2019.1-r0
perl-xml-treepp-0.43-r1
gconf-3.2.6-r5
perl-xml-treepp-doc-0.43-r1
perl-html-tree-5.07-r0
psmisc-23.2-r1
pstree-2.39-r0
perl-html-tree-doc-5.07-r0
ostree-2019.1-r0
py-django-treebeard-4.3-r0
perl-tree-simple-doc-1.33-r0
mtools-4.0.23-r0
i3wm-save_tree-4.16.1-r2
perl-template-toolkit-2.29-r1
git-subtree-2.22.2-r0
perl-tree-dag_node-1.31-r0
pax-utils-1.2.3-r0
rspamd-1.9.4-r0
libmtp-examples-1.1.16-r0
ostree-doc-2019.1-r0
perl-tree-dag_node-doc-1.31-r0
pstree-doc-2.39-r0
perl-tree-simple-1.33-r0
git-subtree-doc-2.22.2-r0
tree-doc-1.8.0-r0

/ # apk add tree
(1/1) Installing tree (1.8.0-r0)
Executing busybox-1.30.1-r2.trigger
OK: 6 MiB in 15 packages

/ # tree -?
tree: Invalid argument -`?'.
usage: tree [-acdfghilnpqrstuvxACDFJQNSUX] [-H baseHREF] [-T title ]
        [-L level [-R]] [-P pattern] [-I pattern] [-o filename] [--version]
        [--help] [--inodes] [--device] [--noreport] [--nolinks] [--dirsfirst]
        [--charset charset] [--filelimit[=]#] [--si] [--timefmt[=]<f>]
        [--sort[=]<name>] [--matchdirs] [--ignore-case] [--fromfile] [--]
        [<directory list>]
```

※alpineのコンテナに入ってtreeコマンド実行すると、デフォルトでは提供されていないので、apkによりtreeパッケージを追加インストールしている例です。


---

---

#その他メモ

## Go言語(コンテナと関係ないけど...)

```xxx:インストール
vagrant@ubuntu-xenial:~/docker_test/test01$ go version
プログラム 'go' はまだインストールされていません。 'go' を利用するために、コンピュータの管理者に 'golang-go' をインストールすることを相談してください

vagrant@ubuntu-xenial:~/docker_test/test01$ sudo apt-get update
ヒット:1 https://download.docker.com/linux/ubuntu xenial InRelease
取得:2 http://security.ubuntu.com/ubuntu xenial-security InRelease [109 kB]
ヒット:3 http://archive.ubuntu.com/ubuntu xenial InRelease
<略>
取得:12 http://archive.ubuntu.com/ubuntu xenial-backports/universe amd64 DEP-11 Metadata [5,328 B]
1,582 kB を 13秒 で取得しました (115 kB/s)
パッケージリストを読み込んでいます... 完了

vagrant@ubuntu-xenial:~/docker_test/test01$ sudo apt-get install golang-go
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
<略>
```

```xxx:実行例
vagrant@ubuntu-xenial:~/docker_test/test01$ cat main.go
package main

import (
        "fmt"
        "log"
        "net/http"
)

func main(){
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
                log.Println("received request")
                fmt.Fprintf(w, "Hello Docker!")
        })

        log.Println("start server")
        server := &http.Server{Addr: ":8080"}
        if err := server.ListenAndServe(); err != nil {
                log.Println(err)
        }
}

vagrant@ubuntu-xenial:~/docker_test/test01$ go run main.go
2019/09/26 08:51:51 start server
```