플러그인으로 kubectl 확장

kubectl 플러그인을 작성하고 설치해서 kubectl을 확장한다.

이 가이드는 kubectl 확장을 설치하고 작성하는 방법을 보여준다. 핵심 kubectl 명령을 쿠버네티스 클러스터와 상호 작용하기 위한 필수 구성 요소로 생각함으로써, 클러스터 관리자는 플러그인을 이러한 구성 요소를 활용하여 보다 복잡한 동작을 만드는 수단으로 생각할 수 있다. 플러그인은 새로운 하위 명령으로 kubectl 을 확장하고, 주요 배포판에 포함되지 않은 kubectl 의 새로운 사용자 정의 기능을 허용한다.

시작하기 전에

동작하는 kubectl 바이너리가 설치되어 있어야 한다.

kubectl 플러그인 설치

플러그인은 이름이 kubectl- 로 시작되는 독립형 실행 파일이다. 플러그인을 설치하려면, 실행 파일을 PATH 에 지정된 디렉터리로 옮기면 된다.

Krew를 사용하여 오픈소스에서 사용 가능한 kubectl 플러그인을 검색하고 설치할 수도 있다. Krew는 쿠버네티스 SIG CLI 커뮤니티에서 관리하는 플러그인 관리자이다.

주의: Krew 플러그인 인덱스를 통해 사용할 수 있는 kubectl 플러그인은 보안 감사를 받지 않는다. 써드파티 플러그인은 시스템에서 실행되는 임의의 프로그램이므로, 사용자는 이를 인지한 상태에서 설치하고 실행해야 한다.

플러그인 디스커버리

kubectl 은 유효한 플러그인 실행 파일을 PATH 에서 검색하는 kubectl plugin list 명령을 제공한다. 이 명령을 실행하면 PATH 에 있는 모든 파일을 탐색한다. 실행 가능하고, kubectl- 로 시작하는 모든 파일은 이 명령의 출력 결과에 PATH 에 있는 순서대로 표시된다. 실행 파일이 아닌 파일이 kubectl- 시작하는 경우 경고가 포함된다. 서로의 이름과 겹치는 유효한 플러그인 파일에 대한 경고도 포함된다.

Krew를 사용하여 커뮤니티가 관리하는 플러그인 인덱스에서 kubectl 플러그인을 검색하고 설치할 수 있다.

제한 사항

현재 기존 kubectl 명령을 덮어 쓰는 플러그인을 생성할 수 없다. 예를 들어, 플러그인 kubectl-version 을 만들면 기존의 kubectl version 명령이 항상 우선하므로, 플러그인이 실행되지 않는다. 이 제한으로 인해, 플러그인을 사용하여 기존 kubectl 명령에 새로운 하위 명령을 추가할 수도 없다. 예를 들어, 플러그인 이름을 kubectl-create-foo 로 지정하여 kubectl create foo 하위 명령을 추가하면 해당 플러그인이 무시된다.

kubectl plugin list 는 이를 시도하는 유효한 플러그인에 대한 경고를 표시한다.

kubectl 플러그인 작성

커맨드-라인 명령을 작성할 수 있는 프로그래밍 언어나 스크립트로 플러그인을 작성할 수 있다.

플러그인 설치 또는 사전 로딩이 필요하지 않다. 플러그인 실행 파일은 kubectl 바이너리에서 상속된 환경을 받는다. 플러그인은 이름을 기반으로 구현할 명령 경로를 결정한다. 예를 들어, kubectl-foo 라는 플러그인은 kubectl foo 명령을 제공한다. PATH 어딘가에 플러그인 실행 파일을 설치해야 한다.

플러그인 예제

#!/bin/bash

# 선택적 인수 처리
if [[ "$1" == "version" ]]
then
    echo "1.0.0"
    exit 0
fi

# 선택적 인수 처리
if [[ "$1" == "config" ]]
then
    echo "$KUBECONFIG"
    exit 0
fi

echo "I am a plugin named kubectl-foo"

플러그인 사용

