サイボウズサマーインターン2021 報告 〜 Kubernetes基盤開発コース

こんにちは、Necoチームの鈴木、石井、そしてストレージチームのsatです。

サイボウズは毎年サマーインターンシップを開催しています。去年に続き、今年もCOVID-19の影響でフルリモート開催でした。 インターンには様々なコースがありますが、本記事ではその中で我々が取り組んだKubernetes基盤開発コースの模様をお届けいたします。ここでいう「Kubernetes基盤」とはKubernetesを用いたサイボウズの次期インフラ基盤Necoのことを指します。

cybozu.co.jp

今年のKubernetes基盤開発コースは8月23日~9月3日(10日間)の日程で開催、7人の学生が参加してくれました。

彼らには本コースが提供する以下3つのチームに分かれて課題に取り組んでもらいました。

  1. コントローラチーム
    • Kubernetesコントローラの実装方法を学び、サイボウズで開発しているKubernetesコントローラ(meows)の機能追加をしてもらいました。
  2. Networkチーム
    • eBPFベースのNetworkingソフトウェアであるCiliumをKubernetesクラスタに導入し、そのL4LB機能を検証する課題に取り組んでもらいました。
  3. ストレージチーム
    • Necoが提供する分散ストレージの開発に参加してもらいました。

全体講義

まずは全員が以下の講義を受講しました。

  • Introduction to Kubernetes
    • Kubernetesの使い方の説明
  • つくって学ぶKubebuilder
    • Kubernetesコントローラの開発に欠かせないKubebuilderというツールの使い方を学ぶチュートリアル
  • 実践OSS
    • 企業がどういう意図で自社プロダクトをOSSとして公開しているか、また、既存のOSSの開発に参加しているのかについてサイボウズを具体例として説明

これによって、彼らはKubernetesのユーザ及び開発者としての基礎知識、およびNecoの開発におけるOSSの位置づけについて学びました。

この後は上述の3つのチームに分かれて作業をしました。以下、それぞれのチームについて紹介します。

コントローラチーム

Necoでは、GitHub Actionsのself-hosted runnerを管理するKubernetesコントローラmeowsを開発しています。 このチームでは、meowsを題材にKubernetesコントローラの機能追加に取り組んでもらいました。

コントローラチームでは、学生3名、社員2名の計5名で、リモートモブプログラミングを行いました。 チーム全員が常時Zoomで接続し、誰か1人の画面を共有しながらプログラミングを進めていきました。

実施したタスク

コントローラチームでは、KubernetesやKubernetesコントローラの仕組みを理解してもらうことを目的としていました。 また、開発を進めるにあたりmeowsの動作も理解してもらう必要があったため、次の5つのタスクを順番に取り組んでもらいました。

1 サポートするKubernetesのバージョンの追加

Kubernetesは、4ヶ月に1度の頻度で新しいバージョンがリリースされます。 それに合わせて、Necoで運用しているKubernetesクラスタも定期的にアップデートをしています。 近々、NecoのKubernetesクラスタをv1.21にバージョンアップするため、meowsでも必要な対応をしました。

今回は以下2点を行い、現行及びバージョンアップ後のKubernetesで動作することを確認しました。

  • Kubernetesライブラリのバージョンアップ
  • E2E(End to End)テストのKubernetesバージョンの追加
    • CIで複数バージョンのKubernetes(v1.20、v1.21)でテストを実施

このタスクで、リポジトリの構成や開発の進め方に慣れてもらいました。

2 不具合改修

meowsでは、Podをself-hosted runnerとして登録します(このPodのことをRunner podと呼びます)。 Runner podは、ジョブ終了後に削除されるのですが、デバッグ用にジョブ終了後もRunner podを延長する機能があります。 この機能に不具合があったため、調査及び改修をしてもらいました。

不具合調査や改修確認を行うことで、meowsのアーキテクチャや動作を理解してもらいました。

3 機能追加1: 作業ボリュームの指定

