Chatwork Creator's Note

ビジネスチャット「Chatwork」のエンジニアとデザイナーのブログです。

ビジネスチャット「Chatwork」のエンジニアとデザイナーのブログです。

読者になる

ChatworkのKubernetesを支えるツールたち(2020年版)

こんにちは。SRE部坂本です。毎年最低1回はフルマラソンに出ていますが、2020年はあえなく参加できずに終わりました。 2月にギリギリ行われたハーフマラソンではなんとか90分切り(89分台)を達成し、今年は3時間10分以内を目指してただけに残念ですが、仕方ありません。

特に部活等で走っていたわけでもなく、トラックの大会に参加するのはやや抵抗があり、年間の走行距離ぐらいしか目標がなく、これを書いている12月中旬で2591kmとなっています。昨年が2724kmだったので、なんとか更新したいなーというのが今の気持ちです。

さて、Chatworkでは2016年からKubernetesを導入しております。EKSもない時代ですので、kube-awsというツールを利用してEC2にホスティングして運用していましたが、今年EKSに移行しました。

aws.amazon.com

そんなChatworkのKubernetesを支えるツールたち(2020年版)を紹介したいと思います。ツールは、kubectlやhelmといった、コマンドではなく、Kubernetesにアプリケーションとして動かし、サービスのアプリケーションを支えるツールたちです。

これらのツールはEKSではデフォルトで入らないもので、GKEやAKEだとデフォルトで入っているものも含みます。

ツールの一覧

まず使っているツールを箇条書きしたいと思います。

  1. dns-autoscaler(cluster-proportional-autoscaler)
  2. node-local-dns
  3. metrics-server
  4. cluster-autoscaler
  5. aws-alb-ingress-controller
  6. aws-node-termination-handler
  7. aws-ebs-csi-driver(試験運用中)
  8. node-problem-detector
  9. draino
  10. cert-manager
  11. external-dns
  12. reloader
  13. fluent-bit
  14. fluentd
  15. datadog-agent
  16. newrelic
  17. postfix
  18. aws-secret-operator
  19. kube-schedule-scaler
  20. flux
  21. argocd

なかなか多いですね。あれもこれも、という感じでやや肥大化した感はありますが、どれも使っているツールです。 すべてを詳細に書くと長くなってしまうのと、SRE部尾崎が

fluentとpostfixとnewrelicは僕の方で取り上げるので

とのことなので、おまかせするとして、それ以外に関して、ざっくりとあるいはやや細かく、書いていきたいと思います。

ツールたち

dns-autoscaler(cluster-proportional-autoscaler)

EKSではデフォルトでCoreDNSが2Podデプロイされます。CoreDNSは非常にパフォーマンスがよいので、ある程度規模のクラスタであれば2Podで十分捌けますが、もちろん限界があり、溢れます。溢れた話はまたどこかで書きたいと思いっていますが、ここでは省きます。

で、HPAを使ってもよいのですが、HPAではメトリクスベースなのである程度詰まる前に広げたい場合にしきい値に悩みます。 そこで利用するのが、cluster-proportional-autoscalerで、下記の記事を参考にして導入しました。

kubernetes.io

cluster-proportional-autoscalerはノードの台数や、全体のCPUの個数をベースに特定のDeploymentを広げてくれるもので、これを利用して、ノードのスケールに応じてCoreDNSを広げるようにしています。

CoreDNSが安定して広がるだけで、EKSのDNSまわりはかなり安定すると思います。

node-local-dns

CoreDNSだけでも十分にパフォーマンスは出ますが、できるだけクラスタ内のノード間のDNSのリクエストを減らすことで全体的なパフォーマンスアップが可能です。そこで利用するのがnode-local-dnsです。

kubernetes.io

ただし!!注意点が2つあります。

  • EKSでnode-local-dnsを利用する場合、絶対にforce_tcpを利用しない

timeoutが頻発してまったく使えなくなります。AWSのドキュメントではnot recommendですが、かなりパフォーマンスが劣化し、クラスタ全体のパフォーマンスに影響します。外すだけではなくて、prefer_udpにしたところ安定しました。

When running CoreDNS on Amazon EC2, we recommend not using force_tcp in the configuration and ensuring that options use-vc is not set in /etc/resolv.conf

https://github.com/awsdocs/amazon-eks-user-guide/blob/master/doc_source/kubernetes-versions.md#kubernetes-115

どうやらEC2(nitroベース)の制限で、dns over tcpだと同時接続数が2までしか対応してないようです。

We have identified the root cause as limitations in the current TCP DNS handling on EC2 Nitro Instances. The software which forwards DNS requests to our fleet for resolution is limited to 2 simultaneous TCP connections and blocks on TCP queries for each connection

https://github.com/aws/amazon-vpc-cni-k8s/issues/595#issuecomment-658635050

  • nodeのdnsの向き先を変える必要はない

