Edited at

今日から始める人のためのKubernetes on AWSベストプラクティス

More than 1 year has passed since last update.

今年一年Kubernetes on AWSをやってきて、kube-awsメンテナ目線で、「今日から、できるだけ楽に、安定して本番運用」するための個人的ベスト・プラクティスをまとめておきます。


TL;DR


  • EKSはまだプレビュー申込の段階。実際に動くものがあるかもわからない。

  • EKSとkops、kube-aws、kubesprayなどは組み合わせて使うもの。代替えにはならない。

  • SaaSありなら分散ログ、分散トレース、リソースモニタリングはDatadogに寄せると運用が楽

  • istioは安心して本番運用できるフェーズではない(Service Meshが必要なら、まだLinkerdのほうがよい)

  • アプリケーションにPrometheusエンドポイントを生やしてメトリクスを取れるようにすべき

  • アプリケーションはOpenTracingやZipkin、Jaegerなどのトレーサを組み込み、Zipkin v1スパンを送るべき


前置き

kube-awsはパーツの一つでしかありませんので、kube-aws成分は少なめです。

また、長くなりすぎないよう、詳細についてはできるだけこの記事内に書くのではなく各参考記事におまかせする方向性にしておきます(とはいえついつい書いてしまったところもありますが・・・)。

最後になりますが、あくまで「今日から、できるだけ楽に、安定して本番運用をする」という観点でまとめますので、あまりエッジのきいたものは紹介しません(し、実際、してないと思います。たぶん)。


Dos


これだけは入れておきたいツールたち


  • kubectl

  • kubectx

  • kubens

  • helm

  • minikube


アプリのデプロイメント関連


SecretやConfigmapは変更ではなく新規作成して切り替える

Kubernetesでは、アプリケーションの設定値はConfigmap、クレデンシャルはSecretというK8Sリソースに定義して、それを環境変数やローカルファイルにマッピングしてアプリケーションプロセスから読ませるという方法がよく使われます。

その前提でK8Sを使い始めるとハマるのが、環境変数の値はConfigmapやSecretが変更されても自動的には置き換わらないということです。アプリケーションプロセスが環境変数をConfigmapやSecretから読み取るわけではなく、K8Sがdocker runするときに読んで環境変数を設定するようなイメージなので自明かもしれませんが。

Configmapを変更したときに、自動的にPod(とコンテナ)を作り直すために

https://github.com/fabric8io/configmapcontroller

のようなOSSを利用する人もいます。それはそれでいいのですが、ConfigmapやSecretをそもそも変更せず、新規作成して切り替えたほうが、内容が間違っていた場合にロールバック可能という利点があります。


helmを使う場合

helmを使う場合は、依存先configmap/secretのchecksumを使ってPod(とコンテナ)を自動的に再作成させることができます。helmが提供するのはchecksumの計算と参照だけなので、対応していないchartもあります。利用するchartがそれに対応していればよいのですが、対応していなければぷるりを出すと喜ばれるかもしれません。また、helm chartを自作する場合はこれを考慮しておくと便利です。

https://github.com/kubernetes/helm/blob/master/docs/charts_tips_and_tricks.md#automatically-roll-deployments-when-configmaps-or-secrets-change


古いデプロイメントの

あわせて読みたい:


Pod、EC2インスタンスの入れ替えによりダウンタイムが発生しないようにする


  • ステートレスなPodは最低2個以上セットにする


    • Podがノードの入れ替え等で一時的に増減するのは当たり前に起こることなので、それに対処しておく

    • できるだけそれぞれ別のEC2インスタンスにスケジュールされるようにする


      • podAntiAffinity

      • クラスタ自体がMulti-AZの場合のみ。



    • できるだけそれぞれ別のAZにスケジュールされるようにする


      • podAntiAffinity

      • クラスタ自体がMulti-AZの場合のみ。





  • Podにreadiness/health probesを設定する


    • 起動中のPod、障害発生中のPodを自動的にロードバランス対象から外すために必要



  • SIGTERMを受けたらGraceful Stopすること。N秒後にSIGKILLで強制停止させられるから。


    • NはterminationGracePeriodSecondsで変更可能



  • ノードが


    • PodDisruptionBudget



合わせて読みたい:


EKSでK8Sクラスタ自体の運用を楽にしていく

AWS re:Invent 2017でKubernetesのマネージドサービスがついに発表されましたね!

