2019/04/29

k3sを使ってオンプレミスなKubernetesクラスタを構築したよ!

概要

GKE が大好きで非常に満足していたのですが、以下のような願望もありました。
  • Kubernetes勉強しながら好き勝手出来るスクラッチ用のクラスター環境が欲しい
  • Raspberry Piなどエッジで動かすコンテナを、Kubernetesクラスターでコントロールしたい
そこで、オンプレミスなKubernetesクラスターを構築することにしました。

k3s is 何?

「エッジでも動く!」という噂を聞いて、k3sを使うことに決めました。
  • 超軽量なKubernetes。
    • バイナリが40 MB以下
      • 小さいことはいいことだ。
    • RAMが512 MBあれば動く
      • ラズパイとかのエッジでも動くよ。凄い!
クラスタの動作イメージは、以下の通りです。(公式からの引用です。)
引用元: k3s.io

この記事でやること

上図のkemo-clusterのようなKubernetesクラスターを作ります。
  • ホストkemo-masterで、k3sをServerとして起動
  • ホストkemo-node01kemo-node02で、k3sをAgentとして起動
  • クラスター外のホストkemo-clientからクラスターに対して操作を実行する。
    • 入門 Kubernetesのサンプルアプリケーションkuardを使ってReplicaSetを作成
    • LoadBalancerタイプのServiceを起動してブラウザからアクセス

使用環境

  • Ubuntu Server: 18.04.2 LTS
  • k3s: v0.4.0

では始めましょう!ʕ◔ϖ◔ʔ

Server

インストールとサービス起動

k3sをインストールしてServerとして起動します。
curl -sfL https://get.k3s.io | sh -
上記を実行するだけで、ホスト環境に合わせたバイナリのダウンロードや配置、systemdの登録と起動まで自動でやってくれます。公式のREADMEのsystemdに詳しい情報があります。

サービスの設定ファイル/etc/systemd/system/k3s.serviceを確認すると、以下のようになっています。
kemokemo@kemo-master:~$ cat /etc/systemd/system/k3s.service
[Unit]
Description=Lightweight Kubernetes
Documentation=https://k3s.io
After=network.target

[Service]
Type=notify
EnvironmentFile=/etc/systemd/system/k3s.service.env
ExecStartPre=-/sbin/modprobe br_netfilter
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/k3s server
KillMode=process
Delegate=yes
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
TimeoutStartSec=0

[Install]
WantedBy=multi-user.target

Tokenの確認

AgentからServerへと接続するために必要となるTokenを確認します。
sudo cat /var/lib/rancher/k3s/server/node-token
後ほどAgentのインストール時に使いますのでどこかにメモしておきます。

動作確認

動いているか確認しましょう。
kubectl get nodes
実行結果は以下のようになります。
kemokemo@kemo-master:~$ kubectl get node
NAME          STATUS   ROLES    AGE    VERSION
kemo-master   Ready    <none>   113s   v1.14.1-k3s.4

Agent

インストール

こちらも、READMEのsystemdの内容に沿ってインストールします。
curl -sfL https://get.k3s.io | K3S_URL=https://{server_url}:6443 K3S_TOKEN={Token} sh -
  • {server_url}: Serverのホスト名を指定します。家庭ネットワークなどDNSが効かない環境ではServerのIPアドレスを指定します。
  • {Token}: Serverで確認したものを指定します。

サービスの設定ファイル/etc/systemd/system/k3s-agent.serviceは、以下のようになっています。
kemokemo@kemo-node01:~$ sudo cat /etc/systemd/system/k3s-agent.service
[sudo] password for kemokemo: 
[Unit]
Description=Lightweight Kubernetes
Documentation=https://k3s.io
After=network.target

[Service]
Type=exec
EnvironmentFile=/etc/systemd/system/k3s-agent.service.env
ExecStartPre=-/sbin/modprobe br_netfilter
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/k3s agent
KillMode=process
Delegate=yes
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
TimeoutStartSec=0

