序章

Kubernetes を使用すると、ユーザーは1つのコマンドで復元力のあるスケーラブルなサービスを作成できます。 良すぎると思われるものと同様に、問題があります。最初に適切な Docker イメージを準備し、徹底的にテストする必要があります。

継続的インテグレーション(CI)は、更新のたびにアプリケーションをテストする方法です。 これを手動で行うのは面倒でエラーが発生しやすいですが、CIプラットフォームはテストを実行し、エラーを早期にキャッチして、エラーが発生したポイントを特定します。 リリースと展開の手順は、多くの場合、複雑で時間がかかり、信頼性の高いビルド環境が必要です。 継続的デリバリー(CD)を使用すると、人間の介入なしに、更新ごとにアプリケーションを構築およびデプロイできます。

プロセス全体を自動化するには、継続的インテグレーションおよびデリバリー(CI / CD)プラットフォームであるセマフォを使用します。

このチュートリアルでは、Node.jsを使用して名簿APIサービスを構築します。 APIは、データベース内の人を作成、削除、および検索するための単純な RESTfulAPIインターフェースを公開します。 Git を使用して、コードをGitHubにプッシュします。 次に、セマフォを使用してアプリケーションをテストし、Dockerイメージを構築して、 DigitalOceanKubernetesクラスターにデプロイします。 データベースの場合、 DigitalOcean ManagedDatabasesを使用してPostgreSQLクラスターを作成します。

前提条件

読み進める前に、次のものがあることを確認してください。

  • DigitalOceanアカウントとパーソナルアクセストークン。 パーソナルアクセストークンの作成に従って、アカウントにトークンを設定します。
  • DockerHubアカウント。
  • GitHubアカウント。
  • セマフォアカウント。 GitHubアカウントでサインアップできます。
  • と呼ばれる新しいGitHubリポジトリ addressbook プロジェクトのために。 リポジトリを作成するときは、このリポジトリをREADME チェックボックスで初期化し、 Add.gitignoreメニューでNodeを選択します。 詳細については、GitHubのリポジトリの作成ヘルプページをフォローしてください。
  • Git がローカルマシンにインストールされ、がGitHubアカウントで動作するようにを設定します。 慣れていない場合や復習が必要な場合は、Gitの使用方法リファレンスガイドを読むことを検討してください。
  • curlがローカルマシンにインストールされています。
  • Node.jsがローカルマシンにインストールされています。 このチュートリアルでは、Node.jsバージョンを使用します 10.16.0.

ステップ1—データベースとKubernetesクラスターを作成する

アプリケーションを強化するサービス(DigitalOceanデータベースクラスターとDigitalOcean Kubernetesクラスター)をプロビジョニングすることから始めます。

DigitalOceanアカウントにログインし、プロジェクトを作成します。 プロジェクトを使用すると、アプリケーションを構成するすべてのリソースを整理できます。 プロジェクトを呼び出す addressbook.

次に、PostgreSQLクラスターを作成します。 PostgreSQLデータベースサービスはアプリケーションのデータを保持します。 利用可能な最新バージョンを選択できます。 サービスの準備が整うまでに数分かかるはずです。

PostgreSQLサービスの準備ができたら、データベースとユーザーを作成します。 データベース名をに設定します addessbook_db ユーザー名をに設定します addressbook_user. 新しいユーザー用に生成されたパスワードをメモします。 データベースは、PostgreSQLのデータを整理する方法です。 通常、各アプリケーションには独自のデータベースがありますが、これに関する厳格なルールはありません。 アプリケーションは、ユーザー名とパスワードを使用してデータベースにアクセスし、データを保存および取得できるようにします。

最後に、Kubernetesクラスターを作成します。 データベースが実行されているのと同じリージョンを選択します。 cluserに名前を付けます addressbook-server ノード数をに設定します 3.

ノードのプロビジョニング中に、アプリケーションの構築を開始できます。

ステップ2—アプリケーションの作成

展開するアドレス帳アプリケーションを作成しましょう。 まず、前提条件で作成したGitHubリポジトリのクローンを作成して、 .gitignore ファイルGitHubが作成され、リポジトリを手動で作成しなくても、アプリケーションコードをすばやくコミットできます。 ブラウザを開き、新しいGitHubリポジトリに移動します。 クローンまたはダウンロードボタンをクリックして、提供されたURLをコピーします。 Gitを使用して、空のリポジトリをマシンに複製します。

  1. git clone https://github.com/your_github_username/addressbook

プロジェクトディレクトリを入力します。

  1. cd addressbook

リポジトリのクローンを作成すると、アプリの作成を開始できます。 2つのコンポーネントを構築します。データベースと対話するモジュールと、HTTPサービスを提供するモジュールです。 データベースモジュールは、名簿データベースから人を保存および取得する方法を認識し、HTTPモジュールは要求を受信し、それに応じて応答します。

厳密には必須ではありませんが、コードの記述中にコードをテストすることをお勧めします。そのため、テストモジュールも作成します。 これは、アプリケーションの計画されたレイアウトです。

  • database.js:データベースモジュール。 データベース操作を処理します。
  • app.js:エンドユーザーモジュールとメインアプリケーション。 ユーザーが接続するためのHTTPサービスを提供します。
  • database.test.js:データベースモジュールのテスト。

さらに、プロジェクトの package.json ファイルが必要になります。このファイルには、プロジェクトとその必要な依存関係が記述されています。 エディターを使用して手動で作成することも、npmを使用してインタラクティブに作成することもできます。 を実行します npm init ファイルをインタラクティブに作成するコマンド:

  1. npm init

コマンドは、開始するためにいくつかの情報を要求します。 例に示すように値を入力します。 リストに回答が表示されない場合は、回答を空白のままにします。これは、括弧内のデフォルト値を使用します。

npm output
package name: (addressbook) addressbook version: (1.0.0) 1.0.0 description: Addressbook API and database entry point: (index.js) app.js test command: git repository: URL for your GitHub repository keywords: author: Sammy the Shark <[email protected]>" license: (ISC) About to write to package.json: { "name": "addressbook", "version": "1.0.0", "description": "Addressbook API and database", "main": "app.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" } Is this OK? (yes) yes

これで、コードの記述を開始できます。 データベースは、開発しているサービスの中核です。 他のコンポーネントを作成する前に、適切に設計されたデータベースモデルを用意することが不可欠です。 したがって、データベースコードから始めるのは理にかなっています。

