ふるさとチョイスのSREとしてこの1年やってきたこと

この記事は、[トラストバンク Advent Calendar 2021](https://qiita.com/advent-calendar/2021/trustbank)の20日目です:rocket:

トラストバンクでSREをしている[@Tocyuki](https://qiita.com/Tocyuki)（としゆき）です！
トラストバンクへ入社してちょうど1年となるので本記事ではこの1年SREとしてやってきたことを書きたいと思います！

# 一人目のSREとして
私は去年の12月に一人目のSREとしてトラストバンクへ入社しました。

入社の経緯やキャリア等については弊社Wantedlyのストーリーにインタービュー記事があるので是非見てみて下さいー！
https://www.wantedly.com/companies/trustbank/post_articles/305115

トラストバンクの運営しているサービスに[ふるさとチョイス](https://www.furusato-tax.jp/)というふるさと納税サイトがあります。
ふるさと納税サイトの先駆けであり、入社前から知っているサイトでもありました。

入社前までは社内にインフラ担当がおらず、インフラ運用管理を外部MSPへ委託している、という状況で、SREとして入社後、以下のミッションに基づいて活動していくことになりました。

- 開発組織にDevOpsを実装する
- ふるさとチョイスのインフラをAWSへ移行する
- 改善改善改善！！！

# 開発組織にDevOpsを実装する
自分が入社した時点では「SRE？DevOps？なにそれおいしいの？」という雰囲気もあり、社内への説明や啓蒙活動をしてきました。


まず、DevOpsについてかなり抽象的ではありますが、自分は以下のように、社内へ説明および啓蒙しています。
※なぜDevOpsが必要かという部分については本記事では割愛します:pray:

```
DevOpsとは、開発（Dev）と運用（Ops）が協力し合ってサービスを作り上げていく思想や文化
```

開発（Dev）と運用（Ops）が協力し合ってサービスを作り上げていくためにはたくさんの仕組みが必要になります。
個人的な解釈としてはこの開発（Dev）と運用（Ops）が協力していけるための仕組みづくりの部分の実装を担う役割がSREだと考えています。

なので[SRE本](https://sre.google/workbook/how-sre-relates/)にあるSREを表す以下表現は個人的にもとてもしっくりきます。

```java
class SRE implements interface DevOps
```


DevOpsを実装する具体的な方法論の一つがSREである、という理解のもと社内へ説明および啓蒙していきました。
そしてSREとしてトラストバンクの開発組織にDevOpsを実装すべくジャングルの奥地へ向かい始めたのです。

# ふるさとチョイスのインフラをAWSへ移行する
現在も鋭意移行プロジェクト進捗中ですが、この1年で開発環境の移行がほぼほぼ完了できたのでその中でも以下の部分について軽く触れていきたいと思います。

- AWSアカウント設計
- Infrastructure as Code
- CI/CD

また、ふるさとチョイスの現在のインフラや開発環境周りについては7月に入社してくれた2人目のSREである[@butadora](https://qiita.com/butadora)がアドベントカレンダー12日目の記事で軽く触れてくれているので是非見てみて下さい。

https://qiita.com/butadora/items/e89568cc091494c1a059

## AWSアカウント設計
### 基本設計
現在マルチアカウント設計に関しては[AWS Control Tower](https://aws.amazon.com/jp/controltower/?control-blogs.sort-by=item.additionalFields.createdDate&control-blogs.sort-order=desc)にお任せしちゃえば良いのかなぁという感じですが、AWS移行プロジェクト開始時はまだ東京リージョンがサポートされていなかったため、[Landing Zone](https://aws.amazon.com/jp/solutions/implementations/aws-landing-zone/)を参考にして、マルチアカウント設計を行い、独自に実装しました。

各アカウントやOU[^1]については以下のようになっています。

|アカウント名|OU|役割|
|---|---|---|
|admin|core|Oraganization管理アカウント、AWS SSOもここで動かす|
|security|core|SecurityHubをここで一元管理し、CloudTrailやConfigのログを受ける|
|shared|core|DirectConnectやRoute53で共通レコードの管理等、他アカウントから共通で利用されるリソースを作成する|
|{service_name}-dev|service|サービス開発環境用アカウント|
|{service_name}-stg|service|サービスステージング環境用アカウント|
|{service_name}-prd|service|サービス本番環境用アカウント|
|{user_name}|sandbox|開発者毎に払い出すAWS検証用アカウント|

sandboxアカウントに関してはまだ[SCP](https://docs.aws.amazon.com/ja_jp/organizations/latest/userguide/orgs_manage_policies_scps.html)での制御を入れられていないので運用開始できていないですが、今後SCPである程度のガードレール敷設後開発者へもAWSアカウントを配布して、AWS力を上げてもらうような活動もできるようにしていきたいと考えています。

ユーザー管理はAWS SSOで行っていてマルチアカウントでAWSを使う場合に使わない選択肢はないだろと断言できるサービスですのでAWSをマルチアカウント運用する全人類各位は必ず導入するようにしてくださいお願いします。

ちなみにAWSリソースの命名規則はクラスメソッドさんの以下記事を参考にしています。
https://dev.classmethod.jp/articles/aws-name-rule/

### サーバー接続
AWS移行後のふるさとチョイスサーバーは基本的にはEC2で稼働しているのですが、[SessionManager](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager.html)での接続を基本としているため、鍵は配置していません。
また前述の通り、AWS SSOでユーザー管理しているため、CLIで[`aws configure sso`](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-sso.html)して[`aws ssm start-session`](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager-working-with-sessions-start.html)する、もしくはマネコンからEC2へ接続できるような構成となっていてとても便利です。

あと`gossm`という`SessionManager`でEC2へ接続している全人類へオススメしたいOSSもあるので是非試してみてください。

https://github.com/gjbae1212/gossm

そして、これらの取り組みはAWSを初めて利用するメンバーにも強制的にAWS CLIを使わせることもできるのでオススメです。

## Infrastructure as Code
今回のAWS移行プロジェクトでは**可能な限りコード化する**ということを必須要件として掲げスタートさせました。
なぜここを必須要件としたかというと前述のDevOpsを実現するための最も有効な手段の一つがIaC[^2]であると強く感じており、また途中からIaCを導入することの大変さを今までの経験から身を持って感じているためです。

幸い今回のような一からインフラ基盤を構築できるような場合にIaC導入が非常にやりやすいという部分もあり必須要件としてプロジェクトをスタートさせました。

ちなみにIaCで採用したツール群は以下となります。

|名前|役割|
|---|---|
|[Terraform](https://github.com/hashicorp/terraform)|AWS、Cloudflareなどのリソースのコード化を行う|
|[Ansible](https://github.com/ansible/ansible)|サーバープロビジョニングのコード化を行う|
|[Packer](https://github.com/hashicorp/packer)|AMI作成をコード化する|
|[Vagrant](https://github.com/hashicorp/vagrant)|Ansibleのローカル開発環境として利用|

現行サーバーの設定や入っているミドルウェア、ライブラリなどはSSHでサーバーに入り洗い出すという泥臭い作業を行い、AnsibleでPlaybook化してPackerでAMIを焼く[^3]ということを繰り返していきました。
AWSに関してもアカウント設計を行ったあと、当時Terraformで実装できなかったAWS SSO以外の部分はすべてTerraform化しています。

## CI/CD
入社時点ではGitHubでPR作成するとJenkinsでのUnitTestが動くという部分は実装されていたのですが、デプロイは`git pull`だったり、オリジナルツールだったりでmasterサーバーにデプロイし、`lsync`で各サーバーへ配布されるようになっている等使い勝手があまり良くない状況でした。

また、開発環境もVirtualHostで論理的に分割されて、予約制のような形になっていて開発が活発になると開発環境の利用に待ちが発生する状況でした。

### ふるさとチョイス開発環境のCI/CD
開発環境のAWS移行に伴い以下のようにCI/CD環境を整備しました。
ちなみにこのPR毎に立ち上がる環境を`feature`環境と呼んでいます。

![feature-ci-cd.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79134/0164014e-1450-5595-1454-41ef1d3281ca.jpeg)

PRを作成した段階でUnitTestと専用環境構築のための`terraform apply`が走り、環境構築完了後、PRを開いたブランチのアプリケーションがCodeDeployによりデプロイされるようになりました。

PRにコミット追加時の`terraform apply`も`tfstate`を分けているため、`no changes`で環境構築ジョブは通過してCodeDeployで変更分がデプロイされて変更箇所がすぐに確認できるようになっています。

これまで課題となっていた、デプロイのやりづらさ、開発環境の確保といった部分が一気に解消されました。
Jenkinsは本当は使いたくないのですが、以下理由により既存のJenkinsで実装しています。

- アプリケーションリポジトリがEC2で立てているGitHub Enterprise Server上で稼働している
- Jenkinsで実装されているUnitTestを剥がすのが結構大変

既存の仕組みをうまく活用しつつ素早く改修していくという判断も大事なので一旦このような構成になっていますが、もちろん今後さらなる改善をする予定です。

（2021/12/24追記）
Terraformアドベントカレンダー24日の記事としてこの部分を詳しく書いた記事を投稿したので是非見てみてくださいー:pray:

https://qiita.com/Tocyuki/items/723e8c51ff16bca6dd19

### AnsibleのCI/CD
EC2環境ということもありアプリケーションのライフサイクルとは異なるため、こちらも別途以下のような実装で用意しました。

![ansible-ci-cd.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79134/1aed205f-f7d9-339b-b951-bcf166f99ccf.jpeg)

ポイントとしては、起動テンプレートはTerraform管理となっているが、AMIは管理していないため、PackerでAMIを作成後、起動テンプレートを管理しているTerraformリポジトリを持ってきて`terraform apply`することで、Terraform自体の変更は発生せずに起動テンプレートが更新され、[`instance refresh`](https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/asg-instance-refresh.html)の仕組みによりインスタンスの入れ替えがトリガーされ、その流れで[`lifecycle hook`](https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/lifecycle-hooks.html)もトリガーされてCodeDeployでアプリケーションが新しく起動するインスタンスにデプロイされるというという部分です。

EC2をAnsibleで管理しているとどうしてもデプロイ部分で悩むことが多かったのですが、個人的にこの実装はなかなか良い設計だなと思っておりますので是非参考にしてみて下さい。

### TerraformのCI/CD
Terraformに関しても基本的にGitHub Actionsでデプロイの自動化を行っています。
Terraformのディレクトリ設計としてはモノレポで実装しており、GitHub Actionsの[`paths`](https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#onpushpull_requestpaths)で環境（AWSアカウント）毎のデプロイを実現しています。

![terraform-ci-cd.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79134/6cd10053-dc55-dc80-90da-83709ae2f1b2.jpeg)

このあたりもいつかアウトプットしたいぞ〜！！

### 新規プロジェクトのCI/CD
現在、新規に立ち上がった開発プロジェクトの基本的な技術スタックは以下となっています。

|項目|技術スタック|
|---|---|
|基盤|ECS on Fargate|
|CI|GitHub Actions|
|Deploy|[ecspresso](https://github.com/kayac/ecspresso)|

新規の開発ではコンテナ最適を考慮したアプリケーションの実装となるようにしていて、本番環境の基盤もECS on Fargateとなっているため運用や実装がだいぶ楽になっています。

デプロイにはカヤックの藤原さんが主に開発している[ecspresso](https://github.com/kayac/ecspresso)を採用し、定義ファイルをアプリケーションリポジトリに配置することで開発メンバーのみである程度ECS部分の変更もできるようにしています。

インフラリソースはすべてTerraformで実装している関係もあり、このecspressoの設計思想がドンピシャにハマってとても良い感じです。

また、新規開発ではLambdaを活用するシーンも増えてきそうなので悩ましいLambdaのデプロイもecspressoと同じ作者の藤原さんが開発している[lambroll](https://github.com/fujiwara/lambroll)の利用を推進していこうと考えています。

# 改善改善改善！！！
その他色々やったことを振り返ってみたいと思います。

## コスト改善
主に以下の部分で対応を行い、月額で数十万以上のコスト削減を行うことが出来ました。

- 不要なサーバーの洗い出し及び廃棄
- 不要なライセンスの購入の洗い出し及びライセンス数の変更
- 交渉余地のあるライセンス費用減額交渉

インフラ担当がいなかったこともあり、すでに利用していないサービスやサーバーのリソースが放置気味だったので、状況を確認しながら退役を進めました。
また、ライセンス費用も一部定価以上のものがあったりと、怪しいものは片っ端から更新タイミングでライセンス費用の交渉を行っていきました。

## GitHub Enterprise Cloud導入
弊社では元々GitHub Enterprise Serverを利用しているのですが、統合ライセンス（Server版とCloud版両方使えるライセンス）に切り替えるだけでCloudも利用可能になる状況だったので、入社後早々にライセンスを切り替えて新規開発のリポジトリは基本的にCloud版で作成するようにしています。

Cloud版ではCIはGitHub Actionsを利用するようにしており、今後、Server版にあるリポジトリも順次Cloud版へ移行し、脱Jenkinsを図りたいと考えています。

## Cloudflare活用促進
弊社CDNではCloudflareを利用しているのですが、CDN以外の機能があまり活用されていない状況だったため、主に以下のシーンでの活用を進めました。

- Nginxで行っていた下記制御をCloudflareで実施
    - IP制御
    - リダイレクト処理
    - ヘッダー追加
- Rate Limit処理
- ファイアウォールルール
- キャンペーンサイト等の静的サイトを[Cloudflare Pages](https://pages.cloudflare.com/)にホスティング

Nginxでの設定変更はかなりめんどくさかったのでこのあたりの対応がCloudflareでサクッと実装できるようになったのはとても良かったです。
また、今までキャンペーン等で作成していた静的サイトも今まではすべてサーバーを立ててコンテンツを載せていたところをCloudflare Pagesを利用することで、サーバーの構築、デプロイ構築、運用管理がなくなり、運用工数がほぼ0になりました。

今後予定しているふるさとチョイスの本番移行も[CloudflareのLoadBalancing](https://www.cloudflare.com/ja-jp/load-balancing/)を活用する予定となり、このようにCloudflareは有用な機能のリリースがどんどん行われているのでしっかりキャッチアップして今後も活用していきたいと考えています。

ちなみにCloudflareも[Terraform Provider](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs)が用意されているで新規のリソースについてはTerraformでコード化しています:ok_hand:

# おわりに
この一年、SREとしてやってきたことをざっくり振返りながら紹介させていただきました。
本当はもっと色々やっていることはあるのですが、締め切りの都合上（？）掻い摘みながらとなってしまいましたが、まだまだやるべきこと、やりたいことがあるのでこれからも頑張って色々な改善をしていきたいです。

個人的に感じる大きな変化としては、新規開発の設計段階での選択肢が格段に広がっている感じがします。
AWSを利用し、各種マネージドサービスを組み合わせての開発は今までにない設計の幅をもたらしてくれるだけではなく、色々な技術的チャレンジを可能にしてくれています。

これからの一年でDevOpsを実装するための土台作りを終え、実装フェーズに入っていければより素早く、確実にソフトウェアエンジニアリングによる価値提供が可能になると考えています。

そんな弊社では一緒にSRE文化を育くみ、DevOpsを開発組織へ実装してくれる仲間を募集しています。
興味のある方、ぜひ一度お話しましょう！！

https://www.wantedly.com/projects/854879

[^1]: [Organization Unit（組織単位）](https://docs.aws.amazon.com/ja_jp/organizations/latest/userguide/orgs_manage_ous.html)の略
[^2]: Infrastructure as Codeの略。コンピューティング・インフラ（プロセス、ベアメタルサーバー、仮想サーバーなど）の構成管理・機械処理可能な定義ファイルの設定・プロビジョニングを自動化するプロセス
[^3]: AMIを焼くって言う人どれぐらいいるんだろう？