kagoshima hackathon kiban

技術基盤チームが鹿児島オフィスで開発合宿を行いました

kagoshima hackathon kiban

執行役員 VP of Engineering 兼技術部長の @hsbt です。

私がマネージャを務める技術部 技術基盤チームのメンバー全員でペパボの鹿児島オフィスにて開発合宿を行ってきました。本エントリではペパボの技術基盤チームの開発合宿の成果を題材として、チームが今取り組んでいる開発項目についてご紹介します。

hsbt

私、@hsbt は GitHub Enterprise Server(以下、GHE)の SAML 対応の検証と、内部で利用しているメンバーの追加・削除の自動化スクリプトの cron job 化を行いました。

現在、ペパボの情報システムでは Directory Service として Miscrosoft の Active Directory (AD) を用いているものの、AD を社内システム横断の IdP として利用するまでに至っておらず、GHE や Slack などはコーポレートエンジニアリンググループ(CEG)のエンジニアによる手作業でアカウントの追加、停止などを行っています。将来的には IdP として利用している OneLogin と AD を同期し、さらにそこから OneLogin と SAML 認証によるアカウントの一元管理を行うべく開発計画を進めています。

今回、OneLogin を IdP として GHE を SAML 認証するとどのようにユーザーの認証フローが変わるのかをステージング環境を用いて検証を行いました。結論としては、以下の全てのケースにおいて、期待通りの動きになることを確認できたので、年内に SAML 認証に切り替えていく予定です。

  • GHE にアカウントがあり、IdP のメールアドレスのユーザ名が一致するユーザー
  • GHE にアカウントがあり、IdP のメールアドレスのユーザー名が一致しないユーザー
  • GHE にアカウントがないユーザー

SAML 認証を用いる場合、IdP のどのパラメータを用いてサービスのアカウントを識別するか、という点が一番の肝ですが GHE の SAML 認証はこの点が柔軟に設定可能である印象を受けました。

また、ペパボでは GHE の organization が事業部やサービスの商材ごとに作成する構造をとっており、30 以上の organization のアカウントやチームのメンテナンスをする必要があります。GHE を用いている組織の方ならわかるかもしれませんが、GitHub は複数の org をまたがって共通のアカウント権限を付与するという機能が弱く、隣のチームのコードや施策についてコメントをしたり、パッチを投げたりしたいということが気軽には行えません。

全てを public リポジトリとして利用することで、記載したような権限管理は不要となる面もありますが、organization の下のリポジトリの中には他の事業部のメンバーも見ても良い情報、見てはいけない情報が混在するため、ペパボでは原則として private でリポジトリを作成し、社員であれば誰でも見ても良い情報を public にするというホワイトリスト方式にしています。

GHE では private リポジトリを前提として使用する場合、organization のメンバーに所属していなければ、閲覧権限のリクエストも出すことができません。そのため、ペパボでは、入社時点で商材を扱っている organization についてはメンバーとして追加を行い、その後開発やディレクターなどのチームへの加入リクエストを行えるようにしています。

さて、前置きが長くなりましたが、今回の開発合宿では、この入社時にメンバーとして追加するという自動化スクリプトを CEG のメンバーが毎回手で実行しなくても自動で実行されるように、スクリプトを Docker コンテナ経由で実行できるようにし、heroku shckeduler で定期実行するようにしました。できれば社内で稼働させている k8s のクラスタで動かせればよかったのですが、時間が足りずにまずは自動化したいという課題を解決するだけの結果になってしまいました。

GHE をより効果的に扱うために引き続き周辺ツールについては開発を続けていきたいと思います。

pyama

こんにちは、チーム内で唯一の薩摩藩出身の pyama86でごわす。おいどんはペパボで広く利用されているPowerDNSをRoute53のようにヘルスチェックを行ったり、名前ベースのフェイルオーバーが可能になるようにする、いわゆる GSLB](Global Server Load Balancing))を開発していました。Pythonでは既に実装があったりするのですが、そんなに大きいものでもないので自分でGoで書いてしまうぞということで開発しました。

実装した内容としては以前から進めていた APIにエンドポイントを追加したのと、ヘルスチェックを行う Workerの実装が6割位終わりました。開発については9月末にペパボの開発合宿があるので継続して行う予定です。

技術選定としては、APIにはOpenAPIを採用し、クライアントコードの動的生成に対応しています。次にWorkerについてはRedisにキューイングし、それを go-workers で実装された、レジスタ、ワーカーが逐次処理するような実装にしています。

最終的にはkubernetes上でシュッと動くようなモデルを目指しているので今後の開発にご期待ください。

tnmt

