Cloud Penguins

Flying pengiuns in the cloud.

ここらでひとつCFの昔話をしながら変遷を振り返る(その2)

Cloud Foundry Advent Calendar 2017の11日目

前回に引き続きCFの昔話を。

言語

現在のCFはほとんどがGoで書かれていますが、CFv1はRubyで書かれていました。CFv2も当初はRubyで書かれていましたが、徐々にGoに書き換えられていきました。

現在Rubyが残っているのはCloud Controllerくらいでしょうか。なおUAAに関しては出た当初から今に至るまでJavaで書かれています。おそらくSpring Securityを使いたかったからかと思われます。

Router

現在はGoで書かれたGorouterが使われていますが、CFv1からCFv2の初期に使われていたRouterは、Nginx+Lua+Rubyという構成でした。

github.com

NATS経由でのルーティング情報のやりとりはRubyで書かかれたアプリケーションが担い、実際にトラフィックを捌くのはNginx+Luaという仕組みです。 枯れているNginxを利用しているだけあってパフォーマンスは悪くなく、Gorouterの登場当初は旧Routerよりも速いというのが公式の見解でしたが、実際には旧Routerのほうがパフォーマンスが良いというケースもしばしばありました。

CLI

CFv1はcfコマンドではなく、vmcコマンドというものを使っていました。

vmcコマンドはRubyで書かれており、利用するにはまずRuby環境をととのえ、その上でgem install vmcを行う必要がありました。今みたいにGolangで書いて1バイナリで配布なんてことが出来なかった時代です。

現在でもRubygems.orgに残っており、インストールできます。(といっても使い道はないですが)

vmc | RubyGems.org | your community gem host

最終バージョンは0.5.1となっていますが、0.5系や0.4系は非常に不安定であり、かつUAA導入の過渡期でもあったため、利用できない環境が数多く存在しました。

CFv1利用者の中では「CFを使うならvmc 0.3.23を使え」が合い言葉であり、結局CFv1終焉まで0.3.23が利用され続けました。

vmc tunnel

vmcコマンドでユニークなものとしては、vmc tunnel コマンドが挙げられます。 vmc tunnelコマンドを打つとCF上にcaldecottと呼ばれるアプリがデプロイされ、caldecottとvmcコマンド間でトンネルが張られ、サービス(MySQLやPostgres)にコマンドを打ったりdumpしたり出来ました。

なぜか当時は存在しなかったはずのPivotalのサイトにblog記事が残っていました。 Now You Can Tunnel into Any Cloud Foundry Data Service

$ vmc tunnel postgresql-12345

Trying to deploy Application: 'caldecott'.
    Create a password: 

Uploading Application:
 Checking for available resources: OK
 Processing resources: OK
 Packing application: OK
 Uploading (1K): OK
Push Status: OK
Binding Service [postgresql-12345]: OK
Staging Application: OK
Starting Application: OK
Getting tunnel connection info: .OK

Service connection info:
 username : ua76003139485469989d57b22f9cb83xx
 password : p8214ebd2a7254698913e01c86a4432xx
 name : da281fa2162f947028876d0500ae31cxx

Starting tunnel to postgresql-12345 on port 10000.
1: none
2: psql
What client would you like to start?: 2
Launching 'PGPASSWORD='p8214ebd2a7254698913e01c86a4432xx' psql -h localhost -p 10001 -d da281fa2162f947028876d0500ae31cxx -U ua76003139485469989d57b22f9cb83xx -w'

psql (9.0.4)
Type "help" for help.
da281fa2162f947028876d0500ae31cxx=> d
                     List of relations
 Schema | Name  | Type  |               Owner
--------+-------+-------+-----------------------------------
 public | hotel | table | ua76003139485469989d57b22f9cb83xx

da281fa2162f947028876d0500ae31cxx> select * from hotel;
  1 | 3555 S. Ocean Drive                    | Hollywood           | USA           | Westin Diplomat                | 199.00 | FL        | 33019
  2 | 890 Palm Bay Rd NE                     | Palm Bay            | USA           | Jameson Inn                    |  60.00 | FL        | 32905
  3 | The Cottage, Southampton Business Park | Southampton         | UK            | Chilworth Manor                | 199.00 | Hants     | SO16 7JF

結構便利じゃないですか?これ。

vmcコマンドからサービスに直接psqlコマンド叩きにいけるんですよ。

CFv2に移行して一番不便に感じたのが、この機能が無いことでした。初期のCFv2はcf sshコマンドも無かったため、v1で出来たこのあたりの操作を行う代替案が限られていたんですよね。