Runner podで使用する作業ディレクトリを、Kubernetes的な方法で指定できるようにしました。

このタスクでは、controller-runtimeを使ったコントローラの実装やテスト方法、 またOverlayFSの概要やKubernetesでのVolumeの指定方法を説明しました。

4 機能追加2: Runner podの補充

meowsは、複数のRunner podをプールして、常にジョブを実行できるようにしています。 ただし、複数のジョブが並行して実行されると、Runner podが枯渇する可能性があったため、 ジョブが割り当てられたら、すぐにRunner podを補充するようにしました。

実装の詳細は割愛しますが、このタスクを通じてKubernetesのDeploymentの仕組み (ReplicaSetとの関係やpod-template-hashラベル) について理解してもらいました。

5 Slack通知機能の改良

上記4つのタスクを通じて、Kubernetesやmeowsの動作を知ってもらったので、最後に学生主導で機能改修をしてもらいました。 インターン終盤で時間が限られる中、無事テストまで実装しタスクを完了できました。

これらのタスクを通じて、KubernetesやKubernetesコントローラの仕組みについて理解していただけたと思います。

Networkチーム

Networkチームでは、まずKubernetesクラスタのNetworkコンポーネントに慣れてもらうために、Calicoの不具合対応に取り組んでもらい、その後にCiliumを導入するPoCに取り組んでもらいました。

Calicoの不具合対応

NecoのクラスタではCalicoのNetwork Policy機能を利用していますが、下記の不具合を踏んでしまい、MySQL Operator MOCOが期待通りにSwitch Overオペレーションを実施できない問題が発生していました。
Nodeの再起動時にMySQL PodがEvictionされる際、PodはPreStop Hookで20秒間待機し、その間にMOCOがSwitch Overオペレーションを実施する、というのが期待動作なのですが、
実際にはPodにDeletionTimestampが付くと、CalicoがすぐにiptablesのRuleを破棄してしまい、MOCOがPodに接続できずにオペレーションができない状態になっていました。

github.com

問題の再現を確認し、Calico 3.20に更新して問題が発生しないことを確認、と一連の流れを体験してもらうことで、 Networkコンポーネントの構成や動作を理解してもらえたのではないかと思います。

Cilium導入のPoC

現在のNecoの環境ではLoadbalancer serviceの実装にMetalLBをBGP modeで利用しています。
こちらの制約にある通り、BGPベースのロードバランシングはステートレスであるため、バックエンドのサーバーが増減した場合に既存のTCPコネクションがrehashされて別のサーバーに送られてしまい、接続が切れてしまう問題があります。

この問題を回避するためにL4LB機能の導入を検討しているのですが、有力候補としてeBPFベースのNetworkingソフトウェアであるCiliumを考えています。
Ciliumのkube-proxy replacementを導入し、Maglev hashingによるロードバランシング機能を使うことで、L4LBをKubernetesクラスタに導入することを検討しています。

cilium.io

こちらの課題では、現在稼働しているCNIプラグイン Coilと組み合わせてCiliumを利用する想定でPoCを行いましたが、なかなかうまく動かず苦戦しました。
インターンの時間的制約もあるため、一旦Coilとの組み合わせはあきらめて、最終的にはCiliumのみでKubernetesクラスタを構築して、Loadbalancer serviceの疎通確認、hubbleによるトラフィックの可視化までを体験してもらいました。

実業務でのPoCを体験してもらうことで、どのように利用するソフトウェアを調査して導入を進めていくのかを学んでいただけたと思います。
また、CNIの設定やCiliumのコンポーネントやアーキテクチャも理解していただけたと思います。
今回のPoCによって得られた知見は今後のチームのタスクに役立つもので、すばらしい成果をあげてくれました。

ストレージチーム

ストレージチームには3人の学生たちが参加しました。このチームではNecoが提供する分散ストレージの開発をしてもらいました。分散ストレージにはRookCephを使っています。具体的には彼らは次の3つの課題に取り組みました。

  • Rook/Cephクラスタのディスク交換オペレーションの自動化
  • オブジェクトストレージのスケーラビリティに関する問題の解決
  • OSS開発体験