技術基盤チーム 兼 技術部CTL の@tnmt です。最近見た映画は「ヴァイオレット・エヴァーガーデン 外伝 -永遠と自動手記人形-」です。2回泣きました。

昨年からペパボでもKubernetesの本格利用が始まり、本番環境では minne を皮切りに、各サービスでの導入が進んでいます。

ところでペパボでは、全社のサーバのセキュリティ監査の統合基盤として Wazuh を利用しています。Wazuh の導入の経緯や運用については拙スライドや、@pyamaのスライドをご覧いただくとして、全社横断のWazuh managerは現在、弊社のプライベートクラウド上に docker-compose で複数台VMからなるクラスタを構築しています。しかし、現状の構成では、Wazuhに必要なロール、例えばElasticsearchやKibanaなどが分離出来ておらず、1VM (= 1docker-compose)のメンテナンスが全てのロールに影響を及ぼすなど運用しづらい状況にありました。また、agentからのアクセスに対するロードバランシングなども、その場その場で設定してきたため見通しが悪く、構築に当たった tnmt, pyama86 しか構成が満足に分からないと言う問題もありました。

今回Wazuhを構成するロールの分離と、複雑な設定をより宣言的で分かりやすくするため、この全社用Wazuhクラスタを社内Kubernetes基盤に載せるべく、開発合宿期間中の新基盤構築に臨みました。

1日目は現行のWazuh on Kubernetesの実現方法について調べ、オフィシャルで提供されているwazuh/wazuh-kubernetesのmanifestを読むなどしていました。また、すでにあるk8sクラスタを利用するか、新規にクラスタを構築するかについて検討し、今後Wazuhと同じような全社基盤で且つ我々技術部で運用するものがより増えてくることが予想されることから、新規にクラスタを構築することを選び、udzuraと同じく社内k8sクラスタ構築用のツールのキャッチアップを行いました。1日目成果としては、ツールに必要な設定、例えば秘匿情報管理のためのVaultを利用するための設定を終え、検証用のクラスタの作成を行う目処まで立てました。

2日目の始めに検証用クラスタの作成を終え、いざwazuh/wazuh-kubernetesのデプロイとカスタマイズを行おうとしたところに、現行稼働しているWazuhクラスタの不具合を発見し、結局そのトラブルシューティングに一日を費やすことになりました。事象としては構成変更を行っていないにも関わらず、社内のWazuh agentが全てmanagerから切断されるという状況となっており、問題のありそうなmanager側のoss-remotedのデバッグや該当コードの調査を行っていました。調査の結果、WazuhをホストしているOpenStack VMのリソース不足の疑いが強くなったためVMのスケールアップを行いました。またElasticsearch側でもshardsの再配置に必要なメモリ割り当て不足のメッセージを発見したため、解決のためにJVMのヒープサイズの調整を行いました。しばらくWazuhクラスタの停止が伴っていたため、このタイミングでWazuh自体も現行の最新バージョンまでのバージョンアップを行いました。

2日目が十分に作業できず、結果現行のWazuhクラスタのメンテナンスで終わってはしまいましたが、今の構成での調査や対応の複雑さに疲弊したため、Kubernetes基盤への移行はあらためて有意義に感じています。引き続き現行のクラスタと並行して新クラスタの整備を進めていきます。

linyows

福岡で Netflixオリジナルの番長をしています、GoTypeScriptのコミュニティオーガナイザの@linyowsです。Netflixコンテンツを完全制覇のために眠れぬ日々を送っています。

さて、今回の合宿で私が取り組んだのは、クラウドのエッジロケーションにおけるWebAssemblyアプリの開発です(この表現だと作ったものに対してかなり大げさですが、最終的なゴールとしては正しいです)。WebAssemblyは、ネイティブコードによる高いパフォーマンスとサンドボックスによる安全性により、"ブラウザに拡張性をもたらしているWeb標準"である、というのが、私の理解です。しかし、今年の春に公開された、mozillaの Lin Clark氏による WebAssemblyをWeb外で実行させるためのインターフェース(WASI標準化)の記事を読んで、WebAssemblyはブラウザ外でも活用できるのだな!と、感銘をうけました。したがって、いくつかの自分のアイデアを実現すべく、サーベイを兼ねてこのような取り組みにしました。

クラウドのエッジというと通常CDNを思い浮かべるでしょう。CDNプロバイダで有名なFastlyは、mozillaのWASIのアナウンスに合わせて、CDN上のコンピューティング環境をWASIを使ったWebAssemblyで提供するために、LucetというWebAssemblyランタイムをOSSとして公開しています。このCDNコンピューティング環境は、まだ本展開されていませんが、Terrariumという名で、15分限定のコンピュートリソースが提供されています。

