OpenStackとIngress Controllerで作るContainer-nativeロードバランシング

OpenStackとIngress Controllerで作るContainer-nativeロードバランシング

E43a47bb90476a0bf6fd7fd5ab61b094?s=128

Shuichiro MAKIGAKI

July 23, 2019
Tweet

Transcript

  1. OpenStackとIngress Controllerで作る Container-nativeロードバランシング 牧垣 秀⼀朗 (Shuichiro MAKIGAKI) 株式会社サイバーエージェント 全社システム本部・adtech studio

    Cloud Native Days Tokyo 2019 / OpenStack Days Tokyo 2019
  2. 背景

  3. 株式会社サイバーエージェント • 株式会社サイバーエージェント(英称︓CyberAgent, Inc.)は、Ameba(アメーバブログ)関連事業とイン ターネット広告事業を主とする企業である。本社は東 京都渋⾕区に所在。⽇経平均株価の構成銘柄の⼀つ。 (Wikipedia: 2019-07-10)

  4. adtech studio • 開発効率の向上、各サービスの技術⼒および精度強化 を⽬的に2013年10⽉1⽇に設⽴。サイバーエージェン トグループのアドテクノロジー分野におけるサービス 開発・提供を⾏う横断組織。 • 約200名のエンジニアと約100名のビジネスによって、 アドテクノロジー分野およびAI・ロボットサービス事

    業におけるサービスを多数提供。 • エンジニア開発体制を強化するほか、エンジニアの技 術⼒向上をサポートする環境づくり、ビジネス側の知 識向上のサポートなど様々な制度の導⼊などを⾏って いる。
  5. Infrastructure as a Service • IaaS︓2006~ (Wikipedia調べ)(浪⼈⽣→⼤学⽣くらいの時期……) • 流れの速い業界なので「早い・安い・旨い」IaaSが必要 Amazon

    Web Service, Google Compute Engine, On-premise Data Center, etc. 弊業界に限らないかもしれません • その時点で使えるもののうちで、最も適したもの選んで使う これができるのが弊社の強みです • On-premise環境にOpenStackでプライベートクラウド環境を構築
  6. Adtech Container Engine • Kubernetes (k8s) on on-premise OpenStack •

    通称「AKE」 • OpenStack Heat(CloudFormation相当)を使ってk8sク ラスタを1コマンドで構築 • 特徴 GKE 並に簡単なデプロイとスケーリング クラスタ外部から疎通できる VIP の払い出し Keystone 連携による Kubernetes Cluster への認証 Designate 連携による柔軟な FQDN によるアクセス 外部ボリュームの利⽤ (EBS 相当の Cinder 連携) NFSもサポート
  7. 本⽇話すこと オンプレのk8sで動いているコ ンテナに外部疎通性が欲しい •本質的には、やりたかったのはこれ だけ、なんですが…… •もちろんできなくはないんだけど、 ちょっと困る部分があって…… •それを何とかしたいのです •という発表です ところでKubernetesでそれをや

    るにはどうすればいいんでし たっけ︖
  8. k8s Networkの復習 (1/3) • k8sクラスタは複数のノードから構成される • 今回の場合は、ノード==OpenStack Novaで 作ったVM LB

    VM Network Pod Network
  9. k8s Networkの復習 (2/3) • VM NetworkとPod Networkが存在する • 実装は様々(VLAN, VXLAN,

    etc.) LB VM Network Pod Network
  10. k8s Networkの復習 (3/3) • Pod Networkはクラスタ外からの疎通 性はない LB VM Network

    Pod Network VM
  11. 余談 • k8sの原型は「Borg」というGoogleの社内システム Verma, A., Pedrosa, L., Korupolu, M., Oppenheimer,

    D., Tune, E., & Wilkes, J. (2015, April). Large-scale cluster management at Google with Borg. In Proceedings of the Tenth European Conference on Computer Systems (p. 18). ACM. • ⾃分「いや、疎通できないの困らないの︖」 • 紙⽈く、In Borg, all tasks on a machine use the single IP address of their host, and thus share the host’s port space. … Kubernetes can take a more user-friendly approach that eliminates these complications: every pod and service gets its own IP address, allowing developers to choose ports… 超約︓ホストのIPを共有、ポートをやりくりする • つまりKubernetesは(他のやり⽅もあるので)Borgよりマシ(↑紙⽈く) 論⽂から察するにBorgの⽬的は「巨⼤な計算資源を効率よく使うこと」であって、コンテナとそのオーケ ストレーションは⼿段に過ぎなかった(と思われる) でもそれをインフラ抽象化としてOSSで売りに出したのはGoogleの巧みな術
  12. 問題

  13. 課題解決における3本の⽮(︖) コンテナ に外部疎 通性が欲 しい いろいろな⽅法 がある やってみると ちょっと問題が あった

  14. `type: LoadBalancer` page 014

  15. Balancing(kube-proxyのproxy-mode) • userspace Userspace上のkube-proxyがバランシング • iptables iptablesがバランシング kube-proxyはiptablesのエントリを管理 • ipvs

    ipvsがバランシング kube-proxyはipvsのエントリを管理 • 2段階ロードバランシング
  16. となると、困ること(1) SRC IPがわからない •NATされてるから •通信制御・アクセス統計や解析など、送信元IPが必要となるケースは多い 弊社の外部LBはL4専⾨(BIG-IP) •重いのでL7は処理しない •よって、それ以外のどこかでX-Forwarded-Forを付与してほしい

  17. そこでIngress • クラスタ内のServiceに対して、外部疎通性を与えるAPIオブジェクト https://kubernetes.io/docs/concepts/services-networking/ingress/ プロトコルはHTTPとHTTPSに対応 ロードバランシング、SSL終端、名前ベースのVirtual Hostの機能も提供する • 実体はNginxだったりnghttpxだったりする •

    このIngressをControlするのがIngress Controller 実体とControllerが同じPodだったりする(話がややこしい)
  18. ⾃作 Ingress Controller v1 • 2017-12~ • Ingress=L7ロードバランサーを作る • いい感じにリソースを操作することで、GKE-likeなIngressを実現

    • Controller によりオペレーションを⾃動化 1. Ingressリソースのingress-classを変更 2. Nginx-IngressのDeploymentを作成(上記のingress-classを指定) 3. Serviceを作成
  19. となると、困ること(2) L4 LB VM Network Pod Network 必要なリソース • Deployment

    (Nginx Ingress) • Service(type: LoadBalancer) L7を処理するPodを作成してオフロード
  20. 困ること(まとめ) 結局、SRC IPはわからない • NATされてるから • 通信制御・アクセス統計や解析など、送信元IPが必要となるケースは多い 弊社の外部LBはL4専⾨(BIG-IP) • 処理が重すぎるのでL7は処理しない

    • それ以外のどこかでX-Forwarded-Forを付与してほしい DeploymentやService などをいちいち作る必要がある ingress-classを利⽤しないとリソースごとに分離できない
  21. なんかもうL4LB配下にIngressぶら下げて、 そこでX-FF付けちゃって、 そこからコンテナに直接パケット通して︕ → Container-native load balancing+Ingress 駄々をこねる⼈のイラスト(男の⼦)

  22. ⾃作 Ingress Controller

  23. Container-native LB L4 LB VM Network Pod Network VM .

    VM . L7 LBを外側に構築 L4 LB v1 L4 LB VM . v2
  24. Container-native LB L4 LB VM Network Pod Network VM .

    VM . Calico により VM から Pod への 疎通性確保
  25. Calico? • 読み︓キャリコ Scalable, distributed control plane Policy-driven network security

    No overlay required Pluggable Data Plane Integrated with all major cloud platforms Widely deployed, and proven at scale • TL;DR: BGPでコンテナへの経路を得る Pod IPへの経路を広報して、ホストのIPに吸い込む つまりBIRDのControllerとも⾔える それをやっちゃえば、それはできそう(⽇本語)
  26. Calico⼤変そう︖ • VM に対して伝搬しているだけ • Nginx IngressからPodへの疎通性を確保 L4 LB VM

    Network Pod Network VM .
  27. Calico⼤変そう︖ • 既存のNginx Ingressを利⽤することで⼤幅な実装コストダウンできそう Nginx Ingressの各エントリは、もともとPodのIPアドレス 構築・運⽤の範囲をController化するだけでよさそう VM . VM

    Network Pod Network L4 LB L4 LB VM .
  28. ⾃作V2 (Container-native) に向けて • Controller が⻩⾊い部分を作成 • 先ほどの Deployment の代わり

    にVM Cluster を構築する • OpenStack Heatを使⽤ OpenStack Heat ≒ CloudFormation L4 LB VM Network Pod Network VM . VM .
  29. 余談 • そこまでしてやる意味あるの︖無理してない︖ Q︓外部LBみたいな転職できない技術使わないで、オープン・スタンダードなk8sの世界にすべて ⼊れれば理想なのでは︖Googleが作ってるんだし。 A︓No 既存のリソースを活⽤できるのが、Kubernetesのいいところ • コンピュータエンジニアの所作︓あるなら使う、ダメなら直す、無いなら作る それが価値の創造

    • ※個⼈の感想です • ※諸説あります
  30. 作る

  31. 開発のPhase分け Phase 1: Ingress ControllerだけでMonolithicに動かす • レプリカ数など管理するものが多い、コントロール対象(関⼼事)は狭めたい Phase 2: HeatStack

    Controllerを分離 • Heatのスタック状態を⾒る部分を別のControllerとして分離 • 状態管理ループの中で⼤きな「待ち」を⼊れるのは、得策ではない • さっきの紙︓”Borgmaster was originally designed as a monolithic system, but over time, … , we split off the scheduler and the primary UI (Sigma) into separate processes, and added services for admission control, vertical and horizontal auto-scaling, re- packing tasks, periodic job submission (cron), workflow management, and archiving system actions for off-line querying.” • 超約︓Monolithicはやっぱりスケールしないわ • Heatの待ちが移動しただけだが、ロック粒度は⼩さくなった
  32. Controller超約 • あるべきリソースを定義して、保管して おく よって、保管されている定義が常に「真」 「真」が間違っているのは、オペミス扱い • 常に現在のリソース状態を監視し、ある べき状態との差分が出ると、収束させよう とする

    取得 • APIサーバーへ 問い合わせる 照合 • あるべき姿と現 状を照合する 実⾏ • 差分があれば埋 めて収束させる
  33. ⾃作Ingress Controller • kubeconfigの構築とHeatへの引き渡し Ingressが動く実VMはk8sの「外」にあるので、 kubeconfigを渡さないとクラスタの状態を知るこ とができない これ実装が意外とめんどくさいんですよ(70⾏くらい) • Heat

    Stackの作成 +Annotation経由で来るパラメータのValidation 正確にはHeatStackカスタムリソースの登録 実際にHeatを叩くのはHeatStack Controller apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-sample annotations: ake.adtech.cyberagent.io/ingress-controller-flavor ake.adtech.cyberagent.io/ingress-controller-replicas ake.adtech.cyberagent.io/fluentd-s3-bucket # etc. spec: rules: - http: paths: - path: /a backend: serviceName: np-a servicePort: 80
  34. ⾃作HeatStack Controller • HeatStack CRD (Custom Resource Definition) カスタムしたリソースの定義(そのまま) つまりHeatのStackをk8sのリソースとして管理

    の対象にさせる Spec (あるべき状態): TemplateURL, Timeout, Params, Tags Status (実際の状態): StackStatus, LastOutputs, LastParams HeatのOutputと同期 • VMとLBの状態管理に集中 取得 • APIサーバーへ 問い合わせる 照合 • あるべき姿と現 状を照合する 実⾏ • 差分があれば埋 めて収束させる
  35. Heatをカスタム • LB (BIG-IP) を操作できるHeatのカスタム リソースを⾃作 プール、メンバー、Virtual ServerをHeatのリ ソースとして指定可能 1.

    BIGIPPoolとBIGIPVSを準備 2. Nova::ServerでVMを作って 3. BIGIPPoolMemberとする • こういうのが既存なので楽です resource_group_anlb: type: OS::Heat::ResourceGroup resource_def: instances_anlb: type: OS::Nova::Server bigip_poolmember_anlb: type: ADTECH::AXC::BIGIPPoolMember bigip_pool_anlb: type: ADTECH::AXC::BIGIPPool bigip_vs_anlb_v2: type: ADTECH::AXC::BIGIPVS
  36. Heatでやること • インスタンスの中でやること → あと全部cloud_initでやる cloud_init_anlb: type: "OS::Heat::MultipartMime" properties: parts:

    - config: {get_resource: cloud_init_anlb_11_set_sysctl} - config: {get_resource: cloud_init_anlb_12_set_kubeconfig_calico} - config: {get_resource: cloud_init_anlb_13_set_kubeconfig_ingress} - config: {get_resource: cloud_init_anlb_14_set_interface} - config: {get_resource: cloud_init_anlb_15_set_bgppeer_yaml} - config: {get_resource: cloud_init_anlb_16_set_bird_config} - config: {get_resource: cloud_init_anlb_17_set_dd_config} - config: {get_resource: cloud_init_anlb_18_set_fluentd_config} - config: {get_resource: cloud_init_anlb_19_set_run_script} - config: {get_resource: cloud_init_anlb_20_set_logrotate} - config: {get_resource: cloud_init_anlb_99_wc_notify}
  37. Validating Webhook • レプリカ以外が書き換えられると困る すべての VM を再構築してしまう可能性あり (Heat の仕様)(マジかよ) •

    そこでValidating Webhookも作成 しないで欲しいParamsの変更はRejectされる kind: HeatStack metadata: name: sample-stack spec: templateURL: http://.../cls.yaml params: replicas: "3" flavor: ar1-standard-4 ingress_name: sample-ingress kubeconfig: ... status: lastOutput: bigip_vsip: x.x.x.x stackStatus: CREATE_COMPLETE
  38. 実装 • Gophercloud: SDK for OpenStack ちょいちょいバグっぽい愛嬌のある⼦です • Kubebuilder: SDK

    for building Kubernetes APIs using CRDs https://github.com/kubernetes-sigs/kubebuilder LoopはSDK任せで、イベント発⽣時のロジックを書いていくイメージ こういうのがちゃんと提供されているのがとても良い ちゃんと動いちゃって愛嬌がない • Editor(Go⾔語) Atom / VS Code / Vim / Goland (←⾃分) / Emacs (←⾃分) • Workflow → Pull Requestする → ReviewしてMergeする → 動かしてみるが、問題がみつかる → 直す → 最初に戻る
  39. うん、で、実際は︖ • Commit数で⾒ると超絶優秀な⼯数 • ⽴ちふさがる困難で⾒ると 書くには余⽩がたりない

  40. まとめ

  41. まとめ(教科書的) CalicoによるContainer-native load balancingと、Ingress Controllerの独⾃実装 • 以下の問題を解決できた • SRC IPがわからない・外部LBはL4専⾨・単純なIngressだとDeploymentなどを作る必要がある

    賢いSDKと少⼈数チームで、短期間で実装 • たいへんよくできました 使ってみたの︖ • ちょうど社内Wikiのインフラ刷新案件があったので、さっそく適⽤ • 動いてくれています(感動) 性能(RPS) • 1台: 1734~3529 → 2台: 3874~5520 → 3台: 5735~8446 • もうひとこえ︖まだまだ仕事があってうれしいなぁ(遠い⽬)
  42. まとめ(本質) •オンプレ資産の活⽤法が増えた • オンプレは価格的に競争⼒が⾼い • そこでGKEみたいな機能が(全部じゃないけど)最低限使える • AWSやGCP以外にもう⼀つのクラウドの選択肢が維持できる •アプリケーション抽象化により、インフラ屋さんサイ ドは楽になった

    •プライベートクラウドの成⻑と、その機能が増えてい くことを⽰せた • そうやってLBとコンテナって連携すればいいのか、というのを⽰せた • これをインフラチームから⾔える、のは強み この仕事の価値 とは︖