Dockerまとめ

# はじめに

ついに年末がやってきましたね。初めまして、長い研修がやっと終わったばかりの新人SEです。来月からプロジェクトにアサインされるわけですが、どうやらDockerを使ってコンテナをこねこねするらしいので自分のメモ用にこの記事を書きました。私以外にもこれからDockerを使いたい！という人や、どうやって使うんだっけ？っていう人はぜひ参考にしてください。なお、この記事は「Docker/Kubernetes 実践コンテナ開発入門」という技術書の内容に則っています。
※随時更新予定

# Dockerfileとは

Dockerイメージを構築するための手順を記述したファイル。以下の句から構成される。(主なものだけ)

- FROM

    作成するDockerイメージのベースとなるイメージを指定。デフォルトではDocke Hubからイメージを取得する。

- RUN

    Dockerイメージビルド時に、Dockerコンテナ内で実行するコマンドを定義する。RUNの引数にはDockerコンテナ内で実行するコマンドをそのまま指定する。

- COPY

    Dockerを動作させているホストマシン上のファイルやディレクトリをDockerコンテナ内にコピーする為のインストラクションである。似た挙動をする句としてADDがある。

- CMD

    Dockerコンテナとして実行する際に、コンテナ内で実行するプロセスを指定します。CMDはコンテナ起動時に１度実行される。引数にはコマンドを空白で分割したものを配列化した形式で指定する。似た挙動をする句としてENTRYPOINTがある。両句の違いについては以下の記事を参照してください。

 - [DockerfileのCMDとENTRYPOINTを改めて解説する](https://qiita.com/uehaj/items/e6dd013e28593c26372d)

    ```
    # コマンド
    $ go run main.go
    # 対応するCMD
    CMD ["go", "run", "main.go"]
    ```

- 記述例

```dockerfile:Dockerfile
FROM golang:1.9

RUN mkdir /echo
COPY main.go /echo

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

# Dockerイメージとは

Dockerコンテナを構成するファイルシステムや、実行するや設定をまとめたもので、コンテナを作成するために利用されるテンプレートとなるもの。

Dockerfileからイメージをビルドするには以下のコマンドを実行する。

```
$ docker image build -t イメージ名[:タグ名] Dockerfile配置ディレクトリのパス
```

Dockerイメージのビルドに成功したかを確認するには以下のコマンドを実行する。

```
$ docker image ls
```

docker image buildコマンドのその他のオプションは以下の通り。

- -fオプション

    デフォルトでは**Dockerfile**という名前のDockerfileを探しに行きます。そうでない場合は-fオプションでファイル名を指定する。

- --pullオプション

    イメージをビルドする際、DockerfileのFROMで指定されているイメージを一度レジストリからダウンロードし、それをベースイメージにして新たなイメージをビルドする。この時、一度取得したDockerイメージは削除しない限りホスト内に保持される。--pullオプションでtrueを指定すると、ベースイメージを強制的に再取得させることができる。

# Dockerコンテナとは

Dockerイメージを基に作成され、具体化されたファイルシステムとアプリケーションが実行されている状態。

Dockerコンテナを実行するには以下のコマンドを実行する。-dオプションはコンテナ実行をバックグラウンド実行するためのオプション。

```
$ docker container run -d イメージ名[:タグ名]
```

コンテナの実行に成功したかを確認するには以下のコマンドを実行する。

```
$ docker cocntainer ls
```

# ポートフォワーディング

コンテナ上で動作しているアプリケーションにアクセスしたい場合、そのアプリケーションが公開されているポートに向けてリクエストを送るが、コンテナで実行されているアプリケーションは**コンテナポート**と呼ばれるコンテナ内に限定されたポートで公開されている。そのため、コンテナの外からは直接利用することができない。コンテナの外から利用したい場合はDockerのポートフォワーディングを設定する必要がある。

ポートフォワーディングの設定をする前にコンテナを停止する。

```
$ docker container stop コンテナID
```

ポートフォワーディングの設定付きでコンテナを実行する。

```
$ docker container run -d -p ホスト側ポート:コンテナポート イメージ名[:タグ名]
```

コンテナ内で実行されているのがWEBアプリケーションの場合は以下のコマンドで確認できる。

```
$ curl http://localhost:ホスト側ポート/
```

# イメージの検索

DockerイメージのレジストリであるDocker Hubではユーザーや組織がリポジトリを持つことができ、それぞれのDockerイメージを管理することができる。それらのリポジトリ内のDockerイメージを利用すれば、全てのDockerイメージを自前で用意する必要はない。

Docker Hubのレポジトリに登録されているリポジトリを検索するには以下のコマンドを実行する。--limitを指定することで表示件数を制限できる。

```
$ docker search --limit 5 mysql
NAME                  DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
mysql                 MySQL is a widely used, open-source relation…   8967                [OK]
mysql/mysql-server    Optimized MySQL Server Docker images. Create…   667                                     [OK]
mysql/mysql-cluster   Experimental MySQL Cluster Docker images. Cr…   59
bitnami/mysql         Bitnami MySQL Docker Image                      35                                      [OK]
circleci/mysql        MySQL is a widely used, open-source relation…   16
```

実行結果を見るとmysqlに関連するリポジトリの一覧が表示される。１つ目に表示されているmysqlのリポジトリには名前空間名がついていないが、このリポジトリは公式リポジトリであるためこのような表記になっている。

# イメージの取得

DockerレジストリからDockerイメージをダウンロードしてくるには、以下のコマンドを利用します。

```
$ docker image pull リポジトリ名[:タグ名]
```

タグ名を省略した場合はタグ（多くはlatest）が利用される。

# Dockerコンテナのライフサイクル

Dockerkコンテナは**実行中・停止・破棄**という３つの状態に分類される。これをDockerコンテナのライフサイクルと呼ぶ。

- 実行中

    docker container runで指定されたDockerイメージを基にコンテナが作成され、DockerfileのCMDなどで定義されているアプリケーションの実行を開始する。このアプリケーションが実行中なら、Dockerコンテナは実行中である。

- 停止

    実行中のコンテナはユーザーが明示的に停止するか、コンテナで実行されているアプリケーションが正常・異常を問わずに終了した場合に自動的に停止する。しかし、にコンテナ終了時の状態は保持されているので再実行可能である。

- 破棄

    停止したコンテナは明示的に破棄しない限りディスクに残り続ける。

# コンテナの作成と実行

docker container runはDockerイメージからコンテナを作成、実行するコマンドである。

```
$ docker container run [options] イメージ名:[タグ] [コマンド] [コマンド引数...]
```

コマンド引数を与えることでDockerfileで指定していたCMDを上書きできる。

また、--nameオプションでコンテナに明示的に名前を付けることができる。dockerコマンドでコンテナIDの代わりにコンテナ名も指定できるため便利である。

docker container runコマンドのその他のオプションは以下の通り。

- -iオプション

    docker起動後にコンテナ側の標準入力をつなぎっぱなしにする。このためシェルに入ってコマンド実行などができる。擬似端末を有効にするオプションである-tオプションと共に使うことがほとんどである。

- -rmオプション

    コンテナ終了時にコンテナを破棄する。

# コンテナの一覧

docker container lsコマンドは実行中および終了したコンテナの一覧を表示する。

```
$ docker container ls [options]
```

一覧の表示項目は以下の通り。

|項目|内容|
|---|---|
|CONTAINER ID|コンテナに付与される一意のID|
|IMAGE|コンテナ作成に使用されたDockerイメージ|
|COMMAND|コンテナで実行されているアプリケーションのプロセス|
|CREATED|コンテナが作成されてから経過した時間|
|STATUS|Up（実行中）、Exited（終了）といったコンテナの状態|
|PORTS|ホストのポートとコンテナポートの紐づけ|
|NAMES|コンテナ名|

docker container runコマンドのオプションは以下の通り。

- -qオプション

    コンテナID（省略形）だけを抽出する。

- --filterオプション

    特定の条件に一致するものだけを抽出する。

    ```
    # コンテナ名で抽出
    $ docker container ls --filter "name=echo1"
    ```

    ```
    #イメージで抽出
    $ docker container ls --filter "ancestor=example/echo"
    ```

- -aオプション

    終了したコンテナも含めて表示する。

# コンテナの停止

実行したコンテナを終了するには以下のコマンドを実行する。

```
$ docker container stop コンテナIDまたはコンテナ名
```

この時、コンテナ内のファイルなどのデータは保持されますが、メモリの状態はリセットされるので注意しましょう。

# コンテナの再起動

一度停止したコンテナは破棄しない限り以下のコマンドで再実行可能である。

```
$ docker container restart コンテナIDまたはコンテナ名
```

# コンテナの破棄

停止したコンテナをディスクから完全に破棄する場合は以下のコマンドを実行します。

```
$ docker container rm コンテナIDまたはコンテナ名
```

-fオプションを付けることで実行中のコンテナの停止と削除を行うことができます。

# 標準出力の取得

実行している特定のDockerコンテナの標準出力を表示するには以下のコマンドを実行する。

```
$ docker container logs [options] コンテナIDまたはコンテナ名
```

-fオプションを付けると標準出力を取得し続ける。

# 実行中コンテナでのコマンド実行

実行しているDockerコンテナの中で任意のコマンドを実行するには以下のコマンドを実行する。

```
$ docker container exec [options] コンテナIDまたはコンテナ名 コンテナ内で実行するコマンド
```

-itオプションを付けることが多い。

# ファイルのコピー

コンテナ間コンテナ・ホスト間でファイルのコピーを行うことができる。

```
$ docker container cp [options] コンテナIDまたはコンテナ名:コンテナ内のコピー元 ホストのコピー先
```

# コンテナやイメージの一括削除

実行していないコンテナやイメージを一括で削除することができる。

```
# コンテナの一括削除
$ docker container prune [options]
# イメージの一括削除
$ docker image prune [options]
```

利用されていないDockerコンテナやイメージ、ボリューム、ネットワーク解いた全てのDockerリソースを一括で削除することができる。

```
$ docker system prune
```

# 利用状況の取得

コンテナ単位でのシステムリソースの利用状況を知るには以下のコマンドを実行する。

```
$ docker container stats [options] [表示するコンテナID...]
```

# docker-composeによるコンテナの実行

yaml形式の設定ファイルで、複数のコンテナを一括管理できる。

以下の実行例と同じものをdocker-composeで作成する。

```
$ docker container run -d -p 9000:8080 example/echo:latest
```

```yml:docker-compose.yml
version: "3"
services:
    echo:
        image: example/echo:latest
        ports:
            - 9000:8080
```

version: "3"はdocker-compose.ymlのファイルフォーマットのバージョンであり、services要素のechoはコンテナ名である。image要素はDockerイメージ、portsではポートフォワーディングを指定している。

以上の定義を基にコンテナ群を起動するには以下のコマンドを実行する。

```
$ docker-compose up -d
```

停止は以下のコマンド

```
$ docker-compose down
```

Composeでは、docker-compose up時にDockerイメージのビルドも一緒に行い、実行できる。以下のようなディレクトリ構造であるとする。

```
echo --- main.go
      |- Dockerfile
      |- docker-compose.yml
```

ここでのdocker-compose.ymlにはimage属性を指定せずに、Dockerfileが存在する。ディレクトリの相対パスをbuild属性として指定する。

```yml:docker-compose.yml
version: "3"
services:
    echo:
        build: .
        ports:
            - 9000:8080
```

docker-compose up -dを実行するとすでにComposeでイメージをビルドされている場合はビルドを省略するが、--buildオプションを付けることで、必ずビルドを行わせることができる。

# 最後に

本当はdocker-composeで複数コンテナを実行するところまで書こうと思っていたのですが、ここで力つきました（笑）あとは読んでいる方への宿題ということで終わりたいと思います。気が向いたら続きを書くかもです。次は実際にコンテナにアプリケーションを乗っけて動かしてみたいと思います。