これは、このセクションの複数ページの印刷可能なビューです。 印刷するには、ここをクリックしてください.

このページの通常のビューに戻る.

Documentation

K-SOTは、クラウドネイティブなアプローチでネットワークのInfrastructure as Codeを可能にするオープンソースのフレームワークです。 ネットワークの高レベルなモデルへの抽象化とCUE言語を用いたデータマッピング、Kubernetesカスタムオペレータを用いたGitOpsなどで構成され、 ソフトウェア開発のIaCやGitOpsで培われたプラクティスをネットワークに適用し、高度なネットワーク設定の自動化を実現します。

1 - Getting Started

K-SOTを動かしてみよう

このチュートリアルでは、以下のステップでK-SOTを構築し、動作確認を行います。

  1. ローカルKubernetesクラスタ作成
  2. 検証用のGithubレポジトリの作成
  3. K-SOTをインストール、各種ファイル設定
  4. 装置エミュレータを立ち上げる
  5. K-SOTのデプロイ
  6. 動作確認

事前準備

  1. golang (v1.21.0+)) をインストールしてください。装置設定導出ロジックを書くのに必要です。
  2. docker (v20.10.24+) をインストールしてください。kindの実行に必要です。
  3. kind (v0.12.0+) をインストールしてください。ローカルのKubernetesクラスタの構築に使用します。
  4. 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レポジトリを作成してください。

  1. K-SOT Example レポジトリの Use this template ボタンをクリックしてください。

  2. レポジトリ名を入力して、 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-emulatorYANGフォルダ内の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"
					}
				}
...
}

本項で使用している外部ツール

2 - Concepts

K-SOTのコンセプト、アーキテクチャ、その他の技術関連情報について

Goを用いた Network Configuration as Code

K-SOTは、複雑なネットワーク装置のコンフィグを抽象化し、ユーザのインテントを簡単に記述できる高レベルのデータモデルとAPIを公開することをサポートします。ネットワーク装置のデータモデルは、数多のネットワーキング機能を提供するために詳細かつ複雑であり、Infrastructure as Codeのリソースモデルとして扱うには適していません。ユーザのインテントを簡単に表現できるデータモデルを提供するためには、複雑さを隠蔽しわかりやすく抽象化した高レベルなデータモデルが必要です。加えて、E2E接続のようなドメイン全体を抽象化したモデルを実現するには、複数のネットワーク装置をまたいで設定を行うデータモデルが必要になります。

このような上位モデルへの抽象化を行うと、上位モデルから低レベルな装置コンフィグへのデータマッピングは非常に複雑になります。 上位モデルと下位モデルは多対多の関係性を持つため、データマッピングに加えてデータの合成も同時に行う必要があります。このとき、データの欠損や競合、データ制約違反を起こさないように配慮しなければなりません。 Python/Jinjaを用いたシンプルなテキストテンプレートのアプローチでは、この複雑な問題を解くのは困難です。

K-SOTでは、上位モデルから下位モデルへのデータマッピングロジックをGoで記述できます。また、データの合成についてはユーザーが意識せずに実装することができます。

GitHubによるデータ管理

K-SOTは、ネットワーク装置コンフィグのためのGitHubによるデータ管理を提供します。ネットワーク全体のコンフィグを宣言的に記述し、GitHubリポジトリでバージョン管理し、信頼できる唯一の情報源(Single Source of Truth: SSoT) とすることを目的としています。

K-SOTのコンポーネント

K-SOTは以下のコンポーネントから構成されています。

  • nb-server はサービスモデルを受け取り、装置設定の導出を実施します。
  • github-server はGitHubの更新を行います。
  • sb-server は装置に設定を投入します。

3 - Reference

K-SOTの参考情報