Cockpit (Linux サーバ管理ツール) で Kubernetes クラスタを管理する方法を検証してみた

こんにちは。サイオステクノロジー 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 をインストールしていない場合、このタブは表示されません。)

001_login

002_cluster_tab

この “クラスター” タブを選択すると以下の様な画面が表示されると思います。(kubeconfig が設定されていれば、自動的に Kubernetes クラスタに接続してくれるようです。)

003_cluster_overview

この “概要” 画面では Kubernetes クラスタ全体のリソースの状態 (CPU/Memory/Network) や、Kubernetes の各リソース (Pod/Volume/Node/Service) 等の概要を参照することが可能です。

“ノード” タブでは各ノード毎の詳細な情報やリソースの情報等を参照することが可能です。

004_node_1

005_node_2

006_node_3

“コンテナー” タブでは各 Pod 内で実行されているコンテナ毎の詳細な情報及びログを参照することや、当該コンテナ内で shell を実行することが可能です。

007_container_1

008_container_2

009_container_3

010_container_4

その他のタブでも、様々な情報を参照したり、ノードやボリュームの追加等の管理操作を Web UI から実施できるようです。

011_node_add

012_volume_add

■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) として用意した上で、”概要” タブの “サービス” 欄にある “デプロイ” ボタンを選択します。

013_deploy_1

“デプロイ” ボタンを押すと、以下の様な画面が表示されます。

014_deploy_2

この画面で “マニフェストの選択…” を選択し、準備しておいた YAML ファイルを選択します。

015_deploy_3

次に “Namespace” 欄のプルダウンからデプロイ先の Namespace (今回は “default”) を選択します。

017_deploy_5

最後に “デプロイ” ボタンを選択すればマニフェストが適用できるはず…

018_deploy_6

だったのですが、以下の様なエラーになってしまいました。

019_deploy_7_error

“マニフェストをデコードできない” というメッセージなので、マニフェスト (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 上からのマニフェストの適用は同じエラーになってしまいました。

019_deploy_7_error

このことから、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 上から参照することができました。

020_after_deploy_1

021_after_deploy_2

■最後に

今回は Linux サーバの管理ツールである Cockpit を使って、Web UI から Kubernetes クラスタを管理する方法を検証してみました。

残念ながら、Web UI 上からマニフェストを適用することはできませんでしたが、Kubernetes クラスタの情報を参照することはできました。

Kubernetes クラスタの管理方法には複数の選択肢があると思いますが、検証用の Kubernetes クラスタのちょっとした管理の様な目的 (クラスタの情報を参照する程度) であれば、yum で簡単にインストールできる cockpit-kubernetes も選択肢の一つになるのではないでしょうか。

もちろん、今後新しいバージョンの Kubernetes にも対応していくと思いますので、今後の動向にも注目したいと思います。

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です