eksctlでは、kubeletが設定する、各コンテナのdnsの向き先を変える設定がありますが、node-local-dnsを利用する場合、この設定は不要(つまりkube-dnsのままでOK)です。

これはnode-local-dnsが起動時にdummy deviceとiptablesを作成して、kube-dnsへのリクエストを自分に向けるようにするためです。

なので、node-local-dnsが起動すると、強制的にkube-dnsへのリクエストがnode-local-dnsに行くようになるので、本番への適用は慎重に行って下さい(当たり前ですが)。

参考までに、node-local-dnsのproposal(本家にもあったんですが、いつの間にか削除されており、参考URL)とdummy deviceを作成するあたりの処理のリンクを記載しておきます。

https://github.com/prameshj/enhancements/blob/3877b49166658bf6b903f6a4700d4cf3df731842/keps/sig-network/20190424-NodeLocalDNS-beta-proposal.md

https://github.com/kubernetes/dns/blob/51993552aa12a35bfb4c6b8cc8714cb05842f5be/pkg/netif/netif.go#L40

ここらへんの話だけで1つ記事がかけるので、また別途書く予定です。

metrics-server

github.com

HPAを使うなら必須です。

cluster-autoscaler

github.com

HPAとだいたいセットで効果を発揮すると思いますが、ノードをよしなに広げてくれます。 cluster-autoscalerの運用ポイントは(やや面倒ですが)、下記のドキュメントにあるようにノードグループをAZごとに作成することです。

docs.aws.amazon.com

cluster-autoscalerはPVCを利用するアプリケーションのPVのAZを判断して、ノードを広げてくれますが、1つのノードグループをMulti AZで作成している場合、cluster-autoscalerとしては、どのAZのノードが立ち上がってくるのか判断できないため、ノードを広げません。

これに対応するためにAZごとにノードグループを作成することで、cluster-autoscalerが、PVに対応するノードグループ(実際にはASG)を見つけることができ、ノードが広がります。

aws-alb-ingress-controller

github.com

Chatworkでは、外部からリクエストを受け付けるサービスのアプリケーションはほとんどこれでALBを作成しています。

aws-alb-ingress-controllerは全体的にAPIコールが多く、スロットリングに頭を悩ませている方も多いと思います。 APIコール数削減のために、wafまわりをaws-alb-ingress-controllerで使用していないのであれば、waf、wafv2をoffにすることをおすすめします。

--feature-gates=waf=false,wafv2=false

またAPIコールのcacheもできる機能があるので、気になる場合は下記のオプションを試し、durationを調整してみて下さい(durationはデフォルトで300sです)。

--aws-cache-enable=true
--aws-cache-duration=300s

この2つで、APIコール数はかなり改善します。

ただし、cacheを利用した場合、cacheが開放されず、メモリにたまり続けますw またドキュメントには載っていない機能なので、おそらく実験的な機能だと思います。

メモリに関してはどうにもならないので、OOMで殺されるのを待ちましょう(なので、本番環境であれば、Podは2つにしましょう)👻

あるいはv2(aws-load-balancer-conntroller)に移行するのがよいと思います。 Chatworkではまだ移行準備中ですが、メトリクスレベルでは1/3ほどAPIコール数が減っていました。

aws-node-termination-handler

github.com

Chatworkでは、ほとんどノードをスポットインスタンスで運用しています。最近のスポットはかなり安定していますが、それでも週にいくつかのインスタンスが落ちます。そのときにそのノードからPodをDrainしてくれるのがこのツールです。

だたし、当然ですが、スポットの2分で落ちる仕様は変わらず、そのあたりはtermination periodやpreStopのsleepなどの調整が必要です。

ちなみに最近ASGにCapacity Rebalanceという機能が入って、スポットの停止を予想して起動してくれる機能が入りましたが、試してみたところ、相当にアグレッシブにノードを立ち上げ、むしろ不安定になったのでおすすめはしません。

aws-node-termination-handlerにCapacity Rebalanceに対応した機能がが1.11で入りましたが、現時点(2020/12/17)ではcordonのみでdrainはしませんので、Capacity Rebalanceでノードが落ちる場合はブチッと落ちます。

ちなみにManaged Nodegroupだともともと入っていた気がしていますが、Chatworkでは、すべての non Managed Groupで運用しており、このツールを利用しています。

aws-ebs-csi-driver

github.com

まだすべてを移行していませんが、落としても問題ないアプリケーションに導入しています。 ebs-driverは構造が特殊で、すべての機能を利用する場合、controllerの1Podに6コンテナ含まれます。

いろいろ試してみたのですが、PVをattachしていたノードがいなくなった場合のdetachが、classicに比べて遅く、動きが見切れていないため、まだすべてに展開していません。このあたりはパラメータで調整できるかもしれません。

node-problem-detector, draino

github.com github.com

この2つはセットで記載します。 node-problem-detectorは、kubeletの各種statusやkernelのログを見て、nodeのeventを生成したり、statusを変更してくれます。