アプリケーションのすべてのビットをコーディングする必要はありません。 Node.jsには、再利用可能なモジュールの大規模なライブラリがあります。 たとえば、プロジェクトに Sequelize ORM モジュールがある場合は、SQLクエリを作成する必要はありません。 このモジュールは、データベースをJavaScriptオブジェクトおよびメソッドとして処理するインターフェースを提供します。 また、データベースにテーブルを作成することもできます。 SequelizeがPostgreSQLで動作するには、pgモジュールが必要です。

を使用してモジュールをインストールします npm install とのコマンド --save オプション、それは言う npm モジュールを保存するには package.json. このコマンドを実行して、両方をインストールします sequelizepg:

  1. npm install --save sequelize pg

データベースコードを保持する新しいJavaScriptファイルを作成します。

  1. nano database.js

をインポートします sequelize 次の行をファイルに追加してモジュールを作成します。

database.js
const Sequelize = require('sequelize');

. . .

次に、その行の下で、 sequelize システム環境から取得するデータベース接続パラメータを持つオブジェクト。 これにより、コードにクレデンシャルが含まれないため、コードをGitHubにプッシュするときに誤ってクレデンシャルを共有することがなくなります。 使用できます process.env 環境変数、およびJavaScriptにアクセスする || 未定義の変数のデフォルトを設定する演算子:

database.js
. . .

const sequelize = new Sequelize(process.env.DB_SCHEMA || 'postgres',
                                process.env.DB_USER || 'postgres',
                                process.env.DB_PASSWORD || '',
                                {
                                    host: process.env.DB_HOST || 'localhost',
                                    port: process.env.DB_PORT || 5432,
                                    dialect: 'postgres',
                                    dialectOptions: {
                                        ssl: process.env.DB_SSL == "true"
                                    }
                                });

. . .

次に、 Person モデル。 例が複雑になりすぎないようにするには、次の2つのフィールドのみを作成します。 firstNamelastName、両方とも文字列値を格納します。 次のコードを追加して、モデルを定義します。

database.js
. . .

const Person = sequelize.define('Person', {
    firstName: {
        type: Sequelize.STRING,
        allowNull: false
    },
    lastName: {
        type: Sequelize.STRING,
        allowNull: true
    },
});

. . .

これにより、2つのフィールドが定義され、 firstName 必須 allowNull: false. Sequelizeのモデル定義ドキュメントには、使用可能なデータ型とオプションが示されています。

最後に、 sequelize オブジェクトと Person 他のモジュールがそれらを使用できるようにモデル化します。

database.js
. . .

module.exports = {
    sequelize: sequelize,
    Person: Person
};

開発中いつでも呼び出すことができる別のファイルにテーブル作成スクリプトがあると便利です。 これらのタイプのファイルは移行と呼ばれます。 このコードを保持する新しいファイルを作成します。

  1. nano migrate.js

これらの行をファイルに追加して、定義したデータベースモデルをインポートし、 sync() データベースを初期化する関数。これにより、モデルのテーブルが作成されます。

merge.js
var db = require('./database.js');
db.sequelize.sync();

アプリケーションは、システム環境変数でデータベース接続情報を探しています。 というファイルを作成します .env 開発中に環境にロードするこれらの値を保持するには、次のようにします。

  1. nano .env

次の変数宣言をファイルに追加します。 設定していることを確認してください DB_HOST, DB_PORT、 と DB_PASSWORD DigitalOceanPostgreSQLクラスターに関連付けられているものへ:

.env
export DB_SCHEMA=addressbook_db
export DB_USER=addressbook_user
export DB_PASSWORD=your_db_user_password
export DB_HOST=your_db_cluster_host
export DB_PORT=your_db_cluster_port
export DB_SSL=true
export PORT=3000

ファイルを保存します。

警告:環境ファイルをソース管理にチェックインしないでください。 彼らは通常機密情報を持っています。

デフォルトを定義したので .gitignore リポジトリを作成したときのファイルでは、このファイルはすでに無視されています。

これで、データベースを初期化する準備が整いました。 環境ファイルをインポートして実行します migrate.js:

  1. source ./.env
  2. node migrate.js

これにより、データベーステーブルが作成されます。

Output
Executing (default): CREATE TABLE IF NOT EXISTS "People" ("id" SERIAL , "firstName" VARCHAR(255) NOT NULL, "lastName" VARCHAR(255), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, PRIMARY KEY ("id")); Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'People' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;

出力には2つのコマンドが表示されます。 最初のものはを作成します People あなたの定義によるテーブル。 2番目のコマンドは、PostgreSQLカタログでテーブルを検索して、テーブルが実際に作成されたことを確認します。

コードのテストを作成することをお勧めします。 テストを使用すると、コードの動作を検証できます。 システムの各関数、メソッド、またはその他の部分のチェックを記述し、手動でテストしなくても、期待どおりに機能することを確認できます。

jest テストフレームワークは、Node.jsアプリケーションに対するテストを作成するのに最適です。 Jestは、プロジェクト内のファイルをスキャンしてテストファイルを探し、それらを1つずつ実行します。 Jestをインストールします --save-dev オプション、それは言う npm モジュールはプログラムを実行する必要はありませんが、アプリケーションを開発するための依存関係です。

  1. npm install --save-dev jest

データベースからレコードを挿入、読み取り、および削除できることを確認するためのテストを作成します。 これらのテストは、データベース接続とアクセス許可が適切に構成されていることを確認し、後でCI/CDパイプラインで使用できるいくつかのテストも提供します。

を作成します database.test.js ファイル:

  1. nano database.test.js

次のコンテンツを追加します。 データベースコードをインポートすることから始めます。

database.test.js
const db = require('./database');

. . .

データベースを使用する準備ができていることを確認するには、 sync()beforeAll 関数:

database.test.js
. . .

beforeAll(async () => {
    await db.sequelize.sync();
});

. . .

最初のテストでは、データベースに個人レコードを作成します。 The sequelize ライブラリはすべてのクエリを非同期で実行します。つまり、ライブラリはクエリの結果を待ちません。 テストで結果を待機させて検証できるようにするには、次のコマンドを使用する必要があります。 asyncawait キーワード。 このテストでは、 create() データベースに新しい行を挿入するメソッド。 使用する expect 比較するには person.id の列 1. 別の値を取得すると、テストは失敗します。

database.test.js
. . .

test('create person', async () => {
    expect.assertions(1);
    const person = await db.Person.create({
        id: 1,
        firstName: 'Sammy',
        lastName: 'Davis Jr.',
        email: '[email protected]'
    });
    expect(person.id).toEqual(1);
});

. . .

次のテストでは、 findByPk() 行を取得するメソッド id=1. 次に、検証します firstNamelastName 値。 もう一度、使用します asyncawait:

