Slide 1

Slide 1 text

Kubernetes Meetup Tokyo #12 2018/7/11 Kazuki Suda @superbrothers プラグインで kubectl を拡張する

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

Kubernetes の拡張性

Slide 4

Slide 4 text

Kubernetes の拡張性 ▶ ネットワークプラグイン + CNI (alpha) ▶ ストレージプラグイン + CSI (beta) ▶ デバイスプラグイン + NVIDIA GPU device plugin, etc ▶ コンテナランタイム + CRI, docker, containerd, cri-o, rktlet Infrastructure Controllers ▶ クラウドプロバイダ + cloud-controller-manager (beta) ▶ スケジューラ + カスタムスケジューラ ▶ Ingress (L7 LB) + Nginx, HAProxy, AWS, GCE, etc ▶ カスタムリソース + CustomResourceDefinitions + Extension API Servers ▶ Admission Control + ValidatingAdmissionWebhooks (beta) + MutatingAdmissionWebhooks (beta) + Initializers (alpha) ▶ 認証認可 + AuthN: TokenReview API + AuthZ: SubjectAccessReview API API

Slide 5

Slide 5 text

Kubernetes の拡張性 ▶ kubectl + kubectl plugin (alpha) Command Line
 Interface

Slide 6

Slide 6 text

kubectl plugin:
 プラグインで kubectl を拡張する

Slide 7

Slide 7 text

kubectl plugin: Extend kubectl with plugins ▶ kubectl plugin 下に任意のコマンドを追加する拡張機能 ▶ v1.7.0 で実装されたが、v1.8.0 またそれ以降での利⽤を推奨 ▶ $HOME/.kube/plugins 下に⼀つ以上の plugin.yaml とバイナリまたはスクリ プトを配置する + $KUBECTL_PLUGINS_PATH でパスを変更できる # Loads plugins from both /path/to/dir1 and /path/to/dir2 KUBECTL_PLUGINS_PATH=/path/to/dir1:/path/to/dir2 kubectl plugin -h

Slide 8

Slide 8 text

name: "targaryen" # REQUIRED: the plugin command name, to be invoked under 'kubectl' shortDesc: "Dragonized plugin" # REQUIRED: the command short description, for help longDesc: "" # the command long description, for help example: "" # command example(s), for help command: "./dracarys" # REQUIRED: the command, binary, or script flags: # flags supported by the plugin - name: "heat" # REQUIRED for each flag: flag name shorthand: "h" # short version of the flag name desc: "Fire heat" # REQUIRED for each flag: flag description defValue: "extreme" # default value of the flag tree: # allows the declaration of subcommands - ... # subcommands support the same set of attributes plugin.yaml の記述

Slide 9

Slide 9 text

$ kubectl plugin targaryen --help Dragonized plugin Options: --heat='extreme': Fire heat Usage: kubectl plugin targaryen [flags] [options] Use "kubectl options" for a list of global command-line options (applies to all commands).

Slide 10

Slide 10 text

▶ プラグイン名と同じ名前のサブディレクトリを作成する ▶ 依存するバイナリやスクリプトはサブディレクトリ下に配置する 推奨するディレクトリ構造 ~/.kube/plugins/ └── targaryen ├── plugin.yaml └── dracarys

Slide 11

Slide 11 text

