docker-composeを使ってnginx上でVueアプリケーションを動かす

vue-cliを使った開発時には「npm run dev」で動作するwebpack-dev-serverを使っていますが、ビルド後の動作をnginxで確認したいと思い、dockerで環境構築しました。

また、vue自体の環境もdocker上のコンテナで構築し、ローカル環境を汚さないようなコンテナ構成にしています。

備忘録をかねて、コードやディレクトリ構成などを書いていきます。

（docker for Macをインストールしている前提で進めます）

## ディレクトリ構成

「Vue_docker」といったディレクトリを作り、それをルートディレクトリとして解説していきます。

全体のディレクトリ構成は以下です。

```
vue_docker
│ docker-compose.yml
│
├─data
│ │
│ └─www
│   　　│
│       └─vue-cli
│               dist
│  
├─nginx
│    Dockerfile
│    server.conf
│
└─vue
     Dockerfile
```

## Dockerfileを各ディレクトリで作成

まず、nginxとvueディレクトリを作成します。

```
mkdir nginx vue
```

次に、nginxディレクトリ内で、Dockerfileを作成、記述します。内容は以下の通り。

```Dockerfile(nginx)
FROM nginx:latest
  
RUN apt-get update && \
    apt-get install -y vim less
```

そのあと、同じくvueディレクトリ内にもDockerfileを記述。

```Dockerfile(vue)
FROM node:8.11.3-alpine
  
WORKDIR /app

RUN apk update && \
    npm install -g npm && \
    npm install -g vue-cli
```

両方やっていることは単純で、dockerイメージを取得後、最小限のコマンドを走らせているだけです。

## docker-composeファイルを作成

（docker-composeをインストールしていない場合は、まず先にインストールする必要があります。）

それぞれのDockerfileを作成できたら、ルートディレクトリ（vue_docker）にdocker-compose.ymlを作成します。

docker-compose.ymlファイルは、各コンテナを連結させて動かすための設定ファイルのようなもの。これがないとコンテナ起動時にとんでもなく冗長なコマンド入力が必須になります。

```ruby:docker-compose.yml
version: '3'
services:
  nginx:
    build: ./nginx
    ports:
      - '9000:80'
    volumes:
      - ./data/www:/var/www/html
      - ./nginx/server.conf:/etc/nginx/nginx.conf

  vue:
    build: ./vue
    volumes:
      - ./data/www:/app
    tty: true
```

内容について簡単に解説します。

services以下には、同時に起動させる各コンテナを指定します。今回は「nginx」、「vue」と記述していますが、自由に設定できます。

次にbuildについて。docker-composeでは、各Dockerfileを参照してコンテナを起動させます。その際、どのDockerfileを参照するのかをパスで指定してあげる必要があります。

なので、nginxコンテナはnginxディレクトリ内のDockerfileを、vueコンテナについてvueディレクトリ内のDockerfileのパスを指定してあげます。

portsは、ホスト側のポート（今回はmac）とコンテナ側のポートを連結させるパラメータです。'9000:80'と書けば、ホストマシンの9000番ポートとnginxコンテナの80番ポートが連結することになります。

最後にvolumesです。volumesは、ホスト側の指定したディレクトリと、コンテナ側の指定したディレクトリを同期させるパラメータです。

なぜ同期が必要かと言うと、コンテナはデータを永続的に保管することができず、コンテナを廃棄するたびに初期化されてしまうため。

つまり、コンテナを廃棄すると作業内容が丸々吹っ飛んでしまうため、ホスト側にデータを同期させて、永続的に保管できるようにしてあげる必要があるんですね。

また、新規にコンテナを作成した際には、ホスト側の同期しているディレクトリ内容を参照し、その状態を自動的に再現してくれるため、前回の作業状態のまま作業を開始できます。

## コンテナをbuildする

docker-compose.ymlを記述できたら、以下のコマンドを実行してコンテナを起動します。

```
docker-compose build
docker-compose up -d
```

dオプションはコンテナをバックグラウントで起動するオプションです。

無事にコンテナが起動しているかどうかは、以下のコマンドで確認できます。

```
docker-compose ps
```

「State」がUpになっていればOKです。「exit 1」などと表示される場合は、「docker-compose logs nginx」でログを見て、エラーの原因を確認しましょう。

```
      Name                Command          State          Ports        
-----------------------------------------------------------------------
vue_nginx_nginx_1   nginx -g daemon off;   Up      0.0.0.0:9000->80/tcp
vue_nginx_vue_1     node                   Up                          
```

## vueアプリケーションの作成

無事、コンテナが起動できたら、次はvueコンテナの中に入ってvueアプリケーションを作成します。以下のコマンドを実行してください。

```
docker exec -it vue sh
// コンテナ内に入れたら
/app # vue init webpack
/app # npm install                        
```

これで/app以下にvueアプリケーションが作成されます（lsコマンドなどで確認）。

続けて、「npm run build」を実行し、ビルドを行なっておきましょう。distディレクトリが新たに作成されていればOKです。

作成が完了したらexitコマンドでコンテナを脱出し、/vue_docker/data/www/以下にコンテナでの変更が反映されていることを確認しましょう。これは、docker-compose.ymlで設定したvolumesパラメータによるものです。

## nginxのserver.confファイルを編集

ここまででコンテナ内にvueアプリケーションを作ることができました。ただ、このままではnginx上でアプリケーションを動かすことができません。

その目的を達成するために、nginxのサーバー設定を行いましょう。

nginxディクレトリ以下にserver.confファイルを作成します。（ファイルの名前はdocker-compose.ymlのvolumesで設定したファイル名と一致させる必要があります）


```ruby:server.conf
user nginx;
  
events {
  worker_connections 2048;
  multi_accept on;
  use epoll;
}

http {
  charset UTF-8;
  server {
    listen 80 default;
    server_name localhost;
    root /var/www/html/dist;
    index index.html;
    charset utf-8;
  }
}                       
```

主要なパラメータの解説は以下。

listen 80：80番ポートを解放

server_name：このサーバーにアクセスする際のURL。

root：サーバー上で公開するディレクトリのルートパス

index：ルートURLにアクセスした場合に表示するファイルを指定

vueアプリケーションはビルド内容が/dist以下に展開されるので、rootもそれに合わせて設定する必要があります。

## localhost:9000にアクセスしてvueアプリケーションが表示されることを確認

最後に、localhost:9000にアクセスして、vueアプリケーションが表示されることを確認します。前もってvueコンテナ内でvue run buildを行い、ビルドを行なっておきましょう。

nginxの解放ポートは80番ですが、今回、ホストマシンとコンテナの連結は9000番ポートで行なっているので、localhostの後ろに9000をつける必要があります。

これでdockerを使って、nginx上でvueアプリケーションを動作させることができました。

また、vueコンテナ内でnpm run devを実行すれば、webpack-dev-server（ビルトインサーバー）を起動することもできます。

docker、nginxともにまだまだ勉強中ですが、どんどん使って慣れていきたいところです。