【Docker超入門】angularが動くコンテナを作成しよう!

【Docker超入門】angularが動くコンテナを作成しよう!

これは、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のコンテナを作っていきましょう。まずは、大まかな手順を説明します。

  1. angularのプロジェクトを作成する
  2. angularをbuildする
  3. expressでbuild後のappをホスティングする
  4. Node.jsが動くdockerコンテナを作成する(Dockerfileの作成)
  5. 4のコンテナの中に2と3のアプリを配置する
  6. コンテナの起動時にexpressを起動するように設定する
  7. docker imageを作成する
  8. 7を元にコンテナを作成して、port:8000で接続できるようにする
  9. 動作確認

このような順番でごく簡単な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を実装しましょう!

docker/docker-composeにおけるコンテナ間通信を実装する