$ kubectl plugin flags | grep KUBECTL_ | sort KUBECTL_PLUGINS_CALLER=/usr/local/bin/kubectl KUBECTL_PLUGINS_CURRENT_NAMESPACE=default KUBECTL_PLUGINS_DESCRIPTOR_COMMAND=bash -c env KUBECTL_PLUGINS_DESCRIPTOR_EXAMPLE= KUBECTL_PLUGINS_DESCRIPTOR_LONG_DESC= KUBECTL_PLUGINS_DESCRIPTOR_NAME=flags KUBECTL_PLUGINS_DESCRIPTOR_SHORT_DESC=I echo all the flags that have been passed to my plugin as environment variables KUBECTL_PLUGINS_GLOBAL_FLAG_ALSOLOGTOSTDERR=false KUBECTL_PLUGINS_GLOBAL_FLAG_AS= KUBECTL_PLUGINS_GLOBAL_FLAG_AS_GROUP=[] KUBECTL_PLUGINS_GLOBAL_FLAG_CACHE_DIR=/Users/ksuda/.kube/http-cache KUBECTL_PLUGINS_GLOBAL_FLAG_CERTIFICATE_AUTHORITY= KUBECTL_PLUGINS_GLOBAL_FLAG_CLIENT_CERTIFICATE= KUBECTL_PLUGINS_GLOBAL_FLAG_CLIENT_KEY= KUBECTL_PLUGINS_GLOBAL_FLAG_CLUSTER= KUBECTL_PLUGINS_GLOBAL_FLAG_CONTEXT= KUBECTL_PLUGINS_GLOBAL_FLAG_INSECURE_SKIP_TLS_VERIFY=false KUBECTL_PLUGINS_GLOBAL_FLAG_KUBECONFIG= KUBECTL_PLUGINS_GLOBAL_FLAG_LOGTOSTDERR=true KUBECTL_PLUGINS_GLOBAL_FLAG_LOG_BACKTRACE_AT=:0 KUBECTL_PLUGINS_GLOBAL_FLAG_LOG_DIR= KUBECTL_PLUGINS_GLOBAL_FLAG_LOG_FLUSH_FREQUENCY=5s KUBECTL_PLUGINS_GLOBAL_FLAG_MATCH_SERVER_VERSION=false KUBECTL_PLUGINS_GLOBAL_FLAG_NAMESPACE= KUBECTL_PLUGINS_GLOBAL_FLAG_REQUEST_TIMEOUT=0 KUBECTL_PLUGINS_GLOBAL_FLAG_SERVER= KUBECTL_PLUGINS_GLOBAL_FLAG_STDERRTHRESHOLD=2 KUBECTL_PLUGINS_GLOBAL_FLAG_TOKEN= KUBECTL_PLUGINS_GLOBAL_FLAG_USER= KUBECTL_PLUGINS_GLOBAL_FLAG_V=0 KUBECTL_PLUGINS_GLOBAL_FLAG_VMODULE= KUBECTL_PLUGINS_LOCAL_FLAG_FOO= KUBECTL_PLUGINS_LOCAL_FLAG_HELP=false KUBECTL_PLUGINS_LOCAL_FLAG_OUTPUT= github.com/carolynvs/kubectl-flags-plugin

Slide 12

Slide 12 text

k8s.io/kubectl/pkg/pluginutils // InitClientAndConfig uses the KUBECONFIG environment variable to create // a new rest client and config object based on the existing kubectl config // and options passed from the plugin framework via environment variables func InitClientAndConfig() (*restclient.Config, clientcmd.ClientConfig, error) { ...... configFile := os.Getenv("KUBECTL_PLUGINS_GLOBAL_FLAG_CONFIG") kubeConfigFile := os.Getenv("KUBECTL_PLUGINS_GLOBAL_FLAG_KUBECONFIG") if len(configFile) > 0 { kubeconfig = configFile } else if len(kubeConfigFile) > 0 { kubeconfig = kubeConfigFile }

Slide 13

Slide 13 text