[Install]
WantedBy=multi-user.target
インストール時に指定したK3S_URLK3S_TOKENなどの環境変数は、/etc/systemd/system/k3s-agent.service.envに保存されてk3s-agent.service起動時に読み込まれます。

メモ

mDNSを使ってkemo-master.localというホスト名で接続したかったのですが、うまくいきませんでした。仕方ないので、静的IPアドレスを使って接続しています。Ubuntu Server 18.04での静的IPアドレスの指定はこちらを参照。

ノードの登録確認

Serverでノードを確認して、以下のように追加されていれば成功です。
kemokemo@kemo-master:~$ kubectl get node
NAME          STATUS   ROLES    AGE    VERSION
kemo-master   Ready    <none>   52m    v1.14.1-k3s.4
kemo-node01   Ready    <none>   3m4s   v1.14.1-k3s.4
もうひとつのノードkemo-node02も同様にして登録しました。確認結果は以下のようになりました。
kemokemo@kemo-master:~$ kubectl get node
NAME          STATUS   ROLES    AGE    VERSION
kemo-master   Ready    <none>   53m    v1.14.1-k3s.4
kemo-node01   Ready    <none>   4m5s   v1.14.1-k3s.4
kemo-node02   Ready    <none>   5s     v1.14.1-k3s.4

クラスター外からアクセスする

クラスター外のホスト名kemo-clientから、今回作ったk3sクラスターに対して操作を実行できるようにして、PodServiceを起動できるようにセットアップしたいと思います。

まずは、公式READMEを確認しましょう。
Copy /etc/rancher/k3s/k3s.yaml on your machine located outside the cluster as ~/.kube/config. Then replace “localhost” with the IP or name of your k3s server. kubectl can now manage your k3s cluster. Accessing cluster from outside
Serverの/etc/rancher/k3s/k3s.yamlを使えば良いようです。何度か試用する程度なら--kubeconfig=k3s.yamlを指定する方法が、継続的に使うクラスターであれば~/.kube/configに設定を追加する方法が良いでしょう。

順にみていきましょう。

Configファイルを準備する

まずは、クラスター外からアクセスするための情報を整理しましょう。

k3s.yamlをコピー

Serverの/etc/rancher/k3s/k3s.yamlを、scpコマンドなどで手元の環境にコピーします。
scp kemokemo@kemo-master.local:/etc/rancher/k3s/k3s.yaml ~/k3s.yaml

設定内容を編集

k3s.yamlserverのURLを、環境に合わせて編集します。
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: {cert_data}
    server: https://{server_url}:6443
  name: {your_cluster_name}
contexts:
- context:
    cluster: {cluster_name}
    user: {user_name}
  name: {context_name}
current-context: {context_name}
kind: Config
preferences: {}
users:
- name: {user_name}
  user:
    password: {password}
    username: admin

name default value description
{cert_data} - 構築したクラスターごとに異なる値が入っています。そのまま使います。
{server_url} localhost Serverのホスト名、DNSが効かない環境ではServerのIPアドレスを指定します。
{cluster_name} default クラスター名を決めて適宜変更します。
{user_name} default クラスターが区別できるようなユーザー名を決めて、適宜変更します。
{context_name} default クラスターが区別できるようなContext名を決めて、適宜変更します。
{password} - 構築したクラスターごとに異なる値が入っています。そのまま使います。

動作確認

上記で編集したk3s.yamlを使って接続できるか確認してみましょう。
kubectl --kubeconfig=k3s.yaml get node
うまくいくと以下のようになります。
kemokemo@kemo-client:~
ʕ◔ϖ◔ʔ >  kubectl --kubeconfig=k3s.yaml get node
NAME          STATUS    ROLES     AGE       VERSION
kemo-master   Ready     <none>    7m        v1.14.1-k3s.4
kemo-node01   Ready     <none>    4m        v1.14.1-k3s.4
kemo-node02   Ready     <none>    3m        v1.14.1-k3s.4

さぁ、みんなで使えるようにしましょう