database.test.js
. . .

test('get person', async () => {
    expect.assertions(2);
    const person = await db.Person.findByPk(1);
    expect(person.firstName).toEqual('Sammy');
    expect(person.lastName).toEqual('Davis Jr.');
});

. . .

最後に、データベースから人を削除することをテストします。 The destroy() メソッドは、 id=1. それが機能したことを確認するために、もう一度その人を取得して、戻り値が null:

database.test.js
. . .

test('delete person', async () => {
    expect.assertions(1);
    await db.Person.destroy({
        where: {
            id: 1
        }
    });
    const person = await db.Person.findByPk(1);
    expect(person).toBeNull();
});

. . .

最後に、このコードを追加して、データベースへの接続を閉じます。 close() すべてのテストが終了したら:

app.js
. . .

afterAll(async () => {
    await db.sequelize.close();
});

ファイルを保存します。

The jest コマンドはプログラムのテストスイートを実行しますが、コマンドをに保存することもできます package.json. このファイルをエディターで開きます。

  1. nano package.json

を見つけます scripts キーワードと既存のものを置き換えます test 行(これは単なるプレースホルダーでした)。 テストコマンドは jest:

. . .

  "scripts": {
    "test": "jest"
  },

. . .

今、あなたは呼び出すことができます npm run test テストスイートを呼び出します。 これは長いコマンドかもしれませんが、変更する必要がある場合は jest 後でコマンドを実行すると、外部サービスを変更する必要がなくなります。 彼らは電話を続けることができます npm run test.

テストを実行します。

  1. npm run test

次に、結果を確認します。

Output
console.log node_modules/sequelize/lib/sequelize.js:1176 Executing (default): CREATE TABLE IF NOT EXISTS "People" ("id" SERIAL , "firstName" VARCHAR(255) NOT NULL, "lastName" VARCHAR(255), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, PRIMARY KEY ("id")); console.log node_modules/sequelize/lib/sequelize.js:1176 Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'People' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname; console.log node_modules/sequelize/lib/sequelize.js:1176 Executing (default): INSERT INTO "People" ("id","firstName","lastName","createdAt","updatedAt") VALUES ($1,$2,$3,$4,$5) RETURNING *; console.log node_modules/sequelize/lib/sequelize.js:1176 Executing (default): SELECT "id", "firstName", "lastName", "createdAt", "updatedAt" FROM "People" AS "Person" WHERE "Person"."id" = 1; console.log node_modules/sequelize/lib/sequelize.js:1176 Executing (default): DELETE FROM "People" WHERE "id" = 1 console.log node_modules/sequelize/lib/sequelize.js:1176 Executing (default): SELECT "id", "firstName", "lastName", "createdAt", "updatedAt" FROM "People" AS "Person" WHERE "Person"."id" = 1; PASS ./database.test.js ✓ create person (344ms) ✓ get person (173ms) ✓ delete person (323ms) Test Suites: 1 passed, 1 total Tests: 3 passed, 3 total Snapshots: 0 total Time: 5.315s Ran all test suites.

テストされたデータベースコードを使用して、アドレス帳のユーザーを管理するAPIサービスを構築できます。

HTTPリクエストを処理するには、 ExpressWebフレームワークを使用します。 Expressをインストールし、を使用して依存関係として保存します npm install:

  1. npm install --save express

body-parser モジュールも必要です。これは、HTTPリクエストの本文にアクセスするために使用します。 これも依存関係としてインストールします。

  1. npm install --save body-parser

メインアプリケーションファイルを作成します app.js:

  1. nano app.js

をインポートします express, body-parser、 と database モジュール。 次に、のインスタンスを作成します express と呼ばれるモジュール app サービスを制御および構成します。 あなたが使う app.use() ミドルウェアなどの機能を追加します。 これを使用して追加します body-parser アプリケーションがurlエンコード文字列を読み取れるようにするモジュール:

app.js
var express = require('express');
var bodyParser = require('body-parser');
var db = require('./database');
var app = express();
app.use(bodyParser.urlencoded({ extended: true }));

. . .

次に、アプリケーションにルートを追加します。 ルートは、アプリやWebサイトのボタンに似ています。 これらは、アプリケーションで何らかのアクションをトリガーします。 ルートは、一意のURLをアプリケーションのアクションにリンクします。 各ルートは特定のパスを提供し、異なる操作をサポートします。

ハンドルを定義する最初のルート GET のリクエスト /person/$ID パス。指定されたIDを持つ人のデータベースレコードが表示されます。 Expressは、要求された値を自動的に設定します $ID の中に req.params.id 変数。

アプリケーションは、JSON文字列としてエンコードされた個人データで応答する必要があります。 データベーステストで行ったように、 findByPk() IDで個人を取得し、HTTPステータスでリクエストに応答するメソッド 200 (OK)そして個人レコードをJSONとして送信します。 次のコードを追加します。

app.js
. . .

app.get("/person/:id", function(req, res) {
    db.Person.findByPk(req.params.id)
        .then( person => {
            res.status(200).send(JSON.stringify(person));
        })
        .catch( err => {
            res.status(500).send(JSON.stringify(err));
        });
});

. . .

エラーが発生すると、 catch() 実行されます。 たとえば、データベースがダウンしている場合、接続は失敗し、代わりにこれが実行されます。 問題が発生した場合は、HTTPステータスを次のように設定します 500 (内部サーバーエラー)そしてエラーメッセージをユーザーに送り返します:

別のルートを追加して、データベースに人を作成します。 このルートは処理します PUT から個人のデータを要求してアクセスします req.body. 使用 create() データベースに行を挿入するメソッド:

app.js
. . .

app.put("/person", function(req, res) {
    db.Person.create({
        firstName: req.body.firstName,
        lastName: req.body.lastName,
        id: req.body.id
    })
        .then( person => {
            res.status(200).send(JSON.stringify(person));
        })
        .catch( err => {
            res.status(500).send(JSON.stringify(err));
        });
});

. . .

処理する別のルートを追加します DELETE アドレス帳からレコードを削除するリクエスト。 まず、IDを使用してレコードを検索し、次に destroy それを削除する方法:

app.js
. . .

app.delete("/person/:id", function(req, res) {
    db.Person.destroy({
        where: {
            id: req.params.id
        }
    })
        .then( () => {
            res.status(200).send();
        })
        .catch( err => {
            res.status(500).send(JSON.stringify(err));
        });
});

. . .

また、便宜上、データベース内のすべての人を取得するルートを追加します。 /all 道:

app.js
. . .

