おうちk8sのクラスタアップグレードをしたら少しハマった話
Kubernetes 1.18がリリースされたのでおうちk8sに対してもアップグレードを行いました
その際にいくつかハマったので書き起こしておきます
きっかけ
3/26にオンライン配信で開催された Kubernetes Meetup Tokyo #29 Cluster Upgrade 編 にて、
「kubeadmでのクラスタアップグレード:その光と闇」
という発表がありました
おうちk8sもkubeadmで構築していて、この発表を聞いてちょうどいい機会なので自分もアップグレードしてみようと思ったのがきっかけです
発表資料内に
- トラブルシューティングも充実してきた→裏を返せばそれだけトラブる
- 壊れることを前提としたほうがいいかもしれない
との記述がありましたが、うまくいくでしょ、というのとちょっと怖いけどお遊び用クラスタだしいっか、という気持ちでやってみることにしました
クラスタアップグレード
アップグレード自体の手順はkubernetes.ioにある こちら の内容を実施するだけです
補足
1.17.2 -> 1.18.0へのアップグレードで、構成はmaster×1、worker×2です
ハマったとこ
1つめ
masterノードで kubeadm upgrade apply v1.18.0
を実行したところ、途中で以下のようなエラーが連続して出るようになりました
[apiclient] Error getting Pods with label selector "k8s-app=upgrade-prepull-kube-controller-manager" [Get https://172.22.0.151:6443/api/v1/namespaces/kube-sys tem/pods?labelSelector=k8s-app%3Dupgrade-prepull-kube-controller-manager: net/http: request canceled (Client.Timeout exceeded while awaiting headers)] [apiclient] Error getting Pods with label selector "k8s-app=upgrade-prepull-kube-scheduler" [Get https://172.22.0.151:6443/api/v1/namespaces/kube-system/pods? labelSelector=k8s-app%3Dupgrade-prepull-kube-scheduler: net/http: request canceled (Client.Timeout exceeded while awaiting headers)] [apiclient] Error getting Pods with label selector "k8s-app=upgrade-prepull-etcd" [Get https://172.22.0.151:6443/api/v1/namespaces/kube-system/pods?labelSelec tor=k8s-app%3Dupgrade-prepull-etcd: net/http: request canceled (Client.Timeout exceeded while awaiting headers)] [apiclient] Error getting Pods with label selector "k8s-app=upgrade-prepull-kube-apiserver" [Get https://172.22.0.151:6443/api/v1/namespaces/kube-system/pods? labelSelector=k8s-app%3Dupgrade-prepull-kube-apiserver: net/http: request canceled (Client.Timeout exceeded while awaiting headers)] I0405 19:59:28.079111 18090 request.go:621] Throttling request took 1.290517695s, request: GET:https://172.22.0.151:6443/api/v1/namespaces/kube-system/pods? labelSelector=k8s-app%3Dupgrade-prepull-etcd
しかもそこで一旦止めたところ、サーバかかなり重たくなりsshするのも数分かかるように 😞
仕方なくリブートして再度実行したら何故かうまくいきました
2つめ
workerノードの1台で
apt-mark unhold kubelet kubectl && apt-get update && apt-get install -y kubelet=1.18.0-00 kubectl=1.18.0-00 && apt-mark hold kubelet kubectl
を実行後にkubeletの再起動を行ったところうまく立ち上がらず 🤔
あまり原因調査をしないまま、最初から設定やり直そうとし、kubeadm resetしました(ちゃんと調べて対応すればよかったかも)
その後のjoinする際に kubeadm token create --print-join-command
で発行されたコマンドを実施したら以下のエラーが
error execution phase kubelet-start: cannot get Node "raspberrypi-node02": nodes "raspberrypi-node02" is forbidden: User "system:bootstrap:aagt70" cannot get resource "nodes" in API group "" at the cluster scope To see the stack trace of this error execute with --v=5 or higher
調べてみるとkubernetes1.18.0のバグ?で、kubeadm token create
で発行されたtokenだとうまく動かないみたいです
代わりに kubeadm init phase bootstrap-token
で発行されたtokenでjoinがうまく動きました
これでなんとか1.17.2 -> 1.18.0へのアップグレードは成功しました(もう1台のworker nodeは問題なくアップグレードできた 🤔)
まとめ
発表にある通り、kubeadmでのクラスタアップグレードの闇を感じたけどいい経験になった
iTerm2で拡大しようとしたときに"About Shell Integration"のポップアップが出る問題への対処法
MacのiTerm2で「Shift + ⌘ + ;」(Shift + "+")で拡大しようとしたときに "About Shell Integration" のポップアップが出て拡大できない問題への対処法
環境
macOS Mojave バージョン 10.14.6
iTerm2 Build 3.3.9
対応
ショートカットキーを追加する
Preferences... (⌘ + ,) -> Keys -> Key Bindings から「+」で新規ショートカットキーを追加
Keyboards Shortcut | Shift ⌘ + |
Action | Select Menu Item... -> Make Text Bigger |
以上、おわり 🤓
k8sでConfigMap/Secretsの更新時に環境変数へ反映するデプロイフローについて
はじめに
k8sの CofnigMap/Secrets を環境変数に設定し、アプリケーション(Deployment)から利用するパターンはよくあると思います
デプロイ時にDeployment、CofnigMap/Secretsをまとめてデプロイすると思いますが、CofnigMap/Secrets のみの更新時にはDeploymentに自動で反映されません
これはアプリケーションが起動時に CofnigMap/Secrets の値を環境変数に設定するため、起動後に CofnigMap/Secrets が更新されても反映されないためです
アプリケーションにも環境変数の更新を反映をさせたい場合は、Deployment と CofnigMap/Secrets を一緒に更新すればよいわけです
そこで、CofnigMap/Secrets を更新した際に、Deploymentにローリングアップデートをかけるデプロイフローを考えてみます
(CI/CDフローでも使えるよう、デプロイ時にエディタを起動して…などは行わないフローにします)
ローリングアップデートについて
前述したとおり、CofnigMap/Secrets のみの更新ではDeploymentが更新されないため反映が行われません
一般的なデプロイフローでは、各種リソースのyamlファイルを用意してデプロイを行うと思いますが、反映が行われない際のデプロイでは以下のようになっているはずです
$ kubectl apply -f .
configmap/my-configmap configured
deployment.apps/my-deployment unchanged
ComfigMapのみがconfigured
となっていて、Deploymentのほうはunchanged
になってますね
では、特にアプリケーション側に変更が入っていない場合にどのようにローリングアップデートをかければよいのか🤔
上記の記事で、Deploymentのローリングアップデートが起こる条件がすごく分かりやすく説明されています
.spec.template
の情報に変更があったとき- 変更はどの値でもよいが、アノテーション(
.spec.template.metadata.annotations
)が一番影響が少ないと思われる
- 変更はどの値でもよいが、アノテーション(
ローリングアップデートを行う
実際にDeploymentのローリングアップデートを行うデプロイフローをいくつかあげてみます
1. デプロイ時に常にローリングアップデート
CofnigMap/Secrets の更新時を問わず、常にローリングアップデートをかける方法です
$ kubectl apply -f . $ kubectl rollout restart <target_deployment>
applyで更新が入る場合、無駄にローリングアップデートが2度行われるので微妙ですね 🤔
2. アノテーションを動的に変更する
ローリングアップデートが起こる条件に当てはまるよう、.spec.template.metadata.annotations
をデプロイのたびに書き換えるフローです
利用するyamlは動的に書き換えられるよう、deployment.yaml.templateなどとしておきます
deployment.yaml.template
(抜粋)
spec: template: metadata: annotations: update_time: ${UPDATE_TIME}
デプロイ時の書き換えはenvsubstを使ってみます
$ UPDATE_TIME=$(date +%s) envsubst < deployment.yaml.template > deployment.yaml $ kubectl apply -f .
↑の例ではデプロイ時にannotations.update_timeに現在時刻を入れてデプロイしてます
spec.template.annotations.update_time
の値がデプロイのたびに書き換わるのでローリングアップデートが行われます 🎉
CofnigMap/Secrets の更新時のみでよければ CofnigMap/Secrets のハッシュ値などを設定しても良いかもしれません
3. Kustomizeを使う
3つ目の方法はKustomizeの configMapGenerator / secretGenerator を使うやりかたです
configMapGenerator/secretGenerator で作成される CofnigMap/Secrets には自動的にハッシュ値のsuffixがつき、参照側も動的に書き換えてくれます
kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ./deployment.yaml configMapGenerator: - name: my-env literals: - TEST_ENV=hogehoge
deployment.yaml
(抜粋)
spec: template: spec: containers: - envFrom: - configMapRef: name: my-env
上記のファイルを用意し、kubectl kustomize .
を実行すると、
# 抜粋 apiVersion: v1 data: TEST_ENV: hogehoge kind: ConfigMap metadata: name: my-env-c7d2869f5d --- apiVersion: apps/v1 kind: Deployment spec: template: spec: containers: - envFrom: - configMapRef: name: my-env-c7d2869f5d
用意したmy-envに -c7d2869f5d
というsuffixが自動的に付いています
実際にデプロイするには
$ kubectl apply -k .
を実行すれば、上記のyamlの内容がデプロイされます
また、configMapGeneratorの内容を変更し、
@@ -7,4 +7,4 @@ configMapGenerator: - name: my-env literals: - - TEST_ENV=hogehoge + - TEST_ENV=fugafuga
再度 kubectl kustomize .
を実行すると
apiVersion: v1 data: TEST_ENV: fugafuga kind: ConfigMap metadata: name: my-env-9c976df2hh --- apiVersion: apps/v1 kind: Deployment spec: template: spec: containers: - envFrom: - configMapRef: name: my-env-9c976df2hh
-c7d2869f5d
だったsuffixが -9c976df2hh
に変わっています
spec.template.spec.containers
が更新されているため、デプロイ時にローリングアップデートが行われます 🎉
✋注意
Kustomizeでのsuffix付きのリソースはそれぞれ別のリソースとしてデプロイされるため、古くなった CofnigMap/Secrets 自体は残ることになります
--prune
を利用したデプロイを行うようにしたり、利用しなくなった CofnigMap/Secrets の定期的な削除ができるようにしておきましょう
4. Helmを使う
Helmを使っている場合は、公式でローリングアップデートを行うためのTipsが公開されています
Helm | Chart Development Tips and Tricks
この方式は 2. アノテーションを動的に変更する にも記載した、アノテーションに CofnigMap/Secrets のハッシュ値を利用するパターンです
すごくシンプルな以下の構成を例とします
mychart ├── Chart.yaml └── templates ├── configmap.yaml └── deployment.yaml
mychart/templates/configmap.yaml
apiVersion: v1 data: TEST_ENV: hogehoge kind: ConfigMap metadata: name: my-env
mychart/templates/deployment.yaml
(抜粋)
spec: template: metadata: annotations: checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} spec: containers: - envFrom: - configMapRef: name: my-env
annotations.checksum/config
に configmap.yaml のsha256のハッシュ値を設定しています
この状態でドライランをすると
$ helm install my-chart ./mychart --dry-run # 抜粋 # Source: mychart/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment spec: template: metadata: annotations: checksum/config: 3b57b72332cd09882b34fd55bbedec6ccf3ccdf77f8a70fdc41ab518c8ac01d0
checksum/config
にハッシュ値が設定されています
デプロイ後に前回同様 TEST_ENV
の値をhogehoge -> fugafugaに変更してdiffを見ると
$ helm diff upgrade my-chart ./mychart # 抜粋 mychart, my-env, ConfigMap (v1) has changed: # Source: mychart/templates/configmap.yaml apiVersion: v1 data: - TEST_ENV: hogehoge + TEST_ENV: fugafuga ... mychart, mydeploy, Deployment (apps) has changed: spec: template: annotations: - checksum/config: 3b57b72332cd09882b34fd55bbedec6ccf3ccdf77f8a70fdc41ab518c8ac01d0 + checksum/config: f62c80497f97a4b4877958249a1206a3b38bdcb5d5f498df1358ebd3a169c2b7
spec.template.annotations.checksum/config
の値が書き換わっているため、デプロイ時にローリングアップデートが行われます 🎉
まとめ
CofnigMap/Secrets を環境変数に設定して利用する際の、Deploymentのローリングアップデートを行うデプロイフローをいくつかあげてみました
個人的には Kustomize や Helm を利用し、必要に応じて動的にローリングアップデートが行われるフローにするのがよいかと思っています ✋
おうちk8sのPersistentVolumeにNFSを使う
おうちk8sで利用するデータの永続化のためにNFSでのPersistentVolumeを作ってみます
自分が作ったおうちk8sはラズパイ3台構成(master1台/node2台)で、今回はmasterサーバをNFSサーバとして利用します
NFSクライアントの設定
以下nodeサーバ2台にログインしてから行います
$ sudo apt install nfs-common
クライアント側はこれでおわり
NFSサーバの設定
以下masterサーバにログインしてから行います
# NFSサーバのインストール $ sudo apt install nfs-kernel-server # NFSで利用するディレクトリの作成 $ mkdir -p /mnt/share/nfs # NFSサーバ用の設定 $ echo "/mnt/share/nfs 172.22.1.0/24(rw,async,crossmnt,no_root_squash,no_subtree_check)" | sudo tee -a /etc/exports # NFSサーバの起動 $ sudo systemctl start nfs-server.service $ sudo systemctl enable nfs-server.service
NFSサーバ用の設定で指定しているIPレンジはおうちk8sで利用しているサーバのレンジです
自分の環境では
- master -> 172.22.1.161
- node1 -> 172.22.1.159
- node2 -> 172.22.1.162
だったため、上記の設定としています
以上でNFSサーバ/クライアントの設定は終了になります
PV/PVCの作成
確認のためにPV/PVCを作成してみます
grafana用に1GiBのPV/PVCを作ります
事前にmasterサーバに対象のディレクトリを作っておきます
# 以下masterサーバで実行 $ sudo mkdir -p /mnt/share/nfs/grafana
PV
nfs-pv.yaml
kind: PersistentVolume apiVersion: v1 metadata: name: grafana spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: grafana nfs: server: raspberrypi-master.local path: /mnt/share/nfs/grafana
この例ではPVが削除されてもデータが残るよう、persistentVolumeReclaimPolicy
にはRetain
を指定しますが、
ここ を参考に適宜指定してください
PVC
nfs-pvc.yaml
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: grafana spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: grafana
デプロイします 🚀
$ kubectl apply -f nfs-pv.yaml -f nfs-pvc.yaml
確認
$ kubectl get pv,pvc grafana NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE persistentvolume/grafana 1Gi RWO Retain Bound monitoring/grafana grafana 4d19h NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE persistentvolumeclaim/grafana Bound grafana 1Gi RWO grafana 4d19h
(monitoringネームスペースでデプロイしてます)
STATUSがBoundとなって無事デプロイされているようです 🎉🎉🎉
まとめ
おうちk8s上にNFSサーバの設定、NFSを利用したPV/PVCを作ってみました
prometheusやgrafanaのデータの永続化はひとまずこれで運用していきます💪
参考
おうちk8sにPrometheus/Grafanaを導入してNature Remoの可視化をする
前回おうちk8sにKubernetes Dashboardを導入しました
今回はPrometheus/Grafanaの導入に加え、自宅に設置しているNature Remoのセンサーを利用して部屋の室温や湿度などを可視化してみたいと思います
🆙 2020/06/26 更新 master環境にもnode-exporterをデプロイするようvalues.yamlの差分を更新しました
🆙 2020/03/17 更新
データ永続化のためにNFSのPV/PVCを利用するよう修正しました
事前準備
namespace
PrometheusとGrafanaをデプロイするnamespaceは何でも良いですが、今回はすべてmonitoring
というnamespaceを作ってそこにデプロイしていきます
$ kubectl create ns monitoring
kubensなどを使って作成したnamespaceに切り替えておいてください
Helm
PrometheusとGrafanaについてはHelmを使って入れてみます
まずはHelmのインストールから(Macでの動作を想定)
$ brew install helm # 確認 $ helm version version.BuildInfo{Version:"v3.1.0", GitCommit:"b29d20baf09943e134c2fa5e1e1cab3bf93315fa", GitTreeState:"clean", GoVersion:"go1.13.8"}
Prometheus/Grafanaのインストールのために公式のチャートリポジトリを追加します
$ helm repo add stable https://kubernetes-charts.storage.googleapis.com/
追加されたことを確認しておきます
$ helm search repo stable NAME CHART VERSION APP VERSION DESCRIPTION stable/acs-engine-autoscaler 2.2.2 2.1.1 DEPRECATED Scales worker nodes within agent pools stable/aerospike 0.3.2 v4.5.0.5 A Helm chart for Aerospike in Kubernetes stable/airflow 6.1.1 1.10.4 Airflow is a platform to programmatically autho... stable/ambassador 5.3.1 0.86.1 A Helm chart for Datawire Ambassador # ...
あとは対象のチャート名を指定してhelm installでインストール可能ですが、設定ファイルを修正して利用したいので、デフォルトの設定ファイルを取得します
# prometheus $ helm show values stable/prometheus > prometheus-values.yaml # grafana $ helm show values stable/grafana > grafana-values.yaml
Prometheus
Prometheusについては修正箇所がいくつかあります
kube-state-metrics
デフォルトの設定だと、kube-state-metricsのイメージにarmベースのものが用意されていないため、ラズパイ上で動かすことができません
そこで以前書いた、Github Actionsでの複数アーキテクチャ向けのイメージ作成の方法を使ってラズパイ(arm)向けのイメージを作成しました
上記の方法で作ってもらってもOKですが、現時点で最新版(v1.9.5)イメージを作ってあるのでそれを使ってもらっても構いません
作ったイメージは コチラ
PV/PVC
helmでPrometheusをインストールする際に、prometheus-serverとprometheus-alertmanagerにはPersistentVolume/PersistentVolumeClaimが必要になります
マネージドサービスでは動的に作ってくれる設定などもありますが、もちろんラズパイ上に立てたk8sにはそんな機能はありません
PV/PVCを使わずemptyDirを利用するように変更もできますが、Podが再起動した際にデータが消えてしまうので、事前にPV/PVCを作っておきましょう
PersistentVolumeはNFSを利用しますがmasterをNFSサーバとして利用する記事は以下で書いてるので、NFSサーバ/クライアントの設定を事前に行ってください
おうちk8sのmasterサーバにログインし、PVに利用するディレクトリを作っておきます
# masterサーバ上で $ sudo mkdir -p /mnt/share/nfs/prometheus/{alertmanager,server} # 各プロセスをNonRootで動かすため作成したディレクトリの所有権も変えておく $ sudo chown $USER /mnt/share/nfs/prometheus
準備ができたのでPV/PVCを作ります(今回はそれぞれ1GiBを利用する設定)
nfs-pv.yaml
kind: PersistentVolume apiVersion: v1 metadata: name: prometheus-alertmanager spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle storageClassName: alertmanager nfs: server: raspberrypi-master.local path: /mnt/share/nfs/prometheus/alertmanager --- kind: PersistentVolume apiVersion: v1 metadata: name: prometheus-server spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle storageClassName: prometheus-server nfs: server: raspberrypi-master.local path: /mnt/share/nfs/prometheus/server
nfs-pvc.yaml
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: prometheus-alertmanager spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: alertmanager --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: prometheus-server spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: prometheus-server
デプロイします🚀
$ kubectl apply -f nfs-pv.yaml -f nfs-pvc.yaml -n monitoring
values.yaml
今までの変更点をprometheus-values.yaml
にも反映させます
変更差分は以下の通り
@@ -180,7 +180,7 @@ ## alertmanager data Persistent Volume existing claim name ## Requires alertmanager.persistentVolume.enabled: true ## If defined, PVC must be created manually before volume will be bound - existingClaim: "" + existingClaim: "prometheus-alertmanager" ## alertmanager data Persistent Volume mount root path ## @@ -188,7 +188,7 @@ ## alertmanager data Persistent Volume size ## - size: 2Gi + size: 1Gi ## alertmanager data Persistent Volume Storage Class ## If defined, storageClassName: <storageClass> @@ -276,10 +276,10 @@ ## Security context to be added to alertmanager pods ## securityContext: - runAsUser: 65534 + runAsUser: 1001 runAsNonRoot: true - runAsGroup: 65534 - fsGroup: 65534 + runAsGroup: 1001 + fsGroup: 1001 service: annotations: {} @@ -396,7 +396,7 @@ ## kube-state-metrics container image ## image: - repository: quay.io/coreos/kube-state-metrics + repository: sminamot/kube-state-metrics tag: v1.9.5 pullPolicy: IfNotPresent @@ -511,7 +511,7 @@ ## image: repository: prom/node-exporter - tag: v0.18.1 + tag: v1.0.0-rc.0 pullPolicy: IfNotPresent ## Specify if a Pod Security Policy for node-exporter must be created @@ -559,7 +559,8 @@ ## Node tolerations for node-exporter scheduling to nodes with taints ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ ## - tolerations: [] + tolerations: + - operator: "Exists" # - key: "key" # operator: "Equal|Exists" # value: "value" @@ -836,7 +837,7 @@ ## Prometheus server data Persistent Volume existing claim name ## Requires server.persistentVolume.enabled: true ## If defined, PVC must be created manually before volume will be bound - existingClaim: "" + existingClaim: "prometheus-server" ## Prometheus server data Persistent Volume mount root path ## @@ -844,7 +845,7 @@ ## Prometheus server data Persistent Volume size ## - size: 8Gi + size: 1Gi ## Prometheus server data Persistent Volume Storage Class ## If defined, storageClassName: <storageClass> @@ -953,10 +954,10 @@ ## Security context to be added to server pods ## securityContext: - runAsUser: 65534 + runAsUser: 1001 runAsNonRoot: true - runAsGroup: 65534 - fsGroup: 65534 + runAsGroup: 1001 + fsGroup: 1001 service: annotations: {} @@ -972,7 +973,7 @@ loadBalancerSourceRanges: [] servicePort: 80 sessionAffinity: None - type: ClusterIP + type: NodePort ## Enable gRPC port on service to allow auto discovery with thanos-querier gRPC:
- runAsUser/runAsGroup/fsGroup についてはnodeサーバの所有権を変えたユーザのuid/gidを設定します
- 自分の環境でのアカウントは
1001
でした
- 自分の環境でのアカウントは
cat /etc/passwd | grep $USER sminamot:x:1001:1001::/home/sminamot:/bin/bash
node-exporterのイメージはラズパイのCPU温度などを取得できるよう、latestでもある
v0.18.1
ではなく、v1.0.0-rc.0
を使ってますmaster nodeの環境の情報も取得できるようnode-exporterをmasterにも入れます
- nodeExporter.tolerationsの設定を変えてdaemonsetがmasterにも配置されるようにしています
Grafana
GrafanaについてもPV/PVCを作成します
Prometheus同様、おうちk8sのmasterサーバにログインし、PVに利用するディレクトリを作っておきます
# masterサーバ上で $ sudo mkdir -p /mnt/share/nfs/grafana
PV/PVCを作ります
nfs-pv.yaml
kind: PersistentVolume apiVersion: v1 metadata: name: grafana spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: grafana nfs: server: raspberrypi-master.local path: /mnt/share/nfs/grafana
nfs-pvc.yaml
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: grafana spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: grafana
デプロイします🚀
$ kubectl apply -f nfs-pv.yaml -f nfs-pvc.yaml -n monitoring
grafana-values.yaml
を修正します
@@ -111,7 +111,7 @@ ## ref: http://kubernetes.io/docs/user-guide/services/ ## service: - type: ClusterIP + type: NodePort port: 80 targetPort: 3000 # targetPort: 4181 To be used with a proxy extraContainer @@ -186,16 +186,16 @@ ## persistence: type: pvc - enabled: false + enabled: true # storageClassName: default accessModes: - ReadWriteOnce - size: 10Gi + size: 1Gi # annotations: {} finalizers: - kubernetes.io/pvc-protection # subPath: "" - # existingClaim: + existingClaim: "grafana" initChownData: ## If false, data ownership will not be reset at startup
デプロイ
ここまででPrometheus/Grafanaのデプロイ準備が完了したのでデプロイしちゃいましょう🚀
$ helm install prometheus stable/prometheus -f prometheus-values.yaml --namespace monitoring $ helm install grafana stable/grafana -f grafana-values.yaml --namespace monitoring # 更新時は helm upgrade
各種リソースが正常にデプロイされていればOKです
$ kubectl get all -n monitoring
それぞれWebUIでも表示できるか見てみましょう
# Prometheus $ open http://$(kubectl get nodes --namespace monitoring -o jsonpath="{.items[0].status.addresses[0].address}"):$(kubectl get --namespace monitoring -o jsonpath="{.spec.ports[0].nodePort}" services prometheus-server) # Grafana $ open http://$(kubectl get nodes --namespace monitoring -o jsonpath="{.items[0].status.addresses[0].address}"):$(kubectl get --namespace monitoring -o jsonpath="{.spec.ports[0].nodePort}" services grafana)
Grafanaにはログインが必要で、usernameはadmin
、passwordは以下コマンドで確認可能です
$ kubectl get secret --namespace monitoring grafana -o jsonpath="{.data.admin-password}" | base64 -D
ログインできればOK
🎉🎉🎉🎉🎉
Grafanaのカスタマイズ
せっかくPrometheus/Grafanaのインストールができたので、Grafanaでなにかダッシュボードを作ってみます
ブラウザでGrafanaを開きログインしたら、Create a data source
を選択します(画像はすでに追加したあとなので、初回はもしかしたらAdd data source
かも)
"Prometheus" を選択
Settings -> HTTP -> URLにhttp://prometheus-server
と入力
Dashboardsの3つとも"Import"する
Settings から「Save & Test」を押し、正常に設定ができればOK
Dashboards -> Manageから取り込んだ3つのDashboardsが取り込まれればOK
試しに「Prometheus 2.0 Stats」など見てみるとそれっぽいものが表示されるはずです 👍
その他のダッシュボードは Grafana Labs にいろんなダッシュボードが共有されてて、IDを入力するだけでダッシュボードの作成が可能です
ちなみに自分は このダッシュボード を入れてみました
Nature Remoの可視化
やっと本題のNature Remoの可視化です(遅ぇ)
Nature Remo API用のアクセストークン取得
Nature Remo Cloud API のリクエストにはアクセストークンが必要になります
ここのページ からアクセストークンの生成ができるので、値を控えておきます
exporterのk8sへのデプロイ
PrometheusとGrafanaはmonitoring
ネームスペースにデプロイしてましたが、Nature Remo用のexporterはremo
ネームスペースを作ってそこにデプロイしたいと思います
$ kubectl create ns remo
Nature Remo用のexporterを作っている方がいたので使わせてもらいます
↑のリポジトリにはPrometheus/Grafanaのyamlも用意されていますが、先ほど作って不要なため、Nature Remoのexporterのyamlだけ拝借します
使うのはremo-exporter-dep.yaml
とremo-exporter-svc.yaml
ですが、apiVersionの書き方が古かったり、NodePortになってたり(クラスタ内でリクエストできれば良いのでClusterIPでよい)するので、修正を加えたものが以下になります
deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: remo-exporter spec: replicas: 1 selector: matchLabels: app: remo-exporter template: metadata: labels: app: remo-exporter spec: containers: - name: remo-exporter image: kenfdev/remo-exporter:latest ports: - containerPort: 9352 protocol: TCP env: - name: OAUTH_TOKEN_FILE value: '/etc/secrets/api-keys' volumeMounts: - name: api-keys-volume readOnly: true mountPath: '/etc/secrets' volumes: - name: api-keys-volume secret: secretName: api-keys
service.yaml
apiVersion: v1 kind: Service metadata: name: remo-exporter labels: app: remo-exporter spec: type: ClusterIP ports: - port: 9352 protocol: TCP targetPort: 9352 selector: app: remo-exporter
先ほど取得したアクセストークンはsecret/api-keys
に記載しておきます
前回のKubernetes Dashboard と同様、kustomizeを使ってデプロイしましょう
kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: remo resources: - deployment.yaml - service.yaml secretGenerator: - name: api-keys files: - secret/api-keys
いざデプロイ🚀
$ kubectl apply -k .
デプロイができたらexporterから値が取得できるか確認しておきます
$ kubectl run -it --rm alpine --image alpine --restart=Never / # apk update && apk add curl / # curl http://remo-exporter.remo:9352/metrics # HELP go_gc_duration_seconds A summary of the GC invocation durations. # TYPE go_gc_duration_seconds summary go_gc_duration_seconds{quantile="0"} 8.3553e-05 go_gc_duration_seconds{quantile="0.25"} 0.000161035 # ...
正しく取得できてそうです 🎉
Grafanaの設定
exporterもデプロイできたのであとはGrafanaの設定をするだけです
Grafanaの設定はmonitoring
ネームスペースなので戻しておきましょう
独自のscrapeを追加するためにextraScrapeConfigs
の設定を加えます
grafana-values.yaml
のextraScrapeConfigs
に追記してもいいですが、今回は別ファイルで定義して利用してみます
extraScrapeConfigs.yaml
- job_name: 'nature-remo' dns_sd_configs: - names: ['remo-exporter.remo'] port: 9352 type: A refresh_interval: 5s
デプロイします🚀
$ helm upgrade prometheus stable/prometheus -f grafana-values.yaml --set-file extraScrapeConfigs=extraScrapeConfigs.yaml --namespace monitoring
あとはGrafanaのUIからポチポチグラフを追加していくと…
🎉🎉🎉🎉🎉
ダッシュボードのyamlは以下に置いておくので参考にどうぞ ✋
https://github.com/sminamot/raspi-k8s-monitoring/blob/master/grafana/remo/dashboard/grafana.json
まとめ
おうちk8sにPrometheus/Grafanaの導入と、GrafanaへNature Remoを可視化するダッシュボードを追加しました
最近Helmを少し触ってますが、公式のチャート使うと簡単にデプロイできるのでいいですね
あとHelmが2から3にアップデートされてから構成がシンプルになって扱いやすくなりました(まだ2の情報が多いので公式ドキュメント読むのが良さそう、2と3で公式のドキュメントがちゃんと別れてるのが良い)
今回作ったもの
以下に置いておきます
参考
おうちk8sにKubernetes Dashboardを導入する
以前作ったおうちk8s の可視化をしてみるべく、Kubernates Dashboard導入の手順まとめておきます
Kubernates Dashboard
インストール
手順自体は公式に書かれていますが、おうちk8s上からNodePort経由で見られるよう構築します
まず公式のyamlを取得します
$ wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-rc5/aio/deploy/recommended.yaml
kubernetes-dashboardのServiceTypeがClusterIPとなっているため、NodePortへの変更とnodePort指定の変更をしておきます
nodePortは今回30843
としましたが何でもよい or 固定しなくて良ければ指定しなくてOKです
@@ -37,9 +37,11 @@ name: kubernetes-dashboard namespace: kubernetes-dashboard spec: + type: NodePort ports: - port: 443 targetPort: 8443 + nodePort: 30843 selector: k8s-app: kubernetes-dashboard
また、この状態でデプロイすると証明書エラーとなり表示することができないため、オレオレ証明書を作成して設定します
$ mkdir -p secret/certs $ openssl req -nodes -newkey rsa:2048 -keyout secret/certs/dashboard.key -out secret/certs/dashboard.csr -subj "/C=/ST=/L=/O=/OU=/CN=kubernetes-dashboard" $ openssl x509 -req -sha256 -days 365 -in secret/certs/dashboard.csr -signkey secret/certs/dashboard.key -out secret/certs/dashboard.crt
さらにKubernetes Dashboardのログインに使うためのサービスアカウントと権限設定のためのyamlも作成します
これは 公式のドキュメント に載っているyamlと同じものです
admin-user.yaml
apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kubernetes-dashboard --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: admin-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kubernetes-dashboard
あとはデプロイだけですが、Secretの設定をbase64かけてrecommended.yamlに追記するのは面倒なのでkustomizeを利用したいと思います
以下の内容を kustomization.yaml
として保存します
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: kubernetes-dashboard resources: - recommended.yaml - admin-user.yaml secretGenerator: - name: kubernetes-dashboard-certs files: - secret/certs/dashboard.crt - secret/certs/dashboard.csr - secret/certs/dashboard.key generatorOptions: disableNameSuffixHash: true
certs用のsecretはkustomizeによって作られるので、recommended.yaml
のkubernetes-dashboard-certsの項目は削除しておきましょう
--- -apiVersion: v1 -kind: Secret -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard-certs - namespace: kubernetes-dashboard -type: Opaque - ---- - kind: ConfigMap apiVersion: v1 metadata:
設定ファイルが全部揃ったのでkustomizeを使ってデプロイしましょう
今までで用意したファイルの構成は以下の通り
. ├── admin-user.yaml ├── kustomization.yaml ├── recommended.yaml └── secret └── certs ├── dashboard.crt ├── dashboard.csr └── dashboard.key
kubernetes1.14からkustomizeがkubectlに統合されているので別途インストールは不要です
# デプロイされるリソースの確認 $ kubectl kustomize . デプロイします $ kubectl apply -k .
動作確認
Kubernetes Dashboardをブラウザで開いてみましょう
$ open https://$(kubectl get nodes --namespace kubernetes-dashboard -o jsonpath="{.items[0].status.addresses[0].address}"):30843
ログインにはトークンが必要なため、secretの値で確認します
$ kubectl -n kubernetes-dashboard get secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}') -o jsonpath="{.data.token}" | base64 -D
出力された値をコピーして「トークン」に入力します
サインインができて正しく表示されればOK 🎉
metrics-server
公式のドキュメント にもありますが metrics-server を入れることでCPUとメモリ使用量をKubernetes Dashboardに追加することができます
自分のおうちk8sはラズパイ上で動いており、公式のyamlはラズパイ用(arm)向けになっていないのでそこを変更してデプロイします
$ git clone https://github.com/kubernetes-sigs/metrics-server.git
変更点は deploy/kubernetes/metrics-server-deployment.yaml
の以下部分
@@ -29,7 +29,7 @@ spec: emptyDir: {} containers: - name: metrics-server - image: k8s.gcr.io/metrics-server-amd64:v0.3.6 + image: k8s.gcr.io/metrics-server-arm:v0.3.6 args: - --cert-dir=/tmp - --secure-port=4443 @@ -42,9 +42,13 @@ spec: runAsNonRoot: true runAsUser: 1000 imagePullPolicy: IfNotPresent + command: + - /metrics-server + - --kubelet-insecure-tls + - --kubelet-preferred-address-types=InternalDNS,InternalIP,ExternalDNS,ExternalIP,Hostname volumeMounts: - name: tmp-dir mountPath: /tmp nodeSelector: beta.kubernetes.io/os: linux - kubernetes.io/arch: "amd64" + kubernetes.io/arch: "arm"
command
の変更は 参考にした記事 のまま同様の変更を行いましたが、最新版も同じ修正が必要かどうかは未調査 🤔
デプロイします
$ kubectl apply -f metrics-server/deploy/kubernetes
無事CPU/メモリ使用量も確認できるようになりました 🎉
まとめ
可視化したからどうなったわけではないですが、グラフィカルに見えるとなんか嬉しいです
久しぶりにkustomize使ってみたら結構いろんな機能が増えていた(知らなかっただけ?)のと、
GitHubのサンプルだけだと分かりづらいな、と思ってたら 公式のDoc も用意されてて(これも知らなかった)、設定ファイルが簡単に書けるようになりました
また、PrometheusとGrafanaの導入も合わせて書こうと思ってたけど、Kubernetes Dashboardだけで結構なボリュームになってしまったので次回書きます
今回作ったもの
以下に置いておきます
参考
Macの画面キャプチャで高品質なGIFを作る
最近Macの画面キャプチャ(動画)を取る機会があったのでまとめる
きっかけ
git-open という、ターミナルからgitのremoteURLをブラウザで開くCLIツールのGo版(元々npmで提供されていたものを使っていたが、)を作った際に、READMEに動作のアニメーションGIFを置きたいと思った
GIPHY Captureという前にも使ったことのあるアプリを使って画面キャプチャのGIFを作ってみたが、 最高画質の設定で作成しても若干荒く微妙だった 🤔
今回作った方法
GIF作成には Gifski というアプリを使いました
apps.apple.comGifskiは動画ファイルを読み込みGIFへの変換を行います
そのため事前に画面キャプチャの動画を撮る必要がありますが、MacのMojave以降だと「Command(⌘) + Shift + 5」のショートカットキーで撮ることができます
撮り方は以下に記載されています(範囲選択なども可能)
TouchBarが付いているMacであれば録画の停止をTouchBar上から行うことができるので、カーソルが画面内に入らなくて良い(数少ないTouchBarの利点)
録画して保存した動画ファイルをGifskiから開く
サイズやQualityなどを指定して"Convert"を実行するだけでGIF作成完了 👍
出来上がったGIF
実際にGitHubのREADMEにも上げているものがコチラ
すごくキレイ ✨
ちなみにGIPHY Captureで撮った同じキャプチャ(厳密には録画ファイルを再生したとこを撮ったもの)が↓コチラ
なんか薄い 😞
あとがき
ということでこれから画面キャプチャGIF作る際は、Mac標準の画面録画+Gifski でいきたいと思います。
またGIFを作るきっかけとなった git-open ですが、
意外と便利で、自分はgit push後の確認やPR出す際に重宝してるのでよければ使ってみてください ←←