k3sを使う

はじめに

k3s.io

公式サイトがイカ

k3s とは

github.com

k8sの色々を削ぎ落としたものらしい

  • 使われていないコードなど

バイナリ一枚で40MB程度で軽い、とのこと (はたして40MBは軽いと言えるのか)

基本の使い方

Linux 3.10以上のマシンの上で以下を実行

sh curl -sfL https://get.k3s.io | sh -

これでk8sクラスタが完成する、とてもお手軽

agent を追加する

これも簡単で、k3sのバイナリを以下のように実行する

$ sudo k3s agent --server https://参加したいクラスタのIP:6443 --token ${NODE_TOKEN}
NAME STATUS ROLES AGE VERSION
ip-172-31-38-39 Ready 21m v1.13.3-k3s.6
ip-172-31-38-54 Ready 97m v1.13.3-k3s.6

やったね、楽勝

リモートで使いたい

同じネットワーク内でk3sを立ち上げて使う

これは特に問題ないはず

k3sを立ち上げると /etc/rancher/k3s/k3s.yaml にファイルが配置される

これは同じマシン上に存在するクラスタに接続するためのファイルで、別のマシンから接続するにはこのファイルの一部を同じネットワーク内のk3sが建っているマシンに向ける

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: hogefuga
-    server: https://localhost:6443
+    server: https://k3sが建っているマシンのプライベートIPを入れる:6443
  name: default
contexts:
- context:
    cluster: default
    user: default
  name: default
current-context: default
kind: Config
preferences: {}
users:
- name: default
  user:
    password: hogefuga
    username: admin

k3sが建っているマシンのプライベートIPを入れる は 以降 (プライベートIP) と表記する

あとはこのymlを指定しながら kubectl を叩けばよさそう

kubectl --kubeconfig ~/.kube/k3s.yml get all

外部ネットワークからk3sのクラスタに接続する

頑張ってセキュア(?)なままアクセスしてみる

外部から愚直に(グローバルIPを直接指定して)接続する場合、上記手順だけでは接続できない

$ kubectl --kubeconfig ~/.kube/k3s.yml get all Unable to connect to the server: x509: certificate is valid for 127.0.0.1,(プライベートIP), not (グローバルIP)

どうやら証明書の対象が127.0.0.1とプライベートIPのみらしい 確認してみる

$ openssl s_client -connect localhost:6443 2>/dev/null | openssl x509 -text | grep -A 1 "Subject Alternative Name"
  X509v3 Subject Alternative Name:
    DNS:, IP Address:127.0.0.1, IP Address:(プライベートIP)

つまり、表示されたIP以外ではこの証明書は有効にならないのでクライアント側から通信を弾く状態となる

プライベートIPが動的にSANに割り当てられるところを見るとどうやらこの証明書はk3s内部で動的に生成しているようだ

どこで作成しているか追ってみる

k3s/server.go at f90cbed4081e7e1e6972861c196543b2d253bfcc · rancher/k3s · GitHub

func knownIPs() []string {
  ips := []string{
    "127.0.0.1",
  }
  ip, err := net.ChooseHostInterface()
  if err == nil {
    ips = append(ips, ip.String())
  }
  return ips
}

IPアドレスの文字列の配列を返す関数が見つかる

(このオブジェクトは serverConfig.TLSConfig.KnownIPs に渡され、追っていくと後に norman(rancher製のサーバーアプリケーションの実装?) に渡される)

net.ChooseHostInterface というのはk8sでも使われているutilに生えている関数で、ネットワークインターフェイスからIPを1つ取得して返す (Golangわからんけど合ってるよね?)

  • 先程まで雑に「プライベートIP」と読んでいたものの正体はこれっぽい

GoDoc k8s.io/apimachinery/pkg/util/net#ChooseHostInterface

apimachinery/interface.go at master · kubernetes/apimachinery · GitHub

この関数のIPのリストにグローバルIPを追加で書き込んでビルド、起動してみる (良い手ではないと思う)

func knownIPs() []string {
  ips := []string{
    "127.0.0.1",
+    "グローバルIP",
  }
  ip, err := net.ChooseHostInterface()
  if err == nil {
    ips = append(ips, ip.String())
  }
  return ips
}

すると、SANにもグローバルIPが追加される事が分かる

$ openssl s_client -connect localhost:6443 2>/dev/null | openssl x509 -text | grep -A 1 "Subject Alternative Name"
  X509v3 Subject Alternative Name:
    DNS:, IP Address:127.0.0.1, IP Address:(グローバルIP), IP Address:(プライベートIP)

これで kubectl を叩くと接続できるようになる

$ kubectl --kubeconfig ~/.kube/k3s.yml get all
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.43.0.1 443/TCP 49m

これ、手法としてだいぶダーティーだし、本当はもうちょっと別の手を取るべきなんだろうけど全然わからなかった

誰か正しい方法を教えてくれ〜

(もしこれが正しいのであれば何故k3sにはhostnameを受け取る起動引数が無いのだろうか…)

insecure-skip-tls-verify: true する

単にこちら側が弾いているだけなので、tls verifyをスキップすることでクラスターにアクセスできるようになる

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: hogefuga
    server: https://グローバルIP:6443
+    insecure-skip-tls-verify: true
  name: default
contexts:
- context:
    cluster: default
    user: default
  name: default
current-context: default
kind: Config
preferences: {}
users:
- name: default
  user:
    password: hogefuga
    username: admin

または

$ kubectl --kubeconfig ~/.kube/k3s.yml get all --insecure-skip-tls-verify=true

結局どうするのが正解なの??

k3sのユースケース

k3sリポジトリの記念すべき1つめのissueもユースケースを尋ねるものだった

github.com

製作者のDarren Shepherd曰く、これは軽量のk8sを作るためのプロダクトだとのこと

https://github.com/rancher/k3s/issues/1#issuecomment-424943047

軽く使えることが大きな理由となるような事に利用するものなのだろうと想像している

  • 実際公式サイトの方でもEdgeとかIoTとかCIとか書かれている

個人的にとても良いと思っているのはk8sの練習台として使うユースケースがある

k8sの練習を行う場合、勿論ながら何かしらの形でクラスタを用意する必要がある

おおよそminikubeかDocker for Desktopに付属のk8sを使うことになると思うが、ここに第三の選択肢としてk3sを上げることが出来るようになった

これは上で説明したように簡単に立ち上げることが出来るし、他より動作が軽いために気軽さはとても大きいと思う

しかもノードの追加も容易なため、複数ノード構成の練習も簡単に出来る

  • 多分先程挙げたminikube, Docker for Desktopのk8sで複数ノード構成を取るより容易
    • そもそもこの2つで複数ノード構成出来るのか?

↓こんな docker-compose.yml もあるので、 github.com

$ docker-compose up -d
$ kubectl get node --kubeconfig kubeconfig.yaml

とすればすぐにk8sの環境が立ち上がるの、普通に便利では?