app.get("/all", function(req, res) {
    db.Person.findAll()
        .then( persons => {
            res.status(200).send(JSON.stringify(persons));
        })
        .catch( err => {
            res.status(500).send(JSON.stringify(err));
        });
});

. . .

最後のルートが1つ残っています。 リクエストが以前のルートのいずれにも一致しなかった場合は、ステータスコードを送信してください 404 (見つかりません):

app.js
. . .

app.use(function(req, res) {
    res.status(404).send("404 - Not Found");
});

. . .

最後に、 listen() サービスを開始するメソッド。 環境変数の場合 PORT が定義されると、サービスはそのポートでリッスンします。 それ以外の場合は、デフォルトでポートになります 3000:

app.js
. . .

var server = app.listen(process.env.PORT || 3000, function() {
    console.log("app is running on port", server.address().port);
});

あなたが学んだように、 package.json fileを使用すると、テストの実行、アプリの起動、その他のタスクを実行するためのさまざまなコマンドを定義できます。これにより、多くの場合、入力を大幅に減らして一般的なコマンドを実行できます。 に新しいコマンドを追加します package.json アプリケーションを起動します。 ファイルを編集します。

  1. nano package.json

追加します start コマンドなので、次のようになります。

package.json
. . .

  "scripts": {
    "test": "jest",
    "start": "node app.js"
  },

. . .

前の行にコンマを追加することを忘れないでください。 scripts セクションのエントリはコンマで区切る必要があります。

ファイルを保存して、初めてアプリケーションを起動します。 まず、環境ファイルを次のようにロードします source; これにより、変数がセッションにインポートされ、アプリケーションで使用できるようになります。 次に、でアプリケーションを開始します npm run start:

  1. source ./.env
  2. npm run start

アプリはポートで起動します 3000:

Output
app is running on port 3000

ブラウザを開き、に移動します http://localhost:3000/all. 次のページが表示されます [].

端末に戻り、を押します CTRL-C アプリケーションを停止します。

今こそ、コード品質テストを追加する絶好の機会です。 リンターとも呼ばれるコード品質ツールは、プロジェクトをスキャンしてコードの問題を探します。 未使用の変数を残す、セミコロンでステートメントを終了しない、中括弧がないなどの不適切なコーディング方法は、見つけるのが難しいバグを引き起こす可能性があります。

開発依存関係として、JavaScriptリンターであるjshintツールをインストールします。

  1. npm install --save-dev jshint

何年にもわたって、JavaScriptは更新、機能、および構文の変更を受け取りました。 この言語は、 ECMAInternationalによって「ECMAScript」という名前で標準化されています。 約年に1回、ECMAは新しい機能を備えた新しいバージョンのECMAScriptをリリースします。

デフォルトでは、 jshint コードがES6(ECMAScriptバージョン6)と互換性があると想定し、そのバージョンでサポートされていないキーワードが見つかった場合はエラーをスローします。 コードと互換性のあるバージョンを見つける必要があります。 最近のすべてのバージョンの機能テーブルを見ると、 async/await キーワードはES8まで導入されませんでした。 データベーステストコードで両方のキーワードを使用したため、互換性のある最小バージョンがES8に設定されます。

伝えるために jshint 使用しているバージョンで、というファイルを作成します .jshintrc:

  1. nano .jshintrc

ファイルで、 esversion. The jshintrc ファイルはJSONを使用するため、ファイルに新しいJSONオブジェクトを作成します。

.jshintrc
{ "esversion": 8 }

ファイルを保存して、エディターを終了します。

実行するコマンドを追加する jshint. 編集 package.json:

  1. nano package.json

追加する lint プロジェクトへのコマンド scripts のセクション package.json. このコマンドは、これまでに作成したすべてのJavaScriptファイルに対してlintツールを呼び出します。

package.json
. . .

  "scripts": {
    "test": "jest",
    "start": "node app.js",
    "lint": "jshint app.js database*.js migrate.js"
  },

. . .

これで、リンターを実行して問題を見つけることができます。

  1. npm run lint

エラーメッセージは表示されないはずです。

Output
> jshint app.js database*.js migrate.js

エラーがある場合は、 jshint 問題のある行が表示されます。

プロジェクトを完了し、プロジェクトが機能することを確認しました。 ファイルをリポジトリに追加し、コミットして、変更をプッシュします。

  1. git add *.js
  2. git add package*.json
  3. git add .jshintrc
  4. git commit -m 'initial commit'
  5. git push origin master

これで、DigitalOceanパーソナルアクセストークンとデータベースクレデンシャルを使用してSemaphoreを構成することから始めて、アプリケーションをテスト、ビルド、およびデプロイするようにSemaphoreを構成できます。

ステップ3—セマフォでシークレットを作成する

GitHubリポジトリに属していない情報がいくつかあります。 パスワードとAPIトークンはこの良い例です。 この機密データを別のファイルに保存して環境にロードしました。セマフォを使用する場合は、シークレットを使用して機密データを保存できます。

プロジェクトには3種類の秘密があります。

  • Docker Hub:DockerHubアカウントのユーザー名とパスワード。
  • DigitalOceanパーソナルアクセストークン:アプリケーションをKubernetesクラスターにデプロイします。
  • 環境変数:データベースのユーザー名とパスワードの接続パラメーター用。

最初のシークレットを作成するには、ブラウザを開いてセマフォのWebサイトにログインします。 左側のナビゲーションメニューで、CONFIGURATION見出しの下にあるSecretsをクリックします。 新しいシークレットの作成ボタンをクリックします。

シークレットの名前に次のように入力します dockerhub. 次に、環境変数の下に、2つの環境変数を作成します。

  • DOCKER_USERNAME:DockerHubユーザー名。
  • DOCKER_PASSWORD:DockerHubのパスワード。

[変更を保存]をクリックします。

DigitalOceanパーソナルアクセストークンの2番目のシークレットを作成します。 もう一度、左側のナビゲーションメニューのシークレットをクリックしてから、新しいシークレットの作成をクリックします。 この秘密を呼ぶ do-access-token と呼ばれる環境値を作成します DO_ACCESS_TOKEN 値をパーソナルアクセストークンに設定します。

秘密を保存します。

次の秘密のために、環境変数を直接設定する代わりに、 .env プロジェクトのルートからのファイル。

と呼ばれる新しい秘密を作成します env-production. ファイルセクションで、ファイルのアップロードリンクを押して、 .env ファイルし、セマフォに配置するように指示します /home/semaphore/env-production.