詳細は「Amazon Elastic Container Service for Kubernetes (EKS)の所感」にまとめました。まだ実際に利用できるわけではありませんが、今のところでている情報だと、


  • 「Masterノードのマネージドサービス」。WorkerノードはCloudFormationなどで自分で持ち寄る(これは個人的には圧倒的に良い判断だと思いますが、GKEのようなサービスを求めてた人からは評判悪そうですね

  • KubernetesのCluster NetworkingによりAWSネイティブなサポートを追加していく



  • Kubernetes on AWSを便利に使うためのOSSをバンドルしていく


    • kube2iam, heptio/authenticator



の点だけでも、かなりKubernetes on AWSの導入と運用と敷居が下がると考えられ、歓迎すべきサービスだと思います。

一方で、


  • Fargate対応

は実際どのようになるのか次第ですね。


  • LambdaのようにENIをアタッチするために数十秒待たされるような仕様になると「すぐスケールしてほしい」というユースケースには対応できなくなる(むしろSpot Fleetで安価なインスタンスをホットスタンバイでおいておくほうがよいのでは)


  • virtual-kubeletで検討されているような抽象化をするとしたら、Daemonsetはどうするのか(fluentdやdatadog agentでFargateに起動したK8S Podのログやメトリクスをとれるの?たぶんとれない実装になりそう)

などが既にKubernetes on AWSを本番運用している立場からすると気になります。


EKS + kube-aws

手前味噌ですみませんが、kube-awsはEKSと統合予定です。

kube-awsはetcdとcontrollerノードもCloudFormationで管理してくれるのですが、それをEKSに任せられるとkube-awsとしても、その利用者としてもメリットがあるためです。

※kube-awsは、AWS上にカスタマイズ可能なKubernetesクラスタをつくるためのCloudFormation + cloud-initのWrapperなので、EKSとはスコープが違います。kopsも同様です。なので、「EKSがくるから、kopsが不要になる」みたいな話はちょっと間違ってます。もちろん、「EKSで作れないところは手動か自前のスクリプトでやります」なら確かにkopsなどは不要になるのですが、それは自前でkops的なものをつくるのとどれくらい違うのでしょうか、という疑問は残ります!


利便性と運用性の高い分散ロギング

ログストレージにfluentdからログを送って、ほぼリアルタイムにログをフィルタリングしたり追いかけたりできる環境をつくっておくと、デバッグが捗ります。特にマイクロサービスアーキテクチャをとっていて、Kubernetes on AWS上にデプロイされるサービスが複数ある場合は必須だと思います。

具体的には、以下のような組み合わせがおすすめです。


  1. fluentd + Google Stackdriver Logging



    • Google公式のfluent-pluginがあるのが大きい

    • 巷に存在するfluent-pluginのメンテされなさやばいですよね?

    • 公式ならその心配もある程度軽減されます。



  2. fluentd + Datadog Logs(NEW!)



  3. fluentd + Elasticsearch



一番にfluentd + Stackdriver Loggingをおすすめしておいてなんですが、現職では2のDatadog Logsを使っています。

Kubernetes上のアプリケーションログを自動収集する」には、、kube-fluentdをクラスタにデプロイして、StackdriverかDatadog Logsにログを送る方法とその意図を書きました。


Kubernetesネイティブなリソースモニタリングサービス


  • Prometheus

  • Datadog

  • Stackdriver Monitoring

のような、Kubernetesの対応が充実したモニタリングサービスを利用します。外せないポイントは二つあって、一つはカスタムメトリクスのオートディスカバリ、もう一つは標準でKubernetesのノードからPod、Deployment等の汎用的なメトリクスの収集に対応しているかどうか、です。特にオートディスカバリに関しては、Podに所定のAnnotationをつけるだけで自動的にメトリクスをスクレープしてバックエンドサービスに送ってくれるようなソリューションが用意されているPrometheusやDatadogが一歩抜きん出ています。

Datadogのオートディスカバリに関しては、「Kubernetesにデプロイしたアプリケーションのメトリクスを自動収集する」に書きました。


どのマイクロサービスが原因で障害が発生しそうか・したのか知るための分散トレーシング

「分散トレーシングといえばOpenTracing」というような雰囲気もありますが、できるだけ手間をかけず、今後の移行パスも用意しつつ、プロダクション利用したいというようなモチベーションであれば、現状ではZipkin + Datadog APMをおすすめします。

詳細は「Kubernetes上のマイクロサービスを分散トレースする」に書きました。

もちろん、OpenTracingの発展に貢献したい、ぷるりを送ることも辞さない、ということであれば、OpenTracing一択です。

OpenTracingは以下の4パートから構成されますが、それぞれまだまだ改善の余地があるという状況です。


  • 各言語向けのクライアントライブラリであるTracer、

  • Tracerによる計測データを送る先となるバックエンド(Zipkin等)、

  • クライアントとバックエンドのプロトコルまたはspan format、

  • マイクロサービス間でトレースを関連付けするためのpropagation format

Kubernetes界隈で少し例を挙げると、2017/12現在は以下のコントリビュート先があります。


  • Envoy


    • OpenTracingトレーサに非対応


      • Zipkinサポートはビルド時に組み込まれている

      • OpenTracing Tracer(C++)をEnvoyに組み込んだり、OpenTracing Tracerの実装を動的にロードできるようにするようなコントリビューションが考えられます





  • nginx-ingress-controller




Kubernetesへデプロイしたサービスを最速で公開する

KubernetesのDeploymentやServiceのような形でアプリをデプロイしても、本番サービスに必要な


  • Route 53 RecordSet

  • ELB/ALB/NLB

  • TLS証明書

は別途用意する必要があります。そのために、


  • AWSへの一定のアクセス権をエンジニアに配布するのかしないのか、

  • CloudFormationやTerraformを使うのか、

  • どのRecordSet/*LB/証明書がどのサービスと対応するのか、

  • 証明書はどこに保存するのか

  • ...

など、運用を考えると、悩みはつきませんね。

インフラエンジニアが登場したり、そのためだけにKubernetes以外のツールを覚えたりしなくても、もっと気軽にサービスを公開できるようにしたいものです。

そこで、KubernetesのIngressを作成するだけで、ALB、証明書、Record Setを自動生成するようにしました。

をそれぞれ説明しました。


Kubernetesのユーザ管理を効率化

利用者の数だけ個別にKubernetesのService Accountをつくったり、OpenIDなどの設定をするより、AWS IAMの権限でKubernetesに認証してもらったほうが楽です。

EKSでも採用される予定のheptio/authenticatorを使うとできます。

authenticatorの使い方については「heptio-authenticator-awsの使い方」に書きました。


バージョン管理


secretはmozilla/sopsで暗号化


人・チーム


最低二人はKubernetesクラスタ自体の運用+利用手引ができるように

Certified Kubernetes Administrator試験(CKA)に合格するか、そのレベルの、Kubernetes利用者からすると低レイヤーの知識を持った人を一人、二人は育成したほうがいいです。

Kubernetesには、プラットフォームとしての汎用性と、それに応じた複雑性があります。

それをAWS上で動かすためにはAWSの知識も必要になります。本番運用するとなると、JekinsなどとのCI・CDとの統合や、モニタリング、開発者や運用者のワークフロー整備など、Kubernetesの応用に関する実践的な知識も必要になってきます。仮にEKSが利用できるようになっても、その本質は変わりません。(Kubernetes自体の運用に関して自分で責任を持たなければならない範囲は減るのは確かですが)。

CKA合格レベルの知識を身につける近道は、Heptioのブログで紹介されている内容を学ぶことです。

How Heptio Engineers Ace the Certified Kubernetes Administrator Exam


Don'ts

長期的に見ると将来性はありそうですが、OSSにコントリビュートしたい気持ちがない限り「今は」手を出さないほうが無難なものを挙げておきます。

ただし、OSSに貢献したい場合は、むしろ採用してどんどんフィードバックやPRを送るといいですね。


サービスメッシュ関連


istio

pilot/proxy(ingress, sidecar), mixer

istioはアーキテクチャ良し、(Service Meshとしての)将来性よし、golang(!)、メモリフットプリント小さい、Kubernetes Native(!)ということで、最高のサービスメッシュですね。

でも、プロダクション事例を全然聞かないので、K8S on AWSを「今日から、できるだけ楽に、安定して本番運用」するという趣旨には反しますね。

また、具体的な話をすると、以下の点が本番運用を「楽に」するためにはかけているパーツだと思います。


  • 専用のWeb UIがない



    • 公式にもGrafanaのダッシュボードで賄ってくださいと書いてあります

    • Grafanaがだめなのではなく、汎用のWeb UI(+メトリクスのストア)ならPrometheusやDatadog、Stackdriverなども色々候補にあがってきますし、そうすると「Service Meshのモニタリングと操作に特化したダッシュボード」ってしばらくはどこにもない状態になるんですよね。

    • そうすると、たぶんどこかのベンダーがistioのWebダッシュボードをつくって、それとコマーシャルサポートをセット販売することになると思うのですが、それだけで果たしてビジネスになるのか疑問。ビジネスにならなければその独自ダッシュボードの進化も遅くなる。また、Grafana等で賄ってしまう会社も多いと思うので、istioベンダーがとれるパイも少なくなる

    • そういう状況だと、エンジニアが100人くらいはいるそこそこの規模の組織でないとistioは採用できないのでは




Grafeas

https://github.com/Grafeas/Grafeas

https://codefresh.io/blog/write-this-down-grafeas/

Grafeasはコンテナイメージの監査を行うためのAPI仕様です。

Grafeas自体はProduction-readyなAPIサーバの実装が2018/1/5現在存在しないので、本番運用する手軽は方法はないと言っていいと思います。(Grafeas APIのProduction-readyな実装を自分で書いて運用に載せる、というのは「手軽」ではないですよね)

Grafeas APIサーバのリファレンス実装は公式GitHubレポジトリ内にあります。

https://github.com/Grafeas/Grafeas/tree/master/samples/server/go-server/api/server


  • ストレージの実装がインメモリのみ



  • ACL/Authzなし

など本番運用するときにはほしい機能はとりあえずありません。


Webベースのアプリケーションカタログ・コンソール関連


Kubeapps/Monocular

Kubeapps

Monocular

helm installコマンドを打つより親しみやすいのは確か。

ただし、まだ認証機能が不完全なので、本番運用するのは恐ろしい(誰が何を本番クラスタにインストールできるのかを制御できない。ログはとれるのかな?)

細かな権限管理が不要な場合は使ってもいいかもしれません。また、コンソール的には、RancherやKubernetes Dashboardのようにアプリケーションのログやメトリクスも確認できるようになっていくと、より使うメリットが出てくると思います。


権限関連


Namespaceと権限はチーム、プロジェクト、特定システムのサブシステム毎に細かく切る

一番大きな理由は、RBACはSecretのマウントやService Account利用の権限管理ができない、ということです。

Podを作れる権限があれば、そのネームスペース内のSecret全てにアクセスできることを意味します。SecretへのRead自体がRBACで禁止されていても、です。

同様に、あるNamespace内でPodを作る権限があれば、そのネームスペース内のあらゆるService Accountを利用できることになります。

そのため、全員と全システムのK8Sリソースが一つのネームスペースにあると、重要な機能や情報にアクセスできるService AccountやSecretが、おそらく期待しているより多くの人がアクセスできるようになってしまいます。RBACだけではそこまで細かく権限管理ができないので、ネームスペースを細かくわけることを同時にやるとよい、ということです。

ネームスペースを切らないのは以下のようなケースのみです


  • アプリケーションのバージョン違い


    • ネームスペースを分けると、依存元からの依存先バージョンの切り替えが面倒など、色々と不都合が生じる

    • アプリケーションのバージョンアップに伴うコンテナのマイグレーションを自動的にやってくれるのがKubernetesのそもそものメリットの一つ



  • 地理的分散


    • 地理的に分散しているノードがあっても一つのクラスタでうまく扱えるのがKubernetesのそもそものメリットの一つ



  • コスト負担元の違い


    • クラウドプロバイダ側のビリングの仕組みで対応すべき。

    • AWSであれば、請求先が異なる別々のAWSアカウントで作ったWorkerノードを、同じK8Sクラスタに参加させる。



いずれについてもKubernetes: Kubernetes Namespaces: use cases and insightsによくまとまっています。


Namespace毎にNetwork PolicyとResource Quotaを設定する

ネットワークポリシーの具体的な設定方法については、Kubernetes Network Policy Recipesが参考になります。

その他、NamespaceやNetwork Policyに関する主要なユースケースについては以下が参考になります。


アプリケーションのデプロイ関連


前提: デプロイをサポートするツール

Kubernetesアプリケーションのデプロイのために利用するツールは、アーキテクチャと用途毎に大雑把に分類すると、


  • クライアントサイドで動くCLI

  • サーバサイドのみ(kubectl+カスタムリソースでサーバサイドに仕事をさせる、gitレポジトリを監視させるgitops指向など、性格はいろいろ)

  • CLI + サーバサイドのセット

の3種類ある。自分が把握しているだけでも以下のようなツールがある。

@deeeet さんのK8S/YAML問題と著名なツールに関する良いまとめ、その補足についてもぜひ参考にしてください。

あわせて読みたい:


前提: アプリケーションのクレデンシャル管理はデファクトな方法がまだない

helmのこちらのissueが参考になります。

Proposal: secrets shouldn't be stored outside Secrets; secret rotation should be decoupled from release upgrade · Issue #2083 · kubernetes/helm


ksonnet(ks, ksonnet-lib)

ksonnetには、ksonnet-libというjsonnetライブラリと、ksというksonnet-libを利用したk8sマニフェストのフレームワークとそのコマンドラインツールの2つの面がある。


ks

ksonnet-libは利用できる可能性はあるが、ksのほうは時期尚早かも。機密情報をgit commitしてもよい、または機密情報はgit外で管理する、という場合であれば使ってもよさそうだけど、個人的にはおすすめしません。

Support for one-way encrypted secrets like bitnami/sealed-secrets · Issue #255 · ksonnet/ksonnet


Sealed Secrets

Sealed Secrets

SealedSecretという独自リソースをKubernetesにつくって、それにKubernetesのSecretを管理させるというもの。KubernetesのSecretはkubectlがあれば平文で見えるので、それを問題視する場合には使える?

ただし、これを使う利点の一つと説明されている「Kubernetesに保存する機密情報=SecretをGitにコミットできる」という点に関しては、疑問が残る。

おそらくKubernetesを採用するような組織だとKubernetes Secret以外にもGitで管理したい機密情報があると思う。であれば、sopsのような特定のプラットフォームやプロビジョニングツールに依存しない、Gitとの組み合わせを前提としたツールを利用するほうがよさそう。

また、Sealed SecretからSecretへの復号は、クラスタ上で非同期に行われる。なので、SealedSecretとアプリを同時にデプロイすると、復号が終わるまでアプリPodが起動できない。分散システム


カスタムHelm Chart Registry

HelmのChart RegistryはただのHTTPサーバでよく、またカスタムHelmプラグインを用意すればHTTPサーバ以外もChart Registryにすることができる。たとえば、

AWS S3をバックエンドにしたChart Registryをサポートする以下のようなOSSがある。

ローカルファイルシステムをバックエンドにしたChart Registryでよければ以下のようなOSSがある。

また、App Registryという仕様と、その実装(Quay.ioのApplication Registry)もある。

ただ、以下の点がサポートされるまでは、あえて本番運用に載せなくても良いと思う。


  • 手間のかからない権限管理(Application Registryのユーザとその権限管理を個別にやるのがめんどう。せめてIAM User/Roleと統合したい)

  • Audit Log(どのChartを誰がいつダウンロードしたか)


ディザスタ・リカバリ関連

K8Sクラスタをいつ何時落としたり壊しても、比較的短時間で復旧できるようにすると良いです。ここでは、そのために使えそうだけど使えない(と判断した)ツールを紹介します。


K8Sクラスタのフルバックアップツールark

https://github.com/heptio/ark

Kubernetesクラスタにデプロイされているリソースのフルバックアップをとるツール。S3のサーバサイド暗号化にも対応していたりして、痒いところに手がとどく。

Disaster recoveryのためのツールだという触れ込みはわかったうえで、それでも個人的にどういう場面で使えるのかが疑問。

本番環境やステージング環境など、停止時間なしでクラスタのバックアップ&リストア・移行・作り変えをしたいようなユースケースでは、そのままでは利用できない。なぜかというと、Point-in-time recoveryができないから。KubernetesのAPIサーバをread-only(ユーザが変更可能なリソースだけ)にするようなことができれば、それとarkの組み合わせでpoint-in-time recoveryもできそうだけど・・・。

Disaster Recoveryという目的であれば、arkを使って不完全にやるよりも、GitOpsを徹底して、「クラスタが起動次第、Gitレポジトリの内容に従ってデプロイされるべきリソースがデプロイされる」ようにするほうが筋が良いと思う。ただし、GitOpsをやらない場合はこの方法はそもそも使えないと思うので、arkが有力な選択肢になるか?

GitOpsを重要なクラスタへのデプロイで利用するかどうかに関係なく、個人で使うクラスタ、開発用クラスタを停止時間ありで作り変えたりするときならarkは使えるかも?