Docker

# はじめに
Dockerは自分で開発するときも使うし業務でも使うけど、ほとんどqiita見ながら設定するのでちゃんと理解していないので、理解して使えるようになるため

# Dockerとは
Docker社が提供する「コンテナ型仮想化技術」 を実現するプロダクト

# 仮想化とは
PCやサーバといったマシンにインストールされているOS(ホストOS)の上に、別のマシンを仮想的に立ち上げる事

# コンテナ型仮想化
Dockerが提供するのはコンテナ型仮想化

従来のホスト型仮想化とは異なり、ゲストOSを起動せずに、ホストOSの上に動作しているDocker Engineからコンテナと呼ばれるミドルウェアの環境構築がされた実行環境を作成し、その中でアプリケーションを動作させる。従来のホスト型仮想化よりも圧倒的に軽量

# Docker Engine
Dockerを利用するための常駐プログラム

# image
コンテナを起動するのに必要な設定ファイルをまとめたもの
Imageはコンテナの元で、Imageからコンテナを起動する

イメージは以下のような2つの特徴を持つ
1.layer構造になっている
2.一度作成されたimageは編集不可能

imageを用意する方法には
1.他人が作ったimageを取得する(Docker Hubからのimage取得)
2.自分で作る(Dockerfileからのイメージ作成)
がある

一度buildしたimageを、Dockerfileの変更無しに再びbuildする際にはbuild cacheが効いて、以前buildした情報を見に行くようになっているので、RUNにupdateコマンドなどを記述していたとしても普通にbuildし直した場合は、そのコマンドは実行されないことになる点に注意が必要

cacheを無効にしてbuildする場合は

```
docker build —no-cache -t イメージ名
```

# tag
imageのversion

# コンテナ
imageを用意したら、そのイメージからコンテナ(=アプリケーションの実行環境)が起動できる

コンテナ作成
```
docker create --name コンテナに付ける名前 イメージ名
```

コンテナ起動
```
docker run イメージ名
```

## コマンド一覧

- 現在実行中のコンテナを表示
```
docker ps
```

- 現在存在しているコンテナ一覧を表示
```
docker ps -a
```

- 指定したコンテナの詳細情報を表示
```
docker inspect コンテナ名
```

- コンテナの作成
```
docker create —name コンテナにつける名前 -it イメージ名 /bin/bash

-i はコンテナの標準入力を取得して双方向接続するオプション
-t はコンテナ内にTTYを割り当てるオプション
コンテナでシェル実行をして、フォアグラウンドで実行状態にしておきたい場合に -itの組み合わせで使われる
これをつけないとシェルがすぐに終了してコンテナが停止してしまう
```

- コンテナを起動
```
docker start コンテナ名
```

- コンテナを一時停止
```
docker pause コンテナ名
```

- コンテナの一時停止を解除
```
docker unpause コンテナ名
```

- コンテナが再起動
```
docker restart コンテナ名
```

- コンテナが停止
```
docker stop コンテナ名

コンテナが終了後、そのままローカルに残っている状態はExitとなることに注意が必要です。
使わないコンテナは削除しておかないとハードディスクが圧迫されます。
```

- コンテナを削除
```
docker rm コンテナ名
```

- コンテナを強制削除
```
docker rm -f コンテナ名
```

- 起動中のコンテナのシェルへ接続
```
docker attach 起動中コンテナ名

起動中のコンテナがシェルを実行している場合は、シェルに接続できるが
Deamonしか起動していない場合にはDeamonの標準入出力に接続されてしまうことに注意

attachで接続して、exitで抜けると起動中のコンテナが終了してしまうのが特徴です。
起動時に -itフラグをつけている場合は、control + p, control + qで抜けるとコンテナは終了しません。
```

```
docker exec -it 起動中のコンテナ名 /bin/bash

exitで抜けることができ、抜けてもコンテナが停止することはないのが特徴
```

- コンテナからイメージを作成
```
docker commit コンテナ名 image名：タグ名

コンテナの状態を、指定した「image名：タグ名」でイメージとして保存するコマンド
```

- イメージの変更履歴を確認
```
docker history イメージ名
```

# Docker Hubでのimage共有
Githubと殆ど同じです。
Dockerhubのアカウントを持っている必要があります。

# Dockerにおけるデータ管理

起動したコンテナ内で扱う動的なデータは、読み書き可能な最上レイヤー(コンテナレイヤー)に置くこともできるが
・コンテナが削除された時点でそのコンテナ内のデータは消える
・コンテナ間でデータ共有できない
・コンテナレイヤーへのデータ書き込みは、通常のファイルシステムと異なるユニオンファイルシステムが使われているため、書き込み速度が遅い