https://wasm.fastlylabs.com/

合宿成果としては、この Terrarium上に生成されたネィティブコードでGitHub上の画像を取得して返すというシンプルなものになります。WebAssemblyを生成するのは、以下のRustのコードです(こ、これだけです….🦀)。

#[macro_use]
extern crate http_guest;

use http_guest::{Request, Response, RequestExt};

pub fn user_entrypoint(_req: &Request<Vec<u8>>) -> Response<Vec<u8>> {
    let mut vec: Vec<u8> = Vec::new();
    let mut url = "https://raw.githubusercontent.com/linyows/rutouch-terrarium/master/misc/kagoshima.jpg";
    let req = Request::builder()
        .method("GET")
        .uri(url)
        .body(vec)
        .unwrap();
    RequestExt::send(req).expect("request failed")
}

guest_app!(user_entrypoint);

これを手元のMacにインストールした Lucetでやろうとすると以下のフローになります。

Rust — Rustc → WebAssembly — Lucetc → Native Code — Lucet Runtime → Executed

はい、少しややこしいですね。構成を図にするとこんな感じです。

terrarium

忘れてならないのは、WebAssemblyはコンピューティングリソースなので、ネットワークやファイルに対して何もできないのです。そこで、WebAssembly system interface: WASIが登場します。Terrarium では、SystemであるhostのCコードを呼び出すためのラッパーが http_guest というcrateで提供されているので、これを使って外部へhttpリクエストしています。Rustを使っていると、その他のcrateを使いたくなりますが、現状 http_guest依存に入るものしか使用できないようです。もし、どうしても必要であれば同梱するといける気がしています(未検証)。また、 std::fsを使ってローカルファイルをオープンしようとすると、operation not supported on wasm yetと怒られるようです。