플러그인을 사용하려면, 실행 가능하게 만든다.

sudo chmod +x ./kubectl-foo

그리고 PATH 의 어느 곳에나 옮겨 놓는다.

sudo mv ./kubectl-foo /usr/local/bin

이제 플러그인을 kubectl 명령으로 호출할 수 있다.

kubectl foo
I am a plugin named kubectl-foo

모든 인수와 플래그는 그대로 실행 파일로 전달된다.

kubectl foo version
1.0.0

모든 환경 변수도 실행 파일로 그대로 전달된다.

export KUBECONFIG=~/.kube/config
kubectl foo config

/home/<user>/.kube/config
KUBECONFIG=/etc/kube/config kubectl foo config
/etc/kube/config

또한, 플러그인으로 전달되는 첫 번째 인수는 항상 호출된 위치의 전체 경로이다(위의 예에서 $0/usr/local/bin/kubectl-foo 와 동일하다).

플러그인 이름 지정

위 예제에서 볼 수 있듯이, 플러그인은 파일명을 기반으로 구현할 명령 경로를 결정한다. 플러그인이 대상으로 하는 명령 경로의 모든 하위 명령은 대시(-)로 구분된다. 예를 들어, 사용자가 kubectl foo bar baz 명령을 호출할 때마다 호출되는 플러그인은 파일명이 kubectl-foo-bar-baz 이다.

플래그와 인수 처리

참고:

플러그인 메커니즘은 플러그인 프로세스에 대한 사용자 정의, 플러그인 특정 값 또는 환경 변수를 생성하지 않는다.

이전 kubectl 플러그인 메커니즘은 KUBECTL_PLUGINS_CURRENT_NAMESPACE 와 같이 더이상 사용하지 않는 환경 변수를 제공했다.

kubectl 플러그인은 전달된 모든 인수를 파싱하고 유효성을 검사해야 한다. 플러그인 작성자를 대상으로 하는 Go 라이브러리에 대한 자세한 내용은 커맨드 라인 런타임 패키지 사용을 참고한다.

다음은 사용자가 추가 플래그와 인수를 제공하면서 플러그인을 호출하는 추가 사례이다. 이것은 위 시나리오의 kubectl-foo-bar-baz 플러그인을 기반으로한다.

kubectl foo bar baz arg1 --flag=value arg2 를 실행하면, kubectl의 플러그인 메커니즘은 먼저 가장 긴 가능한 이름을 가진 플러그인을 찾으려고 시도한다. 여기서는 kubectl-foo-bar-baz-arg1 이다. 해당 플러그인을 찾지 못하면, kubectl은 대시로 구분된 마지막 값을 인수(여기서는 arg1)로 취급하고, 다음으로 가장 긴 가능한 이름인 kubectl-foo-bar-baz 를 찾는다. 이 이름의 플러그인을 찾으면, kubectl은 해당 플러그인을 호출하여, 플러그인 이름 뒤에 모든 인수와 플래그를 플러그인 프로세스의 인수로 전달한다.

예:

# 플러그인 생성
echo -e '#!/bin/bash\n\necho "My first command-line argument was $1"' > kubectl-foo-bar-baz
sudo chmod +x ./kubectl-foo-bar-baz

# $PATH에 있는 디렉터리로 옮겨 플러그인을 "설치"
sudo mv ./kubectl-foo-bar-baz /usr/local/bin

# 플러그인을 kubectl이 인식하는지 확인
kubectl plugin list
The following kubectl-compatible plugins are available:

/usr/local/bin/kubectl-foo-bar-baz
# test that calling your plugin via a "kubectl" command works
# even when additional arguments and flags are passed to your
# plugin executable by the user.
kubectl foo bar baz arg1 --meaningless-flag=true
My first command-line argument was arg1

보시다시피, 사용자가 지정한 kubectl 명령을 기반으로 플러그인을 찾았으며, 모든 추가 인수와 플래그는 플러그인 실행 파일이 발견되면 그대로 전달된다.

대시와 언더스코어가 있는 이름