注:ファイルが非表示になっているため、コンピューターでファイルを見つけるのに問題が発生する可能性があります。 通常、隠しファイルを表示するためのメニュー項目またはキーの組み合わせがあります。 CTRL+H. 他のすべてが失敗した場合は、非表示になっていない名前でファイルをコピーしてみてください。

  1. cp .env env

次に、ファイルをアップロードして、名前を元に戻します。

  1. cp env .env

環境変数はすべて構成されています。 これで、継続的インテグレーションのセットアップを開始できます。

ステップ4—プロジェクトをSemaphoreに追加する

このステップでは、プロジェクトをSemaphoreに追加し、継続的インテグレーション(CI)パイプラインを開始します。

まず、GitHubリポジトリをSemaphoreにリンクします。

  1. セマフォアカウントにログインします。
  2. プロジェクトの横にある+アイコンをクリックします。
  3. リポジトリの横にあるリポジトリの追加ボタンをクリックします。

Semaphoreが接続されたので、リポジトリ内の変更を自動的に取得します。

これで、アプリケーションの継続的インテグレーションパイプラインを作成する準備が整いました。 パイプラインは、コードがビルド、テスト、およびデプロイされるために移動する必要のあるパスを定義します。 パイプラインは、GitHubリポジトリに変更があるたびに自動的に実行されます。

まず、Semaphoreが開発中に使用していたのと同じバージョンのNodeを使用していることを確認する必要があります。 マシンで実行されているバージョンを確認できます。

  1. node -v
Output
v10.16.0

Semaphoreに、次のファイルを作成することで、使用するNode.jsのバージョンを指示できます。 .nvmrc リポジトリ内。 内部的には、Semaphoreはノードバージョンマネージャーを使用してNode.jsバージョンを切り替えます。 を作成します .nvmrc ファイルを作成し、バージョンをに設定します 10.16.0:

  1. echo '10.16.0' > .nvmrc

セマフォパイプラインは .semaphore ディレクトリ。 ディレクトリを作成します。

  1. mkdir .semaphore

新しいパイプラインファイルを作成します。 最初のパイプラインは常に呼び出されます semaphore.yml. このファイルでは、アプリケーションのビルドとテストに必要なすべての手順を定義します。

  1. nano .semaphore/semaphore.yml

YAML形式でファイルを作成しています。 チュートリアルに示されているように、先頭のスペースを保持する必要があります。

最初の行は、セマフォファイルのバージョンを設定する必要があります。 現在の安定は v1.0. また、パイプラインには名前が必要です。 次の行をファイルに追加します。

.semaphore / semaphore.yml
version: v1.0
name: Addressbook

. . .

セマフォは、タスクを実行するために仮想マシンを自動的にプロビジョニングします。 から選択できるさまざまなマシンがあります。 統合ジョブには、 e1-standard-2 (2 CPU 4 GB RAM)とUbuntu18.04OS。 次の行をファイルに追加します。

.semaphore / semaphore.yml
. . .

agent:
  machine:
    type: e1-standard-2
    os_image: ubuntu1804

. . .

セマフォはブロックを使用してタスクを整理します。 各ブロックには、1つ以上のジョブを含めることができます。 ブロック内のすべてのジョブは並行して実行され、それぞれが分離されたマシンで実行されます。 セマフォは、ブロック内のすべてのジョブが通過するのを待ってから、次のジョブを開始します。

最初のブロックを定義することから始めます。これにより、アプリケーションをテストして実行するためのすべてのJavaScript依存関係がインストールされます。

.semaphore / semaphore.yml
. . .

blocks:
  - name: Install dependencies
    task:

. . .

設定など、すべてのジョブに共通の環境変数を定義できます NODE_ENVtestしたがって、Node.jsはこれがテスト環境であることを認識しています。 このコードを後に追加します task:

.semaphore / semaphore.yml
. . .
    task:
      env_vars:
        - name: NODE_ENV
          value: test

. . .

prologue セクションのコマンドは、ブロック内の各ジョブの前に実行されます。 セットアップタスクを定義するのに便利な場所です。 checkout を使用して、GitHubリポジトリのクローンを作成できます。 それで、 nvm use で指定した適切なNode.jsバージョンをアクティブ化します .nvmrc. 追加します prologue セクション:

.semaphore / semaphore.yml
    task:
. . .

      prologue:
        commands:
          - checkout
          - nvm use

. . .

次に、このコードを追加して、プロジェクトの依存関係をインストールします。 ジョブを高速化するために、Semaphoreはcacheツールを提供しています。 あなたが実行することができます cache store 保存する node_modules セマフォのキャッシュ内のディレクトリ。 cache どのファイルとディレクトリを保存する必要があるかを自動的に判断します。 2回目にジョブが実行されると、 cache restore ディレクトリを復元します。

.semaphore / semaphore.yml
. . .

      jobs:
        - name: npm install and cache
          commands:
            - cache restore
            - npm install
            - cache store 

. . .

2つのジョブを実行する別のブロックを追加します。 1つはlintテストを実行し、もう1つはアプリケーションのテストスイートを実行します。

.semaphore / semaphore.yml
. . .

  - name: Tests
    task:
      env_vars:
        - name: NODE_ENV
          value: test
      prologue:
        commands:
          - checkout
          - nvm use
          - cache restore 

. . .

The prologue 前のブロックと同じコマンドを繰り返して復元します node_module キャッシュから。 このブロックはテストを実行するため、 NODE_ENV 環境変数から test.

次に、ジョブを追加します。 最初のジョブは、jshintを使用してコード品質チェックを実行します。

.semaphore / semaphore.yml
. . .

      jobs:
        - name: Static test
          commands:
            - npm run lint

. . .

次のジョブは単体テストを実行します。 本番データベースを使用したくないので、それらを実行するにはデータベースが必要です。 セマフォのsem-serviceは、完全に分離されたテスト環境でローカルPostgreSQLデータベースを起動できます。 ジョブが終了すると、データベースは破棄されます。 このサービスを開始し、テストを実行します。

.semaphore / semaphore.yml
. . .

        - name: Unit test
          commands:
            - sem-service start postgres
            - npm run test

を助けて .semaphore/semaphore.yml ファイル。

次に、変更をGitHubリポジトリに追加してコミットします。

  1. git add .nvmrc
  2. git add .semaphore/semaphore.yml
  3. git commit -m "continuous integration pipeline"
  4. git push origin master

コードがGitHubにプッシュされるとすぐに、SemaphoreはCIパイプラインを開始します。

パイプラインをクリックして、ブロックとジョブ、およびそれらの出力を表示できます。

