본문 바로가기

Cloud

(Kubernetes) - client-go로 k8s API와 통신하기

반응형

🍳머리말

통신 후 k8s cluster내에 단계별로 접근해보는 예제와 설명글입니다.


📕Prerequisite

📔 k8s cluster

📔 Go lang


📕 공통사항

📔 cluster내 config file 내용 확인 및 저장

k8s api server는 config file을 통해 인증된 사용자와만 통신합니다. 따라서 cluster 외부에서 api server와 통신하기 위해서는 config file 내용이 필요합니다.

주로 cluster config file은 cluster환경이 갖춰진 local computer내에서 /root/.kube/config로써 존재합니다. cat명령어로 내용을 찾아 출력해봅니다.

📔 출력결과

해당 내용을 apiVersion부분부터 복붙해 통신을 시도할 computer의 local 환경에 file을 만들어 저장합니다.


📕 cluster 내 Pod개수 출력하기

📔 code 작성

간단하게 pod개수를 출력하는 code를 작성해봅니다. 해당 code는 k8s docs 내용입니다. config file위치를 적절히 BuildConfigFromFlags에 string형태의 인자로 넘겨줍니다.

package main

import (
  "context"
  "fmt"
  "k8s.io/apimachinery/pkg/apis/meta/v1"
  "k8s.io/client-go/kubernetes"
  "k8s.io/client-go/tools/clientcmd"
)

func main() {
  // kubeconfig에서 현재 콘텍스트를 사용한다
  // path-to-kubeconfig -- 예를 들어, /root/.kube/config
  config, _ := clientcmd.BuildConfigFromFlags("", "kube config file 위치")
  // clientset을 생성한다
  clientset, _ := kubernetes.NewForConfig(config)
  // 파드를 나열하기 위해 API에 접근한다
  //Pods()함수 내 인자는 namespace를 정의할 수 있다 ""인 경우 default
  pods, _ := clientset.CoreV1().Pods("").List(context.TODO(), v1.ListOptions{})
  fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
}

📔 결과

성공적으로 k8s api server와 통신해 cluster내부에 있는 pod개수를 출력하는 모습입니다.


📕 Pod 정보 출력하기

📔 code 작성

특정 namespace의 pod정보를 출력하는 예제입니다. namespace "mskim"의 pod들 중 8번째 pod의 정보를 출력합니다.

package main

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"

	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"
)

func jsonPrettyPrint(in string) string {
	var out bytes.Buffer
	err := json.Indent(&out, []byte(in), "", "\t")
	if err != nil {
			return in
	}
	return out.String()
}

func main() {
    var out io.Writer

    enc := json.NewEncoder(out)
    enc.SetIndent("", "    ")

    // kubeconfig에서 현재 콘텍스트를 사용한다
    // path-to-kubeconfig -- 예를 들어, /root/.kube/config
    config, _ := clientcmd.BuildConfigFromFlags("", "./config")
    // clientset을 생성한다
    clientset, _ := kubernetes.NewForConfig(config)
    // 파드를 나열하기 위해 API에 접근한다
    pods, _ := clientset.CoreV1().Pods("mskim").List(context.TODO(), v1.ListOptions{})
    fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))

    terraformPod, _ := json.Marshal(pods.Items[7])

    fmt.Printf("items", jsonPrettyPrint(string(terraformPod)))
}

📔 출력결과

json.indent함수를 이용해 json객체를 적절히 출력했습니다.


📕 Pod내 container에 특정 명령어 실행하기

📔 code 작성

원격으로 k8s api server와 통신해 특정 namespace의 pod내 container로 명령어를 실행할 수 있습니다. default namespace의 pod개수, namespace "mskim"의 pod들 중 8번째 pod의 정보, 특정 명령 배열을 실행합니다.

package main

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"

	corev1 "k8s.io/api/core/v1"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/tools/remotecommand"
	"k8s.io/kubectl/pkg/scheme"
)

func jsonPrettyPrint(in string) string {
	var out bytes.Buffer
	err := json.Indent(&out, []byte(in), "", "\t")
	if err != nil {
			return in
	}
	return out.String()
}

func main() {
	var stdin io.Reader
	var cmd = [] string{"/bin/bash", "-c", "./terraform init"}
	var out io.Writer
	var stdout, stderr bytes.Buffer

	enc := json.NewEncoder(out)
	enc.SetIndent("", "    ")

  // kubeconfig에서 현재 콘텍스트를 사용한다
  // path-to-kubeconfig -- 예를 들어, /root/.kube/config
  config, _ := clientcmd.BuildConfigFromFlags("", "./config")
  // clientset을 생성한다
  clientset, _ := kubernetes.NewForConfig(config)
  // 파드를 나열하기 위해 API에 접근한다
  pods, _ := clientset.CoreV1().Pods("mskim").List(context.TODO(), v1.ListOptions{})
  fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))

	terraformPod, _ := json.Marshal(pods.Items[7])

	fmt.Printf("items", jsonPrettyPrint(string(terraformPod)))
	
	//pod실행 option을 결정한다
	option := &corev1.PodExecOptions{
		Container: "terraform",
		Command:   cmd,
		Stdin:     true,
		Stdout:    true,
		Stderr:    true,
		TTY:       false,
	}

	if stdin == nil {
		option.Stdin = false
	}

	//요청할 pod, namespace를 지정한다
	req := clientset.CoreV1().RESTClient().Post().Resource("pods").Name("terraform-pod").
		Namespace("mskim").SubResource("exec")

	req.VersionedParams(
		option,
		scheme.ParameterCodec,
	)
	
	exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL())
	err = exec.Stream(remotecommand.StreamOptions{
		Stdin: stdin,
		Stdout: &stdout,
		Stderr: &stderr,
	})
	if err != nil{
		fmt.Println(err)
	}

	//명령어 실행 결과를 출력한다.
	fmt.Println(stdout.String(), stderr.String())
}

*더 나은 내용을 위한 지적, 조언은 언제나 환영합니다.

'Cloud' 카테고리의 다른 글

(kubernetes) - nfs storage사용하기  (1) 2022.04.29
(Terraform) - 용어 정리  (0) 2022.04.28
(Terraform) - Window에 설치  (0) 2022.04.25
(Kubernetes) - TLS/SSL secret 생성하기  (0) 2022.04.19
(Kubernetes) - redis cluster statefulset예제  (0) 2022.04.12