TECHSTEP

ITインフラ関連の記事を公開してます。

kubectl proxyオプションの紹介 ~--accept-hosts, --address, --port, --api-prefix, --www, --www-prefix~

はじめに

Kubernetesの環境でPodのデプロイやClusterの制御などを行う際にはkubectlコマンドを介して操作します。

kubectlにはたくさんのコマンドやオプションが用意されています。その中の一つであるkubectl proxyについて、少しだけ検証する機会がありました。

これまではただただkubectl proxyと叩くだけだったコマンドでしたが、実はいろんなオプションがあって色々とできることを知れたので、備忘録の意味も含めてここに書いておきます。

kubectlの全体像は公式ページのこちらkubectlのコマンド、オプションはこちらから詳しい説明を見ることができます。

kubectl proxyで提供するオプション

kubectl proxy -hコマンドでヘルプを確認すると、以下のように表示されます。

[root@k8s-master-ksonnet guestbook]# kubectl proxy -h
Creates a proxy server or application-level gateway between localhost and the Kubernetes API Server. It also allows
serving static content over specified HTTP path. All incoming data enters through one port and gets forwarded to the
remote kubernetes API Server port, except for the path matching the static content path.

Examples:
  # To proxy all of the kubernetes api and nothing else, use:
  
  $ kubectl proxy --api-prefix=/
  
  # To proxy only part of the kubernetes api and also some static files:
  
  $ kubectl proxy --www=/my/files --www-prefix=/static/ --api-prefix=/api/
  
  # The above lets you 'curl localhost:8001/api/v1/pods'.
  
  # To proxy the entire kubernetes api at a different root, use:
  
  $ kubectl proxy --api-prefix=/custom/
  
  # The above lets you 'curl localhost:8001/custom/api/v1/pods'
  
  # Run a proxy to kubernetes apiserver on port 8011, serving static content from ./local/www/
  kubectl proxy --port=8011 --www=./local/www/
  
  # Run a proxy to kubernetes apiserver on an arbitrary local port.
  # The chosen port for the server will be output to stdout.
  kubectl proxy --port=0
  
  # Run a proxy to kubernetes apiserver, changing the api prefix to k8s-api
  # This makes e.g. the pods api available at localhost:8001/k8s-api/v1/pods/
  kubectl proxy --api-prefix=/k8s-api

Options:
      --accept-hosts='^localhost$,^127\.0\.0\.1$,^\[::1\]$': Regular expression for hosts that the proxy should accept.
      --accept-paths='^.*': Regular expression for paths that the proxy should accept.
      --address='127.0.0.1': The IP address on which to serve on.
      --api-prefix='/': Prefix to serve the proxied API under.
      --disable-filter=false: If true, disable request filtering in the proxy. This is dangerous, and can leave you
vulnerable to XSRF attacks, when used with an accessible port.
      --keepalive=0s: keepalive specifies the keep-alive period for an active network connection. Set to 0 to disable
keepalive.
  -p, --port=8001: The port on which to run the proxy. Set to 0 to pick a random port.
      --reject-methods='^$': Regular expression for HTTP methods that the proxy should reject (example
--reject-methods='POST,PUT,PATCH'). 
      --reject-paths='^/api/.*/pods/.*/exec,^/api/.*/pods/.*/attach': Regular expression for paths that the proxy should
reject. Paths specified here will be rejected even accepted by --accept-paths.
  -u, --unix-socket='': Unix socket on which to run the proxy.
  -w, --www='': Also serve static files from the given directory under the specified prefix.
  -P, --www-prefix='/static/': Prefix to serve static files under, if static file directory is specified.

Usage:
  kubectl proxy [--port=PORT] [--www=static-dir] [--www-prefix=prefix] [--api-prefix=prefix] [options]

Use "kubectl options" for a list of global command-line options (applies to all commands).
[root@k8s-master-ksonnet guestbook]# 

はじめの方でkubectl proxyコマンドの使用用途が書かれています。

Creates a proxy server or application-level gateway between localhost and the Kubernetes API Server. It also allows
serving static content over specified HTTP path. All incoming data enters through one port and gets forwarded to the
remote kubernetes API Server port, except for the path matching the static content path.

localhostとKubernetes API serverの間に、Proxyサーバ/アプリケーションレベルのゲートウェイを作成します。
また特定のHTTPパスを通じて、静的コンテンツを提供することも許可します。
すべてのデータは1つのポートを通して入り、Kubernetes AI Serverのポートにフォワーディングされます。
ただし静的コンテンツのパスに合致する場合は別です。

Kubernetes APIにアクセスする方法は公式ページで幾つか紹介されていますが、kubectl proxyが推奨されています。

--accept-hosts, --addressオプション

--accept-hostsはproxyでアクセスできるホストを明記します。デフォルトでは^localhost$,^127\.0\.0\.1$,^\[::1\]$です。^$は書き方のお作法かもしれませんが、特に使用せずともアクセスは可能でした。

--addressでは外部からアクセスする際に利用するIPアドレスを指定します。デフォルトでは127.0.0.1です。