kubectl 플러그인 메커니즘은 플러그인 파일명에 대시(-)를 사용하여 플러그인이 처리하는 하위 명령 시퀀스를 분리하지만, 파일명에 언더스코어(_)를 사용하여 커맨드 라인 호출에 대시를 포함하는 플러그인 명령을 생성할 수 있다.

예:

# 파일명에 언더스코어(_)가 있는 플러그인 생성
echo -e '#!/bin/bash\n\necho "I am a plugin with a dash in my name"' > ./kubectl-foo_bar
sudo chmod +x ./kubectl-foo_bar

# $PATH에 플러그인을 옮긴다
sudo mv ./kubectl-foo_bar /usr/local/bin

# 이제 kubectl을 통해 플러그인을 사용할 수 있다
kubectl foo-bar
I am a plugin with a dash in my name

참고로 플러그인 파일명에 언더스코어를 추가해도 kubectl foo_bar 와 같은 명령을 사용할 수 있다. 위 예에서 명령은 대시(-) 또는 언더스코어(_)을 사용하여 호출할 수 있다.

# 대시를 포함한 사용자 정의 명령을 사용할 수 있다
kubectl foo-bar
I am a plugin with a dash in my name
# 언더스코어를 포함한 사용자 정의 명령을 사용할 수도 있다
kubectl foo_bar
I am a plugin with a dash in my name

이름 충돌과 오버셰도잉(overshadowing)

PATH 의 다른 위치에 동일한 파일명을 가진 여러 플러그인이 있을 수 있다. 예를 들어, PATH 값이 PATH=/usr/local/bin/plugins:/usr/local/bin/moreplugins 로 주어지고, kubectl-foo 플러그인을 복사한 파일이 /usr/local/bin/plugins/usr/local/bin/moreplugins 에 있을 수 있다. kubectl plugin list 명령의 출력 결과는 다음과 같다.

PATH=/usr/local/bin/plugins:/usr/local/bin/moreplugins kubectl plugin list
The following kubectl-compatible plugins are available:

/usr/local/bin/plugins/kubectl-foo
/usr/local/bin/moreplugins/kubectl-foo
  - warning: /usr/local/bin/moreplugins/kubectl-foo is overshadowed by a similarly named plugin: /usr/local/bin/plugins/kubectl-foo

error: one plugin warning was found

위 시나리오에서, /usr/local/bin/moreplugins/kubectl-foo 아래의 경고는 이 플러그인이 실행되지 않을 것임을 알려준다. 대신, PATH 에 먼저 나타나는 실행 파일인 /usr/local/bin/plugins/kubectl-foo 는 항상 발견되고 kubectl 플러그인 메카니즘에 의해 먼저 실행된다.

이 문제를 해결하는 방법은 kubectl 와 함께 사용하려는 플러그인의 위치가 PATH 에 항상에서 먼저 오도록 하는 것이다. 예를 들어, kubectl 명령 kubectl foo 가 호출될 때마다 항상 /usr/local/bin/moreplugins/kubectl-foo 를 사용하려면, PATH 의 값을 /usr/local/bin/moreplugins:/usr/local/bin/plugins 로 변경한다.

가장 긴 실행 파일명의 호출

플러그인 파일명으로 발생할 수 있는 또 다른 종류의 오버셰도잉이 있다. 사용자의 PATHkubectl-foo-barkubectl-foo-bar-baz 라는 두 개의 플러그인이 있다면, kubectl 플러그인 메커니즘은 항상 주어진 사용자의 명령에 대해 가장 긴 가능한 플러그인 이름을 선택한다. 아래에 몇 가지 예가 있다.

# 주어진 kubectl 명령의 경우, 가장 긴 가능한 파일명을 가진 플러그인이 항상 선호된다
kubectl foo bar baz
Plugin kubectl-foo-bar-baz is executed
kubectl foo bar
Plugin kubectl-foo-bar is executed
kubectl foo bar baz buz
Plugin kubectl-foo-bar-baz is executed, with "buz" as its first argument
kubectl foo bar buz
Plugin kubectl-foo-bar is executed, with "buz" as its first argument