次に、アプリケーションのDockerイメージを構築する新しいパイプラインを作成します。

ステップ5—アプリケーション用のDockerイメージを構築する

Dockerイメージは、Kubernetesデプロイメントの基本ユニットです。 イメージには、アプリケーションの実行に必要なすべてのバイナリ、ライブラリ、およびコードが含まれている必要があります。 Dockerコンテナーは軽量の仮想マシンではありませんが、そのように動作します。 Docker Hubレジストリには、すぐに使用できる数百のイメージが含まれていますが、独自のイメージを作成します。

このステップでは、新しいパイプラインを追加して、アプリのカスタムDockerイメージを構築し、DockerHubにプッシュします。

カスタムイメージを作成するには、 Dockerfile:

  1. nano Dockerfile

The Dockerfile 画像を作成するためのレシピです。 official Node.jsディストリビューションを最初から始める代わりに、開始点として使用できます。 これをあなたに追加してください Dockerfile:

Dockerfile
FROM node:10.16.0-alpine

. . .

次に、コピーするコマンドを追加します package.jsonpackage-lock.json、次に、イメージ内にノードモジュールをインストールします。

Dockerfile
. . .

COPY package*.json ./
RUN npm install

. . .

Dockerがこのステップをキャッシュするため、最初に依存関係をインストールすると、後続のビルドが高速化されます。

次に、プロジェクトルート内のすべてのアプリケーションファイルをイメージにコピーする次のコマンドを追加します。

Dockerfile
. . .

COPY *.js ./

. . .

ついに、 EXPOSE コンテナがポートで接続をリッスンすることを指定します 3000、アプリケーションがリッスンしている場所、および CMD コンテナの起動時に実行するコマンドを設定します。 次の行をファイルに追加します。

Dockerfile
. . .

EXPOSE 3000
CMD [ "npm", "run", "start" ]

ファイルを保存します。

Dockerfileが完成したら、新しいパイプラインを作成して、コードをGitHubにプッシュするときにSemaphoreがイメージを構築できるようにします。 と呼ばれる新しいファイルを作成します docker-build.yml:

  1. nano .semaphore/docker-build.yml

CIパイプラインと同じボイラープレートでパイプラインを開始しますが、名前は Docker build:

.semaphore / docker-build.yml
version: v1.0
name: Docker build
agent:
  machine:
    type: e1-standard-2
    os_image: ubuntu1804

. . .

このパイプラインには、1つのブロックと1つのジョブしかありません。 ステップ3で、という名前のシークレットを作成しました dockerhub DockerHubのユーザー名とパスワードを使用します。 ここでは、を使用してこれらの値をインポートします secrets キーワード。 このコードを追加します:

.semaphore / docker-build.yml
. . .

blocks:
  - name: Build
    task:
      secrets:
        - name: dockerhub

. . .

Dockerイメージはリポジトリに保存されます。 公開画像の数に制限がない公式のDockerHubを使用します。 これらの行を追加してGitHubからコードをチェックアウトし、 docker login DockerHubで認証するコマンド。

.semaphore / docker-build.yml
    task:
. . .

      prologue:
        commands:
          - checkout
          - echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin

. . .

各Dockerイメージは、名前とタグの組み合わせによって完全に識別されます。 名前は通常、製品またはソフトウェアに対応し、タグはソフトウェアの特定のバージョンに対応します。 例えば、 node.10.16.0. タグが指定されていない場合、Dockerはデフォルトで特別なものになります latest 鬼ごっこ。 したがって、を使用することをお勧めします latest 最新の画像を参照するためのタグ。

次のコードを追加してイメージをビルドし、DockerHubにプッシュします。

.semaphore / docker-build.yml
. . .

      jobs:
      - name: Docker build
        commands:
          - docker pull "${DOCKER_USERNAME}/addressbook:latest" || true
          - docker build --cache-from "${DOCKER_USERNAME}/addressbook:latest" -t "${DOCKER_USERNAME}/addressbook:$SEMAPHORE_WORKFLOW_ID" .
          - docker push "${DOCKER_USERNAME}/addressbook:$SEMAPHORE_WORKFLOW_ID"

Dockerがイメージをビルドするとき、既存のイメージの一部を再利用してプロセスを高速化します。 最初のコマンドはプルしようとします latest Docker Hubからのイメージなので、再利用できます。 コマンドのいずれかがゼロ以外のステータスコードを返す場合、セマフォはパイプラインを停止します。 たとえば、リポジトリに何も含まれていない場合 latest 画像、最初の試行ではないため、パイプラインは停止します。 追加することで、失敗したコマンドをセマフォに無視させることができます || true コマンドに。

2番目のコマンドは、イメージをビルドします。 この特定の画像を後で参照するために、一意の文字列でタグ付けできます。 セマフォは、ジョブにいくつかの環境変数を提供します。 それらの中の一つ、 $SEMAPHORE_WORKFLOW_ID は一意であり、ワークフロー内のすべてのパイプライン間で共有されます。 展開の後半でこのイメージを参照するのに便利です。

3番目のコマンドは、イメージをDockerHubにプッシュします。

ビルドパイプラインの準備はできていますが、メインCIパイプラインに接続しない限り、Semaphoreはビルドパイプラインを開始しません。 Promotions を使用して、複数のパイプラインをチェーンし、複雑なマルチブランチワークフローを作成できます。

メインパイプラインファイルを編集します .semaphore/semaphore.yml:

  1. nano .semaphore/semaphore.yml

ファイルの最後に次の行を追加します。

.semaphore / semaphore.yml
. . .

promotions:
  - name: Dockerize
    pipeline_file: docker-build.yml
    auto_promote_on:
      - result: passed

auto_promote_on 開始する条件を定義します docker build パイプライン。 この場合、で定義されたすべてのジョブが semaphore.yml ファイルが通過しました。

新しいパイプラインをテストするには、変更したすべてのファイルをGitHubに追加、コミット、プッシュする必要があります。

  1. git add Dockerfile
  2. git add .semaphore/docker-build.yml
  3. git add .semaphore/semaphore.yml
  4. git commit -m "docker build pipeline"
  5. git push origin master

CIパイプラインが完了すると、Dockerビルドパイプラインが開始されます。

完了すると、DockerHubリポジトリに新しいイメージが表示されます。

ビルドプロセスのテストとイメージの作成が完了しました。 次に、アプリケーションをKubernetesクラスターにデプロイするための最終的なパイプラインを作成します。

ステップ6—Kubernetesへの継続的デプロイの設定

