VirtualBox + Docker
環境で Node.js + Express
を動作させたときの手順メモ
検証環境
Windows10 Home Edition VirtualBox 5.2.22 Docker version 18.05.0-ce, build f150324 docker-machine version 0.14.0, build 89b8332 docker-compose version 1.20.1, build 5d8c71b
パッケージインストールのためのイメージ作成
VirtualBox
の共有フォルダ内にパッケージをインストールしようとすると、シンボリックリンクが作成できずエラーになるため Docker
イメージ内にインストールする
node.Dockerfile
FROM node:8-alpine MAINTAINER takaya030 ENV HOME=/home/node RUN mkdir $HOME/app RUN chown -R node:node $HOME/* USER node WORKDIR $HOME/app RUN yarn add express && \ yarn add @types/express \ typescript ts-loader tslint tslint-loader tslint-config-airbnb \ webpack webpack-cli \ webpack-node-externals \ --dev
docker-compose.yml
version: "3" services: node: build: context: . dockerfile: ./node.Dockerfile image: takaya030/node:8-alpine
イメージのビルド
$ docker-compose build node
作成したイメージから package.json
と yarn.lock
を抽出
イメージからコンテナを作成し、 docker cp
でホストOS側にコピーする
$ docker run --name temp-node takaya030/node:8-alpine /bin/true $ docker cp temp-node:/home/node/app/package.json ./package.json $ docker cp temp-node:/home/node/app/yarn.lock ./yarn.lock
node.Dockerfile
の変更
インストールされるパッケージのバージョンを固定するため node.Dockerfile
を変更する
--- a/node.Dockerfile Sun Feb 10 18:26:36 2019 +++ b/node.Dockerfile Sun Feb 10 19:20:49 2019 @@ -4,14 +4,10 @@ ENV HOME=/home/node RUN mkdir $HOME/app +COPY package.json yarn.lock $HOME/app/ RUN chown -R node:node $HOME/* USER node WORKDIR $HOME/app -RUN yarn add express && \ - yarn add @types/express \ - typescript ts-loader tslint tslint-loader tslint-config-airbnb \ - webpack webpack-cli \ - webpack-node-externals \ - --dev +RUN yarn install + +ENV PATH=$PATH:./node_modules/.bin
変更後の node.Dockerfile
でイメージビルドできるか確認
$ docker-compose build node
各種設定ファイル
以下の各ファイルはこちらのサイトから引用させて頂きました qiita.com
webpack.config.dev.js
const path = require('path'); const nodeExternals = require('webpack-node-externals'); module.exports = { mode: 'development', entry: './src/server.ts', // src下に書いていくので src/server.tsにしとく target: 'node', // Module not found: Error: Can't resolve 'fs'とかいっぱい出たら、この行書き忘れ externals: [nodeExternals()], devtool: 'inline-source-map', module: { rules: [ { enforce: 'pre', loader: 'tslint-loader', test: /\.ts$/, exclude: [ /node_modules/ ], options: { emitErrors: true } }, { loader: 'ts-loader', test: /\.ts$/, exclude: [ /node_modules/ ], options: { configFile: 'tsconfig.dev.json' } } ] }, resolve: { extensions: [ '.ts', '.js' ] }, output: { filename: 'server.js', path: path.resolve(__dirname, 'dist') } };
webpack.config.prod.js
const path = require('path'); const nodeExternals = require('webpack-node-externals'); module.exports = { mode: 'production', entry: './src/server.ts', // src下に書いていくので src/server.tsにしとく target: 'node', // Module not found: Error: Can't resolve 'fs'とかいっぱい出たら、この行書き忘れ externals: [nodeExternals()], module: { rules: [ { enforce: 'pre', loader: 'tslint-loader', test: /\.ts$/, exclude: [ /node_modules/ ], options: { emitErrors: true } }, { loader: 'ts-loader', test: /\.ts$/, exclude: [ /node_modules/ ], options: { configFile: 'tsconfig.dev.json' } } ] }, resolve: { extensions: [ '.ts', '.js' ] }, output: { filename: 'server.js', path: path.resolve(__dirname, 'dist') } };
tsconfig.dev.json
{ "compilerOptions": { "sourceMap": true, "noImplicitAny": true, "module": "es6", "target": "es5", "jsx": "react", "lib": ["es2018", "dom"], "moduleResolution": "node", "removeComments": true, "strict": true, "noUnusedLocals": true, "noUnusedParameters": false, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "strictFunctionTypes": false } }
tsconfig.prod.json
{ "compilerOptions": { "noImplicitAny": true, "module": "es6", "target": "es5", "jsx": "react", "lib": ["es2018", "dom"], "moduleResolution": "node", "removeComments": true, "strict": true, "noUnusedLocals": true, "noUnusedParameters": false, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "strictFunctionTypes": false } }
tslint.json
{ "extends": "tslint-config-airbnb", "rules": { "ter-indent": [true, 4] } }
src/server.ts
こちらはサンプルのソースコードになります
import * as Express from 'express'; const app = Express(); app.get( '/', (req: Express.Request, res: Express.Response) => { return res.send('Hello world.'); }); app.listen( 3000, () => { console.log('Example app listening on port 3000!'); }); export default app;
ビルドと実行
docker-compose.yml
の変更
ビルドと実行のための設定を追加します
--- a/docker-compose.yml Mon Feb 11 11:43:19 2019 +++ b/docker-compose.yml Sun Feb 10 23:14:41 2019 @@ -5,3 +5,9 @@ context: . dockerfile: ./node.Dockerfile image: takaya030/node:8-alpine + volumes: + - .:/home/node/app + - /home/node/app/node_modules + ports: + - "3000:3000" + command: node dist/server.js
ビルド
$ docker-compose run --rm node webpack --config webpack.config.dev.js
実行
$ docker-compose up -d
web ブラウザで http://192.168.99.100:3000 を開いて "Hello World." が表示されれば成功です