이 디자인 선택은 필요한 경우 여러 파일에 플러그인 하위 명령을 구현할 수 있도록 하고 이러한 하위 명령을 "부모" 플러그인 명령 아래에 중첩할 수 있도록 한다.

ls ./plugin_command_tree
kubectl-parent
kubectl-parent-subcommand
kubectl-parent-subcommand-subsubcommand

플러그인 경고 확인

위에서 언급한 kubectl plugin list 명령을 사용하여 kubectl 에 의해 플러그인이 표시되는지 확인하고, kubectl 명령으로 호출되지 못하게 하는 경고가 없는지 확인할 수 있다.

kubectl plugin list
The following kubectl-compatible plugins are available:

test/fixtures/pkg/kubectl/plugins/kubectl-foo
/usr/local/bin/kubectl-foo
  - warning: /usr/local/bin/kubectl-foo is overshadowed by a similarly named plugin: test/fixtures/pkg/kubectl/plugins/kubectl-foo
plugins/kubectl-invalid
  - warning: plugins/kubectl-invalid identified as a kubectl plugin, but it is not executable

error: 2 plugin warnings were found

커맨드 라인 런타임 패키지 사용

kubectl 용 플러그인을 작성하고 있고 Go를 사용한다면, cli-runtime 유틸리티 라이브러리를 사용할 수 있다.

이 라이브러리는 사용자의 kubeconfig 파일을 파싱이나 업데이트하거나, REST 스타일의 요청을 API 서버에 작성하거나, 구성 및 출력과 관련된 플래그를 바인딩하기 위한 헬퍼를 제공한다.

CLI 런타임 리포지터리에 제공된 도구 사용법의 예제는 샘플 CLI 플러그인을 참고한다.

kubectl 플러그인 배포

다른 사람이 사용할 수 있는 플러그인을 개발한 경우, 이를 패키징하고, 배포하고 사용자에게 업데이트를 제공하는 방법을 고려해야 한다.

Krew

Krew는 플러그인을 패키징하고 배포하는 크로스-플랫폼 방식을 제공한다. 이렇게 하면, 모든 대상 플랫폼(리눅스, 윈도우, macOS 등)에 단일 패키징 형식을 사용하고 사용자에게 업데이트를 제공한다. Krew는 또한 다른 사람들이 여러분의 플러그인을 검색하고 설치할 수 있도록 플러그인 인덱스를 유지 관리한다.

네이티브 / 플랫폼 별 패키지 관리

다른 방법으로는, 리눅스의 aptyum, 윈도우의 Chocolatey, macOS의 Homebrew와 같은 전통적인 패키지 관리자를 사용할 수 있다. 새 실행 파일을 사용자의 PATH 어딘가에 배치할 수 있는 패키지 관리자라면 어떤 패키지 관리자도 괜찮다. 플러그인 작성자로서, 이 옵션을 선택하면 각 릴리스의 여러 플랫폼에서 kubectl 플러그인의 배포 패키지를 업데이트해야 한다.

소스 코드

소스 코드를 게시(예를 들어, Git 리포지터리)할 수 있다. 이 옵션을 선택하면, 해당 플러그인을 사용하려는 사람이 코드를 가져와서, 빌드 환경을 설정하고(컴파일이 필요한 경우), 플러그인을 배포해야 한다. 컴파일된 패키지를 사용 가능하게 하거나, Krew를 사용하면 설치가 더 쉬워진다.

다음 내용

  • Go로 작성된 플러그인의 자세한 예제에 대해서는 샘플 CLI 플러그인 리포지터리를 확인한다. 궁금한 사항이 있으면, SIG CLI 팀에 문의한다.
  • kubectl 플러그인 패키지 관리자인 Krew에 대해 읽어본다.
최종 수정 February 21, 2021 at 3:24 AM PST : Update to Outdated files in dev-1.20-ko.5 branch (3) (2d7810496)