このチュートリアルでは、以下のステップでK-SOTを構築し、動作確認を行います。
- ローカルKubernetesクラスタ作成
- 検証用のGithubレポジトリの作成
- K-SOTをインストール、各種ファイル設定
- 装置エミュレータを立ち上げる
- K-SOTのデプロイ
- 動作確認
事前準備
- golang (v1.21.0+)) をインストールしてください。装置設定導出ロジックを書くのに必要です。
- docker (v20.10.24+) をインストールしてください。kindの実行に必要です。
- kind (v0.12.0+) をインストールしてください。ローカルのKubernetesクラスタの構築に使用します。
- kubectl (v1.25.4+) をインストールしてください。Kubernetesクラスタに対してコマンドを実行する際に使用します。
1. ローカルKubernetesクラスタ作成
以下のコマンドを実行して、ローカルのKubernetesクラスタを立ち上げます。
kind create cluster --name ksot-started
実行が完了したら、以下のコマンドを実行して、Kubernetesクラスタが正常に作成されたことを確認します。
kubectl cluster-info
以下のような出力が表示されたら、ローカルクラスタは正常に動作しています。
Kubernetes control plane is running at https://127.0.0.1:52096
CoreDNS is running at https://127.0.0.1:52096/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
2. 検証用のGithubレポジトリの作成
K-SOTをGithubを用いてネットワーク装置の設定を管理するには、GitHubレポジトリを作成する必要があります。 K-SOT Example レポジトリをテンプレートとして使用することで、これらのレポジトリを簡単に作成できます。
以下を実行して、GitHubレポジトリを作成してください。
K-SOT Example レポジトリの Use this template ボタンをクリックしてください。
レポジトリ名を入力して、 Create repository from template ボタンをクリックしてください。レポジトリの公開・非公開については、好きな方を選択してください。今回はレポジトリオーナーをユーザーのアカウントに設定し、レポジトリ名はksot-exampleと設定してください。
3. K-SOTをインストール、各種ファイル設定
K-SOTのレポジトリをclone、submoduleの初期化
レポジトリのclone
git clone https://github.com/nttcom/ksot.git
submoduleの初期化
git submodule update --init --recursive
envファイルの設定
上でcloneしたK-SOTレポジトリに対して、以下envファイルを配置してください。
/.env
KIND_NAME=ksot-started
GITHUB_REPO_URL=https://{Githubユーザー名}:{Githubユーザートークン}@github.com/{Githubユーザー名}/ksot-example
GITHUB_USER_NAME={Githubユーザー名}
GITHUB_USER_MAIL={Github登録メールアドレス}
/github-server/config/overlays/test/.env
GITHUB_REPO_URL=https://{Githubユーザー名}:{Githubユーザートークン}@github.com/{Githubユーザー名}/ksot-example
yangファイルの設定
装置向けyangの設定
本記事で管理対象の装置とするODTN-emulatorのYANGフォルダ内のyangを全て取得。nb-server/pkg/tf/yang/devices
配下にフォルダ(名前: cassini)を作成して先ほど取得したyangファイルを配置してください。
サービス向けyangの設定
nb-server/pkg/tf/yang/services
配下にフォルダ(名前: transceivers)を作成して以下内容のyangファイルをその中に配置します。
module transceivers {
namespace "tf-ksot/transceivers";
prefix ts;
grouping transceivers-top {
list transceivers {
key "name";
leaf name {
type string;
}
leaf-list up {
type string;
}
leaf-list down {
type string;
}
}
}
uses transceivers-top;
}
装置設定導出パッケージの設定
nb-server/pkg/tf/transceivers.go
を以下内容で作成します。
package tf
import (
"encoding/json"
"fmt"
"github.com/nttcom-ic/ksot/nb-server/pkg/model/pathmap"
)
type Transceiver struct {
Name string `json:"name"`
Nos string `json:"nos"`
Up []string `json:"up"`
Down []string `json:"down"`
}
type Transceivers map[string][]Transceiver
func TfTransceivers(ts interface{}) (map[string]pathmap.PathMapInterface, error) {
fmt.Println("hello")
mapByte, err := json.Marshal(ts)
if err != nil {
return nil, err
}
var transceivers Transceivers
if err := json.Unmarshal(mapByte, &transceivers); err != nil {
fmt.Println(err)
return nil, err
}
results := make(map[string]pathmap.PathMapInterface)
fmt.Println("tflogic: ", transceivers)
for _, devices := range transceivers {
for _, device := range devices {
result, err := pathmap.NewPathMap(map[string]interface{}{})
if err != nil {
return nil, err
}
for _, v := range device.Up {
path := fmt.Sprintf("/openconfig-platform:components/component[name=%v]/openconfig-platform-transceiver:transceiver/config/enabled", v)
err = result.SetValue(path, true, map[string]string{})
if err != nil {
return nil, err
}
}
for _, v := range device.Down {
path := fmt.Sprintf("/openconfig-platform:components/component[name=%v]/openconfig-platform-transceiver:transceiver/config/enabled", v)
err = result.SetValue(path, false, map[string]string{})
if err != nil {
return nil, err
}
}
results[device.Name] = result
}
}
fmt.Println("check: ", results)
return results, nil
}
nb-server/pkg/tf/tf.go
を以下の内容に変更します。
package tf
import (
"github.com/nttcom-ic/ksot/nb-server/pkg/model"
)
var TfLogic = model.NewPathMapLogic()
func init() {
// User needs to create a function to generate a pathmap and add it to the MAP.
// Example.
// TfLogic["serviceName"] = serviceName
TfLogic["transceivers"] = TfTransceivers
}
4. 装置エミュレータを立ち上げる
事前にエミュレーターの接続情報を記載したenvファイルを追加 /sb-server/config/overlays/test/.env
cassini=root
以下コマンドでOTDN-emulatorを立ち上げます。
docker pull onosproject/oc-cassini:0.21
docker run -it -d --name odtn-emulator_openconfig_cassini_1 -p 11002:830 onosproject/oc-cassini:0.21
以下のようにコンテナが立ち上がっているか確認してください。
% docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
52da5c9f1c79 onosproject/oc-cassini:0.21 "sh /root/script/pus…" 4 hours ago Up 4 hours 22/tcp, 8080/tcp, 0.0.0.0:11002->830/tcp odtn-emulator_openconfig_cassini_1
コントローラーからOTDN-emulatorへの接続情報追加するため、K-SOTレポジトリにsb-server/connect.json
を作成し以下の内容で保存します。
{
"cassini": {
"ip": "host.docker.internal",
"port": 11002,
"username": "root",
"hostKeyVerify": false,
"if": "netconf"
}
}
5. K-SOTのデプロイ
以下コマンドをK-SOTレポジトリのルートで実行してください。
make getting-started
実行後kubectl get pod
で起動しているpodを確認すると、以下3つのpodが作成されています。
NAMESPACE NAME READY STATUS RESTARTS AGE
default ksot-github-deployment-766b6ff499-72zkr 1/1 Running 0 24s
default ksot-nb-deployment-967757888-dqzw7 1/1 Running 0 24s
default ksot-sb-deployment-6d89c6f85c-zksl5 1/1 Running 0 24s
...
6. 動作確認
ポートフォワードの実施
まずNorthboundとなるk8s serviceにport-forwardを実施しておきます。
kubectl port-forward svc/ksot-nb-service 8080:8080
装置情報の取得
PUT: http://localhost:8080/sync/devices
を実施し、Githubレポジトリに現在の装置設定を反映させます。
検証用GithubレポジトリのDevices/cassini
に以下のファイルが作成されていれば成功です。
- actual.json: 実機から取得した設定
- ref.json: 各サービスから設定されているパラメータ(初期値は空のJSON)
- set.json: コントローラーが投入した設定(初期値は実機から取得したものと同じ)
サービスの作成
以下JSONをbodyとしてPOST: http://localhost:8080/services
を実施、bodyに指定されたサービスを作成し装置の設定を変更します。
今回のサービスではtransceiversのud/downを実施するサービスを作成します。なお作成するサービスについては事前に装置設定導出パッケージを追加する必要があります(前の手順)。
{
"transceivers": {
"transceivers:transceivers": [
{
"name": "cassini",
"up": [],
"down": [
"oe1",
"oe2",
]
}
]
}
}
検証用GithubレポジトリのServices/transceivers
に以下のファイルが作成されていることを確認してください。
- input.json: 投入したサービスの値
- output.json: 設定を変更した装置のxpathと対応する値
装置情報の取得(サービス作成後)
PUT: http://localhost:8080/sync/devices
を実施し、Githubレポジトリに現在の装置設定を反映します。
検証用GithubレポジトリのDevices/cassini/actual.json
が以下のように更新され、OTDN-emulatorの指定した箇所のtransceiversがdownしていることがわかります。
{
...
"name": "oe1",
"config": {
"name": "oe1"
},
"state": {
"type": "openconfig-platform-types:TRANSCEIVER",
"empty": false
},
"openconfig-platform-transceiver:transceiver": {
"config": {
- "enabled": true,
+ "enabled": false,
"form-factor-preconf": "openconfig-transport-types:CFP2_ACO"
}
}
...
"name": "oe2",
"config": {
"name": "oe2"
},
"state": {
"type": "openconfig-platform-types:TRANSCEIVER",
"empty": false
},
"openconfig-platform-transceiver:transceiver": {
"config": {
- "enabled": true,
+ "enabled": false
"form-factor-preconf": "openconfig-transport-types:CFP2_ACO"
}
}
...
}
サービスの更新
以下JSONをbodyとしてPUT: http://localhost:8080/services
を実施、bodyに指定されたサービスを更新し装置の設定を変更します。
今回はoe1のtransceiverについてUPするよう更新します。
{
"transceivers": {
"transceivers:transceivers": [
{
"name": "cassini",
"up": [
"oe1",
],
"down": [
"oe2",
]
}
]
}
}
装置情報の取得(サービス更新後)
PUT: http://localhost:8080/sync/devices
を実施し、Githubレポジトリに現在の装置設定を反映します。
検証用GithubレポジトリのDevices/cassini/actual.json
が以下のように更新され、OTDN-emulatorの指定した箇所のtransceiversがUPしていることがわかります。
{
...
"name": "oe1",
"config": {
"name": "oe1"
},
"state": {
"type": "openconfig-platform-types:TRANSCEIVER",
"empty": false
},
"openconfig-platform-transceiver:transceiver": {
"config": {
+ "enabled": true,
- "enabled": false,
"form-factor-preconf": "openconfig-transport-types:CFP2_ACO"
}
}
...
}
サービスの削除
DELETE: http://localhost:8080/services?name=transceivers
を実施。クエリパラメーターに指定した名前のサービスを削除し、装置の設定を変更します。
検証用GithubレポジトリのServices/transceivers
フォルダが消えるので確認してください。
装置情報の取得(サービス削除後)
PUT: http://localhost:8080/sync/devices
を実施し、Githubレポジトリに現在の装置設定を反映します。
検証用GithubレポジトリのDevices/cassini/actual.json
が以下のように更新され、サービスから投入していたコンフィグ箇所が消えていることがわかります。
{
...
"name": "oe1",
"config": {
"name": "oe1"
},
"state": {
"type": "openconfig-platform-types:TRANSCEIVER",
"empty": false
},
"openconfig-platform-transceiver:transceiver": {
"config": {
- "enabled": true,
"form-factor-preconf": "openconfig-transport-types:CFP2_ACO"
}
}
...
"name": "oe2",
"config": {
"name": "oe2"
},
"state": {
"type": "openconfig-platform-types:TRANSCEIVER",
"empty": false
},
"openconfig-platform-transceiver:transceiver": {
"config": {
- "enabled": false
"form-factor-preconf": "openconfig-transport-types:CFP2_ACO"
}
}
...
}