メインコンテンツまでスキップ
バージョン: 2.0.0

OptXの登録方法

はじめに

この章では開発したDockerImageをOptXとしてNewtroidに登録する方法を説明します。

OptXとは

OptX は Newtroid 上で稼働するコンテナイメージです。 Newtroid では OptX を組み合わせてマイクロサービスアーキテクチャでシステムを構築、運用を行います。 このページでは OptX を開発し、Newtroid に登録し、実際に稼働させるまでの流れをチュートリアル形式で解説します。

newtroid-cicd-architecture

登録方法1:Jenkinsを使ってCI/CDを構築する(推奨)

CI/CDのフロー まず初めに以下に CI/CD のアーキテクチャを記載します。

alt text

Newtroidへのリリースサイクル newtroid-cicd-architecture

登録方法2:マニュアルで登録する

設定ファイル(optx-conf.json)の作成

最終的なディレクトリ構造は以下のようになりました。

TODO

2.2 optx-conf.json の作成

optx-conf.jsonは、環境変数、プロトコル、ポートの設定等、newtroid上でコンテナを起動するのに必要な設定情報を定義します。 optx-conf.jsonはjson形式で以下のパラメータを設定します。

{
version: string,
environments: string[]
io: {
input: {
name: string
portInside: number
type: `http` | `tcp`
}[],
output: {
name: string
type: `http` | `tcp`
}[]
}
}
parameterdescription
versionコンフファイルの形式を指定します。
environmentsnewtroid で optx を起動する前に設定できる環境変数を定義します。開発に.env を使用している場合はその内容を記載することをお勧めします。
ioio には newtroid でコンテナ同士を繋ぐためのインターフェースの設定を記述します。
inputアクセスを許可するポートを定義します。アプリケーションでリッスンするポートに合わせて設定をしてください。
input.name端子名。役割がわかりやすいように名前をつけます
input.portInsideアクセスを受け付けるポート番号
input.type通信プロトコル
outputサービス検出を行う端子を設定します。この端子でスロット同士を接続すると接続したスロットのアクセス情報が環境変数として起動時に与えられます。
output.name端子名。スロットを起動すると環境変数に NEWTROID_[端子名]_URL という環境変数で接続したコンテナのホスト情報が与えられます。例えば name をapiと設定していた場合、NEWTROID_API_URLにホスト情報が与えられます。複数のスロットを接続していた場合、カンマ区切りで変数が与えられます。アプリケーションは動的に接続先を変更することができます。(サービス検出)
output.type通信プロトコル

optx-conf.json の例

{
"version": 1,
"environments": ["MESSAGE"],
"io": {
"inputs": [{ "name": "none", "portInside": 3000, "type": "http" }],
"outputs": [{ "name": "api", "type": "http" }]
}
}

OptXの登録

OptX をリリースするには OptX を newtroid 上で作成し、Jenkinsでジョブを作成し、作成したnJenkinsfileによってビルドを実行する必要があります。 Jenkins のジョブ名に newtroid 上で作成した OptX ID を設定してください。

3.1 OptX の新規作成

Newtroid Console上からOptXを新規作成します。Create NewボタンをクリックしてOptXの名前を入力し、保存してください。 作成後、OptXにIDが割り当てらます。このIDはOptXをJenkinsでリリースする際に使用します。

alt text

コンテナイメージのアップロード

方法②:CI/CDを構築する(Jenkins)

Jenkinsfile を作成する

nJenkins ファイルは Jenkins のパイプラインスクリプト(groovy ベース)であり、OptX として newtroid 上に簡単にリリースできるようになっています。

ご自身の環境に合わせて以下の項目を修正してください。

変数名説明
NEWTROID_REGISTRY_URLDocker イメージを管理する Docker Registry の URL
NEWTROID_API_URLOptX を登録する newtroid の URL
DOCKER_FILE_PATHビルドする Dockerfile のパス。レポジトリのルートディレクトリからの相対パスを指定してください。
OPTX_CONF_PATH登録する OptX の optx-conf.json のパス。レポジトリのルートディレクトリからの相対パスを指定してください。

以下のプログラムが nJenkins のテンプレートになります。 適宜、 NEWTROID_REGISTRY_URLNEWTROID_API_URLDOCKER_FILE_PATHOPTX_CONF_PATH を変更してください。

import com.cloudbees.plugins.credentials.CredentialsProvider
import com.cloudbees.plugins.credentials.CredentialsMatchers
import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials
import com.cloudbees.plugins.credentials.domains.DomainRequirement
import hudson.security.ACL
import jenkins.model.Jenkins
import org.jenkinsci.plugins.plaincredentials.StringCredentials
import java.util.regex.Matcher
import java.util.regex.Pattern

//newtroid.ioリリース用
private void loadVarsFromFile(String path) {
print(path)
def file = readFile(path)
.replaceAll("(?m)^\\s*\\r?\\n", "") // skip empty line
.replaceAll("(?m)^#[^\\n]*\\r?\\n", "") // skip commented lines
file.split('\n').each { envLine ->
def (key, value) = envLine.tokenize('=')
env."${key}" = "${value.trim().replaceAll('^\"|\"$', '')}"
}
}