--kubeconfigを指定する方法

上記の動作確認でも実施したように、以下の方法が手軽に試してもらうのに有効です。
  1. チームメンバーにk3s.yamlを配る
  2. --kubeconfig=k3s.yamlを指定して使ってもらう

~/.kube/configにContextを追加する方法

GKEなど他にも操作対象のクラスターがある場合は、use-contextでクラスターを切り替えて使えるようにするのが良さそうです。Kubernetes公式の Configure Access to Multiple Clusters を参考にしながら設定しましょう。

まずはクラスター情報を設定します。
kubectl config set-cluster {cluster_name} --server=https://{server_url}:6443
certificate-authority-dataを設定します。(こちら参照。)
kubectl config set clusters.{cluster_name}.certificate-authority-data {cert_data}
ユーザー名やパスワードを設定します。
kubectl config set-credentials {user_name} --username=admin --password={password}
最後にContextを設定します。
kubectl config set-context {context_name} --cluster={cluster_name} --namespace=default --user={user_name}
ここまで実行できたら、使うContextを切り替えましょう。
kubectl config use-context {context_name}

ReplicaSetを作成してみる

次は、Podを起動してみましょう。

オライリー本の「入門 Kubernetes」に連動したリポジトリdoublemarket/kuar-examples-1-9の宣言ファイルを使います。これは、原著から使用されているkuardというサービスをPodとして起動します。

まずはダウンロードします。
wget https://github.com/doublemarket/kuar-examples-1-9/raw/master/8-1-kuard-rs.yaml
mv 8-1-kuard-rs.yaml kuard-rs.yaml
上述の方法でContextを追加して切り替え済みの状態で以下を実行します。
kubectl apply -f kuard-rs.yaml
確認してみましょう。
kemokemo@kemo-client:~
ʕ◔ϖ◔ʔ >  kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
kuard-mg85p   1/1     Running   0          4m10s
1つのPodが起動しましたね。ではkuard-rs.yamlをエディタで開いて、replicasを1から3に変更して保存し、再度適用してみましょう。
kemokemo@kemo-client:~
ʕ◔ϖ◔ʔ >  kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
kuard-5wpmh   1/1     Running   0          3s
kuard-8cqxn   1/1     Running   0          3s
kuard-mg85p   1/1     Running   0          10m
うん、3つに増えましたね!

メモ

kubectl applyが以下のようなエラーで失敗する場合、クラスター側と手元のkubectlのバージョンが違っている可能性が高いです。kubectl versionで確認しましょう。
error: SchemaError(io.k8s.api.core.v1.CinderVolumeSource): invalid object doesn't have additional properties

LoadBalancerを起動してブラウザからアクセス可能にする

では最後に、LoadBalancerを起動してPod名kuard内のコンテナで動作しているWebサービスに、クラスター外からアクセスできるようにしてみましょう。
apiVersion: v1
kind: Service
metadata:
  name: my-loadbalancer
spec:
  selector:
    app: kuard
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: LoadBalancer
上記の内容をload-balancer.yamlに保存して適用してみましょう。
kubectl apply -f load-balancer.yaml
確認してみましょう。
kemokemo@kemo-client:~
ʕ◔ϖ◔ʔ >  kubectl get svc
NAME              TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)        AGE
kubernetes        ClusterIP      10.43.0.1       <none>         443/TCP        4d12h
my-loadbalancer   LoadBalancer   10.43.151.181   192.168.3.25   80:31411/TCP   3s
EXTERNAL-IPをブラウザで開いてみましょう。
無事にアクセスできました!

まとめ

k3sを使って、オンプレミスなKubernetesクラスターを作ってみました。クラスター構築自体は簡単で説明も少なくて済んだので、本記事では「クラスター外からのアクセス」に重点をおいて解説する内容にしました(`・ω・´)ゞ
今回作ったKubernetesクラスターを「気軽に使えるスクラッチ環境」として活用したいと思います!ʕ◔ϖ◔ʔ