この記事はKubernetes Advent Calendar 2019 その2の6日目の記事です。
kubernets/cri-apiをGoで使ってみたので、そのやり方を紹介したいと思います。
#cri-apiとは
cri-api
はCRI(Container Runtime Interface)で規定されているI/Fの定義です。
KubernetesにはkubeletとHigh-LevelコンテナランタイムのI/Fを規定したCRIというものが存在します。
これはKubernetesに他のコンテナランタイムを組み込みやすくする事を目的に規定されているもので、CRIを満たしたコンテナランタイムであればKubernetsで動かす事ができます。
このcri-api
はprotocol bufferとgRPCで構成されており、
今回はprotocol bufferを使用してGoでcri-api
を使ってみてます。
試した環境
- macOS Mojave 10.14
- Go 1.13
- protoc 3.11.1
protocol bufferのインストール
protocol bufferをインストールします。
macであればhomebrewでインストール可能です。
# インストール
brew update
brew install protobuf
# 確認
protoc --version #libprotc 3.11.1
Goで実装
今回やってみたのはclientとserverのプログラムを実装して、
client->serverにcri-api
で定義されている構造体を送って確認する、といったものになります。
(実装に当たってはprotocol buffers をGolangで使うを参考にさせて頂いています。)
以下実装していきますが事前に
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
しておきます。
まずはclientから実装していきます。
clientの実装
package main
import (
"net"
"github.com/golang/protobuf/proto"
"k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
)
func main() {
// cri-apiに定義されているPodSandbox構造体
pod := &v1alpha2.PodSandbox{
Id: "1000",
Metadata: &v1alpha2.PodSandboxMetadata{
Name: "FakePod",
Uid: "123456789",
Namespace: "System",
Attempt: 0,
},
State: v1alpha2.PodSandboxState_SANDBOX_READY,
CreatedAt: 1,
}
// シリアライズ化
out, err := proto.Marshal(pod)
if err != nil {
panic(err)
}
conn, err := net.Dial("tcp", "localhost:9000")
if err != nil {
panic(err)
}
// serverにデータを送信
conn.Write(out)
}
cri-api
で定義されているPodSandbox
構造体を作成。
構造体に適当な値を入れてシリアライズ化した後にlocalhost:9000
宛に送信しています。
(cri-api
はPodSandbox
以外にも多くの定義がありますが今回はPodSandbox
を使っています)
次にserverを実装します。
serverの実装
package main
import (
"bytes"
"io"
"net"
"os"
"github.com/golang/protobuf/jsonpb"
"github.com/golang/protobuf/proto"
"k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
)
func main() {
// localhost:9000で待ち受け
ln, err := net.Listen("tcp", ":9000")
if err != nil {
panic(err)
}
for {
conn, err := ln.Accept()
if err != nil {
panic(err)
}
go func() {
// 受け取ったデータをbufにcopy
var buf bytes.Buffer
io.Copy(&buf, conn)
// 受け取ったデータをPodSandbox型の変数に格納
pod := &v1alpha2.PodSandbox{}
if err := proto.Unmarshal(buf.Bytes(), pod); err != nil {
panic(err)
}
// jsonに変換して標準出力に出力
versionMarshal := jsonpb.Marshaler{Indent: " "}
versionMarshal.Marshal(os.Stdout, pod)
}()
}
}
clientから受け取ったデータを分かりやすいようにjsonに変換した上で標準出力に出力しています。
動作確認
事前に作成したserverのプログラムを起動してlocalhost:9000
宛に通信ができるようにしておきます。
その上でclientプログラムを起動させると、以下のように表示されてcri-api
で定義されている内容を利用してデータを受け取れている事が確認できます。
{
"id": "1000",
"metadata": {
"name": "FakePod",
"uid": "123456789",
"namespace": "System"
},
"createdAt": "1"
}
まとめ
cri-api
で定義されている構造体を簡単ではありますが、Goで使ってみる事ができました。
何かの参考になれば幸いです。