Docker再入門 導入手順とコンテナ立ち上げまで..【一回落ち着こう】


#「再入門」の意図
kubernetes のマネージドサービスがどんどん出てきていて、サービスの基盤として使えるものなのか、実際検証してみたけどベストプラクティスは？ など皆様の会社やプロジェクトでも本格的に導入を検討する段階に来ているかもしれません。

そのための情報収集を始める際に「コンテナ仮想化」、「Docker」という単語はまあ出てきますが、一回落ち着いて「Docker」って何ができるんだっけ？というところから復習してみませんか？

この記事ではDockerをVPSに導入し、アプリを動かして「ほら簡単でしょ？」という手順を振り返りたいと思います。「そのへんはもう大丈夫！」という人はよければ研修などの参考記事として使ってください。


# この記事でやること
**① VPS サーバーを立てる**
今回は１時間単位の課金で使える「ConoHa VPS」を使って試していきます。作った環境をすぐに破棄すれば数円でOKですし、そのまま使っても630円/月で運用できます。

**② Docker環境を構築する**
Docker 公式ドキュメントに従って忠実に環境を構築していきます。

**③ Docker でWEBサーバーを立ててみる**
基本的な dockerコマンドを使用してコンテナを動かします。

**④ docker-compose でもう少し便利に使う**
複数のコンテナを一度に立ち上げてくれる機能を使って簡単にいろいろなアプリケーションを実行していきます。
（kubernetesなどのクラスタ環境ではサーバーをまたいでコンテの管理を行うのでもっと複雑になりますが、基本的には docker-compose がもっと高機能になったものと考えても良いかと思います。）


では 順番にやっていきましょう


