clientcmd를 사용한 일관된 API 서버 접근

발행: (2026년 1월 20일 오전 03:00 GMT+9)
13 min read

Source: Kubernetes Blog

만약 Kubernetes API용 명령줄 클라이언트를 개발하고 싶다면—특히 kubectl 플러그인으로 사용할 수 있는 경우—사용자에게 kubectl과 친숙하게 느껴지도록 만드는 방법이 궁금할 수 있습니다.
kubectl options 출력물을 한눈에 보면 압도적일 수 있습니다:

“정말로 저 옵션들을 모두 구현해야 하나요?”

걱정하지 마세요! Kubernetes 프로젝트에서는 대부분의 복잡한 작업을 대신해 주는 두 개의 라이브러리를 이미 제공하고 있습니다:

  • clientcmd – kubectl 스타일의 명령줄 인수를 파싱하고 restclient.Config를 구축합니다.
  • cli‑runtimeclientcmd 위에 추가 기능을 제공합니다.

이 글에서는 clientcmd 라이브러리에 초점을 맞춥니다.

일반 철학

clientcmdclient‑go의 일부이므로 궁극적인 목적은 API 서버에 요청을 보낼 수 있는 restclient.Config를 생성하는 것입니다. 이는 kubectl과 동일한 의미 체계를 따릅니다:

소스설명
~/.kube/config (또는 동등한 파일)기본 설정
KUBECONFIG 환경 변수내용이 병합되는 하나 이상의 파일
명령줄 인수위의 모든 것을 재정의

clientcmd는 자동으로 --kubeconfig 플래그를 추가하지 않습니다; “플래그 바인딩” 섹션에서 추가하는 방법을 확인할 수 있습니다.

사용 가능한 기능

clientcmd는 프로그램이 다음을 처리하도록 합니다:

  • KUBECONFIG를 통한 kubeconfig 선택
  • 컨텍스트 선택
  • 네임스페이스 선택
  • 클라이언트 인증서 및 개인 키
  • 사용자 가장(임퍼시네이션)
  • HTTP 기본 인증(사용자 이름/비밀번호)

구성 병합

  • KUBECONFIG는 파일들의 콜론으로 구분된 목록을 포함할 수 있으며, 내용이 병합됩니다.
  • 맵 기반 설정첫 번째 정의가 적용되고, 이후 정의는 무시됩니다.
  • 맵이 아닌 설정마지막 정의가 적용됩니다.
  • KUBECONFIG에 지정된 존재하지 않는 파일은 경고만 발생시킵니다.
  • 사용자가 경로를 명시적으로 제공할 경우(예: --kubeconfig), 해당 파일은 존재해야 합니다.
  • KUBECONFIG가 설정되지 않은 경우, ~/.kube/config가 사용됩니다(존재한다면).

전체 프로세스

일반적인 사용 패턴은 clientcmd 패키지 문서에 요약되어 있습니다:

// 1️⃣ 로딩 규칙 구축 (기본값은 KUBECONFIG 또는 ~/.kube/config)
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
//   – 필요에 따라 여기서 순서/파일을 사용자 정의할 수 있습니다

// 2️⃣ 오버라이드 준비 (플래그에서 나중에 채워짐)
configOverrides := &clientcmd.ConfigOverrides{}

// 3️⃣ 지연 로딩 클라이언트 구성 생성
kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
    loadingRules,
    configOverrides,
)

// 4️⃣ 최종 REST 구성 해결
config, err := kubeConfig.ClientConfig()
if err != nil {
    // 오류 처리
}

// 5️⃣ 클라이언트 구축 (동적 클라이언트를 사용하는 예시)
client, err := dynamic.NewForConfig(config)
if err != nil {
    // 오류 처리
}

이 글에서는 위 번호가 매겨진 주석에 해당하는 여섯 단계를 차례대로 살펴보겠습니다:

  1. 로드 규칙 구성
  2. 오버라이드 구성
  3. 플래그 집합 구축
  4. 플래그 바인딩
  5. 병합된 구성 구축
  6. API 클라이언트 얻기

1️⃣ Configure the Loading Rules

loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
  • KUBECONFIG가 설정되어 있으면 사용하고, 그렇지 않으면 ~/.kube/config를 사용합니다.
  • 기본 파일이 사용될 경우, 매우 오래된 기본값(~/.kube/.kubeconfig)에서 설정을 마이그레이션할 수 있습니다.

표준이 아닌 순서나 추가 파일이 필요하면 사용자 정의 ClientConfigLoadingRules를 만들 수 있지만, 대부분의 경우 기본값으로 충분합니다.

2️⃣ Configure the Overrides

clientcmd.ConfigOverrides는 kubeconfig 파일에서 로드된 내용에 덮어쓰기할 값을 저장하는 구조체입니다. 이 가이드에서는 오버라이드를 명령줄 플래그(pflag 라이브러리, Go의 flag 패키지를 대체하는 라이브러리)를 통해 채웁니다.