terrarium-rutouch master 🏄 make
terrctl {src,assets}/**
[2019-09-10 01:24:20] [INFO] Preparing upload of directory [src/lib.rs]
[2019-09-10 01:24:20] [INFO] Guessed programming language: rust
[2019-09-10 01:24:20] [NOTICE] Upload in progress...
[2019-09-10 01:24:28] [NOTICE] Upload done, compilation in progress...
[2019-09-10 01:24:32] [INFO] Building...
[2019-09-10 01:24:35] [INFO] Generating machine code...
[2019-09-10 01:24:41] [INFO] Codegen complete...
[2019-09-10 01:24:44] [INFO] Deploy complete: https://learn-separate-soldier-giving.fastly-terrarium.com/
[2019-09-10 01:24:44] [INFO] Instance is deployed
[2019-09-10 01:24:50] [NOTICE] Instance is running and reachable over HTTPS
[2019-09-10 01:24:50] [NOTICE] New instance deployed at [https://learn-separate-soldier-giving.fastly-terrarium.com]

これらを、 Terrarium APIをCLIから実行できる terrctlを使ってUpload, Build, Deployが行われると、URLが発行されるので、そのURLにアクセスするとGitHubに配置した画像がCDN上のWebAssemblyランタイムから返えされます。

shiden

合宿先の路面電車がかわいい鹿児島中央駅前☝️

今回の成果は、最終的なゴールに対しての第一歩ではあります。そして、WebAssemblyはWeb内外で発展途上にあります。私たちは、このような新しい技術を積極的に使って、新しいサービスを生み出していきたいと考えていますので、引き続き、進捗があればご報告をさせていただきます。Yo

P.S. 今週末に福岡のRustコミュニティでこの話をもっと詳しくするので興味があれば参加してくれると嬉しいです。

udzura

技術基盤チーム @udzura です。普段は福岡勤務です。Fukuoka.rb#ふくばねてすなどのコミュニティにも携わっています。最近Duolingoでエメラルドリーグに進出できました。

私は今回、Kubernetesに関して、ロギングやパフォーマンス計測に関する調査とプロトタイプ作りを行いました。ペパボでは様々なサービスでKubernetesの検証や導入が始まっていますが、現実の運用となるとセキュリティ、アップデート、何よりエラーや監査、調査など様々な用途でのロギングが重要です。その基盤固めの一環としてログ・計測周りの足場固めをしました。

成果としては、まずは @r_takaishi と @pyama86 が事前に作ってくれた社内Kubernetes基盤(クラスタ作成ツール、ログ基盤)のキャッチアップを行い、検証用のクラスタとKafkaとGraylogを利用したログ連携を設定しました。その後、perf、eBPF、Sysdigといったパフォーマンス計測やトレーシングのツールを検証し、これらがコンテナ/Kubernetes環境においてはどのように利用できるかを確認しました。

特にperfに関しては比較的コンテナと利用しやすいのでないかという結論になりました。基本的には、計測したいターゲットに対して shareProcessNamespace: true となっているサイドカーコンテナを立てて、そのコンテナでperfを実行すればターゲットコンテナの情報が取得可能です。また、以下の記事にある通り、Kubernetesのadmission APIである MutatingWebhookConfiguration を用いてperfを実行するサイドカーをinjectするサンプルもあります。

一方でeBPFの場合は、eBPFでホストレベルで取れるProcess IDが、どのコンテナやPodに所属しているかという情報を別途用意する必要がありそうだとわかりました。eBPF自体は強力な機能ですが、もう少しKubernetesで使うエコシステムを注視する必要がありそうという感想です。

そしてこの開発合宿を通して、 kubectl exec を利用してコンテナの内部を作業をせざるを得ない時、少しだけ便利になるサイドカーコンテナ向けのツール pikebubbles をリリースしました。

これをcommandに指定したコンテナをサイドカーとして加えて、execでアタッチをすると、 /var/run/pikebubbles.fifo というFIFOファイルが作成されていることが分かります。その後、exec中に実行した全てのコマンドの標準出力・標準エラー出力をそのFIFOにリダイレクトすれば、結果的にサイドカーコンテナ自体の標準出力にフォワードできます。execでのコマンド出力をコンテナとして標準的な方法でログに残すことができるという仕組みです。

たとえばpikebubblesサイドカーを shareProcessNamespace: true にしておけば、このサイドカーに対してexecを経由してperfコマンドをガチャガチャと実行し、それをそのままコンテナ自体のログに残し、Graylogで確認したりs3に永続化したりする仕組みが作れます。

コンテナのログや監査、トレーシングは引き続き取り組みたいところです。今回はSysdigについては導入レベルしか触れられなかったので、引き続きご報告できればと思います。

r_takaishi

こんにちは、@r_takaishiです。最近はペパボが運用しているプライベートクラウド上でKubernetesを動かすため、あれこれとコードを書いています。さて、今回の合宿では、Kubernetesのノード管理を効率化するためのコントローラー開発を行いました。ペパボではプライベートクラウド上にKubernetesを構築・運用するために独自ツールを用いているのですが、ノードの管理があまり効率的ではないという課題がありました。例えば、全ノードに対して何か更新を行う場合、1ノードずつDrain&CordonしてAnsibleで更新し、Uncordonしていました。数台なら問題ないのですが、ノードが数十台規模になってくると非常に時間がかかり、非効率だったわけです。この課題を解決すべく、ノードを管理するKubernetesのカスタムコントローラーを書いたわけです。

カスタムコントローラーを書いた、とは言っても全て自分で書いたわけではありません。ClusterAPIというKubernetesクラスターを管理するためのAPIがsig-cluster-lifecycleのサブプロジェクトとして存在しています。いろいろ調べた結果、このClusterAPIの仕組みを用いるのが良いと判断し、ClusterAPI用の独自プロバイダーを実装した、というのが主な内容です。

なぜClusterAPIの仕組みを用いたかというと、ノード用のインスタンスを扱うMachineリソース、Machineを複数扱うMachineSetリソース、MachineSetのデプロイを扱うMachineDeploymentがClusterAPI本体に存在しており、後はペパボのプライベートクラウドに合わせた実装を行えばよかったからです。また、ClusterAPIはCluster自体を管理する機能も持ちますが、今回はノードだけを管理したかったので必要なコントローラーだけを呼び出す形で実装しました。

さらには、これまで使ってきたクラスター管理ツールであるNKEとの連携部分の実装も行いました。これまではNKE側でノードの管理を行っていたので、その部分をカスタムリソースを作成してコントローラーと連携するように書き換えるということをしました。

最終的には、時間切れで実装できなかった機能が残ってはいるものの既存ツールのNKEから利用でき、Kubernetesのノード作成・スケールアウト・スケールイン・ローリングロールアウトなどが行えるところまで進めることができました。今後は未実装の部分を実装し、本番への導入に向けて試験などを行っていく予定です。また、Cluster APIについてもいろいろ調査したので、整理して別途アウトプットする予定です。

まとめ

技術基盤チームメンバー

以上、6名それぞれが開発した内容について紹介しました。技術基盤チームは、特定の事業部に所属することなく、ペパボのサービスが稼働しているプラットフォーム、社内の情報システムやモニタリングシステムの設計や構築を行う横断組織です。今回、紹介した開発の内容はペパボが今後重視していく技術スタックの一部にはなりますが、記載しているような領域について一緒に取り組んでいくエンジニアを随時募集しています。一緒におもしろい技術にチャレンジしていきましょう。