Kubernetesデプロイメントの構成要素は、ポッドです。 ポッドは、単一のユニットとして管理されるコンテナのグループです。 ポッド内のコンテナは同時に開始および停止し、常に同じマシン上で実行され、そのリソースを共有します。 各ポッドにはIPアドレスがあります。 この場合、ポッドにはコンテナが1つだけあります。

ポッドは一時的なものです。 それらは頻繁に作成および破棄されます。 開始するまで、各ポッドにどのIPアドレスが割り当てられるかはわかりません。 これを解決するには、 services を使用します。これは、パブリックIPアドレスが固定されているため、着信接続の負荷を分散してポッドに転送できます。

ポッドを直接管理することもできますが、デプロイメントを使用してKubernetesに処理させることをお勧めします。 このセクションでは、クラスターの最終的な望ましい状態を説明する宣言型マニフェストを作成します。 マニフェストには2つのリソースがあります。

  • 展開:必要に応じてクラスターノードでポッドを起動し、そのステータスを追跡します。 このチュートリアルでは3ノードのクラスターを使用しているため、3つのポッドをデプロイします。
  • サービス:ユーザーのエントリポイントとして機能します。 ポートでトラフィックをリッスンします 80 (HTTP)そして接続をポッドに転送します。

と呼ばれるマニフェストファイルを作成します deployment.yml:

  1. nano deployment.yml

マニフェストを Deployment 資源。 次の内容を新しいファイルに追加して、デプロイメントを定義します。

deploy.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: addressbook
spec:
  replicas: 3
  selector:
    matchLabels:
      app: addressbook
  template:
    metadata:
      labels:
        app: addressbook
    spec:
      containers:
        - name: addressbook
          image: ${DOCKER_USERNAME}/addressbook:${SEMAPHORE_WORKFLOW_ID}
          env:
            - name: NODE_ENV
              value: "production"
            - name: PORT
              value: "$PORT"
            - name: DB_SCHEMA
              value: "$DB_SCHEMA"
            - name: DB_USER
              value: "$DB_USER"
            - name: DB_PASSWORD
              value: "$DB_PASSWORD"
            - name: DB_HOST
              value: "$DB_HOST"
            - name: DB_PORT
              value: "$DB_PORT"
            - name: DB_SSL
              value: "$DB_SSL"


. . .

マニフェストのリソースごとに、 apiVersion. 展開には、 apiVersion: apps/v1、安定版。 次に、このリソースがDeploymentwithであることをKubernetesに伝えます kind: Deployment. 各定義には、で定義された名前が必要です。 metadata.name.

の中に spec 望ましい最終状態が何であるかをKubernetesに伝えるセクション。 この定義では、Kubernetesで3つのポッドを作成する必要があります replicas: 3.

Labels は、Kubernetesリソースを整理および相互参照するために使用されるキーと値のペアです。 ラベルを定義する metadata.labels、および一致するラベルを探すことができます selector.matchLabels. これは、要素を相互に接続する方法です。

キー spec.template Kubernetesが各ポッドを作成するために使用するモデルを定義します。 中身 spec.template.metadata.labels ポッドに1つのラベルを設定します。 app: addressbook.

spec.selector.matchLabels デプロイメントにラベルが付いたポッドを管理させる app: addressbook. この場合、このデプロイメントにすべてのポッドの責任を負わせます。

最後に、ポッドで実行されるイメージを定義します。 の spec.template.spec.containers 画像名を設定します。 Kubernetesは、必要に応じてレジストリからイメージをプルします。 この場合、Docker Hubからプルします)。 コンテナの環境変数を設定することもできます。これは、データベース接続にいくつかの値を指定する必要があるため、幸いです。

デプロイメントマニフェストを柔軟に保つために、変数に依存することになります。 ただし、YAML形式では変数が許可されていないため、ファイルはまだ有効ではありません。 Semaphoreのデプロイメントパイプラインを定義するときに、この問題を解決します。

展開は以上です。 しかし、これはポッドを定義するだけです。 トラフィックがポッドに流れるようにするサービスがまだ必要です。 3つのハイフンを使用している限り、同じファイルに別のKubernetesリソースを追加できます(---)セパレータとして。

次のコードを追加して、ポッドに接続するロードバランサーサービスを定義します。 addressbook ラベル:

deploy.yml
. . .

---

apiVersion: v1
kind: Service
metadata:
  name: addressbook-lb
spec:
  selector:
    app: addressbook
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 3000

ロードバランサーはポートで接続を受信します 80 それらをポッドのポートに転送します 3000 アプリケーションがリッスンしている場所。

ファイルを保存します。

次に、マニフェストを使用してアプリをデプロイするSemaphoreのデプロイメントパイプラインを作成します。 に新しいファイルを作成します .semaphore ディレクトリ:

  1. nano .semaphore/deploy-k8s.yml

バージョン、名前、イメージを指定して、通常どおりパイプラインを開始します。

.semaphore / deploy-k8s.yml
version: v1.0
name: Deploy to Kubernetes
agent:
  machine:
    type: e1-standard-2
    os_image: ubuntu1804

. . .

このパイプラインには2つのブロックがあります。 最初のブロックは、アプリケーションをKubernetesクラスターにデプロイします。

ブロックを定義し、すべてのシークレットをインポートします。

.semaphore / deploy-k8s.yml
. . .

blocks:
  - name: Deploy to Kubernetes
    task:
      secrets:
        - name: dockerhub
        - name: do-access-token
        - name: env-production

. . .

DigitalOcean Kubernetesクラスター名を環境変数に保存して、後で参照できるようにします。

.semaphore / deploy-k8s.yml
. . .

      env_vars:
        - name: CLUSTER_NAME
          value: addressbook-server

. . .

DigitalOcean Kubernetesクラスターは、次の2つのプログラムを組み合わせて管理されます。 kubectldoctl. 前者はすでにセマフォのイメージに含まれていますが、後者は含まれていないため、インストールする必要があります。 あなたは使用することができます prologue それを行うセクション。

このプロローグセクションを追加します。

.semaphore / deploy-k8s.yml
. . .

      prologue:
        commands:
          - wget https://github.com/digitalocean/doctl/releases/download/v1.20.0/doctl-1.20.0-linux-amd64.tar.gz
          - tar xf doctl-1.20.0-linux-amd64.tar.gz 
          - sudo cp doctl /usr/local/bin
          - doctl auth init --access-token $DO_ACCESS_TOKEN
          - doctl kubernetes cluster kubeconfig save "${CLUSTER_NAME}"
          - checkout

. . .