configOverrides := &clientcmd.ConfigOverrides{}

보통 여기서 직접 값을 설정하지 않으며, 다음 단계에서 구조체 필드를 플래그에 바인딩하게 됩니다.

3️⃣ 플래그 집합 만들기

플래그는 명령줄 인수를 나타냅니다 (예: --namespace 또는 -n). clientcmd는 각각 FlagInfo 구조체로 감싸진 세 그룹의 플래그를 제공합니다:

플래그 그룹일반적인 인수
인증--certificate-authority, --token, --as, --username, --password
클러스터--server, --certificate-authority, --insecure-skip-tls-verify, --proxy-url, --tls-server-name, --compress
컨텍스트--context, --cluster, --user, --namespace

추천 집합에는 세 그룹 모두--timeout 플래그가 포함됩니다.

추천 플래그 생성자

// No prefix → flags like --context, --namespace, etc.
flags := clientcmd.RecommendedConfigOverrideFlags("")
// With a prefix → flags like --from-context, --from-namespace, etc.
flags := clientcmd.RecommendedConfigOverrideFlags("from-")
  • --timeout 플래그는 기본값이 0입니다.
  • --namespace 플래그는 짧은 별칭 -n도 가집니다.

주의: 접두사는 짧은 이름에 영향을 주지 않습니다. 여러 접두사가 붙은 플래그 집합을 만들 경우, -n 별칭을 유지할 수 있는 것은 하나뿐입니다. 다른 집합에서는 짧은 이름을 비워 주세요:

kflags := clientcmd.RecommendedConfigOverrideFlags(prefix)
kflags.ContextOverrideFlags.Namespace.ShortName = "" // removes -n

4️⃣ 플래그 바인딩

이제 플래그 정의를 ConfigOverrides 구조체에 연결하여 명령줄에 입력된 값이 오버라이드에 채워지도록 합니다.

// Assume you have a pflag.FlagSet called fs
fs := pflag.NewFlagSet("myclient", pflag.ExitOnError)

// Build the flag structs (choose a prefix if you like)
flags := clientcmd.RecommendedConfigOverrideFlags("")

// Register the flags
flags.BindFlags(fs)                     // registers the flags
flags.BindFlagSet(fs, configOverrides) // populates configOverrides when parsed

kubectl과 동일하게 --kubeconfig 플래그도 필요하다면 직접 추가합니다:

fs.StringVar(&configOverrides.ClusterInfo.KubeConfigPath, "kubeconfig", "", "Path to the kubeconfig file")

마지막으로 명령줄을 파싱합니다:

if err := fs.Parse(os.Args[1:]); err != nil {
    // handle parse error
}

5️⃣ 병합된 구성 만들기

로드 규칙과 오버라이드가 준비되면, 지연 로딩 클라이언트 구성을 생성하고 최종 rest.Config를 해결합니다:

kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
    loadingRules,
    configOverrides,
)

restConfig, err := kubeConfig.ClientConfig()
if err != nil {
    // handle error (e.g., missing kubeconfig, invalid overrides)
}

restConfig에는 이제 다음으로부터 병합된 설정이 포함됩니다:

  • KUBECONFIG(또는 기본 파일)로 지정된 파일들
  • 플래그를 통해 제공된 오버라이드

6️⃣ API 클라이언트 얻기

rest.Config를 사용하여 필요한 Kubernetes 클라이언트를 인스턴스화합니다. 다음은 몇 가지 일반적인 예시입니다:

// CoreV1 client
coreClient, err := kubernetes.NewForConfig(restConfig)

// Dynamic client (works with any resource)
dynClient, err := dynamic.NewForConfig(restConfig)

// Discovery client
discClient, err := discovery.NewDiscoveryClientForConfig(restConfig)

여기서부터는 kubectl이 하는 것처럼 클러스터와 상호작용할 수 있습니다.

TL;DR – 6단계 체크리스트

단계코드 스니펫
1️⃣ Loading rulesloadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
2️⃣ OverridesconfigOverrides := &clientcmd.ConfigOverrides{}
3️⃣ Flagsflags := clientcmd.RecommendedConfigOverrideFlags("")
4️⃣ Bindflags.BindFlags(fs); flags.BindFlagSet(fs, configOverrides)
5️⃣ MergekubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides); restConfig, _ := kubeConfig.ClientConfig()
6️⃣ Clientclient, _ := kubernetes.NewForConfig(restConfig)

이 단계들을 따르면 kubectl과 동일한 외관과 동작을 Go CLI에 적용할 수 있으며, 모든 플래그를 직접 구현할 필요가 없습니다. 즐거운 코딩 되세요!

플래그 비활성화

플래그를 완전히 비활성화하려면, 해당 플래그의 긴 이름을 비워두세요:

kflags.ContextOverrideFlags.Namespace.LongName = ""

플래그 바인딩 (대안)

