Docker上にVue.jsの開発環境を構築する方法。docker-composeで簡単に作成する手順

vue-js-prograshi(プロぐらし)-kv Docker
記事内に広告が含まれていることがあります。
[PR]

dockerを使ってvue.jsの開発環境を簡単に構築できるようにする方法についてです。

本番に応用できるよう、DockerfileのENTRYPOINTでコンテナ内のスクリプトを実行しています。また、実行はdocker-composeを使用しています。

実行順序は docker-composeファイル -> Dockerファイル -> スクリプトファイル です。

複数人のプロジェクトを想定して、作成したファイル群をgithubにアップして、git cloneしvue.jsの開発環境を立ち上げるところまでの手順になります。


Dcokerのインストール

Dockerの公式ページからOSに合ったDockerをインストール

Get Docker
Download and install Docker on the platform of your choice, including Mac, Linux, or Windows.

設定が完了したら、正しくインストールされているかターミナルで確認。

$docker -v
Docker version 19.03.12

$docker-compose -v
docker-compose version 1.26.2

dockerとdocker-composeのバージョンがそれぞれ表示されたらOK。


Dockerfileの作成

環境開発時のコマンドはdocker-composeで実行するが、独自のイメージを作成(build)する際に、Dockerfileを指定する。

Dockerfileはコンテナ内の処理となる。

プロジェクトフォルダを作成したい階層に移動。
ここでは、PJのルートディレクトリとしてvuecliを作成する。

#vuecliフォルダを作成し移動
$ mkdir vuecli && cd vuecli

#Dockerfileを作成
$ touch Dockerfile

#vimエディタでファイルを開く
$ vi Dockerfile

▼vimエディタの超基本コマンド

  • 貼り付け:p
  • インサートモード: i
  • インサートモード終了: esc
  • 保存して終了: :wq



▼Dockerファイルの内容
Dockerfileは拡張子不要。
Dockerfileには下記を記述。

#nodeイメージをpullする
FROM node:10.15.3-alpine

#working directory
WORKDIR /app

#vuecliインストール
RUN npm install -g @vue/cli

#shファイルをコンテナにコピー
COPY ./scripts/docker.start.sh /scripts/start.sh

