Vagrant （プロバイダは Virtual Box） と Ubuntu で始める Docker / Docker Compose 入門


# このページについて

Vagrant / Virtual Box と Ubuntu を用いて、Docker を使い始めるための情報を記載する。

参考情報：http://www.atmarkit.co.jp/ait/articles/1701/30/news037.html


## はじめに - Docker とは

参考情報：https://www.docker.com/what-docker

Docker とはソフトウェアコンテナプラットフォームである。

コンテナとはソフトウェアをパッケージ化するための手法である。
パッケージは OS に依存せず共通のフォーマットを取る。
後に述べるが、要するに Docker で動作するアプリケーション（Docker コンテナと呼ぶ）は OS に寄らず動作させることができるということである。（必ず動作することを担保はできない）

コンテナは VM と異なり OS そのものとアプリケーション環境がセットになったものではなく、動作するために必要なライブラリや設定がセットになったものである。ハードウェアと OS の基本機能はコンテナ同士で共有される一方で、アプリケーションの実行環境を他のプロセスから隔離して、仮想的なアプリケーション実行環境を提供する。

VM 環境と比べて、コンテナ環境ではコンテナ毎にサービスを不要に立ち上げる必要がなくコンパクトであり、ソフトウェアが毎回同じ環境で動作することができるため効果的であることが特徴である。

コンテナ技術により隔離される環境

- 名前空間
  - ファイルシステムやコンピュータ名、ユーザ名（ユーザID）、グループ名（グループID）、プロセスID、ネットワーク機能 等
- リソース
  - CPU やメモリ、ディスク I/O

Docker は Docker Engine と呼ばれるアプリケーション実行環境を提供する。この Docker Engine は Docker クライアントから API (Docker API) を通じて操作される。

Docker が管理するアプリケーション実行環境は Docker コンテナと呼ばれる。Docker コンテナはファイルとして保存・配布が可能であり、ファイルは Docker イメージと呼ばれる。Docker イメージは基本的にどの Docker コンテナ環境でも動作する。

また、Docker イメージがある時点での Docker コンテナのスナップショットであるのに対して、Docker スクリプトにより、ベースとする Docker イメージに特定の操作を与えることができる。

Docker イメージはベースイメージからの差分で管理される。イメージとして変更がコミットされた時点のものを Docker のレイヤと呼ぶ。

非常に小さなソフトウェアであれば Docker コンテナが 1 つで済むが、複数のコンテナが必要となり、DB や App のように連携が必要である場合はコンテナの起動順序も考慮しないといけない。このようなケースでは、複数の Docker コンテナをまとめ、起動順序も指定することのできる Docker Compose を使う。

尚、複数のホストで Docker 環境をクラスタとして管理する Docker Swarm 等がある。
※ Docker Swarm は使ったことが無いので説明は割愛する。

## Docker / Docker-Compose クイックスタート

*記載当時（2017/10/13）の Docker バージョンは Docker Client/Server 17.09.0-ce、Docker Compose バージョンは 1.16.1 (build 6d1ac21) である。*

