例
このセクションには、Things Cloud APIおよびその他の第三者サービスを使用するマイクロサービスを開発するための一連のチュートリアルを紹介します。ここで使用されるサンプルコードはGitHubリポジトリで見つけることができます。
Things Cloudプラットフォームでは、マイクロサービスのホスティングはDockerコンテナの上に構築されています。これにより、技術に依存しないため、開発者は任意の技術スタックでアプリケーションを作成することができます。
このセクションには、Things Cloud APIおよびその他の第三者サービスを使用するマイクロサービスを開発するための一連のチュートリアルを紹介します。ここで使用されるサンプルコードはGitHubリポジトリで見つけることができます。
Things Cloudプラットフォームでは、マイクロサービスのホスティングはDockerコンテナの上に構築されています。これにより、技術に依存しないため、開発者は任意の技術スタックでアプリケーションを作成することができます。
このチュートリアルでは、Python で記述されたマイクロサービスを作成して実行する方法を学びます。
最新バージョンのDockerがインストールされていることを確認してください。例えば、お使いのオペレーティングシステムに合ったDocker Desktopをインストールできます。
Things Cloudはlinux/amd64 Dockerコンテナをホストしています。例えば、Appleシリコンを搭載した最近のMacを使用している場合、Dockerを設定してlinux/amd64コンテナをビルドする必要があります。
$ export DOCKER_DEFAULT_PLATFORM=linux/amd64
この例では、Python 3、WebフレームワークFlask、HTTPサーバーWaitressを使用します。まず、以下の内容の application.py スクリプトを作成します。
#!flask/bin/python
from flask import Flask, jsonify
import os
app = Flask(__name__)
# Hello world endpoint
@app.route('/')
def hello():
return 'Hello world!'
# Verify the status of the microservice
@app.route('/health')
def health():
return '{ "status" : "UP" }'
# Get environment details
@app.route('/environment')
def environment():
environment_data = {
'platformUrl': os.getenv('C8Y_BASEURL'),
'mqttPlatformUrl': os.getenv('C8Y_BASEURL_MQTT'),
'tenant': os.getenv('C8Y_BOOTSTRAP_TENANT'),
'user': os.getenv('C8Y_BOOTSTRAP_USER'),
'password': os.getenv('C8Y_BOOTSTRAP_PASSWORD'),
'microserviceIsolation': os.getenv('C8Y_MICROSERVICE_ISOLATION')
}
return jsonify(environment_data)
if __name__ == '__main__':
import logging
logging.basicConfig(level=logging.INFO)
from waitress import serve
serve(app, host="0.0.0.0", port=80)
アプリケーションは 3 つのエンドポイントを公開します。
これはポート80でHTTPサーバーを実行します。これはすべてのマイクロサービスに必要です。
ログは「INFO」レベルに設定されており、管理アプリケーションでのいくつかのログ情報を表示します。ログレベルの設定を削除すると、警告のみが記録されます。
アプリケーションを含む実行可能なDockerイメージをビルドするために、application.py スクリプトと同じディレクトリに「Dockerfile」を作成し、次の内容を追加します。
FROM python:alpine
COPY application.py /
RUN pip install flask waitress
ENTRYPOINT ["python"]
CMD ["-u", "application.py"]
Dockerfileは次のことを行います。
Dockerイメージに加えて、Things Cloud はDockerイメージを正しく実行するためにいくつかの追加情報を必要とします。これはアプリケーションマニフェストで提供されます。他のファイルと同じフォルダに cumulocity.json ファイルを作成し、以下の内容を追加してください。
{
"apiVersion": "2",
"version": "1.0.0",
"provider": {
"name": "Things Cloud"
},
"isolation": "MULTI_TENANT",
"replicas": 2,
"livenessProbe": {
"httpGet": {
"path": "/health"
},
"initialDelaySeconds": 10
},
"readinessProbe": {
"httpGet": {
"path": "/health"
},
"initialDelaySeconds": 10
},
"requiredRoles": [ ],
"roles": [ ]
}
マイクロサービス:
次のDockerコマンドを実行してDockerイメージをビルドし、image.tar として保存します。
$ docker build -t hello-python-microservice .
$ docker save hello-python-microservice > "image.tar"
次に、image.tar とマニフェスト cumulocity.json をZIPファイルにパッケージ化します。
$ zip hello-microservice cumulocity.json image.tar
生成された hello-microservice.zip ファイルにはマイクロサービスが含まれており、Things Cloudプラットフォームにアップロード可能となりました。
hello-microservice.zip をプラットフォームにアップロードするには、UIを使用します。管理アプリケーションの、エコシステム > マイクロサービスに移動し、マイクロサービスの追加をクリックします。マイクロサービスのZIPファイルをドロップして、サブスクライブをクリックします。マイクロサービスZIPファイルのアップロードに関する詳細は、カスタムマイクロサービスを参照してください。
マイクロサービスがテナントによって正常にアップロードされ、サブスクライブされた後、それはDockerコンテナ内で実行されます。管理アプリケーションでマイクロサービスのステータスおよびログタブを確認することで、これを確認できます。
マイクロサービスを試すには、curlのようなコマンドラインツールを使用します。tenantID は、ユーザーアイコン をクリックしたときに表示される右の引き出しのプラットフォーム情報の下にあります。
$ curl -u '<tenantID>/<username>:<password>' https://<URL>/service/hello/environment
{
"microserviceIsolation": "MULTI_TENANT",
"mqttPlatformUrl": "tcp://cumulocity:1881",
"password": "...",
"platformUrl": "https://cumulocity:8111",
"tenant": "mytenant",
"user": "servicebootstrap_hello-microservice"
}
注意点として、マイクロサービスへのすべてのリクエストは自動的に認証されます。認証なしでcurlコマンドを実行してみてください。
$ curl -v https://<URL>/service/hello/environment
…
< HTTP/1.1 401 Unauthorized
…
{"error":"general/internalError","message":"No auth information found","info":"https://cumulocity.com/guides/reference/rest-implementation"}
マイクロサービスユーティリティツールを使用して、アプリケーションをビルド、アップロード、およびサブスクライブすることもできます。このツールは、Dockerfile とアプリケーションファイルを含む docker フォルダが必要です。
docker/Dockerfile
docker/application.py
cumulocity.json
このHello worldマイクロサービスのソースコードは、GitHubリポジトリにあります。さらに、GitHubリポジトリには、より包括的なPythonマイクロサービスアプリケーションも用意されています。このアプリケーションはThings Cloud REST APIを使用し、マイクロサービスが稼働しているかどうかを確認したり、デバイスを作成してランダムな測定値を取得したり、特定のテナントの現在のアプリケーションサブスクリプションを取得したりするためのエンドポイントを公開しています。
Things Cloud は、Javaを使用してマイクロサービスを開発するためのSDKを提供します。ただし、一般的な要件を満たす限り、マイクロサービスを開発するための好みの技術スタックを選択することができます。
この例では、Node.jsベースのマイクロサービスを作成してデプロイする方法を学びます。アプリケーションは、マイクロサービスが正常に動作しているかどうかを確認し、一部の環境変数を取得するためのエンドポイントを公開します。
このアプリケーションは、Things Cloud @c8y/client JavaScriptライブラリを使用してアラームにサブスクライブします。新しいアラームが作成されると、Slackチャンネルに通知が届きます。
PORT=80
SLACK_OAUTH_TOKEN=<YOUR-TOKEN-GOES-HERE>
SLACK_CHANNEL_ID=<YOUR-CHANNEL_ID-GOES-HERE>
まず、ファイルを含むフォルダー node-microservice を作成します。そのフォルダー内で、次のコマンドを使用してプロジェクトを初期化します。
$ npm init
これにより、プロジェクトを識別し、その依存関係を管理するための package.json ファイルが作成されます。プロンプトが表示されたら、プロジェクトの情報を入力し、エントリポイントとして app.js を指定します。ファイルが作成されると、以下を使って依存関係をインストールします。
$ npm install --save @c8y/client @slack/web-api dotenv express
最終的に、package.json ファイルは次のようになります。
{
"name": "node-microservice",
"version": "1.0.0",
"description": "Things Cloud microservice application",
"main": "app.js",
"dependencies": {
"@c8y/client": "^1004.0.7",
"@slack/web-api": "^5.0.1",
"dotenv": "^8.0.0",
"express": "4.17.0"
},
"scripts": {
"start": "node app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "<your-name>",
"license": "MIT"
}
次に、アプリケーションのメインエントリポイントとなるファイル app.js を作成します。Expressフレームワークを使用してポート80でリッスンするサーバーを起動し、エンドポイントを定義し、コントローラーが Things Cloud とSlack APIを使用するように要求します。
"use strict";
require("dotenv").config();
const express = require("express");
const app = express();
// Application endpoints
const routes = require("./routes");
routes(app);
// Server listening on port 80
app.use(express.json());
app.listen(process.env.PORT);
console.log(`${process.env.APPLICATION_NAME} started on port ${process.env.PORT}`);
// Things Cloud and Slack controllers
require("./controllers");
既に気づいているかもしれませんが、routes
と controllers
が必要です。以下の内容を持つ routes.js ファイルを作成します。
"use strict";
module.exports = function(app) {
// Hello world
app.route("/").get(function(req, res) {
res.json({ "message" : "Hello world!" });
});
// Health check
app.route("/health").get(function(req, res) {
res.json({ "status" : "UP" });
});
// Environment variables
app.route("/environment").get(function(req, res) {
res.json({
"appName" : process.env.APPLICATION_NAME,
"platformUrl" : process.env.C8Y_BASEURL,
"microserviceIsolation" : process.env.C8Y_MICROSERVICE_ISOLATION,
"tenant" : process.env.C8Y_BOOTSTRAP_TENANT,
"bootstrapUser" : process.env.C8Y_BOOTSTRAP_USER,
"bootstrapPassword" : process.env.C8Y_BOOTSTRAP_PASSWORD
});
});
};
この時点で、マイクロサービスはウェブ経由でアクセスできるようになり、「Hello world」メッセージを返したり、マイクロサービスが正常に動作しているかどうかを確認したり、一部の環境変数を取得したりできます。
コントローラーを実装するには、まずSlackアプリを作成し、Web APIを使用するためのトークンを取得する必要があります。Slack API: Applications にアクセスして新しいアプリケーションを作成します。ワークスペースを選択し、アプリに名前を付けます(例:C8Y Slackボット)。次に、OAuthアクセストークンを取得してください。
Slackアプリとトークンを準備したら、以下の内容を持つ controllers.js ファイルを作成します。
"use strict";
/********************* Slack *********************/
// Create a new instance of the WebClient class with the OAuth access token
const { WebClient } = require("@slack/web-api");
const web = new WebClient(process.env.SLACK_OAUTH_TOKEN);
// Slack channel ID to know where to send messages to
const channelId = process.env.SLACK_CHANNEL_ID;
// Format a message and post it to the channel
async function postSlackMessage (adata) {
// Alarm severity
let color = {
"WARNING" : "#1c8ce3",
"MINOR" : "#ff801f",
"MAJOR" : "#e66400",
"CRITICAL": "#e0000e"
};
// Send a message from this app to the specified channel
let src = adata.source;
await web.chat.postMessage({
channel: channelId,
attachments : [{
"text": adata.text,
"fields": [
{
"title": "Source",
"value": `<${src.self}|${src.name ? src.name : src.id}>`,
"short": true
},
{
"title": "Alarm type",
"value": adata.type,
"short": true
}
],
"color": color[adata.severity]
}]
});
}
/********************* Things Cloud *********************/
const { Client, FetchClient, BasicAuth } = require("@c8y/client");
const baseUrl = process.env.C8Y_BASEURL;
let cachedUsers = [];
// Get the subscribed users
async function getUsers () {
const {
C8Y_BOOTSTRAP_TENANT: tenant,
C8Y_BOOTSTRAP_USER: user,
C8Y_BOOTSTRAP_PASSWORD: password
} = process.env;
const client = new FetchClient(new BasicAuth({ tenant, user, password }), baseUrl);
const res = await client.fetch("/application/currentApplication/subscriptions");
return res.json();
}
// where the magic happens...
(async () => {
cachedUsers = (await getUsers()).users;
if (Array.isArray(cachedUsers) && cachedUsers.length) {
// List filter for unresolved alarms only
const filter = {
pageSize: 100,
withTotalPages: true,
resolved: false
};
try {
cachedUsers.forEach(async (user) => {
// Service user credentials
let auth = new BasicAuth({
user: user.name,
password: user.password,
tenant: user.tenant
});
// Platform authentication
let client = await new Client(auth, baseUrl);
// Get filtered alarms and post a message to Slack
let { data } = await client.alarm.list(filter);
data.forEach((alarm) => {
postSlackMessage(alarm);
});
// Real time subscription for active alarms
client.realtime.subscribe("/alarms/*", (alarm) => {
if (alarm.data.data.status === "ACTIVE") {
postSlackMessage(alarm.data.data);
}
});
});
console.log("listening to alarms...");
}
catch (err) {
console.error(err);
}
}
else {
console.log("[ERROR]: Not subscribed/authorized users found.");
}
})();
このコードには2つの部分があります。最初の部分は、SlackのOAuthトークンとチャンネルID(メッセージが投稿されるチャットグループ)を必要とします。アラームの重大度に応じた色を使用してメッセージをフォーマットします。このメッセージはSlackチャンネルに投稿されます。
2つ目の部分は、Things Cloud プラットフォームへの基本認証を使用し、すべてのアクティブアラームを取得してSlackチャンネルにアラームメッセージを投稿します。その後、アラームにサブスクライブし、サブスクライブされたテナントで新しいアラームが作成されるたびにSlackチャンネルに通知します。
以下の内容を持つマイクロサービスマニフェスト cumulocity.json を作成します。
{
"apiVersion": "2",
"version": "1.0.0-SNAPSHOT",
"provider": {
"name": "Things Cloud"
},
"isolation": "MULTI_TENANT",
"replicas": 2,
"requiredRoles": [
"ROLE_ALARM_READ",
"ROLE_ALARM_ADMIN"
],
"roles": [ ]
}
最後に、Dockerはマイクロサービスのビルド方法を知る必要があります。次のように Dockerfile を作成してください。
FROM node:alpine
WORKDIR /usr/app
COPY ./package.json ./
RUN npm install
COPY ./ ./
CMD ["npm", "start"]
必要なファイルがすべて揃ったら、マイクロサービスアプリケーションのビルドとデプロイは非常に簡単です。以下のDockerコマンドを実行してDockerイメージをビルドし、image.tar として保存します。
$ docker build -t node-microservice .
$ docker save node-microservice > "image.tar"
次に、image.tar をマニフェスト cumulocity.json と共にZIPファイルにパックします。
$ zip node-microservice cumulocity.json image.tar
結果として得られる node-microservice.zip ファイルには、あなたのマイクロサービスが含まれており、Things Cloud プラットフォームにアップロードする準備が整いました。プラットフォームに node-microservice.zip をアップロードすることは、UIを介して行うことができます。管理アプリケーションで、エコシステム > マイクロサービスに移動し、マイクロサービスを追加をクリックします。マイクロサービスのZIPファイルをドロップして、次にサブスクライブをクリックします。
マイクロサービスZIPファイルのアップロードに関する詳細については、カスタムマイクロサービスを参照してください。
マイクロサービスがテナントに正常にアップロードされてサブスクライブされると、Dockerコンテナで実行されます。リクエストは次のようなものになります。
GET <URL>/service/node-microservice/environment
HEADERS:
"Authorization": "<AUTHORIZATION>"
適切な認証情報(サブスクライブされたテナントのユーザーとパスワード)を使用すると、次のようなレスポンスが返されます。
{
"appName": "node-microservice",
"platformUrl": "http://cumulocity:8111",
"microserviceIsolation": "MULTI_TENANT",
"tenant": "t...",
"bootstrapUser": "...",
"bootstrapPassword": "..."
}
認証ヘッダーは「Basic <Base64(<tenantID>/<username>:<password>)>」として形成されます。例えば、テナントID、ユーザー名、パスワードがそれぞれ t0071234 、testuser 、secret123 である場合、次のコマンドを使用してBase64文字列を取得できます。
$ echo -n t0071234/testuser:secret123 | base64
dDAwNzEyMzQvdGVzdHVzZXI6c2VjcmV0MTIz
認証ヘッダーは次のようになります。"Authorization": "Basic dDAwNzEyMzQvdGVzdHVzZXI6c2VjcmV0MTIz"
テナントにアクティブなアラームがある場合、あなたのSlackチャンネルに通知が届きます。また、Things Cloud REST APIを使用して新しいアラームを作成し、マイクロサービスが新しいアラームをリッスンしているかどうかを確認できます。あなたのSlackチャンネルにも通知が届きます。
このノードマイクロサービスのコードは、私たちの公共のGitHubリポジトリにあります。