はじめに
Docker は、軽量で仮想化された、ポータブルな、ソフトウェア定義の標準化された環境であるコンテナプラットフォームです。これにより、物理ホストマシン上で実行されている他のソフトウェアから隔離された状態でソフトウェアを実行できます。Dockerは、ソフトウェア開発における継続的開発および統合(CI/CD)の側面を定義する重要なコンポーネントです。これは、仮想マシンに代わる軽量な選択肢 を提供し、開発者が分散アプリケーションアーキテクチャを利用できるようにします。Dockerエコシステムの詳細な概要については、こちらの記事をご覧ください.
Dockerを使用してアプリケーションを構築するプロセスは、開発者がアプリケーションのイメージを作成することから始まります。その後、そのイメージがコンテナ内にデプロイされます。イメージには、アプリケーションコード、ライブラリ、設定ファイル、環境変数、ランタイム環境など、アプリケーションを定義するコンポーネントが含まれています。イメージはコンテナ内の環境を標準化し、コンテナ化にポータビリティ(移植性)の特徴をもたらします。Node.js は、Webブラウザの外でJavaScriptコードを実行できる、オープンソースでクロスプラットフォームのバックエンドJavaScriptランタイム環境です。これは、ChromeのV8 JavaScript Engine. Express.js は、Node.js上で動作するミニマリストなバックエンドJavaScriptフレームワークです。
このチュートリアルでは、Expressフレームワーク上で動作するWebサイトのイメージを作成します。フロントエンドの見た目を良くするために、フロントエンドライブラリである Bootstrap を使用します。イメージを作成したら、コンテナをビルドして Docker Hub にプッシュします。Docker Hubを使用すると、開発者はコンテナ化されたアプリケーションをホストして、任意のDocker環境に簡単にデプロイできます。コンテナがDocker Hubにホストされたら、それをプルして、実際にWebサイトを提供する別のイメージをビルドします。
前提条件
これは実践的なチュートリアルです。手順に沿って進められる環境を作成してください。
- 初期の動作環境として、Ubuntu 20.04がインストールされている必要があり、またsudo権限を持つ非ルートユーザーを作成する必要があります。非ルートユーザーでログインし、次の手順に進んでください。
- Dockerをインストールする必要があります。私たちのチュートリアル「UbuntuでDockerをインストールして操作する方法」のステップ1、2、3、4に従ってください。これは、どのUbuntuディストリビューションでも機能するはずです。
- Docker Hubアカウントをお持ちでない場合は、作成してください。こちらのリンクからDocker Hubクイックスタートガイド.
- Node.jsとNPMをインストールします。NPMはJavaScriptのパッケージマネージャーです。インストールについては、Nodeとnpmのインストールに関するこちらの指示に従ってください.
ステップ1:アプリケーションの依存関係の設定
イメージを作成する前に、アプリケーションのソースコードを作成する必要があります。アプリケーションのソースコードには、コンテナにコピーされるコード、静的コンテンツ、および依存関係が含まれます。まず、非ルートユーザーのホームディレクトリにプロジェクト用のディレクトリを作成します。ここでは、そのディレクトリを「node_express」と呼びますが、お好みのディレクトリ名を使用して構いません:
|
1 |
mkdir node_express |
次に、このディレクトリに移動します:
|
1 |
cd node_express |
これがアプリケーションのルートディレクトリになります。node.js アプリケーションは、ルートフォルダに package.json ファイルがあることを想定しています。Npm はこのファイルを使用して、アプリケーションに必要な依存関係を決定します。次のコマンドを入力して、このファイルを作成します:
|
1 |
nano package.json |
その後、次のコードスニペットをファイルに追加します。名前、作成者、説明、およびエントリポイントファイルは、必要に応じて更新できます:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
{ "name": "node-express-docker-image", "version": "1.0.0", "description": "Nodejs Express Docker Image Example", "author": "hackins", "main": "index.js", "license": "ISC", "keywords": [ "nodejs", "express", "bootstrap" ], "dependencies": { "express": "^4.17.1" } } |
ご覧のように、このファイルはプロジェクト名、バージョン、作成者、およびアプリケーションコードが共有されるライセンスを指定します。プロジェクトには、次の場所での重複を避けるために、短くてわかりやすい名前を使用することをお勧めします:npmレジストリ。このプロジェクトには、ISCライセンスを指定しており、これによりアプリケーションコードの自由なコピー、変更、または配布が許可されます。
最も重要な点として、ファイル内の次のディレクティブに注意する必要があります:
- “
main」:このディレクティブはアプリケーションのエントリポイントを指定します。ここでは index.js に設定しています。このファイルは間もなく作成します。 - “
dependencies」:このディレクティブは、次のコマンドを実行したときに npm レジストリから取得されるアプリケーションの依存関係を指定します:npmコマンド。今回のケースでは、Express バージョン 4.17.1 以上が必要です。
Ctrl + O を押してファイルを保存できます。次に、Ctrl + X を押してファイルを閉じます。次に、以下のコマンドを実行して依存関係をインストールします:
|
1 |
npm install |
このコマンドは、次のファイルで指定されたアプリケーションの依存関係をインストールします:package.json ファイル。インストール先は次のディレクトリ内です:node_modules ディレクトリ。これらはコマンドを最初に実行したときに自動作成されます。アプリケーションの依存関係がインストールされたので、アプリケーションコードの追加を開始できます。
ステップ 2:アプリケーションコードファイルの追加
基本的なレシピウェブサイトを作成します。提供元は allrecipes です。アプリケーションのメインエントリポイントは、次のファイルです:index.js ファイル。次のディレクトリを追加します:views ディレクトリ。ここにはプロジェクトのさまざまなページや静的アセットが保持されます。ウェブサイトには、紹介情報といくつかのレシピへのリンクを含むランディングページが用意されます。
ランディングページのコードは、次のファイルに配置されます:home.html ファイル。まず、index.js ファイルを作成するために、次のコマンドを入力します:
|
1 |
nano index.js |
以下のコードを追加します。これは Express アプリケーションをインポートして作成します。また、Router オブジェクト、ベースディレクトリ、およびこのアプリが提供されるポートも指定します:
|
1 2 3 4 5 6 |
const express = require('express'); const app = express(); const router = express.Router(); const path = __dirname + '/views/'; const port = 8090; |
require はモジュールをロードする JavaScript 関数です。この例では、express モジュールをロードしています。次に、インポートしたモジュールを使用して express オブジェクトと router オブジェクトを作成します。router オブジェクトは、チュートリアルを進めるにつれてこのオブジェクトに追加される HTTP メソッド呼び出しに応答することで、アプリのルーティング機能を実行します。
また、path と port も設定しました。path 定数はコードのベースディレクトリを定義します。今回のケースでは、プロジェクトのルートディレクトリ内にある次のサブディレクトリです:views サブディレクトリ。また、port は express アプリがリッスンするポートを指定します。この例では、次のように設定しています:8090.
定数が用意できたら、次のオブジェクトを使用してアプリケーションのルートを指定できます:router オブジェクト。ルートを指定するために、次のファイルに以下のコードを追加します:index.js ファイル:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
router.use(function (req,res,next) { console.log('/' + req.method); next(); }); router.get('/', function(req,res){ res.sendFile(path + 'home.html'); }); router.get('/lasagna', function(req,res){ res.sendFile(path + 'lasagna.html'); }); router.get('/guacamole', function(req,res){ res.sendFile(path + 'guacamole.html'); }); router.get('/banana-bread', function(req,res){ res.sendFile(path + 'banana_bread.html'); }); |
You can ミドルウェアを追加するには、次の関数を使用します:router.use。この例では、ルーターのリクエストをアプリケーションのルートに渡す前にログに記録する関数を追加します。アプリケーションのベースに対する GET リクエストは、次のファイルを返します:home.html ページ。次に、特定のレシピページへのGETリクエストを使用して取得される、3つのレシピのページを追加しました。
最後に、次のコードを追加して、router ミドルウェアとアプリケーションの静的アセットをマウントします。さらに、expressアプリケーションに次のポートでリッスンするように指示します。8090:
|
1 2 3 4 5 6 |
app.use(express.static(path)); app.use('/', router); app.listen(port, function () { console.log('Nodejs Express Example App listening on port ' + port) }) |
完成した index.js ファイルは次のようになります。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
const express = require('express'); const app = express(); const router = express.Router(); const path = __dirname + '/views/'; const port = 8090; router.use(function (req,res,next) { console.log('/' + req.method); next(); }); router.get('/', function(req,res){ res.sendFile(path + 'home.html'); }); router.get('/lasagna', function(req,res){ res.sendFile(path + 'lasagna.html'); }); router.get('/guacamole', function(req,res){ res.sendFile(path + 'guacamole.html'); }); router.get('/banana-bread', function(req,res){ res.sendFile(path + 'banana_bread.html'); }); app.use(express.static(path)); app.use('/', router); app.listen(port, function () { console.log('Nodejs Express Example App listening on port ' + port) }) |
これでファイルを保存して閉じることができます。次のステップでは、静的なウェブページを views ディレクトリに追加します。まず、次のコマンドを入力してディレクトリを作成します。
|
1 |
mkdir views |
次のコマンドを入力して、home.html ランディングページファイルを開きます。
|
1 |
nano views/home.html |
ファイルに次のコードを追加します。このコードはBootstrapをインポートし、ウェブサイトの訪問者にこのウェブサイトがどのようなものであるかについての情報を提供します:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors"> <meta name="generator" content="Hugo 0.80.0"> <title>最高のレシピ</title> <!-- Bootstrap core CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous"> <link href="css/custom.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md"> <div class="container"> <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">ナビゲーションを切り替える</span> </button> <a class="navbar-brand" href="#">最高のレシピ</a> <div class="collapse navbar-collapse justify-content-center" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav justify-content-center"> <li class="active nav-item"> <a href="/" class="nav-link">ホーム</a> </li> <li class="nav-item"> <a href="/lasagna" class="nav-link">ラザニア</a> </li> <li class="nav-item"> <a href="/guacamole" class="nav-link">ワカモレ</a> </li> <li class="nav-item"> <a href="/banana-bread" class="nav-link">バナナブレッド</a> </li> </ul> </div> </div> </nav> <main> <section class="py-5 text-center container"> <div class="row py-lg-5"> <div class="col-lg-6 col-md-8 mx-auto"> <h1 class="fw-light">素晴らしいレシピ</h1> <p class="lead text-muted"> これらの素晴らしいレシピから、毎日の料理のインスピレーションを見つけて共有しましょう。レシピ、料理人、 お気に入りの料理やフォローしている友達に基づいた動画、ハウツーを見つけましょう。 <br /> <em>(深刻なものではありません。これはデモ用のnode-express-dockerイメージアプリのためのものです)</em> </p> </div> </div> </section> </main> </body> </html> |
Bootstrapをインポートするだけでなく、このページには基本的なナビゲーションメニューが追加されており、ページ間の移動やランディングページへの戻りを容易にします。また、カスタムCSSファイルをインポートするための行も追加しました。
|
1 |
<link href="css/custom.css" rel="stylesheet"> |
後ほど、このファイルを使用してアプリケーションにカスタムスタイリングを追加します。それでは、レシピ用の3つのページを作成しましょう。まずは、ラザニアのページから始めます。次のコマンドを使用して、nanoエディタでファイルを開きます。
|
1 |
nano views/lasagna.html |
開いたファイルに、次のコードを追加します。このファイルはBootstrapとcustom.cssファイルをインポートし、ナビゲーションメニューを指定して、ラザニアのレシピ情報を提供します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors"> <meta name="generator" content="Hugo 0.80.0"> <title>ラザニアのレシピ</title> <!-- Bootstrap コア CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous"> <link href="css/custom.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md"> <div class="container"> <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">ナビゲーションを切り替え</span> </button> <a class="navbar-brand" href="#">Awesome Recipes</a> <div class="collapse navbar-collapse justify-content-center" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav justify-content-center"> <li class="active nav-item"> <a href="/" class="nav-link">ホーム</a> </li> <li class="nav-item"> <a href="/lasagna" class="nav-link">ラザニア</a> </li> <li class="nav-item"> <a href="/guacamole" class="nav-link">ワカモレ</a> </li> <li class="nav-item"> <a href="/banana-bread" class="nav-link">バナナブレッド</a> </li> </ul> </div> </div> </nav> <main> <section class="py-5 text-center container bg-light"> <div class="row py-lg-5"> <div class="col-lg-6 col-md-8 mx-auto"> <h1 class="fw-light">最高のラザニアレシピ</h1> <p class="lead text-muted"> これまでで最高のラザニアが作れます。 <br /> <em>(大したものではありません。これはデモ用のnode-express-dockerイメージアプリのためのものです)</em> </p> <h3>材料</h3> <ul class="list-group"> <li class="list-group-item">スイートイタリアンソーセージ 1ポンド</li> <li class="list-group-item">牛挽き肉(赤身) ¾ポンド</li> <li class="list-group-item">みじん切り玉ねぎ ½カップ</li> <li class="list-group-item">にんにく 2片(つぶしたもの)</li> <li class="list-group-item">クラッシュトマト缶 1缶(28オンス)</li> <li class="list-group-item">トマトペースト缶 2缶(各6オンス)</li> <li class="list-group-item">トマトソース缶 2缶(各6.5オンス)</li> <li class="list-group-item">水 ½カップ</li> <li class="list-group-item">白砂糖 大さじ2</li> <li class="list-group-item">乾燥バジル 小さじ1 ½</li> <li class="list-group-item">フェンネルシード 小さじ½</li> <li class="list-group-item">イタリアンシーズニング 小さじ1</li> <li class="list-group-item">塩 小さじ1 ½(分けて使用、またはお好みで調整)</li> <li class="list-group-item">黒コショウ(粉末) 小さじ¼</li> <li class="list-group-item">刻んだ生のパセリ 大さじ4</li> <li class="list-group-item">ラザニア用パスタ 12枚</li> <li class="list-group-item">リコッタチーズ 16オンス</li> <li class="list-group-item">卵 1個</li> <li class="list-group-item">モッツァレラチーズ(スライス) ¾ポンド</li> <li class="list-group-item">粉パルメザンチーズ ¾カップ</li> </ul> </div> </div> </section> </main> </body> </html> |
同じ手順で、guacamoleのレシピページのファイルを作成しましょう。次のコマンドを実行して、nanoでファイルを開きます。
|
1 |
nano views/guacamole.html |
次に、このコードをファイルに追加します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors"> <meta name="generator" content="Hugo 0.80.0"> <title>ワカモレのレシピ</title> <!-- Bootstrapコア CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous"> <link href="css/custom.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md"> <div class="container"> <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">ナビゲーションを切り替える</span> </button> <a class="navbar-brand" href="#">Awesome Recipes</a> <div class="collapse navbar-collapse justify-content-center" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav justify-content-center"> <li class="active nav-item"> <a href="/" class="nav-link">ホーム</a> </li> <li class="nav-item"> <a href="/lasagna" class="nav-link">ラザニア</a> </li> <li class="nav-item"> <a href="/guacamole" class="nav-link">ワカモレ</a> </li> <li class="nav-item"> <a href="/banana-bread" class="nav-link">バナナブレッド</a> </li> </ul> </div> </div> </nav> <main> <section class="py-5 text-center container bg-light"> <div class="row py-lg-5"> <div class="col-lg-6 col-md-8 mx-auto"> <h1 class="fw-light">最高のワカモレのレシピ</h1> <p class="lead text-muted"> お好みに合わせて、このアボカドサラダをなめらかにしたり、具だくさんにしたりできます。 <br /> <em>(大したものではありません。これはデモ用のnode-express-dockerイメージアプリのためのものです)</em> </p> <h3>材料</h3> <ul class="list-group"> <li class="list-group-item">アボカド 3個(皮をむき、種を取り、つぶしたもの)</li> <li class="list-group-item">ライム 1個(果汁を絞る)</li> <li class="list-group-item">塩 小さじ1</li> <li class="list-group-item">みじん切りにした玉ねぎ 1/2カップ</li> <li class="list-group-item">刻んだ新鮮なパクチー 大さじ3</li> <li class="list-group-item">ローマ(プラム)トマト 2個(さいの目に切る)</li> <li class="list-group-item">みじん切りにしたにんにく 小さじ1</li> <li class="list-group-item">カイエンペッパーパウダー ひとつまみ(お好みで)</li> </ul> </div> </div> </section> </main> </body> </html> |
最後に、banana_bread.html ファイルを次のコマンドを入力して作成しましょう:
|
1 |
nano views/banana_bread.html |
次に、以下のHTMLコードをファイルに追加します:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors"> <meta name="generator" content="Hugo 0.80.0"> <title>バナナブレッドのレシピ</title> <!-- Bootstrap core CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous"> <link href="css/custom.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md"> <div class="container"> <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">ナビゲーションを切り替える</span> </button> <a class="navbar-brand" href="#">Awesome Recipes</a> <div class="collapse navbar-collapse justify-content-center" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav justify-content-center"> <li class="active nav-item"> <a href="/" class="nav-link">ホーム</a> </li> <li class="nav-item"> <a href="/lasagna" class="nav-link">ラザニア</a> </li> <li class="nav-item"> <a href="/guacamole" class="nav-link">ワカモレ</a> </li> <li class="nav-item"> <a href="/banana-bread" class="nav-link">バナナブレッド</a> </li> </ul> </div> </div> </nav> <main> <section class="py-5 text-center container bg-light"> <div class="row py-lg-5"> <div class="col-lg-6 col-md-8 mx-auto"> <h1 class="fw-light">最高のバナナバナナブレッドのレシピ</h1> <p class="lead text-muted"> バナナの風味を妥協する必要はありません。このバナナブレッドは、バナナの風味がたっぷりで、しっとりとしていて美味しいです!友人や家族も私のレシピを気に入ってくれて、間違いなく最高だと言ってくれます!トーストしても素晴らしいです!!お楽しみください! <br /> <em>(深刻なものではありません。これはデモ用のnode-express-dockerイメージアプリのためのものです)</em> </p> <h3>材料</h3> <ul class="list-group"> <li class="list-group-item">中力粉 2カップ</li> <li class="list-group-item">重曹 小さじ1</li> <li class="list-group-item">塩 小さじ1/4</li> <li class="list-group-item">バター 1/2カップ</li> <li class="list-group-item">ブラウンシュガー 3/4カップ</li> <li class="list-group-item">溶き卵 2個</li> <li class="list-group-item">つぶした完熟バナナ 2 1/3カップ</li> </ul> </div> </div> </section> </main> </body> </html> |
これで、すべてのページが作成されました。覚えているかと思いますが、css/custom.css ファイルを追加します。次のコマンドを入力してディレクトリを作成します。
|
1 |
mkdir views/css |
次に、以下のコマンドを使用して、nanoエディタでファイルを作成して開きます。
|
1 |
nano views/css/custom.css |
必要に応じて、ウェブサイトをスタイリングするためにさらにCSSコードを追加できます。簡潔にするために、ファイルに次のコードスニペットを追加しましょう。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.bd-placeholder-img { font-size: 1.125rem; text-anchor: middle; -webkit-user-select: none; -moz-user-select: none; user-select: none; } @media (min-width: 768px) { .bd-placeholder-img-lg { font-size: 3.5rem; } } |
完了したら、ファイルを保存して閉じます。
アプリケーションのソースコードとプロジェクトの依存関係がインストールされたので、アプリケーションを起動できます。
アプリがポート8090でリッスンするように設定しました。ファイアウォールにこのポート経由のトラフィックを許可するように指示するには、次のコマンドを実行します。別のポートを指定した場合は、コマンド内のポート番号を置き換えてください。
|
1 |
sudo ufw allow 8090 |
これで、アプリケーションを起動できます。ただし、その前に、次のコマンドを実行してプロジェクトのルートディレクトリにいることを確認してください。
|
1 |
cd ~/node_express |
node index.js でアプリケーションを起動します。別のエントリポイントを指定した場合は、それをエントリポイントに置き換えてください。
|
1 |
node index.js |
ブラウザでhttp://your_public_server_ip:8090にアクセスすると、定義されたレシピのランディングページが表示されます。
ナビゲーションにさまざまなレシピへのリンクが表示されています。いくつかクリックしてみましょう。以下はLasagnaのレシピページです。
そして、こちらがGuacamoleのレシピページです。
ここまでに、アプリケーションを作成し、期待通りに動作することを確認しました。Ctrl + C を押してサーバーを終了し、Dockerfileの作成に進むことができます。Dockerfileは、必要に応じてアプリケーションのインスタンスを再作成できるようにすることで、スケーラビリティに役立ちます。
ステップ 3: Dockerfileの作成
Dockerはイメージをビルドする際、Dockerfileに指定された命令を読み取ります。これはアプリケーションの実行環境を指定するものです。そのため、開発者が依存関係の不一致や実行環境のバージョンの変更による問題を避けるのに役立ちます。次のコマンドを入力してDockerfileを作成します。
|
1 |
nano Dockerfile |
Dockerイメージは、互いに積み重ねられた複数のイメージレイヤーを使用して作成されます。まず、アプリケーションの開始点となるベースイメージを追加することから始めます。
アプリケーションは node.js 環境で動作することを想定しているため、まずは node:10-alpineイメージ(node.js用)を追加することから始めます。このチュートリアルを執筆している現在、これはNode.jsの推奨LTSバージョンです。この特定のイメージを選択したのは、それがAlpine Linuxプロジェクトに由来しているためです。これにより、イメージサイズを最小限に抑えることができます。Docker HubのNodeイメージページDocker HubのNodeイメージページには、ニーズに応じて選択できるいくつかのイメージバリアントがあります。
次のコードを追加し、FROMディレクティブを使用してアプリケーションのベースイメージを設定します。
|
1 |
FROM node:10-alpine |
このイメージにはNode.js and npmが含まれています。すべてのDockerfileは、FROMディレクティブで始まる必要があります。Dockerのnodeイメージには、デフォルトで非rootのnodeユーザーが含まれています。これを使用して、アプリケーションコンテナをrootとして実行することもできますが、Dockerのセキュリティ推奨事項では、コンテナをrootとして実行せず、そのリソースを実行するために必要な権限のみに制限することを推奨しています。
そのため、今回はnodeユーザーのホームディレクトリをアプリケーションの作業ディレクトリとして使用し、コンテナ内のユーザーとしても使用します。詳細については、こちらのDocker Nodeイメージのベストプラクティスガイドを参照してください。
アプリケーションコードの権限を合理化するために、node_modulesサブディレクトリを、アプリディレクトリとともに/home/node内に作成します。これらのディレクトリを作成することで、コンテナ内でローカルにnpm installコマンドを実行したときに、適切な権限が設定されるようになります。ディレクトリを作成したら、それらの所有権をnodeユーザーに設定する必要があります。Dockerfile内に次の行を追加してこれを行います。
|
1 |
mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app |
次に、以下の行を追加して作業ディレクトリを設定します。
|
1 |
WORKDIR /home/node/app |
Dockerがデフォルトでディレクトリを作成するのを防ぐために、常にWORKDIRを設定することをお勧めします。
次の行を追加して、package.jsonとpackage-lock.jsonファイルをコピーします。
|
1 |
COPY package*.json ./ |
It’s recommended to add the COPY命令は、npm installを実行したり、アプリケーションのソースコードをコピーしたりする前に追加することをお勧めします。これにより、Dockerのキャッシュメカニズムを利用できます。ビルドプロセス中、Dockerはすべての命令に対してキャッシュされたレイヤーがあるかどうかを確認します。つまり、package.jsonファイルが変更されていない場合、Dockerは既存のイメージレイヤーを使用し、node modulesの再インストールを回避するため、ビルドプロセスが高速化されます。
Before running npm installを実行する前に、次の行を追加してユーザーをnodeに切り替え、すべてのアプリケーションファイルとnode_modulesディレクトリが非rootのnodeユーザーによって所有されるようにします。
|
1 |
USER node |
これで、コンテナでnpm installコマンドを実行する準備が整いました。Dockerfileに次の行を追加します。
|
1 |
RUN npm install |
Once node_modulesがインストールされたら、次の行を追加して、適切な権限と所有権(すなわち非rootのnodeユーザー)でアプリケーションコードをコンテナ上のアプリケーションディレクトリにコピーするようDockerに指示します。
|
1 |
COPY --chown=node:node . . |
最後のステップは、コンテナのポート8090を公開することです。これはエントリーファイルであるindex.jsで定義した通りです。
|
1 2 |
EXPOSE 8090 CMD [ "node", "index.js" ] |
EXPOSEは、実行時にコンテナのどのポートを開くかを設定します。CMDはアプリケーションを起動するコマンドを実行します。この場合はnode index.jsです。
Dockerfile内で有効になるのは最後のCMDコマンドのみであるため、CMDコマンドは1つだけにする必要があります。次のDockerfileリファレンスドキュメント を参照して、Dockerfileで実行できることの一覧を確認してください。
完成したDockerfileは以下のようになります。
|
1 2 3 4 5 6 7 8 9 |
FROM node:10-alpine RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app WORKDIR /home/node/app COPY package*.json ./ USER node RUN npm install COPY --chown=node:node . . EXPOSE 8090 CMD [ "node", "index.js" ] |
これでファイルを保存して閉じることができます。
次に行うのは、.dockerignore ファイルの追加です。.gitignore ファイルと同様に、.dockerignore は、プロジェクトディレクトリ内のどのファイルやディレクトリをコンテナにコピーしないかを指定します。
nanoエディタでファイルを開きます:
|
1 |
nano .dockerignore |
ファイル内に以下の行を追加します:
|
1 2 3 4 |
node_modules npm-debug.log Dockerfile .dockerignore |
もし git リポジトリを使用している場合は、.git ディレクトリと .gitignore ファイルも追加する必要があります。ファイルを保存して閉じます。
すべてがうまくいったら、docker build コマンドを使用してアプリケーションイメージをビルドします。–t フラグを docker build コマンドに追加することで、Dockerがデフォルトで設定するランダムな文字列ではなく、覚えやすい名前でイメージにタグを付けることができます。また、このイメージをDocker Hubにプッシュするため、タグにDocker Hubのユーザー名を含めるのが最適です。
タグ名として nodejs-express-image を使用します。お好みのタグ名を自由に選択してください。イメージをビルドするコマンドは以下の通りです:
|
1 |
sudo docker build -t your_dockerhub_username/nodejs-express-image . |
your_dockerhub_username は実際の Docker Hub ユーザー名に置き換えてください。末尾の . (ドット) は、ビルドコンテキストが現在のディレクトリであることを指定しています。
ビルドプロセスには1〜2分かかります。完了したら、イメージを確認するコマンドを入力します:
|
1 |
sudo docker images |
以下のような出力が表示されるはずです:
なお、your_dockerhub_username は実際のユーザー名に置き換えています。
イメージがビルドされたことを確認したら、docker run を使用して、そのイメージからコンテナを作成できます。以下のフラグが含まれます:
-p:コンテナ上のポートを公開し、ホストシステムのポートにマッピングします。デモンストレーション目的で、ホストシステムではポート80を使用します。ただし、そのポートで別のプロセスが実行されている場合は、必要に応じて自由に変更してください。詳細については、Dockerドキュメントのポートバインディングを参照してください。.-d:デタッチドモード用。コンテナをバックグラウンドで実行し続けることができます。--name:Dockerにランダムな文字列を割り当てさせる代わりに、覚えやすい名前を設定するために使用できます。
コンテナを構築するコマンドは以下の通りです。Docker Hubのユーザー名を適切に置き換えてください:
|
1 |
sudo docker run --name nodejs-express-image -p 80:8090 -d your_dockerhub_username/nodejs-express-image |
コンテナが構築され、実行が開始されるまで待ちます。実行中のすべてのコンテナを検査するには、次のコマンドを使用します:
|
1 |
sudo docker ps |
以下のような出力が表示されるはずです:
出力に示されているように、コンテナは現在実行中です。ブラウザでポート番号を指定せずにサーバーのパブリックIPアドレスにアクセスすると、ブラウザで表示できます。ホームページがロードされます:
Dockerを使用してNode Expressの静的ウェブサイトのデプロイに成功しました。将来の使用やスケーリングのために、このイメージをDocker Hubにプッシュする方法を見てみましょう。
ステップ 4: Dockerイメージリポジトリの操作
イメージをDocker Hubなどのイメージレジストリにプッシュして、将来の使用のために保存したり、他の開発者と共有したり、コンテナのスケーリングを可能にしたりできます。作成したイメージをDocker Hubにプッシュし、それを使用してコンテナを再作成できます。
次のコマンドを使用して、Docker Hubアカウントにログインします。実際のDocker Hubユーザー名に置き換えてください。
|
1 |
sudo docker login -u your_dockerhub_username |
プロンプトが表示されたらパスワードを入力します。ログインすると、~/.docker/config.json ファイルがユーザーのホームディレクトリに作成され、そこにDocker Hubの資格情報が含まれます。
設定が完了したら、次のコマンドを入力してイメージをDocker Hubにプッシュします。その際、先ほどイメージをビルドしたときに設定したタグを指定します。
|
1 |
sudo docker push your_dockerhub_username/nodejs-express-image |
このコマンドは、DockerイメージをDocker Hubアカウントにプッシュします。アカウントにアクセスすると、最近プッシュされたイメージを確認できます。
現在のアプリケーションコンテナを破棄し、リポジトリ内のイメージを使用して再構築することで、イメージリポジトリの有用性をテストできます。
次のコマンドを入力して、現在のコンテナを一覧表示します。
|
1 |
sudo docker ps |
次のような出力が表示されるはずです。
出力に表示されている CONTAINER ID をメモしてコピーし、次のコマンドでコンテナを停止するために使用します。IDはご自身のものに置き換えてください。
|
1 |
sudo docker stop 1bb2d65279bb |
次のコマンドを入力して、システムで利用可能なすべてのDockerイメージを一覧表示します。
|
1 |
sudo docker images –a |
出力には、作成したイメージの名前、node.jsイメージ、およびビルドプロセスからのその他のイメージが表示されます。
次のコマンドを入力して、未使用または宙ぶらりん(dangling)なイメージを含むイメージを削除します。
|
1 |
sudo docker system prune |
Type y と入力して確認します。これにより、停止したコンテナとイメージが削除されます。一覧表示すると、出力に空のリストが表示されます。
これで、アプリケーションを実行しているコンテナとイメージ自体の両方が削除されました。Dockerコンテナ、イメージ、およびボリュームの削除についての詳細は、チュートリアルを参照してください.
これで、まず次のコマンドを使用してDocker Hubからイメージをプルすることで、プロセス全体を再作成できます。Docker Hubのユーザー名は適切に置き換えてください。
|
1 |
sudo docker pull your_dockerhub_username/nodejs-express-image |
次のコマンドで、Dockerイメージを再度一覧表示します。
|
1 |
sudo docker images |
出力にイメージが表示されるはずです。
これで、ステップ3 のコマンドを使用してコンテナを再構築できます。もちろん、必要に応じてDocker Hubのユーザー名を置き換えてください。
|
1 |
sudo docker run --name nodejs-express-image -p 80:8090 -d your_dockerhub_username/nodejs-express-image |
コンテナを一覧表示して、再構築されたことを確認します。
|
1 |
sudo docker ps |
同様の出力が表示されるはずです。
ブラウザでサーバーのパブリックIPアドレスにアクセスすると、アプリが実行されているのを確認できるはずです。
結論
ここまでチュートリアルを進めてきたなら、ExpressとBootstrapで作成され、Dockerでデプロイされた静的ウェブサイトが完成しているはずです。静的ウェブサイトのファイルを使用してDockerイメージをビルドし、そのイメージを使用してコンテナを作成しました。その後、イメージをDockerイメージレジストリであるDocker Hubにプッシュし、将来の使用やスケーリングに利用できるようにしました。イメージレジストリの使用をテストするために、イメージとコンテナを破棄し、レジストリからイメージをプルして、コンテナを再構築しました。
このチュートリアルでは、Node.jsアプリをデプロイする方法を説明しました。別のウェブ開発スタックの使用方法を学びたい場合は、Nginx上でDocker Composeを使用してLaravelアプリをデプロイする.
Dockerの活用に関するその他のリソースについては、次のチュートリアルを参照してください。
ハッピーコンピューティング!











コメント
コメントはまだありません。最初のコメントを投稿しましょう。