前提として Ubuntu インストールまでは Vagrant を使う手順である。既に Ubuntu 環境があれば割愛してよい。その場合は [Ubuntu に Docker / Docker-Compose をインストールする](#install-docker-and-docker-compose) から読むこと。

### Vagrant で Ubuntu の Box を作成する

Ubuntu インストールまでは Vagrant と Virtual Box を使う。既にUbuntu環境があれば割愛してよい。Vagrant と Virtual Box の簡単な説明ついては、本ページ内 [参考情報 - Vagrant とは](#hello-vagrant) を参照すること。

1. Vagrant をインストールする。（参考情報：[Vagrant](https://www.vagrantup.com/)）
1. コマンドラインから Vagrant コマンド `vagrant version` が実行できるようになれば成功。
1. Virtual Box をインストールする。（参考情報：[Oracle VM VirtualBox - Downloads | Oracle Technology Network | Oracle](http://www.oracle.com/technetwork/server-storage/virtualbox/downloads/index.html?ssSourceSiteId=otnjp)）
1. インストール完了後に OS を再起動して Virtual Box が起動できれば成功。
1. Vagrant 公式サイトから **[FIND BOXES](https://app.vagrantup.com/boxes/search)** を辿って Ubuntu の Box を探す。（ここでは例として relativkreativ/ubuntu-16-minimal を使わせて頂く）
1. Box 毎の Vagrant 設定ファイルをフォルダ別に保管するためのフォルダを作成する。
  1. `mkdir c:\vagrant\`
  2. `cd c:\vagrant\`
  3. `mkdir ubuntu-16-minimal`
  4. `cd ubuntu-16-minimal`
1. `vagrant init relativkreativ/ubuntu-16-minimal` を実行する
1. `vagrant up` を実行する
1. `vagrant ssh` を実行してログインできれば Box 環境へログインできる。
  - ターミナルアプリケーションを使って SSH ログインしたい場合は、[ターミナルから SSH でログインする方法](#ssh-login-from-terminal) を参照のこと。

<a name="install-docker-and-docker-compose"></a>
### Ubuntu に Docker / Docker-Compose をインストールする

1. Docker をインストールする。（参考情報：[docker docs - Get Docker CE for Ubuntu](https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/)）
  - 参考情報のページを上から参照していき、`% sudo docker run hello-world` を実行して Hello World メッセージが出力されたら成功。
  - 失敗したら後続の Install from a package を実施すること。（Install from a package は実施したことないので詳細は不明だが、そのように説明されている。）
  - docker を実行する度に sudo を実行したくない場合は、`docker` グループにユーザを参加させる。（USERA を docker グループへ参加させる方法：`usermod -a -G docker USERA`)
1. Docker Compose をインストールする。（参考情報：[docker docs - 
Install Docker Compose](https://docs.docker.com/compose/install/)）
    - ubuntu 18 では '18/06/16 現在 stable リポジトリに docker-ce が存在しないため docker.io を代わりにインストールするとよい。
        - `$ sudo apt-get install docker.io`
1. 動かしたい Docker が既にある場合はファイルをダウンロードして `sudo docker-compose on` を実行してコンテナが起動したら成功。
1. 動かしたいファイルがない場合はサンプルを使う。（参考情報：[Get started with Docker Compose](https://docs.docker.com/compose/gettingstarted/)）
  1. 参考情報を参考にして、app.py, requirements.txt, Dockerfile, docker-compose.yml ファイルを作成する。
  1. `mkdir composetest` を実行する。
  1. `cd composetest` を実行する。
  1. composetest フォルダに作成したファイルを配置する。
  1. `sudo docker-compose on` を実行してコンテナが起動することを確認する。（実行したターミナルにて、プロンプトは帰ってこない）
  1. `http://localhost:5000` へアクセスして Hello World が出力されることを確認する。アクセスを繰り返すとカウンタ値が上がっていくことが確認できる。

```bash:ubuntu/amd64でのdockerインストールコマンド('18/11/24時点で有効であることを確認) 
$ sudo apt-get update && \
sudo apt-get -y remove docker docker-engine docker.io && \
sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common && \
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - &&
sudo apt-key fingerprint 0EBFCD88 | grep '9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88' && \
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" && \
sudo apt-get update && \
sudo apt-get -y install docker-ce
```

### vagrant で立ち上げた Box へのログイン方法

- Provider のターミナルから `vagrant ssh` でログインする。
- VirtualBox を使ってコンソールからログインする。
- ターミナルから SSH でログインする。

<a name="ssh-login-from-terminal"></a>
#### ターミナルから SSH でログインする方法

- ユーザのログインID / PASSWD は vagrant / vagrant である。
- SSH 秘密鍵の暗号化パスワードも vagrant である。

その他、アクセス先の IP アドレスやポート番号、秘密鍵の設置場所は下記のとおり `vagrant ssh-config` コマンドで調べる。

- アドレス（HostName）/ポート（Port）：127.0.0.1:2222
- 秘密鍵：`c:/Users/test/vagrant/ubuntu-16-minimal/.vagrant/machines/default/virtualbox/private_key`

```text:vagrant_sshコマンドを実行した結果
> vagrant ssh-config
Host default
  HostName 127.0.0.1
  User vagrant
  Port 2222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile c:/Users/test/vagrant/ubuntu-16-minimal/.vagrant/machines/default/virtualbox/private_key
  IdentitiesOnly yes
  LogLevel FATAL
```


### Docker Compose up した時のエラー

Docker Compose ファイルのバージョンが 3 に対して、実行する Docker Compose 環境や Docker Engine のバージョンが古いと `docker-compose up` がエラーとなり失敗する場合がある。

docker-compose.yml に記載されたバージョンに対して必要な Docker Engine 実行環境は表 [Compose file version 3 reference - Compose and Docker compatibility matrix](https://docs.docker.com/compose/compose-file/) に従うこと。

例えば、次のように docker-compose.yml に書かれたバージョンが 3 の場合、Docker Engine は 1.13.0 より新しいものを使う必要がある。

> | Compose file format | Docker Engine release |
|---------------------|-----------------------|
| 3.0                 | 1.13.0+               |

尚、Docker はバージョンが v1.13 からアップデート版の v17.03 がリリースされてから採番体系が変わった。v17 以降、採番体系は「年 2 桁.月 2 桁.リビジョン」である。また、Docker-CE と、コミュニティエディションを示す "-ce" が追加された。エンタープライズエディションを示す "-ee" もある。（参考情報：[Publickey - Docker v17.03がリリース。今月からバージョン番号制度が変更になり、毎月リリース体制に](http://www.publickey1.jp/blog/17/docker_v1703.html)）

Docker Engine と Docker Compose の間にもバージョンの制約があり、Docker Compose は v1.5.2-1 は Docker v17.03 以降を必要とする。


### docker-compose up 時に ERROR が出た時の対処方法

```text:docker-compose_up時のエラー
% sudo docker-compose up
ERROR: Version in "./docker-compose.yml" is unsupported. You might be seeing this error because you're using the wrong Compose file version. Either specify a version of "2" (or "2.0") and place your service definitions under the `services` key, or omit the `version` key and place your service definitions at the root of the file to use version 1.
```

このエラーが出た原因は不明だったが、docker-compose バージョンが古く（Docker Compose v1.5）、アップデート（Docker Compose v1.16.1）したら解消された。


### apt-get update 時に GPG エラーが出た時の対処方法

```text:apt-get_update時のGPGエラー
% apt-get update
W: GPG error: https://apt.dockerproject.org/repo ubuntu-xenial InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY F76221572C52609D
W: The repository 'https://apt.dockerproject.org/repo ubuntu-xenial InRelease' is not signed.
N: Data from such a repository can't be authenticated and is therefore potentially dangerous to use.
N: See apt-secure(8) manpage for repository creation and user configuration details.
```

Docker Compose のインストール方法で紹介した方法を記載する前に、古いバージョンでのインストール方法が書かれており、試行錯誤している中で上記エラーが出力された。

パッケージリポジトリの認証に利用している鍵が無いためにエラーとなっているため、鍵を認証対象に追加すればよい。（参考情報：[あれこれ備忘録@はてなブログ - apt-get で公開鍵エラー(NO_PUBKEY)が出た時の対処法](http://arekorebibouroku.hateblo.jp/entry/2015/11/03/150827)）

上記例では apt.dockerproject.org の鍵に対してエラーが出ているため次の方法で鍵を追加する。

```shell-session:apt-keyで鍵を追加する方法
% curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
```

----

<a name="hello-vagrant"></a>
## 参考情報 - Vagrant とは

*※ 記載当時（2017/10/13）のバージョンは Vagrant 2.0.0*

Vagrant とは、異なる仮想化ホスト上で、同じ仮想マシン（VM）の環境を構築するための構成情報管理と構成サポートを行うツールである。ここで、構成サポートとは構成情報を基にして OS のインストール及びミドルウェアのインストールを行うことを指す。

要するに、Vagrant を使うと、構成情報ファイルに従ってコマンド一発で任意の OS とミドルウェア等が VM として作成でき、またミドルウェアを指定したバージョン（又はインストール時の最新等の指定も可能）へアップデートさせるといった操作を VM へ行うことができる。

Vagrant は Windows, Mac OS X, Linux で動作する。対象となる仮想化ホストとしては、VirtualBox, Hyper-V, Docker が利用できる。
※ Vagrant が対象とする仮想化ホストを Provider と呼ぶ

Vagrant が管理の対象とする仮想マシンイメージは Boxと呼ばれる。また、構成管理情報は vagrantfile に記載される。vagrantfile によりメモリ使用率やネットワーク構成等の仮想マシンの H/W 構成を指定できる。

----

## Vagrant コマンドリファレンス

参考情報：https://www.vagrantup.com/docs/cli/

```shell-session:boxの初期化
% vagrant init <box名>
```

- \<box名\>に ```ubuntu/trusty64``` 等と名前を指定すると、Vagrant Cloud から検索して BOX がダウンロードされ Vagrantfile が初期化される。

```shell-session:仮想マシンの起動
% vagrant up
```

```shell-session:仮想マシンの停止
% vagrant halt
```

```shell-session:仮想マシンの休止
% vagrant suspend
```

```shell-session:（休止した）仮想マシンの再開
% vagrant resume
```

```shell-session:Boxステータスの確認
% vagrant status
Current machine states:

default                   running (virtualbox)

The VM is running. To stop this VM, you can run `vagrant halt` to
shut it down forcefully, or you can run `vagrant suspend` to simply
suspend the virtual machine. In either case, to restart it again,
simply run `vagrant up`.
```

```shell-session:SSH情報の確認
% vagrant ssh-config
Host default
  HostName 127.0.0.1
  User vagrant
  Port 2222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile C:/Users/test/vagrant/ubuntu-16-minimal/.vagrant/machines/default/virtualbox/private_key
  IdentitiesOnly yes
  LogLevel FATAL
```

```shell-session:仮想マシンへSSHログインする
% vagrant ssh
```


## Docker コマンドリファレンス

- Docker コマンドで操作する対象には、**Container**, **Volume**, **Network**, **Image** があり、Container は Docker コンテナのこと、Volume はコンテナのデータフォルダ、Network はコンテナが接続されるネットワーク、Image はコンテナイメージと覚えておくとよい。
- Linux コマンドライクに Container の一覧は ```ps``` で確認でき、volume, network, image の一覧は ```ls``` で確認でき、全ての対象は ```rm``` で削除できる。
- Docker のネットワークはルーティングとホスト側のパケットフィルタで制御される。詳細は別途記事にする予定。

### Docker コンテナ操作

- Docker run でよく利用するオプションに次がある。
    - ```-i``` ： アタッチされてなくても STDIN を維持する
    - ```-t``` ： 疑似 TTY を用意する
    - ```--rm``` ：起動し終わったら自動削除する
    - ```--name <some-name>``` ： コンテナイメージの名前を some-name に設定する。（指定しなければ適当な名前が付けられる。）
    - ```--link``` ： 2つの Docker コンテナで通信可能となるよう、Docker コンテナ名から IP アドレスが変換できるようにする。公式ドキュメントでは ```--link``` を利用するより、```bridge``` ネットワークを利用することが推奨されている。
    - ```--net <some_network>``` ： some_default ネットワークへ接続する。
    - ```-d``` ： コンテナを起動したらデタッチする
    - ```--volume /PATH/TO/HOST:/PATH/TO/CONRAINER``` ： ボリュームを接続する。

```shell-session:Dockerコンテナ（ubuntuイメージ）を起動させてbashでコンソール操作する
% docker run -it ubuntu /bin/bash
```

```shell-session:Dockerコンテナを一覧表示する
% docker ps -a
CONTAINER ID        IMAGE                              COMMAND                  CREATED             STATUS                        PORTS                 NAMES
a4b0a351a48e        jenkins                            "/bin/tini -- /usr..."   4 minutes ago       Up 4 minutes                  8080/tcp, 50000/tcp   jolly_montalcini
  : <省略>
```

```shell-session:Dockerコンテナのシェルを操作する
% docker exec -it <ContainerName:ps -aで調べる> bash
```

```text:Dockerコンテナからデタッチする
（コンテナ上で）[Ctrl+P] [Ctrl+Q]
```

### Docker イメージ操作

```shell-session:Dockerイメージファイルを検索する
% docker search <keyword>
AME                                         DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
jenkins                                      Official Jenkins Docker image                   3152      [OK]
jenkinsci/jenkins                            Jenkins Continuous Integration and Deliver...   301
  : (省略)
```
※ [Docker Hub](https://hub.docker.com/) で検索してもよい。

```shell-session:Dockerイメージを作成する（イメージへの動作後の変更をコミット）
% docker commit -m "some packages were added on XX image." BASE_CONTAINER REPOSITORY[:TAG] 
```

- コミットをすることで REPOSITORY の名前でイメージが作成され、コンテナを操作できるようになる。TAG はコンテナの名前は同じだがバージョンの違いを区別したい場合につける。```ubuntu:16.04``` 等。タグを省略すると ```:latest``` となる。

### Docker ボリューム操作

```shell-session:Dockerボリュームを表示する
$ docker volume ls
```

```shell-session:Dockerボリュームを削除する
$ docker volume rm <volume名:volume lsで調べる>
```

```shell-session:Dockerボリュームを全て削除する
$ docker volume rm $(docker volume ls -qf dangling=true)
```

### Docker を使う上での注意事項

- docker コンテナは起動させる際に、name 指定しないと適当な名前がアサインされる。--name で名前を付けないと扱いづらいので使おう。名前を付けると他のコンテナと IP 通信する際にその名前から IP を変換することが出来るため制御がしやすい。
- docker コンテナはコンテナ毎にネットワークが異なる。ネットワークを接続したい場合は --link で接続をしよう。
- docker コンテナは起動するごとに作成される。--rm で削除しないと数が多くなって汚くなるぞ。（docker ps -a で docker コンテナ一覧（と起動有無）が見れる。）
- docker コンソールに接続するためには docker attach コマンドがある。（デーモンで動かしていたコンソールにアタッチする）-it の方がコンテナ内でシェル操作ができるので便利。```例）docker exec -it some-mongo bash```
- docker-compose をデーモン化するには docker-compose run -d を使おう。