Jira/Confluence/BitbucketServerのフロントをCloudFrontにしてみた話

AWS上にAtlassian製品を立てるときに、フロントをALBにするのが普通だと思うのですが、CloudFrontにしたらどうなるかやってみたお話です。

## なんでこれやったの？

[CDN/CloudFront and Atlassian Server apps](https://community.atlassian.com/t5/Jira-discussions/CDN-CloudFront-and-Atlassian-Server-apps/td-p/731230)

Atlassianのコミュニティでやっている人がいたので、本当にこんなに効果があるのか試してみました。

## 構成

`nginx → Jira,Confluence`　で動かしていたのを
`CloudFront → ALB → Jira,Confluence`　に変更しました。

nginxは振り分けとキャッシュとIPアドレス制限しかしていなかったため無くして、CloudFront+WAFに置き換えました。

![aws_atlassian_structure.png](https://qiita-image-store.s3.amazonaws.com/0/135041/1ec05a42-b647-fdbc-1a00-c13ef3351442.png)


## CloudFrontの設定

### Origins

* ALB
* S3 Bucket

基本的にALBに流しますが、一部カスタマイズ用の　`css` `js` `png` など静的ファイルだけS3に置いています。

### Behaivors 

| Precedence | Path Pattern                | Origin or Origin Group | Viewer Protocol Policy | Forwarded Query Strings | 
|------------|-----------------------------|------------------------|------------------------|-------------------------| 
| 0          | /confluence/s/*             | ALB                    | Redirect HTTP to HTTPS | Yes                     | 
| 1          | /confluence/download/*      | ALB                    | Redirect HTTP to HTTPS | Yes                     | 
| 2          | /jira/s/*                   | ALB                    | Redirect HTTP to HTTPS | Yes                     | 
| 3          | /jira/secure/projectavatar* | ALB                    | Redirect HTTP to HTTPS | Yes                     | 
| 4          | /jira/secure/viewavatar*    | ALB                    | Redirect HTTP to HTTPS | Yes                     | 
| 5          | /jira/download/resources/*  | ALB                    | Redirect HTTP to HTTPS | Yes                     | 
| 6          | /jira/images/*              | ALB                    | Redirect HTTP to HTTPS | Yes                     | 
| 7          | /bitbucket/s/*                  | ALB                    | Redirect HTTP to HTTPS | Yes                     | 
| 8          | /bitbucket/*/avatar.png         | ALB                    | Redirect HTTP to HTTPS | Yes                     | 
| 9          | /                           | S3 Bucket                     | Redirect HTTP to HTTPS | No                      | 
| 10         | /static/*                   | S3 Bucket                     | Redirect HTTP to HTTPS | No                      | 
| 11         | favicon.ico                 | ALB                    | Redirect HTTP to HTTPS | No                      | 
| 12         | Default (*)                 | ALB                    | Redirect HTTP to HTTPS | Yes                     | 

各Path Patternの設定値は[CDN/CloudFront and Atlassian Server apps](https://community.atlassian.com/t5/Jira-discussions/CDN-CloudFront-and-Atlassian-Server-apps/td-p/731230)とだいたい一緒にしました。



## 効果

### キャッシュヒット率

![CloudFrontHits.png](https://qiita-image-store.s3.amazonaws.com/0/135041/31a8c4b4-9dc8-e3d8-ff9e-92e37907407c.png)

1つのCloudFrontに全ツール（Jira/Confluence/BitbucketServer）をぶら下げてしまったので、各ツールのヒット率は出せないのですが、うちの環境では `12.65%` になりました。低いですね。

Errorsが結構あるのは、すでに無効になっているユーザーやリポジトリに対してgit pullし続けるようなcronやjenkinsが回っているためです。

> Jira: Of the 689GB traffic initiated by users browsers, 587GB has been served directly from CloudFront, leaving only 102GB needing to go back to the server (origin) ~ 85%
> Confluence: Of 185GB total, 160GB has come from CloudFront, 26GB from the server ~ 86%

Path Patternも設定値も真似て作ったのですが、85%に遠く及ばないヒット率になりました。
使い方によるものはあるのでしょうが、ここはもうちょっと試行錯誤が必要そうです。


### 費用はそれなり

2週間で250万アクセスくらいで1ヶ月稼働させたときの費用。

|Product|Price/month|
|----|----|
|CloudFront|$6.47|
|ALB|$18.34|
|CLB|$15.55|
|WAF|$22.62|

nginxをフロントに立たせてもEC2代がかかるので、同じくらい費用がかかると思います。
nginxで受けたパターンは実際にはAWS上では構築していなかったので比較はないです。

### レスポンスは速くなった気がしないでもない

nginxを使っていたときも当然キャッシュしていたので、あまり変化はなかったです。
逆にCloudFrontに変更しても同じくらいのパフォーマンスは出るとも言えます。

もっと遠くの地域からなら、エッジロケーションの効果も実感できるかもしれませんが今回は試していません。

### WAFのおかげで疎通確認オペレーションが楽になった

WAFのlogはKinesis Data Firehoseに流せるので、あとに続く処理を如何様にもできます。
iptablesでもlog吐いてfluentdでFirehoseに流せば同じことができますが、設定だけでこれが可能になるのは嬉しいところ。

## リクエスト投げる側が困ること

IPアドレス制限をしていてリクエストを受ける側はWAFで制御すればいいのですが、リクエストを投げる側がOutboundを厳密に管理しているような場合、困ることがあります。

CloudFrontは固定のIPアドレスを持たないため、取りうる可能性があるIPアドレス帯をすべてOutboundで許可する必要があります。

[CloudFront エッジサーバーの場所と IP アドレス範囲 \- Amazon CloudFront](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/LocationsOfEdgeServers.html)

固定IPアドレスにしたければNLBを使うことになるのですが、SSLアクセラレーション機能がなかったりセキュリティグループを設定できなったりと、EC2側で対処しなければならないことが増えて微妙です。
（Global Acceleratorを使えばIP固定化できますが、まだ検証できていません）

## BitbucketServerもClouｄFrontの下に置くと困ること

JiraやConfluenceだけなら問題はないが、BitbucketServerも一緒に管理しようとするといくつか問題が出てきます。

### sshが受けられない

CloudFrontで扱えるProtocolは `http` `https` のみ。
ALB直にアクセスしようとしても、ALBで扱えるProtocolも `http` `https` のみ。
`ssh` 用のCLBを別に用意する必要がある。

### 大きいリポジトリをcloneするときにタイムアウトする

httpsでgitを使っても問題が出てくる。
CloudFrontのtimeoutが最大60秒なので、大きいリポジトリをcloneするときタイムアウトしてしまう。
そういうときは `--depth`　を使ってshallow cloneすればいいのだが、初見の人は必ずつまずくので運用上よくはない。

httpsでgit cloneするときのはALB直にすればいいのだが、その時点でもうCloudFrontは使わないと同義となる。
BitbucketServerはssh時のURLは指定できるが、https時のURLはBase URLから取っているため、git cloneのときだけサブドメインを変えたURLにするのは通常の手段ではできない。

[Bitbucket Server config properties \- Atlassian Documentation](https://confluence.atlassian.com/bitbucketserver/bitbucket-server-config-properties-776640155.html)

## 総評

コミュニティに書かれていたような高いキャッシュヒット率を出すことはできませんでしたが、他のCloudFrontの利点（エッジロケーション、マネージドサービス、WAF）は享受できていますし、レスポンス速度が落ちていないのはいいですね。

いくつか気をつけないといけない点はありますが、使い方によって無視してもいいものなので、この構成もありだと思います。