Rook/Cephクラスタのディスク交換オペレーションの自動化

Rook/Cephクラスタに組み込まれたディスクに故障などが発生した場合、当該ディスクをクラスタから削除して、かつ、別のディスクを組み込むというディスクの交換オペレーションをします。このオペレーションは数十行にわたるコマンドを手作業で発行していたのですが、これをスクリプトによって自動化しようというのが本課題です。

この課題では現状のオペレーションをbashスクリプト化しました。課題に取り組む前にあらかじめ手動で面倒なディスク交換を仮想データセンター上で体験してもらっていたこともあり、自動化による恩恵をうまく感じてもらえました。Necoのディスク交換オペレーションは近いうちに自動化スクリプトを使ったものに置き換えられる予定です。

オブジェクトストレージのスケーラビリティに関する問題の解決

Cephが提供するRGWというオブジェクトストレージはbucketごとにオブジェクトへのアクセスを高速化するためのbucket indexというしくみがあります。bucket内のオブジェクト数が増えるとオブジェクトへのアクセス速度劣化を防ぐためにbucket indexを再生成するbucket index reshardingという処理が自動的に動きます。

サイボウズでは以前、このbucket index resharding中にKubernetesのlivenessProbeというしくみによってRGWのPodが強制終了され続け、それがゆえにbucket index reshardingが終わらないという問題に遭遇しました。

github.com

この問題を実験環境で再現させるというのが本課題です。

残念ながらこの課題はインターン期間中に終了まではいかなかったのですが、再現させるのに必要そうな条件を大幅に絞り込めました。

この課題で一番良かったのは、みんなで議論してああでもないこうでもないと仮説を立てて、次にやることを決めていくことによってチームプレイを体験できたことだと思います。

課題そのものとは別に「そもそもRGWのlivenessProbeの設定がおかしいのでは」という話があって、こちらについてはdraft PRを投稿し、これをベースに他の開発者たちとの議論を開始しました。

github.com

現在はストレージチームのメンバーがこのタスクを引き継いで議論を継続中です。

なおbucket index reshardingの問題は先日Kubernetes Meetup Tokyo #44というイベントで発表したものです。興味のあるかたはごらんください。

k8sjp.connpass.com

speakerdeck.com

まさに今現場で困っている問題に取り組んだということで、実際の業務をしているという感覚を強く持ってもらえたのではないでしょうか。

OSS開発体験

Necoの開発においては、必要に応じて社外OSSの修正もします。この課題では、RookやCephに存在する問題を1人につき1つ修正してもらいました。最終的にはインターン期間中に3人全員のPRがマージされるという成果が得られました。

github.com

github.com

github.com

本課題によってコミュニティでの決まりやコードの修正方法,レビュワーとのコミュニケーション方法などを学びました。

Rookの2つの修正については、これらを含んだRookの最新版 v1.7.3が本日リリースされています。他にも社員が事前に課題の一つとして考えていた機能がインターンが始まったころに別の開発者によって実装されてしまうというアクシデント(?)も発生しました。ただし、前述のオブジェクトストレージの課題の中で学生たちが自らドキュメントバグを見つけてくれたことによって、それを修正するための別の課題(上記のCephのPR42928)ができたので事なきを得ました。これらによって、彼らにはOSS開発の醍醐味や速度感を味わってもらえたのではないかと思います。

まとめ

どのチームも時間が経つほど学生さんが自律的に行動する場面が目立つようになってきて、最終的には上述のようなすばらしい成果を出してくれました。今後の彼らの人生になんらかのプラスの影響を及ぼせたのであれば幸いです。

最後になりますが、Necoチームやストレージチームでは一緒に働いてくれるかたを募集中です。以下募集要項を見て興味を持ったかたはぜひご応募ください。 

cybozu.co.jp

cybozu.co.jp