最初のコマンドは、 doctl 公式リリース wget. 2番目のコマンドはそれを解凍します tar それをローカルパスにコピーします。 一度 doctl がインストールされている場合は、DigitalOcean APIで認証し、クラスターのKubernetes構成ファイルをリクエストするために使用できます。 コードをチェックアウトした後、 prologue:

次は、パイプラインの最後の部分であるクラスターへのデプロイです。

にいくつかの環境変数があったことを忘れないでください deployment.yml、およびYAMLはそれを許可しません。 結果として、 deployment.yml 現在の状態では、機能しません。 それを回避するために、 source 変数をロードするための環境ファイルを使用してから、 envsubst 変数を実際の値でインプレースに展開するコマンド。 結果、というファイル deploy.ymlは、値が挿入された完全に有効なYAMLです。 ファイルを配置したら、次のコマンドで展開を開始できます。 kubectl apply:

.semaphore / deploy-k8s.yml
. . .

      jobs:
      - name: Deploy
        commands:
          - source $HOME/env-production
          - envsubst < deployment.yml | tee deploy.yml
          - kubectl apply -f deploy.yml

. . .

2番目のブロックは latest Docker Hubのイメージにタグを付けて、これがデプロイされている最新バージョンであることを示します。 Dockerログイン手順を繰り返してから、Docker Hubをプル、再タグ付け、プッシュします。

.semaphore / deploy-k8s.yml
. . .

  - name: Tag latest release
    task:
      secrets:
        - name: dockerhub
      prologue:
        commands:
          - checkout
          - echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin
          - checkout
      jobs:
      - name: docker tag latest
        commands:
          - docker pull "${DOCKER_USERNAME}/addressbook:$SEMAPHORE_WORKFLOW_ID" 
          - docker tag "${DOCKER_USERNAME}/addressbook:$SEMAPHORE_WORKFLOW_ID" "${DOCKER_USERNAME}/addressbook:latest"
          - docker push "${DOCKER_USERNAME}/addressbook:latest"

ファイルを保存します。

このパイプラインはデプロイを実行しますが、Dockerイメージが正常に生成されてDockerHubにプッシュされた場合にのみ開始できます。 そのため、ビルドパイプラインとデプロイメントパイプラインをプロモーションに接続する必要があります。 Dockerビルドパイプラインを編集して追加します。

  1. nano .semaphore/docker-build.yml

ファイルの最後にプロモーションを追加します。

.semaphore / docker-build.yml
. . .

promotions:
  - name: Deploy to Kubernetes
    pipeline_file: deploy-k8s.yml
    auto_promote_on:
      - result: passed

CI/CDワークフローの設定が完了しました。

残っているのは、変更されたファイルをプッシュし、Semaphoreに作業を任せることだけです。 リポジトリの変更を追加、コミット、およびプッシュします。

  1. git add .semaphore/deploy-k8s.yml
  2. git add .semaphore/docker-build.yml
  3. git add deployment.yml
  4. git commit -m "kubernetes deploy pipeline"
  5. git push origin master

展開が完了するまでに数分かかります。

次に、アプリケーションをテストしてみましょう。

ステップ7—アプリケーションのテスト

この時点で、アプリケーションは稼働しています。 このステップでは、 curl APIエンドポイントをテストします。

DigitalOceanがクラスターに与えたパブリックIPを知る必要があります。 次の手順に従って見つけてください。

  1. DigitalOceanアカウントにログインします。
  2. アドレスブックプロジェクトを選択します
  3. ネットワーキングに移動します。
  4. ロードバランサーをクリックします。
  5. IPアドレスが表示されます。 IPアドレスをコピーします。

確認してみましょう /all を使用したルート curl:

  1. curl -w "\n" YOUR_CLUSTER_IP/all

あなたは使用することができます -w "\n" 確実にするオプション curl すべての行を印刷します:

データベースにはまだレコードがないため、結果として空のJSON配列が取得されます。

Output
[]

を作成して新しい人物レコードを作成します PUT にリクエスト /person 終点:

  1. curl -w "\n" -X PUT \
  2. -d "firstName=Sammy&lastName=the Shark" YOUR_CLUSTER_IP/person

APIは、個人のJSONオブジェクトを返します。

Output
{ "id": 1, "firstName": "Sammy", "lastName": "the Shark", "updatedAt": "2019-07-04T23:51:00.548Z", "createdAt": "2019-07-04T23:51:00.548Z" }

2人目の人を作成します。

  1. curl -w "\n" -X PUT \
  2. -d "firstName=Tommy&lastName=the Octopus" YOUR_CLUSTER_IP/person

出力は、2人目の人物が作成されたことを示しています。

Output
{ "id": 2, "firstName": "Tommy", "lastName": "the Octopus", "updatedAt": "2019-07-04T23:52:08.724Z", "createdAt": "2019-07-04T23:52:08.724Z" }

今、 GET を持っている人を取得するためのリクエスト id2:

  1. curl -w "\n" YOUR_CLUSTER_IP/person/2

サーバーは、要求されたデータで応答します。

Output
{ "id": 2, "firstName": "Tommy", "lastName": "the Octopus", "createdAt": "2019-07-04T23:52:08.724Z", "updatedAt": "2019-07-04T23:52:08.724Z" }

人物を削除するには、 DELETE リクエスト:

  1. curl -w "\n" -X DELETE YOUR_CLUSTER_IP/person/2

このコマンドでは出力は返されません。

データベースには1人だけが必要です。 id1. 取得してみてください /all また:

  1. curl -w "\n" YOUR_CLUSTER_IP/all

サーバーは、1つのレコードのみを含む一連の人物で応答します。

Output
[ { "id": 1, "firstName": "Sammy", "lastName": "the Shark", "createdAt": "2019-07-04T23:51:00.548Z", "updatedAt": "2019-07-04T23:51:00.548Z" } ]

この時点で、データベースに残っているのは1人だけです。

これで、アプリケーション内のすべてのエンドポイントのテストが完了し、チュートリアルの終わりを示します。

結論

このチュートリアルでは、DigitalOceanのマネージドPostgreSQLデータベースサービスを使用して、完全なNode.jsアプリケーションを最初から作成しました。 次に、SemaphoreのCI / CDパイプラインを使用して、コンテナーイメージをテストおよび構築し、Docker Hubにアップロードして、DigitalOceanKubernetesにデプロイするワークフローを完全に自動化しました。

Kubernetesの詳細については、Kubernetesの概要およびその他のDigitalOceanのKubernetesチュートリアルをご覧ください。

アプリケーションがデプロイされたので、ドメイン名の追加データベースクラスターの保護、またはデータベースのアラートの設定を検討できます。