管理ツールとして「GitLab」CI/CDツールとして「GitLab CI/CDツール」を利用

六車光貴氏(以下、六車):六車が『エンジニア1年目の貢献:CI整備を中心に』というタイトルで発表します。まず自己紹介です。六車光貴と申します。ちょっと変わった名前ですが、四国の香川県出身で、香川県だと小学校のクラスに1人はいる名前です。

フォルシアには2020年4月に新卒で入社して、ソフトウェアエンジニアとして働いています。主に大手旅行代理店のサイトの構築をTypeScript、Node.js、React、Next、ポスグレ(PostgreSQL)などを使ってしています。

それにプラスして社内横断的な活動もやっていて、CI/CD、Docker、Kubernetesなどのコンテナ技術を調査したり、推進したりしています。

フォルシアではDevOpsを実践していて、ツールもいろいろと使っています。今回は「GitLab CI/CD」について話したいと思っています。

前提として、フォルシアではGitの管理ツールとして「GitLab」というオープンソースのソフトウェアを使っていて、そのGitLabと親和性が非常に高い「GitLab CI/CD」をCI/CDツールとして使っています。

これはあるプロジェクトの一例ですが、以下のようなことをGitLab CI/CDで行なっています。Jestを使った単体テストや、ESLintを使ったLinter。Cypressは最近流行っていますよね。Cypressを使ったE2Eテスト。Frisbyを使ったスナップショットテスト。

それらにプラスCDの部分だと思うんですが、アプリのbuildをして、かつ、Dockerイメージをbuildするdeployをしています。

CI/CDを使っているとクリーンな開発環境が維持されるので、僕自身もCI/CDなしには生きていけないと……生きていけないはアレですけど(笑)。開発できない体になってしまったくらいなので、非常に生産性の上がるものだと思っています。

「gitlab-ci.ymlの肥大化」と「CIの実行時間の長さ」が課題

ただ、不満点もあります。以下の2点なのですが、まず1つ目がCIの設定ファイルである「.gitlab-ci.ymlの肥大化」です。Kubernetes周りでもyaml地獄などと言われているものがけっこうありますが、GitLab CI/CDでもあります。

僕が担当しているプロジェクトだと、なんと568行もあります。う~ん。ただただ読みづらいですね。かつ、なにか変更しようとなったときも非常にメンテナンスがしづらいです。

2点目。これがけっこうインパクト強くて、多くのエンジニアが同じような悩みを抱えていると思うのですが、「CIの実行時間が長い」ということです。いろいろなことをやっているので、その分実行時間が長くなりました。

実行時間が長くなると、リリースの遅さに直結します。CI/CDを使っている多くのプロセスにおいては、安全安心のためにCIのパイプラインが通ったあとに初めてリリースをすると思います。CIが遅いと、それが遅くなってしまいます。

ほかにも、「コンテキストスイッチに時間がかかる」ということがあります。例えば、ある修正が終わってgit pushして、次の作業をしましょうとブランチを変えてゴニョゴニョやってる間にCIがこけて、また修正しないといけなくなると、いったん今やっている作業を中断して修正をしないといけません。CIが遅くなるとコンテキストスイッチにすごくストレスを感じました。

解決策は「CIファイルの分割」と「適切なcacheの設定」

これをどうにかしましょうということで、1つ目に肥大化した.gitlab-ci.ymlを分割します。これは非常に簡単で、.gitlab-ci.ymlのオプションでincludeというものがあるんですが、こんな感じでyamlの設定ファイルを分割できます。こうすることで、.gitlab-ci.ymlは45行になって、非常に見通しが良くなりました。

余談ですが、GitLab CIは本当に完成度の高いCIサービスで、いろいろと豊富なオプションが用意されています。かゆいところに手が届くオプションがあって、使っていて非常におもしろいツールだなと思っています。

2つ目のCIの実行時間が長いという点ですが、これについては、最初にベンチマークを取りましょう。改善前の実行時間はこんな感じです。一つひとつがパイプラインですね。平均で49分30秒。なかなか長いですね。

もしこのパイプラインの最後のほうで、jobがfailした場合、30分なり40分待ってやっとfailしたことに気づくという感じでした。