import ( "k8s.io/client-go/kubernetes" "k8s.io/kubectl/pkg/pluginutils" ) func main() { ... restConfig, kubeConfig, err := pluginutils.InitClientAndConfig() if err != nil { log.Fatalf("Failed to init client and config: %v", err) } client := kubernetes.NewForConfigOrDie(restConfig) k8s.io/kubectl/pkg/pluginutils

Slide 14

Slide 14 text

予約済みのフラグ $ kubectl options The following options can be passed to any command: --alsologtostderr=false: log to standard error as well as files --as='': Username to impersonate for the operation --as-group=[]: Group to impersonate for the operation, this flag can be repeated to specify m --cache-dir='/Users/ksuda/.kube/http-cache': Default HTTP cache directory --certificate-authority='': Path to a cert file for the certificate authority --client-certificate='': Path to a client certificate file for TLS --client-key='': Path to a client key file for TLS --cluster='': The name of the kubeconfig cluster to use --context='': The name of the kubeconfig context to use --insecure-skip-tls-verify=false: If true, the server's certificate will not be checked for v --kubeconfig='': Path to the kubeconfig file to use for CLI requests. --log-backtrace-at=:0: when logging hits line file:N, emit a stack trace --log-dir='': If non-empty, write log files in this directory --log-flush-frequency=5s: Maximum number of seconds between log flushes --logtostderr=true: log to standard error instead of files --match-server-version=false: Require server version to match client version -n, --namespace='': If present, the namespace scope for this CLI request

Slide 15

Slide 15 text

デモ: github.com/superbrothers/kubectl- view-kubeconfig-plugin

Slide 16

Slide 16 text

$ kubectl plugin view-kubeconfig -h Show a kubeconfig setting to access the apiserver with a specified serviceaccount. Examples: # Show a kubeconfig setting of serviceaccount/default kubectl plugin view-kubeconfig default Usage: kubectl plugin view-kubeconfig [flags] [options] Use "kubectl options" for a list of global command-line options (applies to all commands). $ cat ~/.kube/view-kubeconfig/plugin.yaml name: "view-kubeconfig" shortDesc: "Show a kubeconfig setting to access the apiserver with a specified serviceaccount." example: "# Show a kubeconfig setting of serviceaccount/default\nkubectl plugin view-kubeconfig def command: "./view-kubeconfig"

Slide 17

Slide 17 text

import ( "flag" "fmt" "log" "os" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" clientcmd "k8s.io/client-go/tools/clientcmd" clientcmdapi "k8s.io/client-go/tools/clientcmd/api" "k8s.io/kubectl/pkg/pluginutils" // Initialize all known client auth plugins. _ "k8s.io/client-go/plugin/pkg/client/auth" ) func init() { // Initialize glog flags flag.CommandLine.Set("logtostderr", "true") flag.CommandLine.Set("v", os.Getenv("KUBECTL_PLUGINS_GLOBAL_FLAG_V")) }

Slide 18

Slide 18 text

func main() { if len(os.Args) < 2 { log.Fatalf("Usage: kubectl plugin view-kubeconfig SERVICEACCOUNT") } serviceaccountName := os.Args[1] restConfig, kubeConfig, err := pluginutils.InitClientAndConfig() if err != nil { log.Fatalf("Failed to init client and config: %v", err) } client := kubernetes.NewForConfigOrDie(restConfig) namespace, _, _ := kubeConfig.Namespace()

Slide 19

Slide 19 text

serviceaccount, err := client.CoreV1().ServiceAccounts(namespace).Get(serviceaccountName, metav1.GetOptions{}) if err != nil { log.Fatalf("Failed to get a serviceaccount: %v", err) } if len(serviceaccount.Secrets) < 1 { log.Fatalf("serviceaccount %s has no secrets", serviceaccount.GetName()) } secret, err := client.CoreV1().Secrets(namespace).Get(serviceaccount.Secrets[0].Name, metav1.GetOptions{}) if err != nil { log.Fatalf("Failed to get a secret: %v", err) } caCrt, ok := secret.Data["ca.crt"] if !ok { log.Fatalf("key 'ca.crt' not found in %s", secret.GetName()) } token, ok := secret.Data["token"] if !ok { log.Fatalf("key 'token' not found in %s", secret.GetName()) }

Slide 20

Slide 20 text

デモ: github.com/superbrothers/kubectl- service-plugin

Slide 21

Slide 21 text

$ kubectl plugin service -h Open the Kubernetes URL(s) for the specified service in your browser through a local proxy server using kubectl proxy. Examples: # Open service/kubernetes-dashboard in kube-system namespace. kubectl plugin service kubernetes-dashboard -n kube-system Usage: kubectl plugin service [flags] [options] Use "kubectl options" for a list of global command-line options (applies to all commands).]

Slide 22

Slide 22 text

kubectl plugin の現在と将来

Slide 23

Slide 23 text

kubectl plugin の現在と将来 ▶ Alpha Stability ⚠ (v1.11): 今後下位互換性のない⼤きな変更が⼊る ▶ 現在 kubectl plugin 下にコマンドが追加されるが、将来 kubectl 下になるかも

Slide 24

Slide 24 text

より詳しく知るには

Slide 25

Slide 25 text

より詳しく知るには ▶ https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/ ▶ Install the Service Catalog CLI as kubectl plugin + https://github.com/kubernetes-incubator/service-catalog $ svcat install plugin Plugin has been installed to ~/.kube/plugins/svcat. Run kubectl plugin svcat --help for help using the plugin.

Slide 26

Slide 26 text

We’re Hiring! https://zlab.co.jp/ Kubernetes, Docker, Prometheus, Golang, CoreOS