これは、LCNEMでの自由研究の成果をまとめたHandsOnです。"Dockerとは"と言ったとこらへんから始めて、実際に動くサーバーを立ててangularの本番環境さながらのコンテナを手元で作成することがゴールです。docker-comoseは使わず一つのコンテナだけを作成します。
ホストOS(あなたのpc)の環境
- Node.js
- brew
- @angular/cli
- docker(一応インストール方法は書いてます。)
Dockerとは
Dockerとは、簡単にいうと今使ってるpcとは無関係に動かすことのできる箱を作って色々できるものってイメージです。
たぶんわからないので、ググってみましょう。
この辺りを読んでみるとイメージが湧きそうです。
で、俺なりのdockerのメリットをあげると、環境に依存せずかつimageがあればすぐに確実に起動できることです。
さっきも言ったように今使ってるpcとは無関係に動かせるので、手元のpcで動けばそのまま本番の環境でも動かすことができます。これはデプロイを経験したことがあったらめちゃくちゃありがたいと思えます。
きっと、実際にコンテナを作成する段階でlinux環境を使うので痛感できるはずです。笑
そして、手元のpcで作ったコンテナをほぼそのまま任意のdockerが搭載されたpcで動かすことができます。このときに登場するのがdocker imageです。
Dockerfileというのを書いてそれをbuildすることでdocker imageが得られます。他の人が作ったものをpullしてくることもできます。このdocker imageというのはコンテナ(=実際に動くやつ)のテンプレートのようなものです。
Install
もしdockerがインストールされてなかったらインストールしましょう。
$ brew cask install docker
$ open /Applications/Docker.app
でいけるみたいです。(Mac)
他の環境の人は随時調べて頑張って入れてください。
Let's start!
それでは、実際にdockerのコンテナを作っていきましょう。まずは、大まかな手順を説明します。
- angularのプロジェクトを作成する
- angularをbuildする
- expressでbuild後のappをホスティングする
- Node.jsが動くdockerコンテナを作成する(Dockerfileの作成)
- 4のコンテナの中に2と3のアプリを配置する
- コンテナの起動時にexpressを起動するように設定する
- docker imageを作成する
- 7を元にコンテナを作成して、port:8000で接続できるようにする
- 動作確認
このような順番でごく簡単なDockerfileを書いてコンテナを作成していきます。
まずは完成版を触ってみる
とりあえず、docker imageやdockerコンテナのイメージを掴むために僕が作った完成版を触ってみましょう。
$ docker pull dragontaro/angular:latest
$ docker run -d -it --rm -p 8000:8000 --name sample dragontaro/angular:latest
localhost:8000にブラウザからアクセスしてみましょう。コマンドは今はわからなくて大丈夫です。
次にコンテナの中に入ってみましょう。
$ docker exec -it sample /bin/bash
root@624a0ad165da:/var/www/app#
こんな感じになったら成功です。中をいろいろ触ってみましょう。(ls
とかpwd
とか)
なんとなくイメージが掴めたら次に進みます!
angularプロジェクトを作成する
ここは本筋とは関係がないのでさらっといきます。
$ cd [angularプロジェクトを置いてるディレクトリ]
$ ng new angular-docker
$ cd angular-docker
これで作れます。今回はng serve
は特に使いません。
build後に以下のような配置になるようにしたいので少し設定ファイルを編集していきます。
angular.json
のbuild後のpathを指定している部分を以下のように書き換えます。
"build": {
...
"options": {
"outputPath": "dist/angular-docker",
↓
"build": {
...
"options": {
"outputPath": "dist/src",
必要であれば、.gitignoreも
/dist
↓
/dist/src
と変更しましょう。
$ ng build
を実行してみて思い通りの挙動になっているかを確認してみましょう。
expressでbuild後のappをホスティングする
expressとはNode.jsで簡単にサーバーが構築できる軽量なライブラリーです。
興味があれば調べてみてください。ちなみに僕も今回が触ったのは初めてです。
今回は以下のコードをdist/server.js
に配置してください。
const express = require('express');
const app = express();
app.use(express.static('src'));
app.listen(8000, function() {
console.log('Example app listening on port 8000!');
});
で、
$ npm i express --save
$ node dist/server.js
これで、localhost:8000にホスティングできます。(確認してみましょう)
Node.jsが動くdockerコンテナを作成する
さあ、いよいよDockerfileを書いていきましょう!
今回はdebianというosのコンテナの中に構築していきます。osをインストールするところからやらなくても、debianの公式imageを使うことでdebianがすでに動く状態から始めることができます。これがdockerのすごいところでもあります。(ほんとはnodejsのイメージからでも作成できるけど今回は練習をかねてそれは使いません。)
プロジェクトのrootにDockerfile
を作成し、そこに
FROM debian
# debianに入っているpackageのupdateとcurlコマンドとwgetとgnpupg?のインストール
RUN apt-get update && apt-get install -my curl wget gnupg procps -y
と記述します。コメント行はなくても動きます。
これを説明していくと、まずFROM
でベースとなるdocker imageを指定します。
RUN
と書くとbuild(=docker imageの作成)のときに実行されるコマンドを記述できます。通常は、必要なもののインストール(今回だとpackageのupdateと必要なcurlなどのコマンドのインストール)を行うように指定します。apt-getはbrewみたいな感じでパッケージマネージャーです。
ここまでできたら、実際に動かしてみましょう。
$ docker build ./ -t angular
これでimageがビルドされます。最初は依存imageのダウンロードなどが入るので結構時間がかかります。2回目以降はキャッシュが有効なのでも少し早くなります。
buildの引数にどこのDockerfileを使うかを指定します。今回はカレントディレクトリのDockerfileを使っています。-t
はimageのタグの指定です。angular
と命名して扱いやすくしています。
buildが終わったら、コンテナを起動しましょう。
$ docker run -d -it --rm --name angular-container angular
起動が少しややこしいです。-d
でdaemon実行(バックグラウンド)、--rm
でコンテナの終了と同時に消すオプション指定、--name
で命名して扱いやすく、で最後のangularがrun
の引数で使用するimageの指定です。-it
はややこしいのでこれをつけないとコンテナが終了したり入れなくなると思ってください。
これで、コンテナがバックグラウンドで起動したはずです。確認してみましょう。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
07f32e6c0986 d8c2e45ffaab "/bin/sh -c 'node se…" 2 hours ago Up 2 hours angular
(COMMANDが違うと思うけど気にせず!)
STATUSがUpになっていたら成功です。コンテナの中に入ってみましょう。
$ docker exec -it angular-container /bin/bash
これで入れます。exec
はコンテナ内に入るためのコマンドで、
$ docker exec [コンテナ名 or ID] [実行するコマンド]
と、引数を2個とります。今回は、/bin/bash
を実行して入ったときにbashのシェルが開くようにします。エラーが出なければ中に入れています。curl
などさっき入れたコマンドが動くか試してみましょう。
さて、長くなってしまいましたが、ここからはスピードをあげていきましょう。次はNode.jsのインストールです。
debianのNode.jsのインストール方法を調べてそれに習えばおkです。
# node.jsのインストール(参考: https://github.com/nodesource/distributions/blob/master/README.md#installation-instructions)
RUN curl -sL https://deb.nodesource.com/setup_11.x | bash - \
&& apt-get install -y nodejs
Dockerfileに追記します。
で、buildするのですが、同じコマンドを何回も打つのが面倒なのでMakefileを書きましょう。書き方は適当に調べてください。windows以外はデフォで動くはず。。
build:
docker build ./ -t angular
run:
docker run -d -it --rm --name angular-container angular
exec:
docker exec -it angular-container /bin/bash
kill:
docker kill angular-container
で、
$ make build
$ make run
$ make exec
これで中に入ってnodeが入ってるか確認してみましょう。もしかしたらmake kill
でコンテナを終了&削除しないとコンテナの名前が競合するかもです。
$ make exec
docker exec -it angular-container /bin/bash
root@07f32e6c0986:/# node -v
v11.8.0
こんな感じになってたらおkです。
コンテナ内にアプリを配置する
buildしたファイルたちとserver.jsをコンテナ内に配置しましょう。全て、./dist
配下に存在しているので、それをコピーするだけです。
# /var/wwwにアプリケーションを設置するために移動
WORKDIR /var/www/app
# buildされたファイルをホストOSからコンテナ内の/var/wwwに持ってくる
COPY ./dist .
# expressをinstallする
RUN npm install express
これでやりたいことが実現できます。
少し説明すると、WORKDIR
でアプリを設置したい場所に移動しています。cd
でもいいのですが、みやすさとコンテナ内に入ったときのディレクトリも変更できるためWORKDIR
を使っています。
で、移動した先にCOPY [ホストOSのパス] [コンテナ内のパス]
という形で/dist
以下を設置して、最後にexpressがないとサーバーが動かないのでインストールしています。
ここまでできたら、
$ make build
$ make run
$ make exec
で、もう一度中に入ってみましょう。ログイン先が変わってるはずです。
root@624a0ad165da:/var/www/app# node server.js
Example app listening on port 8000!
サーバーを起動できたら成功です!
コンテナの起動時にサーバーを起動しport:8000で接続できるようにする
ほぼ完成しているのですが、毎回手動でサーバーを起動するのが面倒なのとコンテナ外から接続できないと意味がないのでその設定をやっていきます。
まずはDockerfilに追記します。
# コンテナ起動時にserverを起動
CMD node server.js
これで、docker run
のときに自動的にサーバーが起動してくれます。CMD
はコンテナ起動時に実行するコマンドです。
次にdocker run
コマンドのオプションを追加します。Makefileにて、
run:
docker run -d -it --rm -p 8000:8000 --name angular-container angular
と変更しましょう。これは、ホストの8000にアクセスがあったらコンテナの8000に繋ぐよっていうオプションです。これを指定することで外部との接続ができます。(EXPORSE的なのでもできるはず)
で、
$ make build
$ make run
として、ブラウザでlocalhost:8000を確認してみましょう。
angularの初期画面が表示されていたら成功です!お疲れ様でした。
最後に
実際の開発では...
今回は簡単のためにDockerfileを書く→buildして実行としていましたが、実際に書くときは手元にベースイメージのコンテナを作成→そこでコマンドを実行→うまくいったやつをDockerfileに記述とした方が良さそうです。(実際に僕は今回そうしました)
デバッグのしやすさの観点からそのようにした方がいいと思われます。
課題
今回はNode.jsのexpressでホスティングしましたが別にNode.jsがなくてもbuild後のangularは動作します。
なので、他の言語でホスティングしてみましょう。pythonやgolangなんかはどうでしょう。nginxでindex.htmlだけを表示するのもいいかもですね。
コードはこちら
Dragon-taro/docker/tree/master/angular-docker
次は、コンテナ間の通信やdocker-composeを実装しましょう!