Push型のデプロイ

macopy氏:というわけで、(ここまで)アーキテクチャやプログラミングインターフェイスに関してデプロイの技術を紹介してきましたが、ここからはサーバーへの反映方法について紹介しようと思います。

今までずっとFTPをやっていましたが、FTPの説明をしていないですよね。ですが、まぁ(先ほどデモを)やったからいいかなと思っていて。(FTPを)使ってデプロイしていたのでとりあえず省略。ああいう感じでファイルをそのままピュッと上げるインターフェイスです。

2023年の時点では、生FTPでなにかファイルを上げるのはやめましょう。ちなみにこれ(今回のセッションのデモ)はTailscaleでVPNを張っているから大丈夫です。

FTPもPushの1つなんですが、Push型のデプロイをやっていきます。

(スライドを示して)これはすごく単純な……。「図は要るのか」みたいな感じなんですが(笑)。オペレーション用の端末、手元の端末とかをデプロイする君(デプロイを行う専用のインスタンスなどを指す)ようなところから、サーバーに対してプログラムをアップロードします。

アップロードの手段は、rsyncだったりFTPだったりSCPだったりといっぱいあります。その後にプロビジョニングしてデプロイというかたちになるんですが、複数のファイルを一気にアップロードするとなると、tarballに固めて、その先のほうで展開するとか、例えばアトミックに更新したいからrenameを使うとか、そういう細かいテクニックがいろいろあります。

というわけで、PSGIをPush型デプロイをします。まずデプロイスクリプトがあります。普通にrsyncした後にprovision.sh、リモートのprovision.shを実行します。

shは何をやっているかというと、この頃になるとレンタルサーバーというかたちじゃなくて、依存モジュール、Shebangモジュールをバリバリ使った開発になっているので、最新型ですがCarmelを使っています。ここでcarmel installをした後に、systemctl reload plackup.serviceをしている。

中ではstart serverで動いているプロセスがあるので、plackup.serviceに対してSIGHUPを送ってgraceful restartを行っています。ちょっと早口ですが、すみません。

じゃあやってみましょう。(画面を示して)ちなみにもうデプロイはされているので、こんな感じになっていますね。これでサーブされています。

これをデプロイしたことがわかるように書き換えてみましょう。app/app.psgiにHello Plack with rsync from KRPと入れます。

という感じで入れて、デプロイします。(画面を示して)こんな感じでデプロイされました。

carmel installをしているのでこんな画面が出ます。「デプロイされましたよ」という感じで、見てみましょうか。デプロイされました。

(会場拍手)

ただ、Push型デプロイには難点があります。この頃になるとサーバーの数が多くなりました。CGIの時はレンタルサーバーは当然1台だし、冗長性を確保しても2台とかの世界だったのが、どんどん冗長化したり、大量のリクエストをさばくという要件に合わせて増え始めた。

すると、アップロードするとか、そういうPush型のネットワークのリソースが律速化して、デプロイ速度が遅くなってしまう問題が出てくる。

さらにこの頃になると、今度はパブリッククラウドの普及で台数が可変になっているんですよね。だから「今どのサーバーが生きているか」を知る必要があった。知るのはいいんだけれど、「デプロイしている途中に変わったらどうするの?」とか、そういう問題も出てくる。なのでPush型デプロイは、オートスケールの環境とかで動かすことがけっこう大変になってきた。

Pull型デプロイという提案

というわけで、Pull型デプロイという提案が出てくるわけです。Pull型デプロイ、複雑になりましたね(笑)。

まず、オブジェクトストレージがこのあたり(の時期)で出てきます。S3とかそういうやつです。端末からtarballをWebアプリで固めた後に、オブジェクトストレージにアップロードします。

その後になんらかの方法……。ここでよくConsulだったりSerfというオーケストレータが使われたりするんですが、(それらが)デプロイの号令をしてあげる。サーバー1、サーバー2、サーバー3。そのほかにもいろいろあったりしますが、自律的にオブジェクトストレージからtarballや設定ファイルをPullしてきて、再起動を行う仕組みがPull型デプロイだったんですね。なので、何台に増えてもオペレーション端末のリソースで律速されるということは別にないということです。

というわけで、「stretcher」というツールがあるので、それを使ったPush型のデプロイをしていきます。stretcherは、藤原さんが作ったので……。弊社カヤックではConsulとかがよく使われていたんですけど。

1台だとConsulクラスタがうまく作れなかったので、ここではncでstgに突っ込んで返すという、ふだんではやらないようなことをやってみます。

stretcherに入った標準入力でmanifestファイルが入るようになったので、ここからデプロイを行います。rsync pushのほうは……。なんて名前だったっけ。ど忘れしちゃいましたね。stretcher-pullですね。

複雑になりました。tarballに固めます。app以下をtarballに固めて、ストレージとみなして検証サーバー……。これもサボっていますが、サーバーにtarballをアップロードします。

checksumの計算をしてあげて、checksumをmanifestのファイルの中に埋め込みます。envsubstという環境変数を使ってテンプレートをレンダリングするみたいなコマンドがあるので、manifestファイルを作ってあげて。

manifestファイルもオブジェクトストレージみたいなところにアップロードする。その後にstretcherにデプロイして、ncを介して突っ込む。「manifestはこれだよ」というふうに突っ込んだ上でデプロイを行っています。

デプロイの指令自体はサーバーのリスタート、直接はキックしていません。ただ、stretcherでシェルスクリプトが実行されて、ダウンロードが成功した後、展開が成功した後に、自律的に再起動を行うかたちになっています。

じゃあデプロイしてみましょう。下がローカルで上がリモートです。来ました、プロビジョニング。あっ、もうデプロイに入りましたね。速い(笑)。デプロイはされました。

これで変わるかな。はい、stretcherに変わりました。こんな感じですね。

(次回につづく)