特に時間がかかっている、この4つのパイプラインをstageごとに切り出して時間も計ってみました。見てみるとdeployに一番時間がかかっています。deployは、Dockerイメージをbuildしたり、DBの更新処理をしたりするのでまあまあ時間がかかっています。次点がtestで、これもなかなか時間がかかっていました。

より詳しくということで、とあるjobを見てみました。GitLab CIのjobはセクションごとに分かれているのですが、それぞれのセクションの時間を計りました。一例なのですが、一番時間がかかっているのがbuild_scriptです。

メインの処理なので、テスト実行やビルド実行以外にrestore_cacheとarchive_cacheで合わせて350秒くらい、6分弱かかっています。

このプロジェクトはNode.jsのプロジェクトなんですが、node_modulesのサイズを測ってみると、なんと2837.9MBでなかなか重たいものでした。けっこう有名な図だと思うんですが、宇宙で一番重いものは、node_modulesだと言われています。

このプロジェクトがモノレポ構成の複数のnode_modulesがある構成で、それぞれを合わせるとこんなに重たくなって、すべてのjobについて、すべてのnode_modulesをrestore、archiveしていたのでめっちゃ時間がかかっていました。

解決策として、jobごとに適切なcacheを指定しました。例えば、test_aというyamlファイルですね、jobにおいては、test_a以下のnode_modulesしか必要ないので、このpathにこんなふうに指定することで、cache、archive、restoreしないという設定をします。

もう1つ、keyの設定があります。CI_JOB_NAMEがGitLab CIの環境変数なんですが、test_aにしてプロジェクト全体でjobごとにcacheを共有するように設定しました。これはエムスリー株式会社さんの「Tech blog」が非常に参考になりました。

ほかにもnpm installにnpm install --prefer-offline --no-auditというオプションを付けました。ローカルにキャッシュがある場合、ネットにリクエストせずに脆弱性チェックもしないというものです。

ほかにも、testとbuildを1つのjobにまとめたり、速いと噂のnpm 7にアップグレードしたりしました。この結果、実行時間が27分になりました。約22分、45パーセントを削減できました。

まとめです。今回の発表は非常にシンプルで、CIファイルを分割すると見通しが良くなるので、yaml地獄に陥っている方はぜひやってみてくださいということと、実行時間削減には適切なcacheの設定が有効であることがわかったという話でした。

僕はほかにも横断系の組織で、Dockerファイルのベストプラクティスの整備や、Kubernetesのdeploy手段としてのGitOpsの調査などをやらせてもらいました。これについてはフォルシアでブログを書いています。

入社1年目で、僕もエンジニア経験がほとんどなかったのですが、やりたいと言ったらけっこうやらせてもらえる風土があると思っていて、いい会社だなと感じています。以上です。ご清聴ありがとうございました。

司会者:ありがとうございました。いいまとめでしたね。「個人だとGitHubを使っている人が多いと思いますが、フォルシアでGitLabを使っているのはどういう視点なのでしょう? CI連携に強いからという理由なのでしょうか?」 という質問が来ています。

六車:GitLabはオープンソースで、かつ、オンプレなのでGitLabを使っています。そのGitLabと親和性が高いGitLab CI/CDを使っています。

司会者:なるほど。セルフホストできるのが一番のポイントだと。

六車:そうですね。

司会者:ありがとうございます。私からも1つ質問していいですか?

六車:はい。

司会者:開発効率を上げるための作業ってわりと後回しにしがちかなと思うんですが、今回六車さんが着手できた理由はなんですか? 

六車:まず1つ、僕がCI/CDがとても好きだったというところがあると思います。こんなに面倒くさいことを、自動で動かしてくれるというところに感動をして、そのモチベーションがありました。

もう1つ、定量化して調査できたのが非常によかったかなと思っています。

ベンチマークを測って調べて、これをやったらエンジニアチームのみなさんがかなり快適になると考えながらやったので、やり切れたのかなと思います。

司会者:効果がどれくらいあるのかきちんとわかったうえでやったので、がんばれたんですね。ありがとうございます。これで六車さんの発表は終わりにしたいと思います。ありがとうございました。

六車:ありがとうございました。