플래그 집합이 정의되면, clientcmd.BindOverrideFlags를 사용하여 명령줄 인수를 오버라이드에 바인딩할 수 있습니다. 이는 Go의 표준 flag 패키지 대신 pflag FlagSet이 필요합니다.

--kubeconfig도 바인딩하려면, 로딩 규칙에서 ExplicitPath를 바인딩하여 지금 수행하십시오:

flags.StringVarP(&loadingRules.ExplicitPath,
    "kubeconfig", "", "", "absolute path(s) to the kubeconfig file(s)")

병합된 구성 빌드 (대안)

병합된 구성을 만들기 위해 두 가지 함수가 제공됩니다:

  • clientcmd.NewInteractiveDeferredLoadingClientConfig
  • clientcmd.NewNonInteractiveDeferredLoadingClientConfig

interactive 버전은 제공된 리더를 사용해 인증 정보를 대화형으로 물어볼 수 있는 반면, non‑interactive 버전은 호출자가 제공한 정보만 사용합니다. 두 함수 모두 “지연(deferred)” 방식이며, 명령줄 인수를 파싱하기 이전에 호출할 수 있습니다; 실제로 구성이 생성될 때까지 파싱된 플래그 값이 구성에 반영됩니다.

API 클라이언트 얻기 (대안)

병합된 구성은 ClientConfig 인스턴스로 반환됩니다. ClientConfig() 메서드를 호출하면 해당 인스턴스에서 API 클라이언트를 얻을 수 있습니다.

구성을 찾을 수 없는 경우(예: KUBECONFIG가 비어 있거나 존재하지 않는 파일을 가리키고, ~/.kube/config가 없으며, 명령줄 오버라이드가 제공되지 않은 경우) 기본 설정은 KUBERNETES_MASTER를 언급하는 모호한 오류를 반환합니다. 이 레거시 동작은 kubectl--local--dry-run 플래그에 대해서만 유지됩니다.

Tip: clientcmd.IsEmptyConfig(err) 로 “빈 구성” 오류를 감지하고 사용자에게 더 명확한 메시지를 표시하세요.

Namespace() 메서드도 유용합니다—사용해야 할 네임스페이스를 반환하고, 사용자가 --namespace 플래그를 통해 네임스페이스를 오버라이드했는지 여부를 알려줍니다.

전체 예제

다음은 완전하고 실행 가능한 예제입니다:

package main

import (
	"context"
	"fmt"
	"os"

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

func main() {
	// Loading rules – no configuration yet
	loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()

	// Overrides and flag (command‑line argument) setup
	configOverrides := &clientcmd.ConfigOverrides{}
	flags := pflag.NewFlagSet("clientcmddemo", pflag.ExitOnError)

	// Bind the standard override flags
	clientcmd.BindOverrideFlags(configOverrides, flags,
		clientcmd.RecommendedConfigOverrideFlags(""))

	// Bind the --kubeconfig flag
	flags.StringVarP(&loadingRules.ExplicitPath,
		"kubeconfig", "", "", "absolute path(s) to the kubeconfig file(s)")

	// Parse the command‑line arguments
	flags.Parse(os.Args)

	// Construct the client configuration (non‑interactive)
	kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
		loadingRules, configOverrides)

	// Get a REST config for the client‑go libraries
	config, err := kubeConfig.ClientConfig()
	if err != nil {
		if clientcmd.IsEmptyConfig(err) {
			panic("Please provide a configuration pointing to the Kubernetes API server")
		}
		panic(err)
	}

	// Build the typed clientset
	client, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err)
	}

	// Determine which namespace to use
	namespace, overridden, err := kubeConfig.Namespace()
	if err != nil {
		panic(err)
	}
	fmt.Printf("Chosen namespace: %s; overridden: %t\n", namespace, overridden)

	// Use the client – list all nodes
	nodeList, err := client.CoreV1().Nodes().List(context.TODO(), v1.ListOptions{})
	if err != nil {
		panic(err)
	}
	for _, node := range nodeList.Items {
		fmt.Println(node.Name)
	}
}

코딩을 즐기세요, 그리고 친숙한 사용 패턴으로 도구를 만드는 데 관심을 가져 주셔서 감사합니다!

Back to Blog

관련 글

더 보기 »

Amazon EKS와 함께한 나의 여정: AWS에서 Kubernetes 간소화

Amazon EKS란 무엇인가? Amazon EKS(Elastic Kubernetes Service)는 AWS가 제공하는 관리형 Kubernetes 서비스이다. 이는 복잡한 인프라 관리 작업을 자동화하고, 클러스터의 프로비저닝, 업그레이드, 패치 적용 등을 손쉽게 처리한다. 또한, AWS의 보안, 네트워킹 및 모니터링 서비스와 통합되어 확장성과 가용성을 높여준다.

StatefulSet 프로젝트

전제 조건 StatefulSet은 다음 구성 요소가 필요합니다: - Headless Service – 각 pod에 대해 안정적인 DNS를 제공합니다. - StatefulSet manifest – pod들을 정의합니다.