というデメリットがある

そのため、Dockerではホストマシン上にデータを管理し、それをコンテナにマウントする手法が使われる

手法は主に3つある

## volume
- ホストマシン上に自動生成される指定ディレクトリ(/var/lib/docker/volumes)をコンテナにマウントする
```
docker volume create volumeの名前
```

コンテナを起動する際に
```
$ docker run -itd --name 作成するコンテナ名 --mount source=[マウントするvolume名],target=[コンテナ上のマウント先ディレクトリ] イメージ名

具体例：
$ docker run -itd --name mount-test --mount source=volume1,target=/app nginx

のように、--mountオプション(-vオプションでも可)をつけることで指定したvolumeをマウントすることができる

マウントしたvolumesディレクトリは、マウント元であるホスト上のディレクトリからは直接操作するべきではない点に注意が必要

また、同じホスト内で立てている異なるコンテナでも、それぞれ同じvolumeをマウントすることでファイルの共有ができる
```

- volumeの一覧を確認
```
docker volume ls
```

- volumeの詳細を確認
```
docker volume inspect volume名
```

- volume を削除
```
docker volume rm volume名
```

コンテナを削除してもvolumeは残り続けるので、$ docker volume rm volume名　で削除する必要がある点に注意が必要

## bind mount
bind mount は、ホストマシン上の任意のディレクトリをマウントでき、ホスト側のディレクトリを直接操作をしても良いという点がvolumeと異なるマウント手法

volumeのように事前に設定する必要はなく、以下のコマンドでコンテナの起動時にオプションで指定してマウントする

```
docker run -itd --name [コンテナ名] --mount type=bind,source=[マウント元ディレクトリ],target=[マウント先ディレクトリ] イメージ名

具体例:
docker run -itd —-name bind-mount-test —-mount type=bind,source=“$(pwd)”/mount,target=/app nginx

source(マウント元)のディレクトリが存在しない場合は、エラーになるので
事前に作成しておくこと。(-vオプションを使用した場合は自動作成される)

bind mountでは、もしホスト上の空のディレクトリをコンテナ上の/userなどにマウントしたりした場合は
コンテナ上のデータが消えてしまい、コンテナがまともに動作しなくなることもあるので注意が必要
```

## tmpfs
ホストマシンのメモリ領域をコンテナ上にマウントする手法

ホストマシンが終了した場合も、コンテナが終了した場合も、保持していたデータは解放される

```
$ docker run -itd --name [コンテナ名] --mount type=tmpfs,destination=[マウント先ディレクトリ] イメージ名

具体例:
$ docker run -itd --name tmpfs-test --mount type=tmpfs,destination=/app nginx
のようにコンテナ起動時に、--mountオプションのtypeにtmpfsを指定することでマウントができる

また、ホスト上のメモリを無制限に使用してしまう可能性を排除するために、

$ docker run -itd --name tmpfs-test --mount type=tmpfs,destination=/app,tmpfs-size=800000000,tmpfs-mode=800 nginx
のようにオプションで使用可能なメモリサイズを制限することもできる
```

# Dockerネットワーク
複数立ち上げたコンテナ間で通信する手法について

例えば、Webアプリケーションサーバーの運用を行う場合、APIサーバコンテナとMySQLコンテナを立ち上げるとすると、APIサーバコンテナはMySQLコンテナと通信をする必要がある

ここでのコンテナ間通信の手法として、複数のコンテナを接続し通信するのがDockerネットワーク

Dockerネットワークにはデフォルトで存在する3つのネットワークと独自で定義するネットワークがある


## Bridgeネットワーク
デフォルトで存在するネットワークで、作成されたコンテナがデフォルトで接続されるのが、bridge networkでbridge driverを使用

Bridgeネットワークでは、同じネットワーク内に存在するコンテナとIPアドレス指定で通信することができる
ただ、Bridgeネットワークでは、DNSが定義されていないのでコンテナ名では他のコンテナに通信できない

つまり、Network指定をせずに起動したコンテナ同士は、IPアドレス指定で通信することは可能だが、コンテナ名指定で通信することはできない

また、デフォルト状態では外部に公開されていないネットワークですが、-p オプションで指定したポートを解放することで外部からコンテナにアクセスできるようにもできる

## Hostネットワーク
ホストネットワークは、host driver を使用したデフォルトで存在するネットワーク

接続したコンテナはdocker hostと同じネットワーク設定になる
例えば、host ネットワークに接続したコンテナでnginxコンテナを実行した場合、
hostマシンのIPの80番ポートでlistenしているのと同じことになる

