こんにちは。サイオステクノロジー OSS サポート担当 Y です。
今回は Linux サーバの管理ツールである Cockpit を使って、Web UI から Kubernetes クラスタを管理する方法を検証してみました。(※以下の内容は CentOS 7.6/Cockpit 195/kubeadm 1.16.2/NGINX 1.17.5 にて検証しています。)
■はじめに
前回の記事で Cockpit を利用し Web UI から Docker コンテナを操作する方法を検証しましたが、Cockpit では Web UI から Kubernetes クラスタの管理も実施することが可能です。
今回は、Cockpit の Web UI から Kubernetes クラスタを管理する方法を検証してみました。
なお、先に結論を言ってしまうと、今回の検証にて Kubernetes クラスタの情報を参照することはできたのですが、Web UI からの一部操作 (マニフェストの適用) はエラーになってしまいました。
■インストール
まずはインストールです。以前の記事で紹介したインストール方法を参考にしながら Cockpit をインストールします。
また、今回は Kubernetes クラスタの管理に必要な cockpit-kubernetes というパッケージも一緒にインストールします。
上記 cockpit-kubernetes をインストールすると、Kubernetes の CLI ツール (クライアントツール) である kubectl を含むの依存関係のパッケージ “kubernetes-client” が一緒にインストールされます。
[root@cockpit-k8s ~]# yum install -y cockpit cockpit-kubernetes ~(中略)~ ======================================================================================================== Package アーキテクチャー バージョン リポジトリー 容量 ======================================================================================================== インストール中: cockpit x86_64 195.1-1.el7.centos.0.1 extras 48 k cockpit-kubernetes x86_64 195.1-1.el7.centos.0.1 extras 3.8 M 依存性関連でのインストールをします: cockpit-bridge x86_64 195.1-1.el7.centos.0.1 extras 552 k cockpit-system noarch 195.1-1.el7.centos.0.1 extras 1.6 M cockpit-ws x86_64 195.1-1.el7.centos.0.1 extras 806 k kubernetes-client x86_64 1.5.2-0.7.git269f928.el7 extras 14 M トランザクションの要約 ======================================================================================================== ~(中略)~ インストール: cockpit.x86_64 0:195.1-1.el7.centos.0.1 cockpit-kubernetes.x86_64 0:195.1-1.el7.centos.0.1 依存性関連をインストールしました: cockpit-bridge.x86_64 0:195.1-1.el7.centos.0.1 cockpit-system.noarch 0:195.1-1.el7.centos.0.1 cockpit-ws.x86_64 0:195.1-1.el7.centos.0.1 kubernetes-client.x86_64 0:1.5.2-0.7.git269f928.el7 完了しました! [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# systemctl enable --now cockpit.socket Created symlink from /etc/systemd/system/sockets.target.wants/cockpit.socket to /usr/lib/systemd/system/cockpit.socket. [root@cockpit-k8s ~]#
また、Web UI にアクセス可能にするために Firewalld で Cockpit の通信を許可する設定を実施します。
[root@cockpit-k8s ~]# firewall-cmd --permanent --zone=public --add-service=cockpit success [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# firewall-cmd --reload success [root@cockpit-k8s ~]#
以上でインストール作業は完了です。
■kubeconfig を設定
今回は kubeadm を利用して作成した Kubernetes クラスタを管理するため、当該クラスタに接続するための kubeconfig の情報を取得します。
※kubeadm を利用した Kubernetes クラスタの構築方法については、Cockpit の話からそれてしまうため割愛致します。基本には公式ドキュメント Installing kubeadm 及び Creating a single control-plane cluster with kubeadm を参照しながら構築しています。
kubeadm を利用して作成した Kubernetes クラスタの場合は、当該クラスタへの接続用の kubeconfig が kubeadm init を実行したノード (Master) 上に “/etc/kubernetes/admin.conf” として作成されているので、当該ファイルを Cockpit サーバ上の $HOME/.kube/config ファイルとして保存します。(※今回は root ユーザで Cockpit にログインするため、root ユーザの $HOME 配下に kubeconfig を設定しています。一般ユーザで Cockpit にログインする場合、当該ユーザの $HOME 配下に .kube/config を作成する必要があります。)
[root@cockpit-k8s ~]# mkdir -p $HOME/.kube [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# rsync -av k8s-master.example.com:/etc/kubernetes/admin.conf $HOME/.kube/config root@k8s-master.example.com's password: receiving incremental file list admin.conf sent 43 bytes received 5,546 bytes 2,235.60 bytes/sec total size is 5,450 speedup is 0.98 [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# ls -l $HOME/.kube/config -rw-------. 1 root root 5450 10月 24 12:27 /root/.kube/config [root@cockpit-k8s ~]#
念のため、この状態で kubectl コマンドを利用してリモートにある Kubernetes クラスタにアクセス可能であるか (kubeconfig を読み込むことができているか) を確認します。
[root@cockpit-k8s ~]# kubectl get node NAME STATUS AGE k8s-master.example.com Ready 1h k8s-node-1.example.com Ready 1h k8s-node-2.example.com Ready 1h [root@cockpit-k8s ~]#
上記の通り、Kubernetes クラスタの情報 (クラスタ内のノード情報) が取得できているので、kubeconfig の設定は問題無さそうです。
■Web UI への接続
インストール及び kubeconfig 設定後、Web UI (https://ip-address-of-machine:9090) にアクセスし root ユーザ (kubeconfig を設定したユーザ) でログインすると、画面左から “クラスター” というタブが選択できます。(cockpit-kubernetes をインストールしていない場合、このタブは表示されません。)
この “クラスター” タブを選択すると以下の様な画面が表示されると思います。(kubeconfig が設定されていれば、自動的に Kubernetes クラスタに接続してくれるようです。)
この “概要” 画面では Kubernetes クラスタ全体のリソースの状態 (CPU/Memory/Network) や、Kubernetes の各リソース (Pod/Volume/Node/Service) 等の概要を参照することが可能です。
“ノード” タブでは各ノード毎の詳細な情報やリソースの情報等を参照することが可能です。
“コンテナー” タブでは各 Pod 内で実行されているコンテナ毎の詳細な情報及びログを参照することや、当該コンテナ内で shell を実行することが可能です。
その他のタブでも、様々な情報を参照したり、ノードやボリュームの追加等の管理操作を Web UI から実施できるようです。
■Web UI 上からマニフェストを適用
前述した通り、Cockpit の Web UI では Kubernetes クラスタに関する様々な情報の参照や管理操作が実施できるようですが、今回は Web UI 上でのマニフェストの適用方法を検証してみます。
なお、結論から言ってしまうと、Web UI 上でのマニフェストの適用には失敗してしまいました。明確な原因は特定できておらずあくまで推測なのですが、Cockpit (cockpit-kubernetes) に含まれている Kubernetes 関連のパッケージ (ライブラリ?) のバージョンが古いもの (v1.5.2) であることが原因である可能性がありそうです。
今回は、以下の様なマニフェスト (YAML ファイル) を作成し、Web UI 上から適用します。
apiVersion: v1 kind: Service metadata: name: nginx-pod-service labels: app: nginx-pod spec: selector: app: nginx-pod type: NodePort ports: - protocol: TCP port: 80 targetPort: 80 nodePort: 30080 --- apiVersion: v1 kind: Pod metadata: name: nginx-pod labels: app: nginx-pod spec: containers: - name: nginx-container image: nginx:1.17.5 ports: - containerPort: 80
予め前述したマニフェストを YAML ファイル (.yaml) として用意した上で、”概要” タブの “サービス” 欄にある “デプロイ” ボタンを選択します。
“デプロイ” ボタンを押すと、以下の様な画面が表示されます。
この画面で “マニフェストの選択…” を選択し、準備しておいた YAML ファイルを選択します。
次に “Namespace” 欄のプルダウンからデプロイ先の Namespace (今回は “default”) を選択します。
最後に “デプロイ” ボタンを選択すればマニフェストが適用できるはず…
だったのですが、以下の様なエラーになってしまいました。
“マニフェストをデコードできない” というメッセージなので、マニフェスト (YAML ファイル) 側に何かしらの問題がある可能性がありそうです。
実は、このマニフェストについては事前に Kubernetes クラスタ (サーバ) 側で適用可否を確認しており、その時は問題無く適用できていました。
そのため、正直なところ何が問題なのか分からなかったのですが、試しに SSH でサーバにログインし CLI (kubectl コマンド) を利用して当該マニフェストの適用を試行したところ、以下の様なエラーが出力されました。
[root@cockpit-k8s ~]# kubectl apply -f nginx-pod.yaml error: error validating "nginx-pod.yaml": error validating data: the server could not find the requested resource; if you choose to ignore these errors, turn validation off with --validate=false
どうやら、Cockpit をインストールしたサーバ上からこのマニフェストを適用する場合には、何かしらの問題が発生しているようです。
原因が不明ですが、とりあえずエラーメッセージに記載されている “–validate=false” オプションを付けて再度実行してみたところ、マニフェストの適用は実施できたようです。
[root@cockpit-k8s ~]# kubectl apply -f nginx-pod.yaml --validate=false service "nginx-pod-service" created pod "nginx-pod" created [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# kubectl get pod NAME READY STATUS RESTARTS AGE nginx-pod 1/1 Running 0 1m [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# kubectl get svc NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes 172.30.0.1 443/TCP 15d nginx-pod-service 172.30.161.195 80:30080/TCP 1m
作成した Service (30080 port で LISTEN している) に対して HTTP リクエストを実行すると、NGINX Pod (コンテナ) からも正常に応答がありました。
[root@cockpit-k8s ~]# curl -IXGET https://k8s-master.example.com:30080/ HTTP/1.1 200 OK Server: nginx/1.17.5 Date: Fri, 08 Nov 2019 04:52:55 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Tue, 22 Oct 2019 14:30:00 GMT Connection: keep-alive ETag: "5daf1268-264" Accept-Ranges: bytes [root@cockpit-k8s ~]#
そのため、マニフェストの内容自体に問題は無いようにも思えるのですが、Web UI からだと “–validate=false” を指定できない (“–validate=false” に相当するボタン等が見当たらない) ので、やはり Web UI からではこのマニフェストを適用できません。
そこで、もう少し調べてみたところ、kubectl のバージョンが古いことが確認できました。
[root@cockpit-k8s ~]# kubectl version Client Version: version.Info{Major:"1", Minor:"5", GitVersion:"v1.5.2", GitCommit:"269f928217957e7126dc87e6adfa82242bfe5b1e", GitTreeState:"clean", BuildDate:"2017-07-03T15:31:10Z", GoVersion:"go1.7.4", Compiler:"gc", Platform:"linux/amd64"} Server Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.2", GitCommit:"c97fe5036ef3df2967d086711e6c0c405941e14b", GitTreeState:"clean", BuildDate:"2019-10-15T19:09:08Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"}
上記の通り、Kubernetes クラスタ (サーバ側) が v1.16.2 であるのに対して、kubectl (クライアント側) が v1.5.2 になっています。
そこで、試しにサーバ側と同じバージョン (v1.16.2) の kubectl を使って先程のマニフェストを適用してみました。
今回の検証の場合、kubeadm で構築した Kubernetes クラスタ (サーバ側) に、サーバ側と同じバージョンの kubectl がインストールされているので、そこから v1.16.2 の kubectl コマンドを持ってきます。
[root@cockpit-k8s ~]# rsync -av k8s-master.example.com:/usr/bin/kubectl /usr/local/bin/kubectl_v1.16.2 root@k8s-master.example.com's password: receiving incremental file list sent 20 bytes received 41 bytes 24.40 bytes/sec total size is 46,682,408 speedup is 765,285.38 [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# ls -l /usr/local/bin/kubectl_v1.16.2 -rwxr-xr-x. 1 root root 46682408 10月 16 08:42 /usr/local/bin/kubectl_v1.16.2 [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# kubectl_v1.16.2 version Client Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.2", GitCommit:"c97fe5036ef3df2967d086711e6c0c405941e14b", GitTreeState:"clean", BuildDate:"2019-10-15T19:18:23Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"} Server Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.2", GitCommit:"c97fe5036ef3df2967d086711e6c0c405941e14b", GitTreeState:"clean", BuildDate:"2019-10-15T19:09:08Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"} [root@cockpit-k8s ~]#
先にデプロイしていた各リソース (Service 及び Pod) を削除した上で、v1.16.2 の kubectl を使って、再度マニフェストを適用してみます。
[root@cockpit-k8s ~]# kubectl delete -f nginx-pod.yaml service "nginx-pod-service" deleted pod "nginx-pod" deleted [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# kubectl get pod No resources found. [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# kubectl get svc NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes 172.30.0.1 443/TCP 15d [root@cockpit-k8s ~]#
[root@cockpit-k8s ~]# kubectl_v1.16.2 apply -f nginx-pod.yaml service/nginx-pod-service created pod/nginx-pod created [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# kubectl get pod NAME READY STATUS RESTARTS AGE nginx-pod 1/1 Running 0 2m [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# kubectl get svc NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes 172.30.0.1 443/TCP 15d nginx-pod-service 172.30.220.146 80:30080/TCP 2m [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# curl -IXGET https://k8s-master.example.com:30080/ HTTP/1.1 200 OK Server: nginx/1.17.5 Date: Fri, 08 Nov 2019 05:09:21 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Tue, 22 Oct 2019 14:30:00 GMT Connection: keep-alive ETag: "5daf1268-264" Accept-Ranges: bytes [root@cockpit-k8s ~]#
すると今度は、”–validate=false” を指定していなくてもエラーにならず、マニフェストを適用することができました。
原因を完全に特定できた訳では無いのですが、上記の通りクライアント側 (kubectl) のバージョンが古いことが問題だったようです。
仮に、Web UI 側の処理が裏で kubectl コマンドを利用しているのであれば、その kubectl コマンドのバージョンを新しいものに変更することで、Web UI からもマニフェストを適用できるようになるかもしれません。
そこで、元々インストールされている v1.5.2 の kubectl コマンド (cockpit-kubernetes の依存パッケージである kubernetes-client パッケージに含まれている /usr/bin/kubectl) を v1.16.2 の kubectl に置き換えてみました。
[root@cockpit-k8s ~]# cp -p /usr/bin/kubectl /usr/local/bin/kubectl_v1.5.2 [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# ls -l /usr/local/bin/kubectl* -rwxr-xr-x. 1 root root 46682408 10月 16 08:42 /usr/local/bin/kubectl_v1.16.2 -rwxr-xr-x. 1 root root 81689616 7月 4 2017 /usr/local/bin/kubectl_v1.5.2 [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# cp -p /usr/local/bin/kubectl_v1.16.2 /usr/bin/kubectl cp: `/usr/bin/kubectl' を上書きしますか? y [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# ls -l /usr/bin/kubectl -rwxr-xr-x. 2 root root 46682408 10月 16 08:42 /usr/bin/kubectl [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# kubectl version Client Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.2", GitCommit:"c97fe5036ef3df2967d086711e6c0c405941e14b", GitTreeState:"clean", BuildDate:"2019-10-15T19:18:23Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"} Server Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.2", GitCommit:"c97fe5036ef3df2967d086711e6c0c405941e14b", GitTreeState:"clean", BuildDate:"2019-10-15T19:09:08Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"} [root@cockpit-k8s ~]# [root@cockpit-k8s ~]# systemctl restart cockpit.socket [root@cockpit-k8s ~]#
しかし、Web UI 上からのマニフェストの適用は同じエラーになってしまいました。
このことから、Web UI 上のデプロイボタンは「裏で kubectl コマンドを実行している」という訳では無く、別途何等かの形で Kubernetes クラスタ (kube-apiserver) にリクエストを実行している状況だと思われます。
その場合、(完全に推測ですが) cockpit-kubernetes 関連のパッケージ内で利用されている Kubernetes 関連の機能 (ライブラリ?) のバージョンが古く (恐らく v1.5.2)、それが原因で Web UI 上からマニフェストを適用できないという可能性があると考えられます。しかし、kubectl コマンドと違ってそれらを簡単に新しいバージョンに置き換えることは難しそうです。
ということで、今回の検証では Web UI からマニフェストを適用することはできませんでした。(検証できていないのですが、もしかすると Kubernetes クラスタ (サーバ側) のバージョンが v1.5.2 であれば、Web UI からのマニフェスト適用が実施できるかもしれません。)
しかし、CLI (kubectl コマンド) で適用したマニフェスト (デプロイした Pod や Service) の情報は、Web UI 上から参照することができました。
■最後に
今回は Linux サーバの管理ツールである Cockpit を使って、Web UI から Kubernetes クラスタを管理する方法を検証してみました。
残念ながら、Web UI 上からマニフェストを適用することはできませんでしたが、Kubernetes クラスタの情報を参照することはできました。
Kubernetes クラスタの管理方法には複数の選択肢があると思いますが、検証用の Kubernetes クラスタのちょっとした管理の様な目的 (クラスタの情報を参照する程度) であれば、yum で簡単にインストールできる cockpit-kubernetes も選択肢の一つになるのではないでしょうか。
もちろん、今後新しいバージョンの Kubernetes にも対応していくと思いますので、今後の動向にも注目したいと思います。