private String parseJobName(String jobName) {
def pattern = /optx__r_(.*?)__o_(.*?)__c_(.*?)__t_(.*)/
def compiledPattern = Pattern.compile(pattern)
def matcher = compiledPattern.matcher(jobName)
print(matcher)
if (matcher.find()) {
// マッチングした場合、各グループから値を取得
def repositoryName = matcher.group(1)
def optxId = matcher.group(2)
def contractorNo = matcher.group(3)
def tag = matcher.group(4)

// 結果をマップとして返す
return [
REPOSITORY_NAME: repositoryName,
OPTX_ID: optxId,
CONTRACTOR: contractorNo,
TAG: tag
]
} else {
// マッチしない場合はnullまたはエラーを返す
print("pattern not match")
return null
}
}

private String findApiKey(String credentialsId) {
// Jenkinsインスタンスを取得
def jenkins = Jenkins.getInstance()

// 認証情報を検索
def lookupCredentials = CredentialsProvider.lookupCredentials(
StringCredentials.class,
jenkins,
ACL.SYSTEM,
(List<DomainRequirement>) null
)

// 指定されたIDに一致する認証情報を取得
def credentials = CredentialsMatchers.firstOrNull(
lookupCredentials,
CredentialsMatchers.withId(credentialsId)
)

if (credentials) {
// 秘密テキスト(Secret Text)を取得
def secretText = credentials.getSecret().getPlainText()
println "取得したSecret Text: $secretText"
return secretText
} else {
println "指定されたIDの認証情報が見つかりませんでした。"
return null
}
}

pipeline {
agent any
environment {

SSH_NAME='sakura-vps-002'
NEWTROID_REGISTRY_URL="registry.optxstore.io"
NEWTROID_API_URL="nroid.io"

// ####### #######
// ####### EDIT ENV PATH #######
// ####### #######

DOCKER_FILE_PATH="./Dockerfile"
OPTX_CONF_PATH="./optx-conf.json"

// #########################
// #########################

// build_timestamp = sh(script: 'date +%Y%m%d-%H%M%S', returnStdout: true).trim()
// commit_id = sh(returnStdout: true, script: 'git rev-parse HEAD')
COMMIT_ID_SHORT = sh(returnStdout: true, script: 'git rev-parse --short HEAD')
}

//pre build
stages {
stage('Pre Check'){
steps{
script{
def parsed = parseJobName("${JOB_NAME}")
print(parsed)

env.OPTX_ID = parsed.OPTX_ID
env.CONTRACTOR = parsed.CONTRACTOR
env.OPTX_ID = parsed.OPTX_ID
env.TAG = parsed.TAG

def credentialsId = "${CONTRACTOR}__APIKEY"
env.API_KEY = findApiKey(credentialsId)
}
echo "${OPTX_ID}"
echo "node -v"
}
}

//register call api via groovy
stage('Register OptX'){
steps{
echo 'creates .env file'
script{
def endpoint = "https://${NEWTROID_API_URL}/api/1/contractors/${CONTRACTOR}/optx/${OPTX_ID}/file";
def query1 = String.format("apikey=%s", URLEncoder.encode("${API_KEY}", "UTF-8"));
def query2 = String.format("upsert=%s", URLEncoder.encode("true", "UTF-8"));
def url = endpoint + "?" + query1 + "&"+ query2;
def post = new URL(url).openConnection();

post.setRequestMethod("POST");
post.setDoInput(true);
post.setDoOutput(true);
post.addRequestProperty("Content-Type", "application/json; charset=UTF-8");
File file = new File("${JENKINS_HOME}/workspace/${JOB_NAME}", "${OPTX_CONF_PATH}");
// def text = "{\"hoge\":\"hoge\"}";

String escaped = file.getText("UTF-8");
escaped = escaped.replace("\\", "\\\\");
escaped = escaped.replace("\"", "\\\"");
escaped = escaped.replace("\b", "\\b");
escaped = escaped.replace("\f", "\\f");
escaped = escaped.replace("\n", "\\n");
escaped = escaped.replace("\r", "\\r");
escaped = escaped.replace("\t", "\\t");
// TODO: escape other non-printing characters using uXXXX notation

def json =
"{" +
"\"name\": \"optx-conf.json\"," +
"\"text\":"+"\"" + escaped +"\""+
"}";

println(json);

post.connect();

PrintStream ps = new PrintStream(post.getOutputStream());
ps.print(json);
ps.close();

def res = post.getResponseCode();
}
}
}

//build
stage('Build BaseImange'){
steps{
echo "Building..."
script{
def str = "${OPTX_ID}"
env.OPTX_ID_LOWERCASE= str.toLowerCase();
env.DOCKER_FILE_PATH = "${DOCKER_FILE_PATH}"

}

sh "rsync -avzP ./ ${SSH_NAME}:/home/ubuntu/jenkins_deploy_workspace/${JOB_NAME}"
sh '''ls
ssh ${SSH_NAME} << EOF
cd /home/ubuntu/jenkins_deploy_workspace/${JOB_NAME}
docker build -t ${OPTX_ID_LOWERCASE} . -f ${DOCKER_FILE_PATH}
EOF'''
}
}

//update or create optx
stage('Register Image'){
steps{

echo "Register..."

sh "rsync -avzP ./ ${SSH_NAME}:/home/ubuntu/jenkins_deploy_workspace/${JOB_NAME}"
sh '''ls
ssh ${SSH_NAME} << EOF
cd /home/ubuntu/jenkins_deploy_workspace/${JOB_NAME}
docker tag ${OPTX_ID_LOWERCASE} ${NEWTROID_REGISTRY_URL}/${OPTX_ID_LOWERCASE}:${TAG}
docker tag ${OPTX_ID_LOWERCASE} ${NEWTROID_REGISTRY_URL}/${OPTX_ID_LOWERCASE}:latest

docker push ${NEWTROID_REGISTRY_URL}/${OPTX_ID_LOWERCASE}:${TAG}
docker push ${NEWTROID_REGISTRY_URL}/${OPTX_ID_LOWERCASE}:latest

EOF'''
}
}

}

}