そしてそのeventなどを監視して、当該ノードからdrainを行ってくれるのが、drainoです。 セットで使うことで効果を発揮すると思います。

cert-manager

github.com

最近ようやくv1になった、cert-managerです。積極的に破壊的変更を入れてくるので、やや運用が面倒でしたが、これで安定することを期待しています。

証明書に関して、ほとんどACMを利用していますが、一部利用していないものがあり、その証明書管理をしています。

またaws-load-balancer-controllerでは、Readiness Gateをmutation webhookで差し込んでくれるようになりましたが、その証明書管理でも利用予定です。

external-dns

github.com

Chatworkでは、クラスタはBlue/Green方式を採用しており、その新旧のクラスタ間のリクエストのバランスをRoute53の重みで行っています。その重みの変更は手動ではなく、external-dnsを利用して、manifestだけで行えるようにしています。 manifestだけで行えることで、SREがアプリケーションチームのリリースに関与することなく、デプロイできています。

またaws-alb-ingress-controllerでは、albはクラスタ内に閉じてしまうため、albとレコードの紐付けの自動化としても利用しています。

reloader

github.com

ややニッチなツールですが、アプリケーションと一緒に管理していない外部のconfigmap/secretを利用していて、その利用しているconfigmap/secretが更新されたら、DeploymentのPodを入れ替えたい、というときに使えるツールです。

Deployment側に監視対象のconfigmap/secretを記載することで、reloaderがそれぞれを監視して、適宜入れ替えを行ってくれます。

datadog-agent

Chatworkでは基本的にはDatadogにメトリクスを集約して、モニタリングしています。 最近ではPrometheus exporter形式でメトリクスを公開しているものも多く、それもdatadog-agentで収集しています。

またログレベルでアラートを仕込みたい場合は、datadog logsにログを送って、モニタを仕込んでいます。

Prometheusも興味はありますが、Chatworkではimmutable clusterで、クラスタ自体を破棄していくので、Prometheusを動かすクラスタがなく、Datadogを利用しています。

が、AMPの登場により、変わる可能性(あるいは並行稼動)もあります。

aws.amazon.com

DatadogもKubernetes系のメトリクスを自動で収集してくれたり、いろいろと便利なので、Prometheusつらい、という方は、お値段次第ではありますが、ご検討下さい。

docs.datadoghq.com

aws-secret-operator

github.com

Kubernetesのsecretをどうやって管理するのか、いろいろと苦労されていると思いますが、Chatworkではaws-secret-operatorを利用しています。

これはawsのsecrets managerに保管したクレデンシャルをもとにsecretを作成してくれるツールで、使う方は直接クレデンシャルを記載せず、aws-secret-operatorのCRを定義するだけでよくGitOpsと相性がよいため利用しています。

secrets managerのRDSパスワードローテーションにも対応しています。

kube-schedule-scaler

github.com

KubernetesにはHPAがありますが、すべてのアプリケーションにフィットするわけではなく、ある程度余裕をもたせてPod数を管理したい場合があり、その場合に利用しているのがこちらです。本家からforkして少しだけ直して利用しています。

forkした理由

  • 本家では、HPAのannotationをdeploymentに書く仕様になっていて微妙だった
    • HPAだからHPAに書きたい
  • ログの出し方が微妙で、Datadog logsでparseしにくかった
    • 暫定対応すぎて今もprint debug状態なのが恥ずかしいところです
  • 初回起動スクリプトがバグっていた
    • これは本家にPRを出してもいいかもですが、kube-schedule-scalerには初回起動時に追いかけ実行みたいな処理がありますが、そこがバグっていてうまく動かなかったので、直しました

ですが、GitOpsとの相性がやや悪く(ArgoCDのignore diffでしのいでいる)、悩ましい問題です。

github.com

への移行も検討しています(個人的に)。

Flux、ArgoCD

ChatworkではGitOpsでアプリケーションをデプロイしていますが、上記に上げたツールたちもGitOpsで運用しています。 FluxとArgoCDは2大巨頭ですが、現時点では両方利用しています。

  • Flux
    • eksctlのコマンドで入れることができるので、これ自体のinstallが簡単
    • クラスタ構築時に欲しく、manifestで管理しやすいもの(namespaceやaws-authで利用するRBACなど)
  • ArgoCD
    • それ以外のmanifestが複雑になりやすいアプリケーション

ArgoCDに統合予定ではありますが、現時点では大きな問題ではないので、並行利用しています。

まとめ

2020年版のKubernetesを支えるツールたちでした。 Kubernetesらしいエコシステムを堪能できる一覧になったかな、と思います。

2020年版ですので、来年2021年版も(差分があれば)書く予定です。

最後に

Kubernetesに関していろいろと書きましたが、Kubernetes以外にもいろいろとあるので、興味のある方はぜひ覗いてみて下さい!

www.wantedly.com