前の記事で自身でPrometheusをAKSに構築しKubernets、Nginx、Redisを監視した。 kashionki38.hatenablog.com
それに加えJaegerでのトレーシングも構築する必要があったためIstioを導入することにした。
結果としてPrometheusによるリソース監視、Jaeger/Zipkinによるトレーシングに加え、Istio×Prometheusによるサービス単位のRED監視がデフォルトでできるため、MSA on Kubernetes環境における性能評価には必要なツールであると思えた。
デモ環境
Istioにはサンプルアプリがあって、良い感じにMSAで1ページのWebページを構成している。
istio.io
trace-idをheaderに伝搬する処理も実装済みで、監視/トレーシングやIstioのトラフィックコントロールの検証には持ってこいなのだ。
画面
ちなみにこういうページが構成されており、topがproductpage、各描画部分が後続のdetails, reviews, ratingsから情報を取ってきている。
Istio構築
ということで、AKS上にIstioを構築していく。
Istioのダウンロード
ドキュメント参照。
istio.io
WLS Ubuntu上でやった。
$ curl -L https://istio.io/downloadIstio | sh -
Istioのインストール→AKS
以下参考に。
docs.microsoft.com
Grafanaのシークレットを追加する、でGrafanaのパスワード設定になるので覚えておくこと。
以下、Istioコンポーネントのインストールのためのコマンドだが、installPackagePathはistioをダウンロードした際にinstallディレクトリができているのでそのパスを指定すること。
$ istioctl manifest apply -f istio.aks.yaml --logtostderr --set installPackagePath=./install/kubernetes/operator/charts
istio-1.5.0/ ├── bin ├── install │ ├── consul │ ├── gcp │ ├── kubernetes │ └── tools
istio-system namespaceにpodがいっぱいできている。(Prometheusは後ほどStatefulSetに書き換えたので、それで表示されている)
$ kubectl get po -n istio-system NAME READY STATUS RESTARTS AGE grafana-54db7fcb58-j75l4 1/1 Running 0 8d istio-citadel-57df8745df-jffjn 1/1 Running 0 8d istio-galley-7bd4545f4-6q8rt 2/2 Running 0 8d istio-ingressgateway-85978556b4-f9skz 1/1 Running 86 8d istio-pilot-664c9fcbd4-58q52 2/2 Running 86 8d istio-policy-654557c4f4-8s8nh 2/2 Running 321 8d istio-policy-654557c4f4-mcxx2 2/2 Running 0 3d7h istio-policy-654557c4f4-pqf4n 2/2 Running 0 3d21h istio-policy-654557c4f4-pzrgx 2/2 Running 0 4d23h istio-policy-654557c4f4-rh26l 2/2 Running 0 6d7h istio-sidecar-injector-65d67fc47-2nzth 1/1 Running 0 8d istio-telemetry-7c858cf875-t8b2p 2/2 Running 0 3d21h istio-tracing-cd67ddf8-fbswf 1/1 Running 0 8d kiali-74db4467dc-96xch 1/1 Running 0 8d prometheus-0 1/1 Running 0 3d6h
簡単に、Prometheus、Grafana、Jaeger(istio-tracing)が入ってしまった。
Prometheusはデフォルトだとめっちゃメモリ食うよ
じゃあ、Prometheusはこのまま走らせとけばいいのかというとそうでもない。
(そもそも監視対象クラスタ外に置くべきという話があるので本当は別立てすべきなのだと思うけど)
実はデフォルトのscrape configのままIstioのビルトインPrometheusを走らせているとメモリをめっちゃ食う。
俺はAKSクラスタをStandard_DS2_v2で、各ノードメモリ7GBで運用していたが、普通に7GB以上スパイクする。
そしてpodはOOM-killerに殺されて再起動する。
どうしたものかと色々試行錯誤した結果、Istioのトラフィック系のメトリクスを15秒間隔に取り続けることが原因ということがわかった。
サービスのRED評価に必要なものを残して他のscrape configはコメントアウトすると、起動時に3GB取っていたのが200MB程まで削減され数日稼働しても特にリークせず安定した。
(envoy-stats, istio-proxy, istio-telemetry, pilot, galley, citadel, kubernetes-apiserverをコメントアウトした。まだこのscrape結果を有効活用するまでいたってないので一旦。。。)
IstioビルトインPrometheusについてのprometheus.yamlの設定の仕方だが、configmap経由となっている。
$ kubectl get configmap prometheus -o yaml -n istio-system apiVersion: v1 data: prometheus.yml: |- global: scrape_interval: 15s scrape_configs: # Mixer scrapping. Defaults to Prometheus and mixer on same namespace. # - job_name: 'istio-mesh' kubernetes_sd_configs: - role: endpoints
Prometheus全般に言えるが、バージョンによって書き方が変わったりするのでどのバージョン使っているのか確認した上でドキュメントのバージョンを合わせることを意識したほうが良さそう。
Prometheusのメモリ管理の方式もv1→v2で大きく変わったらしく、基本的にpod limitsまで割り当てられるだけ割り当てるようになっている。
qiita.com
オプションがシンプルになり -storage.local.target-heap-size のチューニングが不要に(後述)
-storage.local.target-heap-size が不要になった理由 -storage.local.target-heap-size による明示的なメモリの指定がいらなくなったのは Go のレイヤで行っていたチャンクデータのキャッシュの処理を、2.0 ではmmap を使いカーネル側に任せることで自前での退避(evict)処理が必要なくなったからだそうです。参考: Unable to deploy v2.0.0-beta.0 #480 のコメント
これもv1時代のドキュメントや質問を見ているとヒープサイズ変更が必要と思い込んでしまうので注意が必要。
v2でできる有効策はscrapeの設定を調整することだ。
Prometheus監視対象拡張
Prometheus自体の設定はOKなので、追加で監視する項目を設定していく。
今回は時間もなかったのでmongodbだけ追加で設定した。
mongodb監視
Exporter
hub.docker.com
mongodbのexporterにはこのイメージを使用。
正直、ほとんどすることはなく対象podに以下の様にサイドカーとして追加するくらい。
- name: mongodb-exporter image: eses/mongodb_exporter imagePullPolicy: IfNotPresent ports: - containerPort: 9104 protocol: TCP resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File
追加後はPrometheus PodからのNW疎通確認をしたりした。以下記事参照。
kashionki38.hatenablog.com
scrape config
scrape configはprometheus.yamlの中にあるため、今回だと上述のようにconfigmapを編集する。
service discoveryやりたかったけど、ここは一旦staticで設定。
# kashinoki38 - job_name: 'mongodb-exporter' static_configs: - targets: ['10.244.1.44:9104']
こんな感じでPrometheusのtargetsに表示されたらOK。
Grafanaダッシュボード
これでGrafanaダッシュボードへのアクセスポートフォワーディングが自動でされる。
$ istioctl dashboard grafana
Grafanaダッシュボードもとりあえずありものを使う。
grafana.com
いい感じのダッシュボードが一旦できあがりましたわ。
Prometheusデータ永続化
さて、Prometheusの監視設定は完了した。
以前できてなかったこととしてデータの永続化がある。せっかくなのでやってみた。
statefulsetへの変更
まずはビルトインPrometheusはdeploy→ReplicaSetでできているので、StatefulSetへと変更する。
StatefulSetって?
StatefulSetにすることで以下の恩恵を受けれる。
- Pod名のサフィックスが数字インデックスになり、再起動時に名前が変わらない(e.g. prometheus-0)
- PersistentVolumeを使っている場合、Pod再起動時に同じディスクを利用して再作成される
ということで、PrometheusはステートフルなデータベースなのでStatefulSetにしたほうが良い。
Deploy→StatefulSet
deployからの変更の仕方だが強引にkindを書き換えて、アップデート戦略部分をコメントアウトすることで完了した。
思っていたよりも簡単。。
apiVersion: apps/v1 kind: StatefulSet (中略) # progressDeadlineSeconds: 600 # strategy: # rollingUpdate: # maxSurge: 25% # maxUnavailable: 25% # type: RollingUpdate
PersistentVolumeClaimの使用
もちろんStatefulSetにするだけではデータ永続化はされずPersistentVolumeを使用する必要がある。
StatefulSet内でPersistentVolumeClaimを書くことができるようなのだが、今回はPersistentVolumeClaim自体は別で書いた。
PersistentVolumeとPersistentVolumeClaim
俺の理解。
- PersistentVolume(PV)は基本的にNW越しに外部のボリュームを提供するシステムを利用する永続化目的のディスク領域。
- PersistentVolumeClaim(PVC)は、どういったPVをPodにアタッチしてほしいかの定義。(selectorでLabelとか指定する感じ)
PersistentVolumeClaimの作成
Azureでどうやってやるのか調べたら、PVCを書けばPVが動的にAzure上で作成/アタッチされるようだ。
docs.microsoft.com
以下作成。
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: azure-managed-disk namespace: istio-system spec: accessModes: - ReadWriteOnce storageClassName: managed-premium resources: requests: storage: 20Gi
PersistentVolumeClaimをPodから利用する
prometheus.yamlの中でPVCを利用するように書く。
Prometheusのデータファイルはデフォルトでは/prometheus/data
に格納されるため、そのパスをPVCにする。
prometheus.yaml
(中略) volumeMounts: - mountPath: /prometheus/data name: azure-pv-volume (中略) volumes: - name: azure-pv-volume persistentVolumeClaim: claimName: azure-managed-disk (中略)
permission denied
以下エラーが発生。
err="opening storage failed: lock DB directory: open /prometheus/lock: permission denied"
ロックファイルがあることと、Permissionの問題のようなのでそれぞれ対応。
(暫定対処的な感じだったので、本来どうあるべきかは別途調べないと、)
--storage.tsdb.no-lockfile追加
ロックファイルを作成しないようにprometheusのコマンドライン引数に--storage.tsdb.no-lockfile
を追加。
prometheus.yaml
(中略) containers: - args: - --storage.tsdb.no-lockfile (中略) name: prometheus (中略)
prometheus.yamlにsecurityContext追加
Prometheusを実行するユーザがPrometheusユーザになってしまうのを上書く目的。
prometheus.yaml
(中略) securityContext: runAsUser: 1000 runAsGroup: 3000 fsGroup: 2000 (中略)
永続化されているかの確認
ここまででPrometheus永続化の設定は完了。
Podをdeleteして確認してみる。
$kubectl delete po -n istio-system prometheus-0
5分弱Podの再起動に時間がかかるのが気になるが、ちゃんと再起動前の情報も見れることを確認できた。
Jaeger
Jaegerも基本的にIstioと共に入っているのでJaegerUIにアクセスするだけいい。 istio.io
さらにBook-infoサンプルはtrace-id等を伝搬してくれているので特にソースの変更も不要。
JaegerUIへのアクセス
$istioctl dashboard jaeger
ここまでで、Istioデモアプリに対するPrometheus監視とJaegerトレーシングの設定は完了した。
突貫的にやった部分も多く、特にIstioに関する概念をあまり理解できていないのでおいおい勉強していかないといけない。
次の記事ではこのデモアプリに負荷をかけてみて実際に監視した内容を書いてみたい。