まずデフォルトの状態でコマンドを実行します。

[root@k8s-master-ksonnet ~]# kubectl proxy &
[1] 6301
[root@k8s-master-ksonnet ~]# 

この状態でmasterクラスターからcurlコマンドを実行し、APIにアクセスしてみます。

[root@k8s-master-ksonnet ~]# curl http://localhost:8001/api
{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "10.0.0.193:6443"
    }
  ]
}[root@k8s-master-ksonnet ~]# 

APIの情報が取得できました。

続いてKubernetesの別ノードからアクセスしてみたいと思います。ひとまず--addressコマンドを用いて、アクセスするIPアドレス(ここではmasterクラスターのプライベートIPアドレス10.0.0.193)を指定します。

[root@k8s-master-ksonnet ~]# kubectl proxy --address='10.0.0.193' &
[1] 6607
[root@k8s-master-ksonnet ~]# Starting to serve on 10.0.0.193:8001

[root@k8s-master-ksonnet ~]# 

まずはmasterクラスターから、再びcurlコマンドでアクセスしてみます。

[root@k8s-master-ksonnet ~]# curl http://10.0.0.193:8001/api
Forbidden
[root@k8s-master-ksonnet ~]# 

Forbiddenメッセージが表示されました。--addressで指定する場合は--accept-hostsでそのアドレスを指定する必要があります。

--accept-hostsを追加した場合は以下のようになります。

[root@k8s-master-ksonnet ~]# kubectl proxy --address='10.0.0.193' --accept-hosts='^10\.0\.0\.193$' &
[1] 12350
[root@k8s-master-ksonnet ~]# Starting to serve on 10.0.0.193:8001


[root@k8s-master-ksonnet ~]# curl http://10.0.0.193:8001/api
{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "10.0.0.193:6443"
    }
  ]
}[root@k8s-master-ksonnet ~]# 

今度は情報を取得できました。 次に別ノードからアクセスしたいと思います。

[root@k8s-node-1-ksonnet ~]# curl http://10.0.0.193:8001/api
{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "10.0.0.193:6443"
    }
  ]
}[root@k8s-node-1-ksonnet ~]# 

こちらも無事にアクセスできました。

--portオプション

続いて--portオプションを使ってみます。これはアクセスするポートを明示的に指定することができるオプションです。デフォルトは8001です。

[root@k8s-master-ksonnet ~]# kubectl proxy --port=8080 &
[1] 13552
[root@k8s-master-ksonnet ~]# Starting to serve on 127.0.0.1:8080

[root@k8s-master-ksonnet ~]# curl http://localhost:8080/api
{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "10.0.0.193:6443"
    }
  ]
}[root@k8s-master-ksonnet ~]# 

また0を指定するとランダムにポート番号を割り当てます。

[root@k8s-master-ksonnet ~]# kubectl proxy --port=0 &
[1] 14654
[root@k8s-master-ksonnet ~]# Starting to serve on 127.0.0.1:45665


# プロセスを落として同じコマンドを実行
[root@k8s-master-ksonnet ~]# kill 14654
[root@k8s-master-ksonnet ~]# 
[1]+  Terminated              kubectl proxy --port=0
[root@k8s-master-ksonnet ~]# 
[root@k8s-master-ksonnet ~]# kubectl proxy --port=0 &
[1] 14718
[root@k8s-master-ksonnet ~]# Starting to serve on 127.0.0.1:44720

--api-prefixオプション

--api-prefixはアクセスするパスを明示的に指定できます。デフォルトは/です。

ここではkubectl proxy -hオプション実行時に表示される例を試してみます。

# --api-prefixオプションを実行しない場合

[root@k8s-master-ksonnet ~]# kubectl proxy &
[1] 18711
[root@k8s-master-ksonnet ~]# Starting to serve on 127.0.0.1:8001

