k3s とは軽量 Kubernetes です。しばしばメモリ消費量が少ない、バイナリが小さいなど軽量であることに注目されますが、シンプルで簡単に Kubernetes の機能を使い始められ、学習にも向いたツールです。
今回は k3s で Kubernetes クラスターを構築します。そのうえで、適当な Web アプリケーションをクラスターにデプロイし、インターネットからアクセスできるようにすることを目標とします。
私は Kubernetes 初心者なので、k3s を使って Kubernetes を学習していきたいと思います。
せっかくなので、node は 2 つにします。k3s だとそのような構成も簡単にできます。
また、各 node 間の通信は VPN で暗号化します。これも k3s だと簡単です。
バージョン情報など
$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.2 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.2 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
$ k3s --version
k3s version v1.27.3+k3s1 (fe9604ca)
go version go1.20.5
$ sudo k3s kubectl version --short
Flag --short has been deprecated, and will be removed in the future. The --short output will become the default.
Client Version: v1.27.3+k3s1
Kustomize Version: v5.0.1
Server Version: v1.27.3+k3s1
本記事の内容に影響しないはずですが、動作確認は AWS EC2 の t3.medium インスタンスで行いました。2vCPU でメモリは 4GB です。このスペックで十分動作しました。これより小さいサーバーでも大丈夫だと思います。
なお、AWS EC2 は簡単にサーバーが作成できるから利用しただけで AWS であることは本記事の内容には関係ないはずです。
前提
最低限のスペック
k3s は軽量ですが、いくつかの最低要件があります。
詳細はRequirementsに記載されていますが、下記は特に注意と思われます。
Spec | Minimum | Recommended |
---|---|---|
CPU | 1 core | 2 cores |
RAM | 512 MB | 1 GB |
ポートを開ける
Protocol | Port | Source | Destination | Description |
---|---|---|---|---|
TCP | 2379-2380 | Servers | Servers | Required only for HA with embedded etcd |
TCP | 6443 | Agents | Servers | K3s supervisor and Kubernetes API Server |
UDP | 8472 | All nodes | All nodes | Required only for Flannel VXLAN |
TCP | 10250 | All nodes | All nodes | Kubelet metrics |
UDP | 51820 | All nodes | All nodes | Required only for Flannel Wireguard with IPv4 |
UDP | 51821 | All nodes | All nodes | Required only for Flannel Wireguard with IPv6 |
クラスターを作成
WireGuard の準備
k3s のドキュメント(Network Options)によると
The default backend for Flannel is vxlan. To enable encryption, use the wireguard-native backend.
とあります。というわけで、コンテナ間通信を暗号化するために、WireGuard を使います。
上記のドキュメントからリンクのあるWireGuard Install Guideに従い、その準備をします。と言っても ubuntu だと apt でインストールするだけです。
sudo apt install wireguard
クラスターの立ち上げ
k3s のドキュメント(Quick-Start Guide)に従い、クラスターを作成します。
今回は次のようなコマンドをクラスターを立ち上げたいサーバー内で実行しました。
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server" sh -s - --flannel-backend wireguard-native
クラスターを立ち上げる最小のコマンドは次のとおりです。
curl -sfL https://get.k3s.io | sh -
これにいくつかのオプションを追加しています。
INSTALL_K3S_EXEC
は k3s のインストール時につけるフラグを指定します。今回は server
を指定しています。server
、agent
は k3s 用語らしいです。server
はKubernetes のコントロールプレーンが動いているノードでagent
はコントロールプレーンがないノードのことです。(参考:Architecture)
INSTALL_K3S_EXEC
にserver
を指定することで、server
としてノードを立ち上げています。(なお、指定しなくてもデフォルトで server として立ち上がるようではあります)
--flannel-backend wireguard-native
は Flannel のバックエンドに WireGuard を使うように指定しています。これで Kubernetes のネットワークが暗号化されます。
続けて、もう一つのサーバーにagent
を立ち上げます。
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="agent --server https://xxx:6443 --token yyy" sh -s -
今回もINSTALL_K3S_EXEC
でオプションを指定しています。
agent
を含めることで、agent
としてノードを立ち上げています。
さらにagent
はserver
に接続するために--server
と--token
を指定しています。
--server
はserver
のアドレスを指定します。
--token
はserver
に接続するためのトークンを指定します。--token
に指定する値はserver
ノードの/var/lib/rancher/k3s/server/node-token
に書かれています。
オプションの指定の仕方はいろいろあるので、下記も参照してください。
動作確認
server
ノードで次のコマンドを実行してみます。
$ sudo k3s kubectl get node
すると、agent
ノードも含めて 2 つのノードが表示されるはずです。
ローカルから kubectl コマンドを実行する
k3s は kubeconfig ファイルを/etc/rancher/k3s/k3s.yaml
に作成しているのでこれをローカルにコピーしてきます。
kubectl コマンドが利用する kubeconfig ファイルの指定方法はいくつかありますが、例えばKUBECONFIG
環境変数に指定します。
なお、Unable to connect to the server: x509: certificate is valid for
というエラーが出る場合は、--insecure-skip-tls-verify
オプションをつけます。証明書の確認をスキップしますが、今回は実運用するわけではなく、学習目的なので、一旦このオプションで解決しても良いと思います。
$ export KUBECONFIG=k3s.yaml
$ kubectl get node --insecure-skip-tls-verify
ノードが 2 つ表示されるはずです。
これでローカルからクラスターを操作できるようになりました。
namespace の作成
アプリケーションをデプロイするための Namespace を作成します。
まず、kubectl get namespace
で既存の Namespace を確認します。
$ kubectl get namespace
NAME STATUS AGE
kube-system Active 9m13s
default Active 9m13s
kube-public Active 9m13s
kube-node-lease Active 9m13s
のようにkube
ではじまる kube システム用の Namespace やdefault
が見つかるはずです。
ここに Namespace を追加します。
kubectl create namespace
コマンドで作成することもできますが、ここでは YAML ファイルを作成してkubectl apply
コマンドで作成します。次のような YAML ファイルを作成します。
apiVersion: v1
kind: Namespace
metadata:
name: app
labels:
name: app
そして、kubectl apply
コマンドで YAML ファイルを Kubernetes に適用します。
$ # (namespace.yamlに上記のYAMLファイルを保存しているとして、)
$ kubectl apply -f namespace.yaml
kubectl get namespace
を再度実行することで、app
が追加されていることがわかります。
deployment の作成
次に deployment を作成します。
再度 YAML ファイルを作成します。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: sample-app
name: sample-app
namespace: app
spec:
replicas: 2
selector:
matchLabels:
app: sample-app
template:
metadata:
labels:
app: sample-app
spec:
containers:
- image: containous/whoami:v1.5.0
name: whoami
ここではwhoamiという動作確認用のイメージを使います。
kubectl apply
コマンドで YAML ファイルを Kubernetes に適用します。
$ # (deployment.yamlに上記のYAMLファイルを保存しているとして、)
$ kubectl apply -f deployment.yaml
Kubernetes で deployment を作成すると Pod と ReplicaSet が作成されます。次のコマンドで確認できます。
$ kubectl get pod -n app
$ kubectl get rs -n app
-n
は Namespace を指定しています。
service の作成
次に service を作成します。
service とは Pod に関するネットワーク関連の設定です。
service の設定は次のような YAML ファイルで行います。
apiVersion: v1
kind: Service
metadata:
labels:
app: sample-app
name: sample-app
namespace: app
spec:
ports:
- name: "whoami"
port: 18080
protocol: TCP
targetPort: 80
selector:
app: sample-app
type: ClusterIP
次のコマンドで service を作成します。
$ # (service.yamlに上記のYAMLファイルを保存しているとして、)
$ kubectl apply -f service.yaml
service が作成されたことは
$ kubectl get svc -n app
で確認できます。
なお、type: ClusterIP
なので、service はクラスター内からしかアクセスできません。現時点でサーバーに curl などでアクセスしようとしてもできないはずです。
port
は何でも良いはずですが、traefik が 80 番ポートを使っているので、targetPort
は 80 以外の適当な値にしています。
現時点ではサーバー内外から curl などでアクセスしようとしてもできません。
ingress の作成
最後に ingress を作成します。
ingress の設定は次のような YAML ファイルで行います。
ingress とは、クラスター外からのクラスター内の service に対するアクセスを管理するものです。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: sample-ingress
namespace: app
spec:
rules:
- http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: sample-app
port:
number: 18080
path
は/api
としています。
whoami コンテナは/
にアクセスすると text で結果を返します。一方で、/api
にアクセスすると JSON で結果を返します。
今回は練習のために/
ではアクセスできず、/api
にアクセスする必要があるように設定してみます。
これで ingress が「Service に対する外部からのアクセス(主に HTTP)を管理」していることが確認できるのではないかと思います。
これを次のコマンドで適用します。
$ # (ingress.yamlに上記のYAMLファイルを保存しているとして、)
$ kubectl apply -f ingress.yaml
ingress が作成されたことは
$ kubectl get ingress -n app
で確認できます。
ingress の確認
ingress が作成されると、traefik が自動的に ingress を認識してルーティングを行います。
traefik は k3s に同梱された k3s とは別の OSS です。
curl でリクエストを送信して動作確認してみます。
もしSSL certificate problem
などと証明書関連のエラーが発生すれば一旦-k
オプションを付けて無視します。
どの node にリクエストを送信しても whoami コンテナのレスポンスを取得できます。whoami コンテナはコンテナがあるサーバーの IP アドレスなども返してくれるので動作確認で便利です。
また、今回は ingress に/api
と指定しているので、/
にアクセスしてもレスポンスを取得できないことも確認できます。
$ curl -k https://aaa.bbb.ccc.ddd/api
これで k3s でアプリをデプロイし、外部からアクセスできるように設定できました。
参考
k3s のドキュメント
k3s 日本語ドキュメント