3.2.1 jenkins にログインします。

newtroid-cicd-architecture

3.2.2 認証情報の設定

初回時及び認証情報を変更した場合に認証情報を設定する必要があります。

SCM の認証情報を設定する

Github等のSCMに認証が必要な場合に設定を行います。

ダッシュボード -> Jenkins の管理 -> Credentials -> System -> グローバルドメインの順に画面遷移します。

alt text

Add CredentialsをクリックしてSSH ユーザ名と秘密鍵を選択します。以下のように項目を設定してください。

  • スコープ: グローバル
  • ID: Credentials で一意となるよう設定してください。
  • 説明: 任意
  • ユーザー名: SCM のユーザー名を設定してください。 秘密鍵
  • 直接入力を選択し、秘密鍵をコピー&ペーストしてください。

設定が完了したら、Createボタンをクリックして設定を保存してください。

newtroid の認証情報を設定する

newtroid に OptX を登録するために、コントラクタと API キーを設定します。

ダッシュボード -> Jenkins の管理 -> Credentials -> System -> グローバルドメインの順に画面遷移します。

alt text

Add CredentialsをクリックしてSecret textを選択します。以下のように項目を設定してください。([]は不要です。)

  • スコープ: グローバル
  • Secret: API キー
  • ID: [CONTRACTOR_NO]__APIKEYのように設定してください。例. コントラクタ playground へ OptX を登録する場合、playground__APIKEY
  • 説明: 任意

設定が完了したら、Createボタンをクリックして設定を保存してください。

3.2.2 新規ジョブの作成

ジョブ名の設定

ジョブ名でリポジトリ名、コントラクタ、OPTX ID、タグを設定します。 以下のようにジョブ名を設定してください。

optx__r_[REPOSITORY_NAME]__o_[OPTX_ID]__c_[CONTRACTOR_NO]__t_[TAG]
  • REPOSITORY_NAME: SCM のリポジトリ名
  • OPTX_ID: リリースする OptX ID
  • CONTRACTOR_NO: コントラクタ
  • TAG: Docker Registry に登録するタグに使用します。Docker Registry には、指定したタグと latest が登録されます。
例.  optx__r_optx-sdk-ts__o_opt_1234567890AbCdEfGHIIJK__c_playground__t_v1.0.0

ジョブスケジュールの設定

ビルドトリガの SCM をポーリングをチェックし*/5 * * * *と入力します。 これで 5 分に一度 Github のリポジトリの更新をチェックします。更新があった場合はジョブが実行されリリースが自動的に行われます。 newtroid-cicd-architecture

SCM の設定

リポジトリの URL、ブランチ、jenkins ファイルのパスの設定をします。

newtroid-cicd-architecture

以上の設定が完了したらジョブを保存します。

3.2.3 ジョブを実行します。

ビルド実行ボタンを押してジョブを実行します。すべてのステージをパスすれば newtroid に OptX が登録されます。 newtroid-cicd-architecture

Trouble Shooting

初回の実行時において、Jenkinのセキュリティの制約上、groovyモジュールが使用できない場合があります。その場合、管理者がスクリプトを承認してください。 Jenkinsの管理 > In-process Script Approvalページに遷移し、対象のモジュールに対してApproveボタンをクリックし、モジュールを承認してください。


方法①:マニュアルで登録する

動作確認

  1. newtroid にログインし、Xervice画面を開きます。
  2. 画面右下のボタンをクリックし、新規パイプラインを作成します。
  3. パイプラインを開き、ボタンで新規スロットを作成します。
  4. スロットをクリックし、画面右部のインスペクタ画面の Select OptXボタンで OptX を選択します。

alt text

OptX の設定

※environments に指定した環境変数は newtroid のインスペクタメニューに表示され、 起動前に設定を行えるようになります。

newtroid-cicd-architecture

※io の設定はスロットの端子として表示されます。 newtroid-cicd-architecture

  1. インスペクタで OptX の設定をし、起動ボタンで起動します。