[root@k8s-master-ksonnet ~]# curl http://127.0.0.1:8001/
{
  "paths": [
    "/api",
    "/api/v1",
    "/apis",
    "/apis/",
    "/apis/admissionregistration.k8s.io",
    "/apis/admissionregistration.k8s.io/v1beta1",
    "/apis/apiextensions.k8s.io",
    "/apis/apiextensions.k8s.io/v1beta1",
    "/apis/apiregistration.k8s.io",
    "/apis/apiregistration.k8s.io/v1",
    "/apis/apiregistration.k8s.io/v1beta1",
    "/apis/apps",
    "/apis/apps/v1",
    "/apis/apps/v1beta1",
    "/apis/apps/v1beta2",
    "/apis/authentication.k8s.io",
    "/apis/authentication.k8s.io/v1",
    "/apis/authentication.k8s.io/v1beta1",
    "/apis/authorization.k8s.io",
    "/apis/authorization.k8s.io/v1",
    "/apis/authorization.k8s.io/v1beta1",
    "/apis/autoscaling",
    "/apis/autoscaling/v1",
    "/apis/autoscaling/v2beta1",
    "/apis/autoscaling/v2beta2",
    "/apis/batch",
    "/apis/batch/v1",
    "/apis/batch/v1beta1",
    "/apis/certificates.k8s.io",
    "/apis/certificates.k8s.io/v1beta1",
    "/apis/coordination.k8s.io",
    "/apis/coordination.k8s.io/v1beta1",
    "/apis/crd.projectcalico.org",
    "/apis/crd.projectcalico.org/v1",
    "/apis/events.k8s.io",
    "/apis/events.k8s.io/v1beta1",
    "/apis/extensions",
    "/apis/extensions/v1beta1",
    "/apis/networking.k8s.io",
    "/apis/networking.k8s.io/v1",
    "/apis/policy",
    "/apis/policy/v1beta1",
    "/apis/rbac.authorization.k8s.io",
    "/apis/rbac.authorization.k8s.io/v1",
    "/apis/rbac.authorization.k8s.io/v1beta1",
    "/apis/scheduling.k8s.io",
    "/apis/scheduling.k8s.io/v1beta1",
    "/apis/storage.k8s.io",
    "/apis/storage.k8s.io/v1",
    "/apis/storage.k8s.io/v1beta1",
    "/healthz",
    "/healthz/autoregister-completion",
    "/healthz/etcd",
    "/healthz/log",
    "/healthz/ping",
    "/healthz/poststarthook/apiservice-openapi-controller",
    "/healthz/poststarthook/apiservice-registration-controller",
    "/healthz/poststarthook/apiservice-status-available-controller",
    "/healthz/poststarthook/bootstrap-controller",
    "/healthz/poststarthook/ca-registration",
    "/healthz/poststarthook/generic-apiserver-start-informers",
    "/healthz/poststarthook/kube-apiserver-autoregistration",
    "/healthz/poststarthook/rbac/bootstrap-roles",
    "/healthz/poststarthook/scheduling/bootstrap-system-priority-classes",
    "/healthz/poststarthook/start-apiextensions-controllers",
    "/healthz/poststarthook/start-apiextensions-informers",
    "/healthz/poststarthook/start-kube-aggregator-informers",
    "/healthz/poststarthook/start-kube-apiserver-admission-initializer",
    "/logs",
    "/metrics",
    "/openapi/v2",
    "/swagger-2.0.0.json",
    "/swagger-2.0.0.pb-v1",
    "/swagger-2.0.0.pb-v1.gz",
    "/swagger.json",
    "/swaggerapi",
    "/version"
  ]
}[root@k8s-master-ksonnet ~]# 


# --api-prefixオプション実行時

[root@k8s-master-ksonnet ~]# kubectl proxy --api-prefix='/custom' &
[1] 17721
[root@k8s-master-ksonnet ~]# Starting to serve on 127.0.0.1:8001

[root@k8s-master-ksonnet ~]# curl http://127.0.0.1:8001/
404 page not found
[root@k8s-master-ksonnet ~]# curl http://127.0.0.1:8001/custom
<a href="/custom/">Moved Permanently</a>.

[root@k8s-master-ksonnet ~]# curl http://127.0.0.1:8001/custom/api
{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "10.0.0.193:6443"
    }
  ]
}[root@k8s-master-ksonnet ~]# 

例のように、--api-prefixコマンド実行時には、指定したパスを指定しないと404 page not foundや専用のページが返されます。

--www, --www-prefixオプション

--wwwコマンドで静的コンテンツの格納ディレクトリを指定できます。デフォルトでは何も指定されていません。

# テスト用htmlファイル
[root@k8s-master-ksonnet ~]# cat /var/www/html/test.html
<p>test</p>
[root@k8s-master-ksonnet ~]# 


[root@k8s-master-ksonnet ~]# kubectl proxy --www='/var/www/html/' &
[1] 29057
[root@k8s-master-ksonnet ~]# Starting to serve on 127.0.0.1:8001

[root@k8s-master-ksonnet ~]# curl http://127.0.0.1:8001/static/
<pre>
<a href="test.html">test.html</a>
</pre>
[root@k8s-master-ksonnet ~]# curl http://127.0.0.1:8001/static/test.html
<p>test</p>
[root@k8s-master-ksonnet ~]# 

--www-prefixでは静的コンテンツへのアクセスパスを指定できます。デフォルトは/static/です。

[root@k8s-master-ksonnet ~]# kubectl proxy --www='/var/www/html/' --www-prefix='/test/directory/' &
[1] 30375
[root@k8s-master-ksonnet ~]# Starting to serve on 127.0.0.1:8001

[root@k8s-master-ksonnet ~]# curl http://127.0.0.1:8001/test/directory/
<pre>
<a href="test.html">test.html</a>
</pre>
[root@k8s-master-ksonnet ~]# curl http://127.0.0.1:8001/test/directory/test.html
<p>test</p>
[root@k8s-master-ksonnet ~]# 

まとめ

kubectl proxyコマンドのオプションを簡単に見てみました。すべてを覚える必要はないとは思いますが、よく使いそうなものだけでも覚えておくと、何かの役に立つかもしれません。