前書き
curl をgolang で行いたい時にはcurl-to-Go を利用することができる。
ConoHa のAPIを利用して トークン発行 を発行するしたい場合には以下のようなcurl を実行する必要がある トークン発行 - Identity API v2.0 / ConoHa API を参照
curl -i -X POST \ -H "Accept: application/json" \ -d '{"auth":{"passwordCredentials":{"username":"ConoHa","password":"paSSword123456#$%"},"tenantId":"487727e3921d44e3bfe7ebb337bf085e"}}' \ https://identity.tyo1.conoha.io/v2.0/tokens
curl-to-Go を利用すると以下のようなコードが生成されて労力を最小限にすることができる。労力が最小なことは嬉しい。ちなみにCLI も利用できるのでかなり使っている。
// Generated by curl-to-Go: https://mholt.github.io/curl-to-go body := strings.NewReader(`{"auth":{"passwordCredentials":{"username":"ConoHa","password":"paSSword123456#$%"},"tenantId":"487727e3921d44e3bfe7ebb337bf085e"}}`) req, err := http.NewRequest("POST", "https://identity.tyo1.conoha.io/v2.0/tokens", body) if err != nil { // handle err } req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "application/x-www-form-urlencoded") resp, err := http.DefaultClient.Do(req) if err != nil { // handle err } defer resp.Body.Close()
まぁこの前書きはマジで何も関係ない
。
概要
kubernetes API にアクセスする時には様々な方法がある。kubectl や curl などでも行う事ができる。でも、kubectl 使うことが一般的だとは思う。しかし、もう少し複雑な事をさせたいと思ったらのなら何かしらのプログラミング言語で実施したくなります。Kubernetes APIにアクセスするにはk8s.io/client-goを使うのはわりと自然な流れかと思いますが。この場合client-goを使うコードを1から書いてもよいですが、kyaml2goを使うと、yamlファイルからclient-goを利用するコードを生成してれるので特定の操作を簡単に行う事ができます。下記のようなyaml があったとしたら そのyaml にcreate
update
get
delete
してくれるコードを生成してくれます。client-go について詳しく学習したい場合には Programming Kuberentes の三章であるBasics of client-go を読んでください。
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80
create を選択した場合(Web UI であるkyaml2go: Kubernetes client-go code generator から引用)
// Auto-generated by kyaml2go - https://github.com/PrasadG193/kyaml2go package main import ( "fmt" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/util/homedir" "os" "path/filepath" ) func main() { // Create client var kubeconfig string kubeconfig, ok := os.LookupEnv("KUBECONFIG") if !ok { kubeconfig = filepath.Join(homedir.HomeDir(), ".kube", "config") } config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) if err != nil { panic(err) } clientset, err := kubernetes.NewForConfig(config) if err != nil { panic(err) } kubeclient := clientset.AppsV1().Deployments("default") // Create resource object object := &appsv1.Deployment{ TypeMeta: metav1.TypeMeta{ Kind: "Deployment", APIVersion: "apps/v1", }, ObjectMeta: metav1.ObjectMeta{ Name: "nginx-deployment", Labels: map[string]string{ "app": "nginx", }, }, Spec: appsv1.DeploymentSpec{ Replicas: ptrint32(3), Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{ "app": "nginx", }, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{ "app": "nginx", }, }, Spec: corev1.PodSpec{ Containers: []corev1.Container{ corev1.Container{ Name: "nginx", Image: "nginx:1.14.2", Ports: []corev1.ContainerPort{ corev1.ContainerPort{ HostPort: 0, ContainerPort: 80, }, }, Resources: corev1.ResourceRequirements{}, }, }, }, }, Strategy: appsv1.DeploymentStrategy{}, MinReadySeconds: 0, }, } // Manage resource _, err = kubeclient.Create(object) if err != nil { panic(err) } fmt.Println("Deployment Created successfully!") } func ptrint32(p int32) *int32 { return &p }
遊ぶ
環境情報
$ go version go version go1.14.5 linux/amd64 $ docker version 4290ms Client: Version: 19.03.8 API version: 1.40 Go version: go1.13.8 Git commit: afacb8b7f0 Built: Tue Jun 23 22:26:12 2020 OS/Arch: linux/amd64 Experimental: false Server: Engine: Version: 19.03.11 API version: 1.40 (minimum version 1.12) Go version: go1.13.12 Git commit: 77e06fd Built: Mon Jun 8 20:24:59 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: v1.2.13 GitCommit: 7ad184331fa3e55e52b890ea95e65ba581ae3429 runc: Version: 1.0.0-rc10 GitCommit: docker-init: Version: 0.18.0 GitCommit: fec3683 $ kind --version # https://kind.sigs.k8s.io/docs/user/quick-start/ kind version 0.8.1
環境構築
クラスタ-の構築
$ kind create cluster --name kyaml2go Creating cluster "kyaml2go" ... ✓ Ensuring node image (kindest/node:v1.18.2) 🖼 ✓ Preparing nodes 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 Set kubectl context to "kind-kyaml2go" You can now use your cluster with: kubectl cluster-info --context kind-kyaml2go Have a nice day!
クラスタ-の確認
$ kind get clusters kyaml2go $ kind get kubeconfig --name kyaml2go > kubeconfig.yaml $ kubectl version --kubeconfig=kubeconfig.yaml Client Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.0", GitCommit:"9e991415386e4cf155a24b1da15becaa390438d8", GitTreeState:"clean", BuildDate:"2020-03-25T14:58:59Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"linux/amd64"} Server Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.2", GitCommit:"52c56ce7a8272c798dbc29846288d7cd9fbae032", GitTreeState:"clean", BuildDate:"2020-04-30T20:19:45Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}
cli のインストール
git clone https://github.com/PrasadG193/kyaml2go.git
cd kyaml2go
make
$(shell go env GOPATH)/bin/kyaml2go
以下にコマンドが生成されているのでそれにyaml を下記のように食わせる(牡蛎食べたい 腹減った)(サンプルには下記のような書き方が書いてあるが複数のアクションを同時に食わせるのは恐らく対応してない)
kyaml2go create/get/update/delete -f /path/to/resource_specs.yaml
設定するファイル
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80
kyaml2go の実行
kyaml2go create -f nginx-deployment.yaml > create-nginx-deployment.go
create-nginx-deployment.go 生成したものを書きだす。~/.config/fish/config.fish
などで set KUBECONFIG ./kubeconfig.yaml:~/.kube/config
を設定するのでカレントディレクトリにkubeconfig.yaml があった場合には$KUBECONFIG
という環境変数にはそちらが優先されて設定されるので便利がいいですね。
// Auto-generated by kyaml2go - https://github.com/PrasadG193/kyaml2go package main import ( "fmt" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/util/homedir" "os" "path/filepath" ) func main() { // Create client var kubeconfig string kubeconfig, ok := os.LookupEnv("KUBECONFIG") if !ok { kubeconfig = filepath.Join(homedir.HomeDir(), ".kube", "config") } config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) if err != nil { panic(err) } clientset, err := kubernetes.NewForConfig(config) if err != nil { panic(err) } kubeclient := clientset.AppsV1().Deployments("default") // Create resource object object := &appsv1.Deployment{ TypeMeta: metav1.TypeMeta{ Kind: "Deployment", APIVersion: "apps/v1", }, ObjectMeta: metav1.ObjectMeta{ Name: "nginx-deployment", Labels: map[string]string{ "app": "nginx", }, }, Spec: appsv1.DeploymentSpec{ Replicas: ptrint32(3), Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{ "app": "nginx", }, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{ "app": "nginx", }, }, Spec: corev1.PodSpec{ Containers: []corev1.Container{ corev1.Container{ Name: "nginx", Image: "nginx:1.14.2", Ports: []corev1.ContainerPort{ corev1.ContainerPort{ HostPort: 0, ContainerPort: 80, }, }, Resources: corev1.ResourceRequirements{}, }, }, }, }, Strategy: appsv1.DeploymentStrategy{}, MinReadySeconds: 0, }, } // Manage resource _, err = kubeclient.Create(object) if err != nil { panic(err) } fmt.Println("Deployment Created successfully!") } func ptrint32(p int32) *int32 { return &p }
clusterへの実行
create-nginx-deployment.go を実行してみたが go 1.14のgo run で乱雑に入るパッケージのいくつかが対応していないのでkyaml2goのgo.mod を参照して入れなおす
$ go run create-nginx-deployment.go Deployment Created successfully! $ go run get-nginx-deployment.go Found object : &Deployment{ObjectMeta:{nginx-deployment default /apis/apps/v1/namespaces/default/deployments/nginx-deployment 7a7fd262-09d1-49ef-89d2-5116c68d4e9e 53121316 1 2020-07-21 13:01:11 +0000 UTC <nil> <nil> map[app:nginx] map[deployment.kubernetes.io/revision:1] [] [] []},Spec:DeploymentSpec{Replicas:*3,Selector:&v1.LabelSelector{MatchLabels:map[string]string{app: nginx,},MatchExpressions:[]LabelSelectorRequirement{},},Template:{{ 0 0001-01-01 00:00:00 +0000 UTC <nil> <nil> map[app:nginx] map[] [] [] []} {[] [] [{nginx nginx:1.14.2 [] [] [{ 0 80 TCP }] [] [] {map[] map[]} [] [] nil nil nil nil /dev/termination-log File IfNotPresent nil false false false}] [] Always 0xc000584068 <nil> ClusterFirst map[] <nil> false false false <nil> PodSecurityContext{SELinuxOptions:nil,RunAsUser:nil,RunAsNonRoot:nil,SupplementalGroups:[],FSGroup:nil,RunAsGroup:nil,Sysctls:[]Sysctl{},WindowsOptions:nil,} [] nil default-scheduler [] [] <nil> nil [] <nil> <nil> <nil> map[] []}},Strategy:DeploymentStrategy{Type:RollingUpdate,RollingUpdate:&RollingUpdateDeployment{MaxUnavailable:25%,MaxSurge:25%,},},MinReadySeconds:0,RevisionHistoryLimit:*10,Paused:false,ProgressDeadlineSeconds:*600,},Status:DeploymentStatus{ObservedGeneration:1,Replicas:3,UpdatedReplicas:3,AvailableReplicas:3,UnavailableReplicas:0,Conditions:[]DeploymentCondition{DeploymentCondition{Type:Available,Status:True,Reason:MinimumReplicasAvailable,Message:Deployment has minimum availability.,LastUpdateTime:2020-07-21 13:01:23 +0000 UTC,LastTransitionTime:2020-07-21 13:01:23 +0000 UTC,},DeploymentCondition{Type:Progressing,Status:True,Reason:NewReplicaSetAvailable,Message:ReplicaSet "nginx-deployment-7fd6966748" has successfully progressed.,LastUpdateTime:2020-07-21 13:01:23 +0000 UTC,LastTransitionTime:2020-07-21 13:01:11 +0000 UTC,},},ReadyReplicas:3,CollisionCount:nil,},}
resourceが生成されているのが確認できたと思う
kubectl でも同様に確認できたので
$ kubectl get pod NAME READY STATUS RESTARTS AGE nginx-deployment-7fd6966748-9km6c 1/1 Running 0 9m26s nginx-deployment-7fd6966748-c9sng 1/1 Running 0 9m26s nginx-deployment-7fd6966748-thk76 1/1 Running 0 9m26s
削除しておく
$ go run delete-nginx-deployment.go Deployment Deleted successfully!
ソースコードなどはココに載せておきます。
最後に
特にないけど Kind で構築したclusterを削除する
kind get clusters kyaml2go kind delete cluster --name kyaml2go Deleting cluster "kyaml2go" ...