そのため　bridgeネットワークのようにコンテナ起動時に-p オプションを設定して外部にポート公開しなくても、コンテナを起動しただけで、Docker hostのIPの80番に接続すればそのコンテナに接続できることになる

## Noneネットワーク
noneネットワークはデフォルトで存在するネットワークで、接続されたコンテナはネットワーク・インターフェースが無くなる
noneネットワークに接続する場合は、他のネットワークから全て切断しなくてはならない点に注意が必要

## ネットワークのコマンド一覧
- ネットワーク一覧を確認
```
docker network ls
```

- ネットワークの詳細を確認
```
docker network inspect ネットワーク名
```

- 新しくネットワークを作成(デフォルトのdriverはbridgeになる)
```
docker network create ネットワーク名
```

- コンテナをネットワークに接続
```
docker network connect 接続するネットワーク名 コンテナ名
```

- コンテナをネットワークから切断
```
docker network disconnect ネットワーク名　コンテナ名
```

# Docker Compose
Docker Composeは複数コンテナのDockerアプリケーションを事前定義して実行するためのツール

コンテナ1つを起動するにも、volumeなどのマウント設定や所属させるDockerネットワークの設定などを明記して

$ docker run -itd —name mount-test —mount source=volume-test, destination=/etc/nginx,readonly nginx
のような複雑なオプション付きのコマンドを打ち込まなければならない

これはとても面倒ですし、ミスにも繋がり、円滑に環境の共有が出来ない原因になる

そこで、それらを自動化できるのがDocker Compose

あるWebサービスの実行環境をDockerで構築する場合、Webサーバー, DBサーバー, Cacheサーバーなどの定義を一つのdocker-compose.ymlファイルに記述しておくことによって、それを元に実行に必要なコンテナをまとめて起動・設定することができる

手順は以下の通り
1.Dockerfileを用意する または Docker Hubなどに使用するイメージを用意する
2.docker-compose.ymlを定義する
3.ymlファイルがあるディレクトリで、$ docker-compose upを実行する

docker-compose.ymlを定義し、docker-compose upコマンド一つで複数コンテナを起動することができる

## docker-composeコマンド一覧
- docker-composeで起動したコンテナの一覧を表示
```
docker-compose ps
```

- docker-compose.ymlに記述した設定からコンテナ起動(既にコンテナが起動中であっても再起動してくれる)
```
docker-compose up
```

- docker-composeで作成されたコンテナやネットワークを削除
```
docker-compose down

-vオプションでvolumeも一緒に削除される
```

- 指定したサービスコンテナ内でコマンドを実行
```
docker-compose run [コンテナ名]　 [コマンド]
```

- 一連のコンテナ停止
```
docker-compose stop
```

- 一連のコンテナ起動
```
docker-compose start
```

# Docker Machine
Docker Machineは、Docker Engineを搭載した仮想マシンの管理(作成、起動、停止、再起動など)をコマンドラインから実行できるツール

Mac OSの場合は、仮想化ソフト(Virtual Box)をドライバーに使用して、Docker Engineを搭載した仮想マシンを管理するのがDocker Machine

docker-machineを起動して、その中でコンテナの実行などのdockerの機能が利用できる

またdocker-machineによって起動したDocker Engineが動作している仮想マシンのことをDockerホストと呼ぶ

## Docker Machineのコマンド一覧
- dockerホストの一覧表示
```
docker-machine ls
```

- Dockerホストを作成
```
docker-machine create —driver virtualbox ホストマシンに付ける名前
```

- Dockerホスト起動
```
docker-machine start ホストマシン名
```

- Dockerホスト停止
```
docker-machine stop ホストマシン名
```

- 指定したDockerホストを操作対象にするための環境変数一覧表示
```
docker-machine env ホストマシン名
```

- DockerホストをActiveにする
```
eval $(docker-machine env ホスト仮想マシン名)
```

- Dockerホストを非アクティブにする
```
docker-machine env -u
```

- Dockerホストにssh接続
```
docker-machine ssh Dockerホスト名
```

- DockerホストのIP確認
```
docker-machine ip Dockerホスト名
```

- Dockerホスト上でコンテナ実行
```
docker run イメージ名
```

# 終わりに
dockerの細かいところやネットワーク関連をうろ覚えだったので確認できてよかった

# 参考
【図解】Dockerの全体像を理解する
https://qiita.com/etaroid/items/b1024c7d200a75b992fc
https://qiita.com/etaroid/items/88ec3a0e2d80d7cdf87a
https://qiita.com/etaroid/items/40106f13d47bfcbc2572