Docker コマンドチートシート

# イントロダクション
## 1. この記事の目的
- Docker を初めて使う人に, 基本的な使い方がパッとわかるように説明する
    - ちなみに私自身も Docker 初心者なので間違えていたら指摘していただけると嬉しいです

## 2. 対象読者
- Docker の概念は他の記事などで知っているけれど, 実際にはこれから初めて使う方
- 他の記事を見たけれど, 使い方がいまいちよくわからない方
- 細かいことはいいからすぐに使いたい方

## 3. 動作環境
- Ubuntu 18.04
- Docker 18.09.2
- Nvidia Docker 2.0.3

## 4. この記事で書かないこと
- 「Docker とは」という類の説明
    - [Docker公式ページ](https://www.docker.com/resources/what-container) を参照してください
- Docker のインストール方法.
  - 以下を参照してください.
    - [Docker公式ページ](https://docs.docker.com/install/linux/docker-ce/ubuntu/)
    - GPU使う場合は, [Nvidia-Docker, Github](https://github.com/NVIDIA/nvidia-docker)

# 本編
## 1. docker の使い方の基本
- イメージからコンテナを起動（run）し, コンテナのプロセス環境下で処理をさせる.
- 覚えておきたい思想　→　1コンテナ1プロセス  
  - http://docs.docker.jp/engine/articles/dockerfile_best-practice.html
  
> ほとんどの場合、１つのコンテナの中で１つのプロセスだけ実行すべきです。アプリケーションを複数のコンテナに分離することは、水平スケールやコンテナの再利用を簡単にします。サービスとサービスに依存関係がある場合は、 コンテナのリンク を使います。

## 2. docker コマンド全体像
- 図のほうがわかりやすいと思ったので作ってみた
- 初めて使う人は, pull -> run あたりの解説を読んで, とりあえず動かしてみると理解が進むと思います

![DockerOverview.png](https://qiita-image-store.s3.amazonaws.com/0/245318/ade45403-5a8e-a727-082d-a63919d45656.png)


## 3. 解説するコマンド一覧
注意：図中に存在しないコマンドもある

- image の操作
  - images
  - search
  - pull
  - tag
  - rmi
- conteiner の操作
  - ps
  - create
  - start
  - stop
  - restart
  - run
  - attach
  - exec
  - status
  - top
  - rm
- image の保存と再構築
  - build
  - commit
  - Dockerfile

## 4. 本記事における表記ルール
- {param}
  - 必須の引数
- [param]
  - option の引数

## 5. コマンド詳細
### 5.1 image の操作
#### docker images
- ホストに存在するイメージを確認する

```bash
$ docker images

#-----------------------------------------------------
# 例
#-----------------------------------------------------
$ docker images
# 結果　->　ホストに存在するイメージの一覧が表示される
REPOSITORY          TAG                  IMAGE ID            CREATED             SIZE
ubuntu              latest               47b19964fb50        3 weeks ago         88.1MB
nvidia/cuda         9.0-cudnn7-runtime   17c50af840b7        4 weeks ago         1.21GB

```
#### docker search
- 公開されているイメージを検索する
 
```bash
$ docker search {image}

#-----------------------------------------------------
# 例
#-----------------------------------------------------
$ docker search ubuntu
# 結果　->　リポジトリで公開されているイメージの一覧が表示される
NAME                                                   DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
ubuntu                                                 Ubuntu is a Debian-based Linux operating sys…   9265                [OK]                
dorowu/ubuntu-desktop-lxde-vnc                         Docker image to provide HTML5 VNC interface …   274                                     [OK]

etc.
```

#### docker pull
- 公開されているイメージをリポジトリから取得する

```bash
$ docker pull {image}[:tag]

#-----------------------------------------------------
# 例
#-----------------------------------------------------
$ docker pull hello-world:latest
# 結果 -> REPOSITORY=hello-world, TAG=latest のイメージが追加される.
$ docker images
REPOSITORY          TAG                  IMAGE ID            CREATED             SIZE
hello-world         latest               fce289e99eb9        8 weeks ago         1.84kB
ubuntu              latest               47b19964fb50        3 weeks ago         88.1MB
nvidia/cuda         9.0-cudnn7-runtime   17c50af840b7        4 weeks ago         1.21GB
```

#### docker tag
- ホストに存在するイメージのイメージ名とタグ名を変更する
- 元イメージを別名で呼べるようになる
  - イメージの実体は共通である点に注意

```bash
$ docker tag {image} {new_image}{:new_tag_name}

#-----------------------------------------------------
# 例
#-----------------------------------------------------
$ docker tag hello-world hello-world2:latest2
# 結果 -> 同一 ID の別名が生成される
$ docker images
REPOSITORY          TAG                  IMAGE ID            CREATED             SIZE
hello-world2        latest2              fce289e99eb9        8 weeks ago         1.84kB
hello-world         latest               fce289e99eb9        8 weeks ago         1.84kB
ubuntu              latest               47b19964fb50        3 weeks ago         88.1MB
nvidia/cuda         9.0-cudnn7-runtime   17c50af840b7        4 weeks ago         1.21GB
```

#### docker rmi
- イメージを削除する
  - イメージ名かイメージIDを指定可能
- option
  - `-f`: イメージを強制的に削除する

```bash
$ docker rmi [opiton] {iamge1} {image2} ...

#-----------------------------------------------------
# 例
#-----------------------------------------------------
$ docker rmi hello-world2
# 結果 -> イメージが削除される
$ docker images
REPOSITORY          TAG                  IMAGE ID            CREATED             SIZE
hello-world         latest               fce289e99eb9        8 weeks ago         1.84kB
ubuntu              latest               47b19964fb50        3 weeks ago         88.1MB
nvidia/cuda         9.0-cudnn7-runtime   17c50af840b7        4 weeks ago         1.21GB
```

### 5.2 conteiner の操作
#### docker ps
- ホストに存在する稼働中のコンテナを表示する
- option
  - `-a`: 停止中のコンテナも含めて全て表示する

```bash
$ docker ps # 稼働中のコンテナ一覧表示
$ docker ps -a # 停止中のコンテナも含めて一覧表示

#-----------------------------------------------------
# 例
#-----------------------------------------------------
$ docker ps
# 結果
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
76368d6f5feb        ubuntu:latest       "/bin/bash"         2 minutes ago       Up 2 minutes                            test2

$ docker ps -a
# 結果 -> 停止中のコンテナも見えるようになる
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                          PORTS               NAMES
76368d6f5feb        ubuntu:latest       "/bin/bash"         About a minute ago   Up About a minute                                   test2
ce64ec84b470        ubuntu:latest       "/bin/bash"         2 minutes ago        Exited (0) About a minute ago                       test1
```

#### docker create
- コンテナを作成する（起動はしない）
- run コマンドとほぼ同じコマンドルールなので詳細は割愛する
  - 詳しくは[公式ページ](http://docs.docker.jp/engine/reference/commandline/create.html)を参照

```bash
$ docker create [option] {image}[:tag] [コンテナで実行するコマンド]
```

#### docker start
- 停止中のコンテナを起動する
- コンテナ名 or コンテナID を指定する

```bash
$ docker start [option] {container} [container]
```
- 主な option

| option            | 説明                          |
| ----------------- | ----------------------------- |
| -a, --attach      | STDOUT、STDERR にアタッチする |
| -i, --interactive | コンテナの STDIN にアタッチ   |

```bash
#-----------------------------------------------------
# 例
#-----------------------------------------------------
# 事前条件
$ docker ps -a

CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                          PORTS               NAMES
76368d6f5feb        ubuntu:latest       "/bin/bash"         About a minute ago   Up About a minute                                   test2
ce64ec84b470        ubuntu:latest       "/bin/bash"         2 minutes ago        Exited (0) About a minute ago                       test1

# コマンド実行
$ docker start test1
$ docker ps
# 停止していたコンテナが稼働する
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
76368d6f5feb        ubuntu:latest       "/bin/bash"         16 minutes ago      Up 16 minutes                           test2
ce64ec84b470        ubuntu:latest       "/bin/bash"         17 minutes ago      Up 3 seconds                            test1
```

#### docker stop
- 起動中のコンテナを停止する
- コンテナ名 or コンテナID を指定する

```bash
$ docker stop {container} [conteiner]

#-----------------------------------------------------
# 例
#-----------------------------------------------------
# 事前条件
$ docker ps

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
76368d6f5feb        ubuntu:latest       "/bin/bash"         31 minutes ago      Up 10 seconds                           test2
ce64ec84b470        ubuntu:latest       "/bin/bash"         32 minutes ago      Up 3 seconds                            test1

# コマンド実行
$ docker stop test2
$ docker ps -a
# test2 が停止する
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
76368d6f5feb        ubuntu:latest       "/bin/bash"         32 minutes ago      Exited (0) 7 seconds ago                       test2
ce64ec84b470        ubuntu:latest       "/bin/bash"         32 minutes ago      Up 33 seconds                                  test1

```

#### docker restart
- コンテナを再起動する
- コンテナ名 or コンテナID を指定する

```bash
$ docker restart {container}
```

#### docker run
重要なコマンドであるため, 使用頻度の高いオプションを含めて細かく解説する.

- コンテナを作成・起動する

```bash
$ docker run [option] {image}[:tag] [コンテナで実行するコマンド]
```

- 代表的な option

| option | 説明 |
| --- | --- |
| --detach, -d | コンテナを生成し、バックグラウンドで実行する |
| --interactive, -i  | コンテナの標準入力を開く |
| --tty, -t | 端末デバイスを使う |
| --name | コンテナに名前をつける. 指定しない場合は, 自動で付与される. |
| --rm | コンテナ実行完了後にコンテナを自動で削除する. つまり, exit でコンテナから抜けたときや stop でコンテナを停止した場合に自動で削除される.  |
| --user {ユーザー名}, -u | ユーザー名または UID を指定する. |
| --add-host={ホスト名：IPアドレス}   | コンテナの /etc/hosts にホスト名とIPアドレスを定義する |
| --net={bridge / none / container:<name / id> / host}  | コンテナのネットワークを設定する. __bridge__(default):ブリッジ接続, __none__: ネットワークに接続しない, __container__:[name / id]: 別のコンテナのネットワークを使う, __host__: ホスト OS のネットワークを使う |
| --hostname, -h | コンテナ自身のホスト名を指定する   |
| --publish, -p {host_port}:{container port} | ホストとコンテナのポートマッピング  |
| --env, -e {環境変数}                        | 環境変数を設定する  |
| --volume, -v {host_dir}:{container_dir}     | コンテナにホストのディレクトリをマウントする  |
| --workdir={パス}, -w                         |  コンテナの作業ディレクトリを指定する |



##### 詳細な説明  
- `-it` オプション
 - run コマンドでコンテナのコンソール入出力を端末のコンソールに繋げる場合は `-it` オプションをつける

```bash
#-----------------------------------------------------
# 例
#-----------------------------------------------------
# -it オプションをつけた場合 --> root で稼働したコンテナのコンソールに入れる
$ docker run -it --name ubuntu1 ubuntu:latest
# 以下も同じ挙動をする
$ docker run -it --name ubuntu1 ubuntu:latest /bin/bash

# -it オプションをつけない場合 --> ホストのコンソールのまま. コンテナは停止状態
$ docker run --name ubuntu1 ubuntu:latest
```

- `--rm` オプション
  - `exit` でコンテナから抜けたときや `stop` でコンテナを停止した場合に自動で削除する
- `-p` オプション
  - ホストのポートとコンテナのポートをポートフォワーディングする

```bash
#-----------------------------------------------------
# 例
#-----------------------------------------------------
# コンテナの80番ポートをホストの8080番ポートに繋げる
$ docker run -it --name ubuntu1 -p 8080:80 ubuntu:latest
```

- `-v` オプション

```bash
#-----------------------------------------------------
# 例
#-----------------------------------------------------
# ホストの /mnt/D をコンテナの /D にマウントする
$ docker run -it --name ubuntu1 -v /mnt/D/:/D/ ubuntu:latest

# 結果 --> マウントされる
root@8d13b1b9dee6:/# ls
D  bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

```

#### docker attach
- 稼働中のコンテナの PIC=0 のプライマリプロセスに接続する
  - exit するとコンテンが停止する

```bash
$ docker attach {container}
```

#### docker exec
- 稼働中のコンテナで別プロセスを実行
    - exit するとそのプロセスのみが停止する

```bash
$ docker exec [オプション] {container} {コンテナで実行するコマンド}
```

#### docker status
- コンテナの稼働状況を確認する

```bash
$ docker status {container}
```

#### docker top
- 稼働コンテナのプロセス確認

```bash
$ docker top {container}
```

#### docker rm
- 停止中のコンテナを削除する

```bash
$ docker rm {container}
```

### 5.3 image の保存と再構築
#### docker build
- Dockerfile をビルドしてイメージを作成する
  - Dockerfile という名前で定義している場合, パスはファイルの親ディレクトリで良い

```bash
$ docker build -t {image_name}:{new_tag_name} {path/for/Dockerfile}
```
- 引数を指定する場合
　-　`--build-arg` オプションコマンドで Dockerfile 内で ARG として定義した引数に値を設定できる. プリセットされている場合は, 上書きされる

```bash
docker build --build-arg USER=SOMEONE
```

#### docker commit
- コンテナからイメージを生成する
- コンテナ上で実施した設定などを反映した image として保存できる

```bash
# 事前条件：　ctl+p ctl+q でコンテナから抜ける
$ docker commit {container} {iamge_name}
```

#### Dockerfile
- 作成方法の基本
  - ベースとなるイメージを記録しておく
  - コンテナ内で行った操作を記録しておく
  - 環境変数などの設定を記録しておく
  - 設定を再現するための Dockerfile を記載する
- 参考
  - [Dockerfile reference](https://docs.docker.com/engine/reference/builder/)
- Dockerfile の基本構文
  ```bash
  # Comment
  {命令} {引数}
  ```
- 命令の一覧

| 名前        | 説明                         |
| ----------- | ---------------------------- |
| FROM        | ベースイメージの設定         |
| RUN         | コマンド実行                 |
| CMD         | コンテナでのコマンド         |
| LABAL       | ラベルを設定                 |
| EXPOSE      | ポートのエクスポート         |
| ENV         | 環境変数                     |
| ADD         | ファイル/ディレクトリの追加  |
| COPY        | ファイルのコピー             |
| ENTRYPOINT  | コンテナの実行コマンド       |
| VOLUME      | ボリュームのマウント         |
| USER        | ユーザーの指定               |
| WORKDIR     | 作業ディレクトリ             |
| ARG         | Dockefile 内の変数           |
| ONBUILD     | ビルド完了後に実行される命令 |
| STOPSIGNAL  | システムコールシグナルの設定 |
| HEALTHCHECK | コンテナのヘルスチェック     |
| SHELL       | デフォルトのシェルの設定     |

- 例
  - [keras team が公開している keras 用の Dockerfile](https://github.com/keras-team/keras/blob/master/docker/Dockerfile)

```shell
ARG cuda_version=9.0
ARG cudnn_version=7
FROM nvidia/cuda:${cuda_version}-cudnn${cudnn_version}-devel

# Install system packages
RUN apt-get update && apt-get install -y --no-install-recommends \
      bzip2 \
      g++ \
      git \
      graphviz \
      libgl1-mesa-glx \
      libhdf5-dev \
      openmpi-bin \
      wget && \
    rm -rf /var/lib/apt/lists/*

# Install conda
ENV CONDA_DIR /opt/conda
ENV PATH $CONDA_DIR/bin:$PATH

RUN wget --quiet --no-check-certificate https://repo.continuum.io/miniconda/Miniconda3-4.2.12-Linux-x86_64.sh && \
    echo "c59b3dd3cad550ac7596e0d599b91e75d88826db132e4146030ef471bb434e9a *Miniconda3-4.2.12-Linux-x86_64.sh" | sha256sum -c - && \
    /bin/bash /Miniconda3-4.2.12-Linux-x86_64.sh -f -b -p $CONDA_DIR && \
    rm Miniconda3-4.2.12-Linux-x86_64.sh && \
    echo export PATH=$CONDA_DIR/bin:'$PATH' > /etc/profile.d/conda.sh

# Install Python packages and keras
ENV NB_USER keras
ENV NB_UID 1000

RUN useradd -m -s /bin/bash -N -u $NB_UID $NB_USER && \
    chown $NB_USER $CONDA_DIR -R && \
    mkdir -p /src && \
    chown $NB_USER /src

USER $NB_USER

ARG python_version=3.6

RUN conda config --append channels conda-forge
RUN conda install -y python=${python_version} && \
    pip install --upgrade pip && \
    pip install \
      sklearn_pandas \
      tensorflow-gpu \
      cntk-gpu && \
    conda install \
      bcolz \
      h5py \
      matplotlib \
      mkl \
      nose \
      notebook \
      Pillow \
      pandas \
      pydot \
      pygpu \
      pyyaml \
      scikit-learn \
      six \
      theano \
      mkdocs \
      && \
    git clone git://github.com/keras-team/keras.git /src && pip install -e /src[tests] && \
    pip install git+git://github.com/keras-team/keras.git && \
    conda clean -yt

ADD theanorc /home/keras/.theanorc

ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8

ENV PYTHONPATH='/src/:$PYTHONPATH'

WORKDIR /data

EXPOSE 8888

CMD jupyter notebook --port=8888 --ip=0.0.0.0
```