# ① VPS サーバーを立てる
どこの会社のものでもよいですが、今回は「１時間単位の課金」ですぐに環境を破棄すれば格安で検証できる[ConoHa VPS](https://www.conoha.jp/vps/?btn_id=header_vps) を使います。
まずアカウントを作成しましょう。（Github や Facebook などのアカウントを使って作成することも可能です。）

ログインすると以下の画面が表示されていると思いますので、左側のメニューの「サーバー追加」を押しましょう。
![①.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332187/e17d4a5f-6163-f131-8158-1ac8edafbcc0.png)


ConoHa VPS はテンプレートがとても豊富で Dockerがインストールされた環境も用意されています。が、今回は導入からやっていきたいので素の Ubuntuで作っていきましょう。
その他入力必須なのは「root パスワード」の部分です。入力が終わったら「追加」を押しましょう。
![②.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332187/4fdfff37-3113-b29e-beca-d33775ace74b.png)

（１円/１時間）と書いてますね。激安です。

起動するまでしばらく待ちます。作成されたVPSの情報を確認してみます。sshから操作をしたいので、VPSのIPアドレスを確認しておきましょう。
<font color ="red">**※今回作ったインスタンスはすでに破棄しています**</font>
![③.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332187/ca3a496f-b049-ba90-2805-2ffc91daa46a.png)


これでDockerを使うためのサーバーを手に入れました。


# ② Docker環境を構築する
では設定した「root パスワード」とサーバーの「IPアドレス」を使ってsshでログインします。
また、ユーザー作成やrootでのログイン禁止設定など継続して使用する場合にはセキュリティ上の設定もしたいところですが、今回はすぐ潰す予定なので割愛いたしました。
![④.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332187/ba0ede78-1c16-5b1a-45b9-3f65144174de.png)

ログイン後は

```sh
apt-get update      #apt updateでもOKです
apt-get upgrade -y  #apt upgrade -y でもOKです
```

を実行しておきましょう。

[Dockerの公式ドキュメント](https://docs.docker.com/install/linux/docker-ce/ubuntu/) に従いDockerを入れていきます。

http経由でのダウンロードなどを可能にするためのコマンドを実行します。（たいていVPSで初期状態から用意されていますが、手順通りにいきましょう。）

```sh
apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
```

 Dockerのパッケージを入手できるようにGPG keyを手に入れましょう。（公式のパッケージで間違いないよ、と確認するためのもの）

 ```sh
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
# OK と表示されます
 ```

ちゃんと認証情報を入手できたか確認します。

```sh
apt-key fingerprint 0EBFCD88

#表示される内容    
pub   rsa4096 2017-02-22 [SCEA]
      9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid           [ unknown] Docker Release (CE deb) <docker@docker.com>
sub   rsa4096 2017-02-22 [S]
```

Docker安定版のパッケージレポジトリを使いしましょう。

```sh
add-apt-repository \
 "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
 $(lsb_release -cs) \
 stable"
```

最後にパッケージをアップデートし、Dockerをインストールしましょう。

```sh
apt-get update
apt-get install docker-ce docker-ce-cli containerd.io
```

ちゃんとDockerをインストールできているかを確認しましょう

```sh
dcoker --version   # docker -v でもOK
 ```

ここでバージョンが表示されればOKです。
![⑤.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332187/31df3627-0baa-d5b8-219d-a35c7bf13ad1.png)


# ③ Docker でWEBサーバーを立ててみる
ここからが本題の「Dockerってそもそも何ができるんだっけ？」という部分になります。

まずは「Ubuntuの入ったVPS」上で「CentOS」の仮想環境を立ち上げてみましょう。コンテナの実行コマンドは" docker run "です。ここにオプションやコンテナ名を入れて使います。

```sh
docker run -i -t centos /bin/bash
# "-i , -t" オプションをつけることでbashの実行をインタラクティブに..などの意味があります
```

dockerコンテナのコンソールに遷移します。" yum update "とか試してみて終了するには" exit "でOKです。
![⑥.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332187/e58b89cc-6c15-38a9-45f0-35e67b05f792.png)


ではWEBサーバーを立てていきましょう。Apache , Nginx それぞれのコンテナを立てていきます。

まずは Apache(httpD) から

```sh
docker run -it -d -p 8080:80 httpd
# "-d"はバックグランドで実行するためのオプションです。
```

いろいろオプションをつけましたが、"-p"が重要です。左の8080ポートはこのVPSのポート番号、右の80ポートはコンテナの公開ポートになっています。つまりこれは、「Apacheコンテナの80番ポートを、VPSの8080番に紐づけて公開」という意味になります。
コンテナを立ち上げたらブラウザからVPSのIPアドレス:ポート番号にアクセスしてみましょう。
![⑦.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332187/180ea2f5-92a1-6c55-d752-187a6cf49739.png)
Apacheのデフォルト設定画面…コンテナの中のファイルを書き換えればちゃんとしたWEBページの表示ができてしまいます！

続いて Nginx も立ててみます。

```sh
docker run -it -d -p 8888:80 nginx
```

 上記と同じオプションで「Nginxコンテナの80番ポートを、VPSの8888番に紐づけて公開」という意味です。
![⑧.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332187/8f3fa1f4-d518-6490-4bcc-0d98df31b0a2.png)


 さて、ここで一旦今まで立ち上げたコンテナを確認してみましょう。

```sh
docker ps
# 以下表示内容です。
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
6c065e6da376        nginx               "nginx -g 'daemon of…"   2 minutes ago       Up 2 minutes        0.0.0.0:8888->80/tcp   wonderful_hypatia
a8b5e87fee68        httpd               "httpd-foreground"       9 minutes ago       Up 9 minutes        0.0.0.0:8080->80/tcp   confident_lederberg
```

さっき動かしたCentOSのコンテナが表示されていませんね。" docker ps "では「稼働中」のものしか表示されないので全部表示するためにオプションをつけましょう。

```sh
docker ps -a
 # 以下表示内容です。
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                         PORTS                  NAMES
6c065e6da376        nginx               "nginx -g 'daemon of…"   About an hour ago   Up About an hour               0.0.0.0:8888->80/tcp   wonderful_hypatia
a8b5e87fee68        httpd               "httpd-foreground"       About an hour ago   Up About an hour               0.0.0.0:8080->80/tcp   confident_lederberg
 # 何度かCentOSの docker run を実行したので複数ありますが本来は１つです、、
cc67fae8bd13        centos              "/bin/bash"              About an hour ago   Exited (0) About an hour ago                          wizardly_ellis
9117d824fb8d        centos              "/bin/bash"              About an hour ago   Exited (0) About an hour ago                          flamboyant_bouman
c8a461493ed7        centos              "/bin/bash"              About an hour ago   Exited (1) About an hour ago                          awesome_mclean
```

その他プションなどについては [Dockerの用語は大体「遊戯王カード」で置き換えられることを発見しました！ ](https://qiita.com/upaldus/items/518e6ae61c24b0a8f750) などでも公開していますのでよければ御覧ください。

# ④ docker-compose でもう少し便利に使う
最後です。
今までで単一のコンテナーの立ち上げ方を記載しましたが、実際のアプリケーション、例えば「WordPress」などは「CentOS」+「Apache」+「MariaDB」+「PHP」などの要素が組み合わさっています。まずこれらひとうひとつのコンテナを立ち上げて、全部のコンテナを同一のサービスとして機能させるのはとても面倒です。また、単一のコンテナにすべての要素を搭載させることも可能ですが、そうすると本来のコンテナのメリットが無くなってしまいます。
※１コンテナ１サービスとして動かしたほうが切り分けが簡単なため、アップデートやちょっとした改修も該当のコンテナを触るだけでよくなります。

ここで複数のコンテナを一度に起動できる  "docker-compose"  の出番になります。

**docker-compose のインストール**
こちらも [公式ドキュメント](https://docs.docker.com/compose/install/) の手順通りに進めていきますが、２行のコマンドを実行するだけです。

docker-composeの安定版をダウンロードします。

```sh
curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
```

ダウンロード先に実行権限を設定して " docker-compose "コマンドを使用できるようにします。

```sh
chmod +x /usr/local/bin/docker-compose
```

以上で docker-compose コマンドが使えるようになりました。

これから docker-compose コマンド一発でアプリケーションを立ち上げていきますが、「WordPress」は [Dockerイメージ](https://github.com/docker-library/wordpress) が配布されており、dockerコマンドでも問題なく動かせるのでもう少し複雑な構成の [Rocket.chat](https://rocket.chat/) というアプリケーションを立ち上げてみましょう。

※ Rocket.chat ..
ビジネスチャットツールである Slack や Teams とほぼ同じ使い方ができるオープンソースのアプリケーションです。無料なのに前者の商用ツールたちと同程度以上の機能を使うことができます。

**必要なもの**

-  " docker-compose "を実行するためのディレクトリ
-  " docker-compose.yml "という立ち上げるコンテナの構成が記載されたファイル

まず " docker-compose "を実行するためのディレクトリを下記のコマンドで作成し、そのディレクトリへ移動します。

```sh
mkdir -p rocketchat/
cd rocketchat/
 ``` 

 " docker-compose.yml "という立ち上げるコンテナの構成が記載されたファイル を作っていきます。このファイルはすでに世の中にあるサービスを使う場合、自分で１から書かないといけないことはそうそうありません。Github の公式レポジトリや Google 検索でほぼ見つけることが可能なので、あとは自分の環境に合わせて少しだけ編集する程度です。今回は [公式のレポジトリ](https://github.com/RocketChat/Rocket.Chat/blob/develop/docker-compose.yml) のファイルを使わせていただきましょう。

ではまずディレクトリの中に " docker-compose.yml "というファイルを作り編集していきます。

```sh:docker-compose.yml
touch docker-compose.yml
vi docker-compose.yml
```

以下内容を貼り付けます。

```yml:docker-compose.yml
version: '2'

services:
 rocketchat:
   image: rocketchat/rocket.chat:latest
   command: >
     bash -c
       "for i in `seq 1 30`; do
         node main.js &&
         s=$$? && break || s=$$?;
         echo \"Tried $$i times. Waiting 5 secs...\";
         sleep 5;
       done; (exit $$s)"
   restart: unless-stopped
   volumes:
     - ./uploads:/app/uploads
   environment:
     - PORT=3000
     - ROOT_URL=http://localhost:3000
     - MONGO_URL=mongodb://mongo:27017/rocketchat
     - MONGO_OPLOG_URL=mongodb://mongo:27017/local
     - MAIL_URL=smtp://smtp.email
#       - HTTP_PROXY=http://proxy.domain.com
#       - HTTPS_PROXY=http://proxy.domain.com
   depends_on:
     - mongo
   ports:
     - 3000:3000
   labels:
     - "traefik.backend=rocketchat"
     - "traefik.frontend.rule=Host: your.domain.tld"

 mongo:
   image: mongo:4.0
   restart: unless-stopped
   volumes:
    - ./data/db:/data/db
    #- ./data/dump:/dump
   command: mongod --smallfiles --oplogSize 128 --replSet rs0 --storageEngine=mmapv1
   labels:
     - "traefik.enable=false"

 # this container's job is just run the command to initialize the replica set.
 # it will run the command and remove himself (it will not stay running)
 mongo-init-replica:
   image: mongo:4.0
   command: >
     bash -c
       "for i in `seq 1 30`; do
         mongo mongo/rocketchat --eval \"
           rs.initiate({
             _id: 'rs0',
             members: [ { _id: 0, host: 'localhost:27017' } ]})\" &&
         s=$$? && break || s=$$?;
         echo \"Tried $$i times. Waiting 5 secs...\";
         sleep 5;
       done; (exit $$s)"
   depends_on:
     - mongo

 # hubot, the popular chatbot (add the bot user first and change the password before starting this image)
 hubot:
   image: rocketchat/hubot-rocketchat:latest
   restart: unless-stopped
   environment:
     - ROCKETCHAT_URL=rocketchat:3000
     - ROCKETCHAT_ROOM=GENERAL
     - ROCKETCHAT_USER=bot
     - ROCKETCHAT_PASSWORD=botpassword
     - BOT_NAME=bot
 # you can add more scripts as you'd like here, they need to be installable by npm
     - EXTERNAL_SCRIPTS=hubot-help,hubot-seen,hubot-links,hubot-diagnostics
   depends_on:
     - rocketchat
   labels:
     - "traefik.enable=false"
   volumes:
     - ./scripts:/home/hubot/scripts
 # this is used to expose the hubot port for notifications on the host on port 3001, e.g. for hubot-jenkins-notifier
   ports:
     - 3001:8080

 #traefik:
 #  image: traefik:latest
 #  restart: unless-stopped
 #  command: >
 #    traefik
 #     --docker
 #     --acme=true
 #     --acme.domains='your.domain.tld'
 #     --acme.email='your@email.tld'
 #     --acme.entrypoint=https
 #     --acme.storagefile=acme.json
 #     --defaultentrypoints=http
 #     --defaultentrypoints=https
 #     --entryPoints='Name:http Address::80 Redirect.EntryPoint:https'
 #     --entryPoints='Name:https Address::443 TLS.Certificates:'
 #  ports:
 #    - 80:80
 #    - 443:443
 #  volumes:
 #    - /var/run/docker.sock:/var/run/docker.sock
 ```

コメントアウトしているのは、SSLアクセスを有効にする場合の設定です。今回アクセスするポート番号は3000番に設定しています。
以上の内容をファイル内にコピペできたら エスケープキー を押し、 " :wp " で上書き保存します。

最後に以下のコマンドでアプリケーションを立ち上げましょう！

```sh
docker-compose up -d
```

初めて立ち上げるときは引っ張るイメージの数やプロセスが多いので結構待ちます。進み具合は下記のコマンドでリアルタイムに確認できます。

```sh
docker-compose logs -f
```

なにやらいろいろなプロセスが実行されていますね。。

数分たったら環境ができていると思いますので、IPアドレス:3000 にアクセスしてアプリケーションを使ってみましょう！
![⑨.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332187/a22dc0ae-fc29-9072-786e-dfe5c5da67a1.png)

順番に設定していけばすぐ使えます。 Slack 使ったことある人ならほぼそのままのイメージで使えます。（公式もそこを売りにしているみたいですね。）

私はもうこのサーバーが必要ないので、ConoHa VPSのコントロールパネルからこのサーバーを削除しました。


# 以上、お疲れさまでした。
開発環境をコード化できるので、いつも手元の環境に依存しない同じ環境で開発をすすめることができますし、立ち上げ、削除もすぐにできてしまうのでサービスの運用も簡単になることがメリットだと言われています。ただそこまで実装できている組織は限られていると思いますので、現状基本だけでも抑えておきたいなと思い、またこの内容が他の方の手助けになるとこの上なく嬉しいです。