CFv1のデプロイ方法からBOSHに至るまで

現在はCFといえばBOSH、BOSHといえばCFというくらい重要な存在になっていますが、BOSHはCFv1の開発と運用の結果、既存の仕組みでは運用に耐えられないということで開発されたものです。つまり、CFv1はBOSHじゃない別の仕組みを使っていたというわけです。

CFv1は、dev_setupというchef-soloを利用した仕組みでデプロイを行っていました。

github.com

chef-soloですのでそのままでは複数台構成にできません。そこで、CFを構築する人たちはcapistranoなどを使ってdev_setupを各ノードに送り込み、コンポーネントごとの設定ファイルを食わせてchef-soloを実行していました。

d.hatena.ne.jp

しかしこの運用はほんとうにツライものでした。

https://github.com/cloudfoundry-attic/vcap/blob/master/dev_setup/cookbooks/python/recipes/default.rb#L9-L11

たとえばChefのcookbook読むとこんな書き方が普通に行われています。

%w[ python-dev python-setuptools ].each do |pkg|
  package pkg
end

aptのリポジトリからpython-devやpython-setuptoolsが落とされてくるわけですが、何が起きるかというと「セットアップを流した時点での最新版が入る」わけです。つまり、昔構築した環境と、新しい環境では異なったバージョンがセットアップされている可能性が高い。

「でも、それが何か? 多少バージョン異なっても問題ないでしょ?」 って思われるかもしれません。でもそれは甘い。

https://github.com/cloudfoundry-attic/vcap/tree/master/dev_setup/cookbooks

これだけのCookbookがあり、それぞれのライブラリが複雑な依存関係を持っている。こうなると、結構高い頻度で依存関係のエラーが起きるんですよね。エラーでセットアップが止まってしまうのもツライし、その後原因特定もツライ。複雑に絡み合った依存関係の中から原因となっているパッケージとバージョンを切り分けて、問題が起きないように修正するという作業は、何も価値を生まない割には時間ばっかり消費する、できれば二度と経験したくないものでした。

BOSHはこういうトラブルが起きないよう、考え抜かれた仕組みになっています。

BOSHは導入の敷居が高く、あまり好ましく思わない人も多いのですが、じゃあたとえば同じ運用をChefでなくAnsibleでやれば上手くいくか?となると、おそらくダメでしょう。Chefの二の舞になって死ぬのが目に見えています。このあたりの運用を経験しないと、なかなかBOSHの良さって理解されないんですよね・・・。

Serviceの仕組み

CFはv1の頃から、今と変わらないServiceの仕組みを備えていました。

vmc create-service vmc bind-service vmc delete-service

一緒ですね。

しかしバックエンドの仕組みは微妙に異なりました。

ozalog.blogspot.jp

Cloud Controllerからのリクエストを受け取るService Proxyと、実際のバックエンドサービスがデプロイされているService Nodeに分かれており、Service ProxyとNode間はNATSで通信を行っていました。

現在のCFで利用されているService Brokerの考え方は、このService Proxyをより汎用的にAPI化したものです。Brokerがどういった形でバックエンドサービスをプロビジョニングするかは定義されおらず、好きに実装してくれというのが今の形です。

CF側でServiceを提供することしか考えられていなかったv1に対し、サードパーティーの提供するServiceも幅広くサポートしようという、エコシステムを意識して発展させた仕組みが現在のService Brokerといえるでしょう。

日本のコミュニティの誕生と今について

日本では2011/10/18に第1回 Cloud Foundry輪読会が開催されています。 当時CFの採用を検討していたNTTや楽天、富士通といった会社のメンバーが中心になっていますね。

atnd.org

また、2012年2月にはNTTをはじめ数社で日本Cloud Foundryグループが設立されています。

www.ntt.co.jp

ビジネス的な色合いの強い日本Cloud Foundryグループと、コードリーディングというディープ志向のCF輪読会。いきなりコミュニティの分断が起きてしまい、一体感を持った盛り上げ方が上手くいかなかったなーというのは振り返っても感じます。

その後日本Cloud Foundryグループは引き続き活動を続けており、関係するメンバーでCloud Foundry Tokyo meetupというものもやっています。

Cloud Foundry輪読会は、その後PaaS勉強会と名前を変え、今でも続いています。

2018年はCloud Foundry Container Runtimeの登場により、Cloud Foundryがカバーする範囲も大きく変わってきます。再度Cloud Foundryのコミュニティを活性化するよう、いろいろ活動していきたいなあと考える今日この頃です。