Docker奮闘記 Dockerでnginx構築編 #2

## 前回までのあらすじ

前回のDocker奮闘記。  
筆者は、愛機にインストールとDockerの基本であるDocker Runをマスターした。  
しかし、Dockerで、できることはまだあることを筆者は知らなかった。

前回の記事：[Docker奮闘記 Docker RunでHelloWorld＃１ \- Qiita](https://qiita.com/gat3ta/items/3df6bfc05195dcbc7c2a)

## nginxを導入する概要

nginx [^1] を導入する。ただし、今回はDocker Runではなく、分解した形でやってみよう。

つまり、前回で紹介したとおり、docker runコマンドを分解したいかの３つのコマンドである

1. Docker pull
1. Docker create
1. Docker start

の順番で実行してみる。

## pullする！　前に、調べる！

pullといえば「git pull」が思い浮かばれる…。何か関連性があるのか？  
だが、難しいことは後だ！　きっと同じだ！　コマンドは腋を締めて右斜め45°えぐるようにして打つべし！

...と思ったが、何をpullすればよいのだろう？  
それが分からなければどうしようもない。

ということで ``` git search nginx ``` というコマンドを打ってみる。
文字通り、nginxに関して調べるコマンドだ。

``` PowerShell
PS E:\workspace> docker search nginx
NAME                                                   DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
nginx                                                  Official build of Nginx.                        11305               [OK]
jwilder/nginx-proxy                                    Automated Nginx reverse proxy for docker con…   1588                                    [OK]
richarvey/nginx-php-fpm                                Container running Nginx + PHP-FPM capable of…   709                                     [OK]
jrcs/letsencrypt-nginx-proxy-companion                 LetsEncrypt container to use with nginx as p…   506                                     [OK]
webdevops/php-nginx                                    Nginx with PHP-FPM                              125                                     [OK]
zabbix/zabbix-web-nginx-mysql                          Zabbix frontend based on Nginx web-server wi…   98                                      [OK]
bitnami/nginx                                          Bitnami nginx Docker Image                      65                                      [OK]
linuxserver/nginx                                      An Nginx container, brought to you by LinuxS…   59              
1and1internet/ubuntu-16-nginx-php-phpmyadmin-mysql-5   ubuntu-16-nginx-php-phpmyadmin-mysql-5          50                                      [OK]
tobi312/rpi-nginx                                      NGINX on Raspberry Pi / ARM                     26                                      [OK]
nginx/nginx-ingress                                    NGINX Ingress Controller for Kubernetes         18               
schmunk42/nginx-redirect                               A very simple container to redirect HTTP tra…   15                                      [OK]
nginxdemos/hello                                       NGINX webserver that serves a simple page co…   14                                      [OK]
blacklabelops/nginx                                    Dockerized Nginx Reverse Proxy Server.          12                                      [OK]
wodby/drupal-nginx                                     Nginx for Drupal container image                12                                      [OK]
centos/nginx-18-centos7                                Platform for running nginx 1.8 or building n…   10              
centos/nginx-112-centos7                               Platform for running nginx 1.12 or building …   7               
nginx/nginx-prometheus-exporter                        NGINX Prometheus Exporter                       4                
nginxinc/nginx-unprivileged                            Unprivileged NGINX Dockerfiles                  4                
1science/nginx                                         Nginx Docker images that include Consul Temp…   4                                       [OK]
mailu/nginx                                            Mailu nginx frontend                            3                                       [OK]
travix/nginx                                           NGinx reverse proxy                             2                                       [OK]
toccoag/openshift-nginx                                Nginx reverse proxy for Nice running on same…   1                                       [OK]
wodby/nginx                                            Generic nginx                                   0                                       [OK]
ansibleplaybookbundle/nginx-apb                        An APB to deploy NGINX                          0                                       [OK]
PS E:\workspace>
```

これで、nginxに関連するレポジトリがわかった。今回は公式でありシンプルな一番上の「nginx」をpullすることにしよう。

## 改めてnginxをpullする！

難しいことを考えずコマンドを打つのだ！

``` PowerShell
PS E:\workspace> docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
27833a3ba0a5: Already exists
ea005e36e544: Pull complete
d172c7f0578d: Pull complete
Digest: sha256:e71b1bf4281f25533cf15e6e5f9be4dac74d2328152edf7ecde23abc54e16c1c

PS E:\workspace>
```

ログを見る限り、```latest: Pulling from library/nginx```や```Status: Downloaded newer image for nginx:latest```とあるので、library/nginxというところからイメージをpullしたのだろう。

実際に、imageがあるのか調べてみる。

``` PowerShell
PS E:\workspace> docker images
REPOSITORY                 TAG                 IMAGE ID            CREATED             SIZE
nginx                      latest              27a188018e18        12 days ago         109MB
hello-world                latest              fce289e99eb9        3 months ago        1.84kB
PS E:\workspace>
```

```git images```という現在のimageに関するリストを表示するコマンドだが、確かにnginxという言葉がある！  
ダウンロードできているようだ。

## createする！

難しいことを考えずコマンドを打つ！

``` PowerShell
PS E:\workspace> docker create -p 18080:80 -v E:\workspace\test:/usr/share/nginx/html nginx
474d58616f68dd6076ae921128ad3841267751d481012a598970fa937f9ee768
PS E:\workspace>
```

終わり！　…といいたいところだが、今回の肝なので少し勉強する。

### Docker createコマンドとは

[create — Docker\-docs\-ja 17\.06\.Beta ドキュメント](http://docs.docker.jp/engine/reference/commandline/create.html)

先に結論となるコマンドを改めて記載する。

``` PowerShell
docker create -p 18080:80 -v E:\workspace\test:/usr/share/nginx/html nginx
```

今回使用したオプションは以下の通り。

``` PowerShell
  -p, --publish=[]              コンテナのポートをホスト側に公開
  -v, --volume=[ホスト側ソース:]コンテナ側送信先[:<オプション>]
                                ボリュームを拘束マウント。カンマ区切りで指定
                                `オプション` は [rw|ro], [z|Z], [[r]shared|[r]slave|[r]private], [nocopy]
                                'ホスト側ソース' は絶対パスまたは名前の値
```

### ちょっと横道

説明の前提として、2つある。

１つは、nginxはWebサーバーであるということだ。すなわち、コンテナ内に何らかの方法によってコンテナ内のnginxにアクセスする必要がある。  
よって、**あらかじめその経路を確保しなければならない。**

２つ目に、dockerのコンテナ内は、基本的に状態の保存が効かないということだ。詳細は、割愛するが、dockerは（少なくともcreateしたタイミングでは）基本的にいつでもどこでも同じ環境が作られる。  
これは、裏を返すと、コンテナを削除して作り直した場合には、 **元のコンテナ内の情報は当然削除されて保持されない** ということを頭に入れておく必要がある。  
よって、データを保持したい場合、**保持する方法を確保しなければならない。**

### create オプション（-p , -v）の説明

#### -p ポートバインド

```-p, --publish=[]              コンテナのポートをホスト側に公開``` とある。  
さて、nginxはWebサーバーだ。Webサーバーといえば、80番ポートにアクセスするわけだが、では、どうやってホスト側からつなげればよいのだろう？

その一つの解として、-pコマンドを利用して、ホスト側のポート番号とゲスト側のポート番号をバインドする（結びつける）方法を取る。

つまり、具体的な方法論を書くと、

[![Image from Gyazo](https://i.gyazo.com/2090ffa8d6730d975476f8d9e2932eb6.png)](https://gyazo.com/2090ffa8d6730d975476f8d9e2932eb6)

という構図である。

これで、ホスト側からlocalhost:18080にアクセスすることで、nginxに対する80番ポートにアクセスすることが可能になる。

#### -v ボリュームバインド

次に、```-v, --volume=[ホスト側ソース:]コンテナ側送信先[:<オプション>]``` とある。  
これは、ホスト側のソースをコンテナ側から利用できする方法だ。すなわち、コンテナ内に保存できないなら、ホスト側のファイルを見れば良いじゃない、という単純な方法である。

[![Image from Gyazo](https://i.gyazo.com/4428d59540d436163e3a313672469bed.png)](https://gyazo.com/4428d59540d436163e3a313672469bed)

#### その他のオプションと注意点

コンテナを作成するときに、コンテナ側の情報だけではどうにもならない場合、あらかじめオプションを指定してやる方法を示した。  
これ以外にも、-Eオプションなど環境変数に関わるオプションなどがあるが、ここでは一旦割愛する。

また、少し蛇足になる。

押さえておくべきは、Createコマンドのオプションの内容は、**ここで作られたコンテナにのみ適用される**ことである。
たくさんの人に活用されるDockerの理念を考えれば、オプションで行う方法は、個人による情報を指定したい場合（ID,パスワードなど）など必要性が高い場合や、補助的な方法として考えておくべきだ。

さもなければ、Dockerfileというimageを構築するための設計図のようなファイルを作成し、あらかじめimageに盛り込んで置くほうが望ましい。

ただ、今回は私の勉強だから、いいのだ！

### コンテナが作られているか確認する

```docker ps -a``` コマンドで今存在するコンテナを表示することができる。

``` PowerShell
PS E:\workspace> docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
474d58616f68        nginx               "nginx -g 'daemon of…"   33 minutes ago      Exited (0) 3 seconds ago                        determined_leakey
26365ee4b6ab        hello-world         "/hello"                 34 hours ago        Exited (0) 34 hours ago                             competent_davinci
PS E:\workspace>
```

nginxコンテナが存在していること分かる。

## startする！

では、お膳立ては完了した。さあ、起動しよう！  
難しいことは（以下略）

``` PowerShell
PS E:\workspace> docker start 47
47
PS E:\workspace>
```

startコマンドはすごく単純だ。一応、オプションはあるが、今回はただ起動したいだけなので、オプションは不要だ。ここでも紹介しないことにする。

なお、引数に指定している「47」とは、コンテナ番号の上二桁だ。ちなみに、別に何桁でもいい。```docker ps -a```を見て、一意のコンテナを識別できるならば１桁でもよい。  
事実、コンテナが２つしかない今の状態において、片方が２から始まるコンテナIDであるから、```docker start 4```としても起動する。

横道に逸れてしまった。今は、これ以上の説明は不要だ。

最後に動作確認する。  
```docker ps```とオプションなしに打つと、現在起動しているコンテナだけが表示される。

``` PowerShell
PS E:\workspace> docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                   NAMES
474d58616f68        nginx               "nginx -g 'daemon of…"   41 minutes ago      Up 4 seconds        0.0.0.0:18080->80/tcp   determined_leakey
PS E:\workspace>
```

PORTSのところも```0.0.0.0:18080->80/tcp ```となっており、ポートがバインドされていることが明示されている。

## 本当にHTTPが繋がるか確認する

前置きとして、ローカルのバインド先であるE:\workspace\testには、以下のindex.htmlファイルが存在する。

``` HTML
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8"/><Title>MyPortal</title></head>
<body><h1 id="myportal">MyPortal</h1> <ul> <li><a href="mermaid.html#md/GTDFlow.md">GTDFlow</a></li> <li><a href="mermaid.html#md/unyokanri.md">運用管理</a></li> </ul> </body>
</html>

```

さあ、localhost:18080にブラウザからアクセスしてみよう。

[![Image from Gyazo](https://i.gyazo.com/aba7d10017651473e57f36555d3df12f.png)](https://gyazo.com/aba7d10017651473e57f36555d3df12f)

つながった！

実際に以下の方法を試みて成功した。
 1. nginx イメージをダウンロードした
 1. nginx イメージからポートとボリュームをバインドさせてコンテナを作成した
 1. コンテナを起動してnginxのWebサーバーに繋がることを確認した。

今回はここまでにしておこう。ただスクリプトを動かしたいだけならば、殆どの場合においてここまでの内容で開発できるんじゃなかろうか？  
しかし、色々なサーバーを経由をする環境は当然ながら考えられる。

ということで、次回は、複数のコンテナを連携させる方法について勉強したい。具体的には、RedMineとMySQLを連携させてみたい。

[^1]: フリーかつオープンソースなWebサーバ。https://nginx.org/en/