このブログの記事投稿画面で、画像をコピー・アンド・ペーストでアップロードできるようにした。以前、ドラッグ・アンド・ドロップではアップロードできるようにしていたが、 GitHub や Kibela ではコピー・アンド・ペーストでアップロードできるようになっておりはちゃめちゃに便利だったので真似してみた。こんな感じ。
ハイパー便利。
このブログの記事投稿画面で、画像をコピー・アンド・ペーストでアップロードできるようにした。以前、ドラッグ・アンド・ドロップではアップロードできるようにしていたが、 GitHub や Kibela ではコピー・アンド・ペーストでアップロードできるようになっておりはちゃめちゃに便利だったので真似してみた。こんな感じ。
ハイパー便利。
この記事は CircleCI Advent Calendar 2018 19 日目の記事ですが間に合わず一日遅れて書いております。すんません 🙇🏻
CircleCI を使った Rails アプリのデプロイフローみたいな話を書こうかなと思ったのですが、すでに他の方が書いてる内容とかぶりそうだし、自分自身ブログに過去何回も書いた話なんで今回はエモ方面の話を書くことにします。技術的な情報はないのでそっち方面を期待している方はすんません。
いまの職場で働き始めて 1 年半なんですが、当初は CI はなく、テストコードもありませんでした。いまはそこで当たり前のように CI が回り、テストのカバレッジもまぁまぁ高く、デプロイは CircleCI 経由でじゃんじゃん行われるような状況となっております。新しく会社に入った人も GitHub の Organization に入ってもらえたらその瞬間から deploy 実行できます。具体的な話は昔書いてますのでよかったらご覧下さい。
8 年くらい前の自分はどうやったら CI だとか自動デプロイだとかできるようになるのか皆目見当が付きませんでした。いま 8 年前の自分と同じような状況にいる人(回りにテストを書く習慣を持つ人がいない人、 CI 動かすためにどうすればよいかわからない人)に何か言いたいと思い筆をとりました。
まずは何はなくとも頑張って一つテストケースを書いてみましょう。最初からカバレッジ 100% とか目指さなくてもよいです。どれか一つ、テストが書きやすそうなコードを見つけてテストを書き、ローカルで実行してテストがパスするのを確認しましょう。テストファーストとかも最初から目指さなくてよいです。
手元でテストが通ることを確認したら、 CI 環境でもテストを実行できるようにしましょう。
昔は Jenkins しか選択肢がなく、 Jenkins が動く環境をセットアップする(サーバーを調達する、 VPS を借りてもらう、などなど)に社内調整が必要でしたが、 CircleCI ならプライベートリポジトリでも 1 プロセスなら無料で使えますので社内調整が非常に楽です(外部にコード出してはダメな職場だと厳しいですね…)。
最初にプロジェクトを追加して言語を選ぶと設定ファイルが自動生成されるので、それをコピペして .circleci/config.yml
として保存し、リポジトリにコミットするだけでとりあえずビルドが実行されるようになります。
昔は難しかった CI 環境構築のうち、お金の問題、設定の難しさの問題を CircleCI は解決してくれます。あとはあなたが頑張るだけです。
CircleCI ならビルド終了ごとに結果を Slack などチャットシステムに通知させることができます。まずはテストケースが一つでもよいのでリポジトリへの push をトリガーにビルドが実行されたら結果を Slack に通知してみましょう。
リポジトリに GitHub を使っているなら Pull Request にビルド結果が表示されるようになるはずです。
これらで「なんかようわからんけどやっとる感」を出していきましょう。
そして過去のコードのことは一旦無視して、あなたが新しく追加する部分に関してはテストコードをセットで書くようにしていきましょう。あなたがコードレビューを依頼するときには必ずテストがグリーンな状態で依頼するようにするのです。
そうこうしているうちに他の人が出した Pull Request でテストが失敗するケースが発生します。 Slack の #circleci
チャンネルに赤色の Failure 通知が届き社内が騒然とするかもしれません。しかしこれはチャンスです。
「よかった、これでバグが未然に防げましたね」
あなたのこの一言でテストや CI がもたらす開発効率の向上がチームの皆さんに伝わるはずです。こうなったらもう一押しです。あなたがテストと CI の伝道師になりましょう。テストを書くことが当たり前になってきたら、 CircleCI からの deploy や定型処理を CircleCI でやらせるような使い方にチャレンジしていきましょう。どんどん周囲を巻き込んで、 CI 文化を定着させていって下さい。
何はともあれ、最初は一つのテストコードを書くことから始まります。変更に強いコードを書いてじゃんじゃん deploy し、じゃんじゃん Money making していきましょう🤑
ジョブキューイングシステムをどうするかでチームのリーダーとやりあって考えたことがあるのでまとめておく。
Rails で使うジョブキューイングシステムの技術選定で、リーダーは Amazon SQS 推し(レガシーシステムで SQS を使っている)、自分は Sidekiq 推しだった。前職時代に Sidekiq を使ってトラブルに遭遇したことはなかったし、とても簡単に使えるので Sidekiq で十分だと思っていた。 Sidekiq は GitHub でのスター数は 9000 オーバーで、 Rails の ActiveJob バックエンドとしては事実上のデファクトスタンダードだといえると思う。ググれば情報がいっぱい出てくるし、チームメンバーもリーダー以外は全員 Sidekiq の使用経験があった。
リーダーが Sidekiq に反対する理由は以下だった。
一方で自分が SQS に反対した理由は以下。
このような議論を経て、結局ジョブキューイングシステムには RabbitMQ を使うことになった。 RabbitMQ はリーダーが求める三つの要件を満たすし、オープンソースなので自分が SQS に反対する理由にも抵触しない。開発環境では Docker で RabbitMQ を動かし、 production では AWS にフルマネージドの RabbitMQ サービスはないので( ActiveMQ のマネージドサービス、 Amazon MQ というのはある)、 RabbitMQ の運用に特化した SaaS を利用することにした。
SQS に対する考えを整理する上で The Twelve-Factor App を改めて読んだが非常に参考になった。特に以下の三つの部分について、 SQS は Twelve-Factor App に反しており使うべきではないと思った。
II. 依存関係
アプリケーションが将来に渡って実行され得るすべてのシステムに存在するかどうか、あるいは将来のシステムでこのアプリケーションと互換性のあるバージョンが見つかるかどうかについては何の保証もない。アプリケーションがシステムツールを必要とするならば、そのツールをアプリケーションに組み込むべきである。
IV. バックエンドサービス
Twelve-Factor Appのコードは、ローカルサービスとサードパーティサービスを区別しない。アプリケーションにとっては、どちらもアタッチされたリソースであり、設定に格納されたURLやその他のロケーター、認証情報でアクセスする。Twelve-Factor Appのデプロイは、アプリケーションのコードに変更を加えることなく、ローカルで管理されるMySQLデータベースをサードパーティに管理されるサービス(Amazon RDSなど)に切り替えることができるべきである。同様に、ローカルのSMTPサーバーも、コードを変更することなくサードパーティのSMTPサービス(Postmarkなど)に切り替えることができるべきである。どちらの場合も、変更が必要なのは設定の中のリソースハンドルのみである。
X. 開発/本番一致
Twelve-Factor Appでは、継続的デプロイしやすいよう開発環境と本番環境のギャップを小さく保つ。
たとえ理論的にはアダプターがバックエンドサービスの違いをすべて抽象化してくれるとしても、 Twelve-Factorの開発者は、開発と本番の間で異なるバックエンドサービスを使いたくなる衝動に抵抗する。 バックエンドサービスの違いは、わずかな非互換性が顕在化し、開発環境やステージング環境では正常に動作してテストも通過するコードが本番環境でエラーを起こす事態を招くことを意味する。この種のエラーは継続的デプロイを妨げる摩擦を生む。この摩擦とそれに伴って継続的デプロイが妨げられることのコストは、アプリケーションのライフサイクルに渡ってトータルで考えると非常に高くつく。
AWS の技術がどんなに優れていたとしても、自分はオープンソースではない AWS 独自のプロプライエタリな技術に依存してアプリケーションを作りたい訳ではない。運用の煩雑さ・手間から解放されたい、スケーラビリティを提供してほしい、というのが AWS に期待するところだ。 SQS はアプリケーションのソースコードの中に入り込んでくる。開発環境ではローカルの PostgreSQL 、 production では RDS の PostgreSQL インスタンスに接続先を変えるだけ、という風にプラガブルに切り替えることができない。開発効率性や移行可能性(ほかの IaaS に移ることができるか)を考えると、運用の効率性に特化して AWS を使いたいと思った。 Redshift とか DynamoDB とか Kinesis とか AWS の技術でしか実現できないことをやりたいときに手を出すのは悪くないと思うけど、AWS が提供するものなら何でも素晴らしいからすぐに飛びつくというのは間違っていると思う。
ちなみに CircleCI との距離の取り方はうまくいってると思う。いま deploy を CircleCI から行なっているが、 CircleCI が止まると deploy できなくなるのは困るので deploy 処理自体はシェルスクリプト化してある(👺 Hubot で Slack から AWS ECS にデプロイ)。 CircleCI が死んだら手元から deploy コマンドを実行するだけでよい。 CircleCI にやってもらっているのは、人間が手でも実行できることの自動化の部分だけだ。 CircleCI というサービスが終了したとしても恐らく簡単にほかのサービスに乗り換えられる。
まとめると、 IaaS / SaaS / PaaS を使う場合は以下に気をつけるべきだと思う。
ヒトデさんの以下のツイートを目にして便利そうだと思ったので fish + peco + vim でやってみることにした。
VSCodeの下にくっついてるターミナルで git ls-files | peco | xargs code とかやってファイルを開くと快適にファイルを探せて便利
— 趣味はマリンスポーツです (@hitode909) June 20, 2018
以下のような fish 関数を追加した上でショートカットキーを bind しておいた。
function peco_gitlsfiles_vim
git ls-files | peco --query "$LBUFFER" | read selected
if [ $selected ]
vim $selected
end
end
function fish_user_key_bindings
fish_vi_key_bindings
bind \cg\cv peco_gitlsfiles_vim
bind -M insert \cg\cv peco_gitlsfiles_vim
end
これまで一旦 vim を閉じてしまうとファイルを開きたいときには vim .
して Unite で調べててたけど、いきなり git ls-files
して peco
して絞り込めるようになってとても便利になった。
Lokka の wysiwyg エディターは jQuery ベースの jwysiwyg といつやつが採用されている。
しかしここ最近はメンテナンスされてなくて、最近の Chrome では利用できない状況だったりする。以前、ファイルアップロード機能を付けたときも jwysiwyg の不具合が原因で wysiwyg モードでの画像アップロードは断念した。
最近のモダンな wysiwyg はどんなのがあるんだろうと調べてみたら Quill ってのが GitHub で 18000 くらいスター付いてて良さそうだった。
ちょっと試してみたところ wysiwyg で画像のアップロードもできるようになったので jwysiwyg からこいつに置き換えるのも悪くはなさそう。
ただ Quill は擬似 textarea なので実際の form には対応していない。 SPA で利用されることが想定されており、 Ajax 前提なつくりとなっている。サーバーサイドで HTML をレンダリングする昔ながらのウェブアプリで使うには一手間必要そうだった( form の onsubmit で texarea を createElement して Quill で入力したデータをぶっこむなど)。
Pull Request 出した。
↑の Pull Request 、 Merge されたんで Lokka の wysiwyg エディターは Quill となりました。
↑の記事を読んで tmux でウィンドウを上下分割して、上でコード書いて下でテスト実行したりするの便利そうだなと思ってまねしてみてる。とてもよい。
ただ分割比を調整するために毎回何度かキー入力が発生するのがいまいちだなと思っていた。 tmux のセッションを開始するときにしかこのコマンドを実行することがないので面倒だなと思いながら都度手動で調整していた。
しかし tmux には select-layout
という機能があって、 Control
+b + Alt+1 とか入力するといい感じに pane を配置し直してくれることを思い出した。上下分割は C-b + M-3 に main-horizontal
というスタイルが割り当てられており、上の pane をメインにして上下分割してくれる。このとき main-pane-height
という設定項目に任意の値を設定しておくと分割した pane の高さを指定できるようだった。デフォルトだとメインの pane の高さは小さめなので自分は set-window-option -g main-pane-height 60
にしておいた。これで tmux を起動してウィンドウを水平分割したあと C-b + M-3 とやるだけで 8:2 くらいで二つの pane に水平分割されるようになった。ちなみに左右で分割したときの値を調整したい場合は set-window-option -g main-pane-width 230
などとしておけばよい。便利。
GW 中、十分インスタンスを用意しておいたが想定を超えるアクセスがあって負荷が高まり、 Alert が飛んでくる事態となった。車を運転中に iPhone をカーステにつないでいたところ Slack がピコピコ鳴り、嫁さんから「休みなのか仕事なのかハッキリしろ!」と言われたので Alert が上がらないようにオートスケールを仕込むことにした。 いみゅーたぶるいんふらすとらくちゃー諸兄からしたら「そんなの常識じゃん」みたいな話ばかりだけど、自分でやってみて得られた知見をまとめておきます。
なおここで言っているのは EC2 インスタンスのオートスケール( EC2 Auto Scaling )であり、 AWS の様々なリソースを包括的にオートスケールする AWS Auto Scaling とは異なります。
オートスケールしてきたインスタンスだけコードが古いとエラーが発生する。
Auto Scaling Group のインスタンスは Stop ではなく Terminate されるため、インスタンス破棄後もログを参照できるように S3 に上げるとかして永続化させる必要がある。 Fluentd や CloudWatch Logs に集約するのでも良い。
オートスケール対象のアプリケーションは枯れていて今更新しいミドルウェアが追加されたりすることはなくてソースコードを git clone してくるだけで十分なのだが、 Gemfile に変更があった場合を想定して少しでもサービスインを早めるため( bundle install を一瞬で終わらせるため)、 master ブランチへの変更が行われなくなる定時間際のタイミングで Packer でビルドして AMI にプッシュするようにしている。
AMI のプッシュが成功したら最新の AMI を利用する Launch Configuration を作成し、 Auto Scaling Group も最新の Launch Configuration を参照するように変更する。 AWS CLI でできるので自動化してある。
Auto Scaling Policy を決め( CPU 使用率が一定水準を超えたらとか、 Load Balancer へのリクエスト数が一定以上になったらとか)、時間指定で Desired Count や Minimum Count を指定したければ Schedule をいい感じに組む。 AWS Management Console 上でポチポチするだけでよい。
当初は Auto Scaling Group のインスタンスには deploy を行わない(業務時間中はオートスケールしない、夜間と土日だけオートスケールさせる)つもりだった。
しかしメトリクスを確認すると朝の通勤時間帯や平日の昼休み時間帯などにもアクセス数が多いことがわかったので一日中 Auto Scaling Group インスタンスを稼働させることにした。となると deploy 対象が動的に増減する、ということなので Capistrano の deploy 対象もいい感じに調整しないといけない。 AWS SDK Ruby で稼働中の EC2 インスタンスの情報はわかるので、 deploy 時には動的に deploy 対象を判定するようにした。
本当は push 型 deploy をやめて pull 型 deploy にするのがナウでヤングなのだろうが、レガシーアプリケーションに対してそこまでやるのは割に合わない。そのうちコンテナで動くもっとナウでヤングなやつに置き換えるのでこういう雑な対応でお茶を濁すことにした。
冒頭に書いているけどあくまで上記は EC2 インスタンスの Auto Scaling であり、周辺のミドルウェアは Scaling されない。例えば RDS を使っていたとして、 RDS インスタンスの方は拡張されないので Connection 数が頭打ちになったり、 CPU を使うクエリが沢山流れたりしたらそこがボトルネックになって障害になってしまう。周辺ミドルウェア、インフラ構成に余力を持たせた状態で行う必要がある場合は AWS Auto Scaling の方を使うことになると思う。
1 と 2 のステップはすでに実現できていたので、自分は 3 、 4 、 5 、 6 をやった。オートスケール、めっちゃむずかしいものというイメージを持っていたけど、まぁまぁすんなり行った(二日くらいで大枠はできて、連休後半には実戦投入した)。負荷に応じて EC2 インスタンスがポコポコ増えて、週末の夜にパソコンを持たずに出かけられるようになった。これで家庭円満です。
オートスケールの設定をしているおかげでアクセスが集中する日曜の夜にもパソコンを持たずスシローに来店することができるけど、スシローの方がオートスケールに対応しておらず待合席で夫婦喧嘩をしながら 120 分待たないといけない。
— morygonzalez (@morygonzalez) May 13, 2018