Nginxが展開できない

解いた人:とり

参照した問題・解説のサイト:Nginxが展開できない

使用環境・ツール

  • Kubernetes
  • Nginx
  • Rook (解説に書いてあった)

Rookとは

kubernetes用のストレージオペレータ。ストレージをストレージソフトウェアを自己管理、自己スケーリング、および自己修復のストレージサービスに変えます。(公式ドキュメントから) なんとなくだけど、ストレージにPodの要素を加えることで、k8sの便利機能(スケーリングや修復)を扱えるようにしたサービスなのではないかと思った。(これはあくまで私の意見)

前提条件

  • /home/user/manifestにあるファイルの内容を変更してはいけない

問題文でされた操作

  • KubernetesのNginx用のマニフェストファイルをApplyした
VM名ホスト名
kzz-k8s-master192.168.12.1
kzz-k8s-node1192.168.12.2
kzz-k8s-node1192.168.12.3
kzz-k8s-node1192.168.12.4

バグの内容

  • NginxのDeploymentがPendingになっている

理想の終了状態

  • pendingとなっていたDeploymentが正常に稼働している。
  • 正常化したDeploymentによって稼働するNginxで、解答するチームの名前が書かれたWebサイトが確認できるようになっている。
  • 開始時と同じマニフェストのみが適用されている。

考えられる検証、修正手順

バグの原因を特定する案

  • ログがあるならログ的なのを確認する → k8s側では特になかった
    • 公式ドキュメントにデバッグ方法があった URL
  • deploymentやserviceのファイルを読んでみる
    • TCP80ポートが接続できる設定になっていない可能性もあると考えたが、その場合はrunning状態で外部IPに接続した時に画面が表示されないという現象が見られるはずなので今回のケースでは除外した。
  • Googleで「nginx Pending k8s」と検索してみた

→ k8sの問題だしこの辺りがあり得そう。今回はこの場合だと考えて答えを作っていく。

修正手順案詳細

デバッグを頑張る
※ ここではhostnamesがnamespaceの名前

  • サービスの存在確認
$ kubectl get svc hostnames
  • サービスはDNS名によって機能しているか
$ nslookup hostnames

Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      hostnames
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local

> これが失敗した場合、おそらくPodとServiceが異なるNamespaceにあるため、ネームスペースで修飾された名前を試す

DNSについて色々試す。

$ nslookup hostnames.default
> クロスネームスペース名を使用するようにアプリケーションを調整するか、同じNamespaceでアプリとServiceを実行する必要がある

$ nslookup hostnames.default.svc.cluster.local

$ nslookup hostnames.default.svc.cluster.local 10.0.0.10
> 完全修飾名では検索できるのに、相対名ではできない場合、Podの/etc/resolv.confファイルが正しいことを確認する必要があります。Pod内から実行します

いっぱいあって全部キャッチアップするのは無理な気がした。

リソースが不十分な場合

  • クラスターにノードを追加する
    • マニフェストをいじらなくてはいけないのかと思ったけど、kubeadmというコマンドを使うと実行中のk8sに対して追加できるらしい

ノードの追加

kubeadm join --token <token> <control-plane-host>:<control-plane-port> --discovery-token-ca-cert-hash sha256:<hash>

トークン一覧を見てみる

kubeadm token list

トークンは一時的なので、トークンの発行もできる。24hできれる

kubeadm token create
  • 不要なPodを削除する
    • これは問題的にできるのかな🤔 可能性としては低そう
  • Podがノードよりも大きくないことを確認する
    • cpu: 1の場合、cpu: 1.1を要求するPodは決してスケジュールされない
    • キャパシティを調べるコマンド
    kubectl get nodes -o yaml | egrep '\sname:|cpu:|memory:'
    kubectl get nodes -o json | jq '.items[] | {name: .metadata.name, cap: .status.capacity}'
    

hostPortの使用

  • PodをhostPortにバインドすると、Podをスケジュールできる場所の数が制限される
    • この辺りも微妙。おそらくこんな感じで設定するのだと考えられるが、これってマニフェストファイルをいじらないとダメな気がする🤔
    ports:
       - name: liveness-port
       containerPort: 8080
       hostPort: 8080
    

解説

めちゃ調べたんだけど全然違った!😭 むずい。

原因

Rookを削除する際にコンフィグ情報やログデータなどが保存されているdataDirHostPathを削除しなかったこと。

原因究明方法

/home/user/manifestには、Flannel 、MetalLB、Rook、NginxのDeploymentが書かれたtest-nginx.yamlなどのマニフェストが保存されています。test-nginx.yamlはPVC 、そのPVCを/usr/share/nginx/htmlにマウントするNginx のDeployment 及び、Nginx を公開するためのLoadBalancer Serviceを定義します。

ここで、なんのサービスを使っているのかを確認する。PVCはPersistentVolumeClaimの略でユーザーによって要求されるストレージのことらしい。(詳細)。ちなみにFlannelはネットワーキングをいい感じにするやつ。MetalLBはベアメタル用のロードバランサー。ベアメタルってなんだよと思って調べたら「OSやソフトウェアなどがインストールされていないまっさらなハードディスク(物理サーバー)」のことらしいです。ベアメタル覚えた!

問題環境では、問題名にあるNginx だけでなくPVC もPendingとなっています。 PendingになっているPVCをkubectl describe pvc cephfs-pvc で確認すると、failed to provision volume with StorageClassとエラーが出ています。

問題文だけでは知らんがな問題。kubectl describe pvc cephfs-pvc でpvcの状態をみれるのは覚えておいた方がいいかも。基本的にはkubectl describe <サービス> <namespace>でいけるのではないかと。覚えとけば、ぐぐりで乗り越えられそう・

このKubernetesクラスタではRookを利用し、CephをPersistent Volumeとして使っています。このことから、Rookの設定の異常等を予想し、Rookのエラーを確認する必要があります。そのため、/home/user/manifestにあるRookのマニフェスト(cluster.yaml)では、無効化されているcrash-collectorを有効化し適用します。立ち上がったcrash-collectorをkubectl describe で確認すると、Unable to attach or mount volumesとなっています。

ここでcrash-collectorを有効化し適用とあるが、crash-collector知らないとできない気がするな〜〜。無効化することができるのかは微妙。無効以外できたら60%くらいの点は入りそう。

Rookがマウントしてそうな場所を探すと、 cluster.yamlの33行目にdataDirHostPath: /var/lib/rookなる行があります。 そして、この直前の31行目のコメントに、 Important: if you reinstall the cluster, make sure you delete this directory from each host or else the mons will fail to start on the new cluster. と書かれています。

日本語に訳すと「クラスタを再インストールする場合は、各ホストからこのディレクトリを削除してください。そうしないと、新しいクラスタでのmonsの起動に失敗します。」みたいです。

解決手順

解決方法としては、RookのDocumentに書かれた通りにクラスターの清掃を行うだけ。

  • 適用されているRookを削除(ここでは6つのyamlに対してkubectl delete -f hoge.yamlをしている)
  • 該当するディレクトリ(/var/lib/rook)を削除
  • crash-collectorを無効化
    • crashモジュールが提供する機能をRookから使う用のコントローラーらしい
    • 無効にするのに設定がいるのかどうなのかよくわからなかった。
    • https://zenn.dev/satoru_takeuchi/articles/33560b2e753972
  • kubectl apply -f hoge.yamlをする
  • kubectl exec -it ”Pod名” -- bashでpodの中に入る
  • その中のShellで、 echo -e "<a>”チーム名”</a>" > /usr/share/nginx/html/index.htmlをする

便利そうなツールのメモ