#shフォルダの権限追加(全員実行可)
RUN chmod +x /scripts/*

#初期実行
# ENTRYPOINT [ "/scripts/start.sh" ]

Dockerfileはイメージを作成するための元となるファイル。

FROM イメージ名:タグ

継承のような機能。指定したイメージを取得し、以下に続く処理を実行する。

タグはバージョンを指定。記載しない場合は最新版(latest)が選択される。

イメージの取得は、まずdocker公式の共有イメージ置き場であるdockerhubで該当するものがあるか探す。ない場合はローカルのDocker内のイメージを探す。

(補足) node:10.15.3-alpineとは?
本当はvue-cliのイメージを取得したいが、現状dockerhubにはないため、nodeのイメージを取得する。

バージョンは10.15.3、OSはlinux alpineを選択。

linux alpineは軽量のOS。dockerのイメージで見かけることが多い。注意点としてはbashファイルが存在せず、shファイルのみとなること。(後々の記述に影響)

WORKDIR パス

コンテナ内のワーキングディレクトリの指定。

デフォルトではルートディレクトリ(/)が指定されているが、WORKDIRで変更することができる。

RUN コマンド

コンテナ内で実行するコマンドを記述。
「npm install -g @vue/cli」で、vueを操作するコマンドラインインターフェース(cli)をインストールする。

exec形式(配列でコマンドと引数を順に記述)での記述も可能。例えば上のコマンドだと、
RUN ["npm", "install", "-g", "@vue/cli"]

COPY ホスト内パス コンテナ内パス

ホスト内のファイルをコンテナの指定したパスにコピーする。
親フォルダが存在しない場合は自動で作成される。

コンテナ内のシェルスクリプトでコマンドを実行する仕様とするため、予めホスト内でコマンドを記述したシェルスクリプトを作成しておき、それをコンテナ内にコピーする。(シェルファイルの作成は後ほど)

シェルスクリプトに実行権限を与え、ファイルパス指定で実行できるようにする。
「RUN chmod +x /scripts/*」で権限を付与。

実行権限を与えない場合は、shコマンドでないと実行できない。「$sh シェルスクリプトパス」

ENTRYPOINT [ "コマンド", "引数",,]

ENTYPOINTはコンテナ初回起動時に実行するコマンド。

コンテナ内のスクリプトファイルのパスを指定することで、コンテナ初回起動時に指定したスクリプトを実行できる。


(補足)ENTRYPOINTCMDの違い

ENTRYPOINTCMDはどちらもコンテナ初回実行時に実行するコマンド。

どちらか一つは必ず必要で、記述がないとエラーになる。

ENTRYPOINTとCMDもexec形式(配列のような形)でコマンドを渡せる。その際、引数の扱いが異なる。

  • ENTRYPOINT: 引数の変更はできない。追加の引数として処理する。
  • CMD: 引数に変数を指定できる(状況に合わせて変更可能)

コマンドの記述でよく見る例
  • CMD [ "/bin/sh" ] : shファイルを実行
  • CMD [ "/bin/bash" ] : bashファイルを実行
  • CMD [ "npm", "run", "serve" ] : 「$npm run serve」コマンドを実行(vue.jsのサーバー起動)


シェルスクリプトの作成

ローカルのPJルートディレクトリにscriptsフォルダを作成し、シェルスクリプト「docker.start.sh」を作成する。

#scriptsフォルダとシェルファイルを作成
$mkdir scripts && touch ./scripts/docker.start.sh

#vimエディタで開く
$vi ./scripts/docker.start.sh

▼シェルスクリプトの記述内容

#!/bin/sh

#node_modulesインストール
echo "npm install"
npm install 

#vue起動
echo "npm run serve. "
npm run serve

#メモを出力
echo "localhost:18080"

※(補足)シェルスクリプトの利用について
指定のシェルスクリプトを使用せず、DockerfileのみでCMD ["npm","run","serve"]でも実行できるが、

実際の開発で、開発環境と本番環境でインストールするライブラリを変更するなど、条件分岐(if)などを使うことを想定。


docker-compose.ymlの作成

docker-composeは複数のコンテナでプロジェクトを立ち上げる時に使う。

例えば、①ruby on rails, ②PostgreSQL, ③Redis, ④Sideqikのコンテナをまとめて立ち上げることができる。

docker-composeで立ち上げたコンテナは自動で独自のネットワーク(コンテナ同士の関連づけ)が設定される。

docker-composeファイルの拡張子はyml(ヤムル)なので、ヤムルの仕様に沿って記述する。

まずはPJのルートディレクトリにファイルを作成する。

#ファイル作成
$touch docker-compose.yml

#vimエディタで開く
$vi docker-compose.yml

▼docker-compose.ymlの記述内容

#docker-composeのバージョンを指定
version: "3.7"

volumes:
    #volumeはホストにコピー or 表示させないもの
    ##バイナリファイル(node_module)など、OS依存があるもの

    #node_moduleを入れるvolume
    vue-cli-node-volume: 

services:
    #コンテナ詳細
    app:
        image: vuecli:1
        build:
            context: .
            dockerfile: Dockerfile
        container_name: vuecli3
        ports:
            - "18082:8080"
        volumes:
            #node_moduleを入れるボリューム
            - vue-cli-node-volume:/app/node_modules

            #コンテナ内の指定ディレクトリをホスト側と同期
            - .:/app/

        #-it
        stdin_open: true
        tty: true

version:"メジャーNo.マイナーNo"

docker-composeのファイルフォーマットのバージョンを指定する。versionにより記述方法に違いがあるため注意。今回は3.7を指定。

マイナーNoを記述しない場合、0に置き換わる。
例: version:”3″ = version:”3.0″

>ファイルフォーマットとdocker-composeのバージョンの対応表
https://matsuand.github.io/docs.docker.jp.onthefly/compose/compose-file/compose-versioning/

volumes:

トップレベルに「volumes:」を記述すると、指定したvolume名を各コンテナで共有できるようになる。

volumeを使用すると、指定したコンテナのディレクトリやファイルをホストのdockerのストレージに保存する。

▼volumeの使い方

volumeの使い方は大きく3つ。


(1)ホスト側のPJルートディレクトリと同期する

コンテナ内のワーキングディレクトリと、PJのルートディレクトリを同期することで、viewファイルやsrcなどがリアルタイムで同期できる。

- .:/app/ (ホスト側のパス:コンテナ側のパス)
上記例では、コンテナのワーキングディレクトリ/app/を、ホスト側のdocker-composeを実行するディレクトリに同期している。

(2)ホスト側にコピーしたくないファイルやディレクトリの指定。

volume名を指定することで、.dockerignoreファイルと組み合わせ、ホスト側に同期させないようにすることができる。

例えば、バイナリファイルが該当する。
バイナリファイルはバイナリ(0,1)で書かれたPC用のテキストファイルでOS毎に内容が異なる(依存性がある)。

コンテナ内にインストールしたnodeはLinux用なので、ホスト側のOSと一致しない場合に不具合を起こす。なので、nodeの入ったnode_modulesはホスト側のPJディレクトに同期させないようにする。(.dockerignoreファイルと合わせて使う)


(3) 同期除外しなくてもいいが、ホスト側にも特に必要ないファイルやディレクトリ

ログファイルなどログ分析用ファイルに同期している場合はホストのPJディレクトリに同期する必要はない。

volumeの記述方法

volumesの記述はホスト側:コンテナ側
実際の記述方法は大きく3つ。

(1)コンテナ側のパスのみ
./logs
/var/lib/mysql

ホスト側のパスを記述しない場合、コンテナ内の指定したフォルダはホストのvolume内のどこかに保存される。

呼び出す必要もないファイルやディレクトリに使う。

(2) ボリューム名で指定
node_volume: ./node_modules

ホスト側をボリューム名で記述する方法。この場合、docker内に指定したボリューム名のディレクトリが作成され、その中に指定したフォルダやファイルが保存される。

ホスト側のPJディレクトリに保存したくない場合に使用。(.dockerignoreを合わせて使う)

(3) パスで指定
./cache:/tmp/cache

パスで指定することも可能。
上記例では、ホスト側を相対パス、コンテナ側を絶対パスで指定。

sevices:

コンテナと使用するイメージを設定する。
今回はappコンテナのみ作成。

image: イメージ名:タグ

コンテナ作成のために使用するimageを指定する。
タグはバージョン。記述しない場合はlatestとなる。

buildがある場合は、buildに記載の内容からイメージを作成する。buildの指定がない場合は、dockerhub、ローカルの順にイメージを探す。

build

イメージを作成するためのDockerfileを指定する。
記述方法は2つ。

(1)Dockerファイルのパスとファイル名で指定

build:
  context: Dockerファイルのパス
  dockerfile: ファイル名


(補足)Dockerfileのファイル名について

Dockerfileのファイル名は「Dockerfile」に限定する必要はない。指定ディレクトリの拡張子のないファイルを構築用ファイルとみなす。

誰が見てもわかりやすいように「Dokerfile」を記述するのが一般的。

▼ファイル名の例

  • Dockerfile
  • Dev.Dockerfile
  • Dockerfile-2

(2)ファイルのパスで指定
構築用ファイル(拡張子のないファイル)がディレクトリに1つのみのとき、ディレクトリパスのみの指定もできる。

build: Dockerファイルのパス

container_name:

作成したコンテナの名前を指定する。
「docker ps -a」 でコンテナの一覧を出した時に表示される名前。

ports: - ホスト側:コンテナ側'

ポートの指定。複数設定することも可能。

「- “18082:8080″」の場合、コンテナ側の通信ポート8080と、ホスト側の18082ポートをつなげる。

ホスト側のブラウザにlocalhost:18082と打ち込むと、コンテナ内で開発用サーバーを立ち上げた時に表示されるlocalhost:8080に接続する。

stdin_open: true

コンテナ起動時のオプション。標準入力(standard in)を許可する。
コンテナ内のOSとbash(sh)を通してコマンド入力する場合に必要。

Dockerのコマンドでは「-i」

tty: true

コンテナ起動時のオプション。標準出力用の擬似ターミナルを起動する。
コンテナ内のOSとbash(sh)を通してコマンド入力する場合に必要。

Dockerのコマンドでは「-t」
基本的に「-t」と「-i」はセット(-it)で使う。


.dockerignoreの作成

ホスト側に同期したくないファイルやディレクトリのパスを記述する。(.gitignoreと同じ機能)

#ファイルの作成
touch .dockerignore

#vimエディタで開く
vi .dockerignore

▼.dockerignoreの内容

#node_modulesは同期しない
node_modules

コンテナ作成を実行すると、ローカル内にnode_modulesという空のフォルダが自動作成される。コンテナ内の同じフォルダの内容を同期しなくなる。


aliasの作成

ここまでで、ようやくイメージとコンテナを作成するために必要なファイルが揃った。

  • docker-compose.yml
  • Dockerfile
  • docker.start.sh
  • .dockerignore

この時点でdocker-composeを実行することもできるが、本番を見据えてdocker-composeコマンドのaliasを作成することで、より簡単に操作できるようにする。

作成の流れは、aliases.shファイルを作成しコマンドを記述。bash_profileでファイルを読み込み、bash_profileをリロード。

#ファイルを作成
$ touch aliases.sh

#vimエディタで開く
$ vi aliases.sh

▼aliases.shの内容

#イメージの作成とコンテナ起動
alias vue-pj="docker-compose up --build app"

#コンテナ内のshファイルを起動
alias vue-exec="docker exec -it vuecli3 sh"

alias ショートカットコマンド="本来のコマンド
イコールの前後にスペースがあるとエラーになる。

docker-compose up --build app
「docker-compose up [サービス名]」:指定したサービスの内容を実行。イメージがない場合はビルドし、コンテナを起動する。

イメージが既に存在する場合は上書きせず、それを使用する。

docker-compose.ymlの変更内容を反映したいため、「–build」オプションをつけることで、イメージが存在しても再度イメージを構築する。(docker-compose build && docker-compose up appと同じ)

▼サービス名の指定がない場合
サービス名を指定しない場合は、記述してある全てのコンテナを起動する。

今回の環境では、appの指定がなくても同じ挙動となるが、実際は開発環境や本番環境で立ち上げるコンテナを切り替えることがあるためあえて指定。

▼「-d」オプション
-dオプションをつけると、バックグラウンドモードでの起動となり、bash(or sh)が起動しない状態となる。
コンテナ内の実行内容が見えなくなってしまうため、今回は付けない。

docker exec -it コンテナ名 sh
指定したコンテナのシェルを立ち上げる。コンテナ内がbashの場合はshではなくbashを指定。

今回はlinux alpineのためshを指定。


aliasファイルの読み込み

作成したaliasが使えるように、bashで読み込む。

#bash_profileをvimエディタで開く
$ vi ~/.bash_profile

▼bash_profileの内容

#作成したファイルを読み込み(フルパスで記述)
source /Users/.../vuecli/aliases.sh 
#bash_profileのリロード
$ source ~/.bash_profile

#aliasの確認
$ alias
alias vue-exec='docker exec -it vuecli sh'
alias vue-pj='docker-compose up --build app'

作成したaliasが表示されていればOK。

bash_profileとは?

bash_profileはシェルをbashで起動したときに読み込まれるファイル。

設定したaliasはシェルを閉じると消えるが、bash_profileに記述することで毎回自動でロードされる。

似たファイルで、より高頻度でロードする、.bashrcというのもある。


docker-composeの実行

いよいよdocker-composeを実行し、イメージとコンテナを作成する。

docker-compose.ymlのあるディレクトリで先ほど設定したコマンドを実行。

vue-pj

これで、コンテナ内にnode.jsとvue-cliがインストールされる。


コンテナ内に入る

コンテナ内でvue-cliを使ってvue.jsの開発環境を作成するため、先ほど作成したaliasでコンテナないのシェルを起動する。

vue-exec
/app #

/app #と表示されれば、docker内に作成したワーキングディレクトリでコマンドを打ち込める状態になっている。


vueの開発環境を作成する

/app #vue create -d pj

vue create プロジェクト名
ここではプロジェクト名をPJとして実行。
オプションの「-d」はデフォルト設定(bavelとeslint)で作成。

「-d」を記述せず、vue-cliの対話モードでオプションを選択してくこともできる。


ファイルの移動と削除

vue createを実行するとフォルダは指定したプロジェクト名のフォルダの中に作成される。

ホスト側のプロジェクトファイルのルートディレクトリとコンテナ内のワークディレクトリを同期させたいため、コンテナ内のプロジェクトフォルダの中身を一階層上に上げる。

.dockerignoreに記述しているnode_modulesは同期するディレクトリに移動できないため、一度削除し再インストールする。

まず、コンテナ内のvue-cliが立ち上がっているので、ctrl + cでいったん終了し、コンテナ内のシェルに戻る。

#pjフォルダを一階層上に移動(隠しファイル含む)
##gitignoreのnode_moduelsは移動できない
mv -f ./pj/* ./pj/.* .


<br>
##node_modulesファイルを削除し、再インストール
rm -r pj && npm install 

##yarn関連ファイルを削除。
rm *yarn* 


##コンテナ内を確認
/app # ls
Dockerfile          node_modules        scripts
aliases.sh          package-lock.json   src
babel.config.js     package.json
docker-compose.yml  public

ホスト側にコンテナ内のファイルが反映されていればOK

image.png


vue開発環境の確認

これで自分のPCでの開発環境の設定が完了したので、実際にWEBページが開けるか確認する。

npm run serveでサーバーを再起動できるが、dockerの練習も兼ね一旦コンテナから出て確認してみる。

#コンテナから抜ける
/app # exit

#起動中のコンテナを確認
$docker ps -a

CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                                            NAMES
ebe0276cb7f0        vuecli:0                    "/scripts/start.sh"      36 minutes ago      Up 4 minutes        0.0.0.0:18080->8080/tcp                          vuecli
#イメージを確認
$docker images
REPOSITORY                                      TAG                 IMAGE ID            CREATED             SIZE
vuecli                                          0                   c6a23f947246        32 hours ago        338MB

#イメージの詳細
$docker image inspect vuecli:0

docker-compose.ymlに記述したコンテナ名とイメージ名のコンテナとイメージがそれぞれ存在していることがわかる。

WEBページを確認するため、再びコンテナ内に入る。

#コンテナ内に入る
$vue-exec

#サーバーを起動
/app # npm run serve


App running at:
  - Local:   http://localhost:8080/

  It seems you are running Vue CLI inside a container.
  Access the dev server via http://localhost:<your container's external mapped port>/

上記が表示されればサーバーの起動完了。

WEBブラウザでページを表示する。
docker-composer.ymlで設定したホスト側のポートを入力。
localhost:18082

WEBページが表示されれば成功。


githubに作成したファイル群をプッシュ

このままでは自分しか使えないため、複数人で開発を進められるようgithubのリモートレポジトリに作成したファイル群をプッシュする。

githubのレポジトリを指定してアップする。

git init
git commit -m "first commit"
git branch -M master
git remote add origin https://github.com/(レポジトリのフルパス)
git push -u origin master


他のプロジェクトメンバーのローカルで実行する

前提条件として、dockerとdocker-composeが入っていること。

#リモートレポジトリをclone
##クローンした際のフォルダ名をvuecli(任意)としている。
$git clone https://github.com/(レポジトリのフルパス) vuecli

#フォルダ移動
$cd vuecli

aliasファイルの読み込み

作成したaliasが使えるように、bashで読み込む。

#bash_profileをvimエディタで開く
$vi ~/.bash_profile

▼bash_profileに以下を記述

#作成したファイルを読み込み(フルパスで記述)
source /Users/.../vuecli/aliases.sh 
#bash_profileのリロード
$source ~/.bash_profile

#aliasの確認
$ alias
alias vue-exec='docker exec -it vuecli sh'
alias vue-pj='docker-compose up --build app'

#イメージとコンテナ作成
$vue-pj

省略
App running at:
  - Local:   http://localhost:8080/

  It seems you are running Vue CLI inside a container.
  Access the dev server via http://localhost:<your container's external mapped port>/

上記が表示されればサーバーの起動完了。

WEBブラウザでページを表示する。
docker-composer.ymlで設定したホスト側のポートを入力。
localhost:18082

WEBページが表示されれば成功。

以上。

タイトルとURLをコピーしました