CyberAgentのアドベントカレンダーを書くのは5回目になりました。普段はDynalystという広告配信プラットフォームのバックエンド開発をしています。今年は所属している事業部のWordPressのリニューアルを手伝ったのでその話をします。新サイトはこちらです。https://cyberagent.ai/8月までは「アドテク本部」という部署だったのですが、9月から組織改編があり「AI事業本部」という組織に変わりました。設立の経緯はこちらの記事をご覧ください。内藤が挑む3つのことサイトをリニューアルするにあたって社内で組織改編の話が出た時にはサイトのデザインやコンテンツのリニューアルのプロジェクトは既に動き始めていました。インフラ面のリニューアルの予定はなかったのですが、普段AWS上で動くプロダクトを開発していることもあり、その知見が活かせるだろうというのと、面白そうだったのでインフラ面のリニューアルを担当させてもらうことにしました。素のEC2にWordPressをインストールして、インターネットに公開していました。性能を上げるためにはスケールアップしか手段がないなどなど問題がありました。考えた構成WordPressの運用は本業ではないので、できるだけ手離れがしやすくて安定する構成を目指しました。具体的に意識したのは以下です。Backupという構成を考えました。それぞれのコンポーネントの役割について説明します。CloudFrontCDNです。記事は静的なコンテンツなのでキャッシュし配信を高速化するのとEC2インスタンスの負荷を減らします。記事を更新したときにキャッシュが残ったままだと実際に反映されるまでに時間がかかってしまうので更新時に自動で該当記事のキャッシュのinvalidationをしてくれるプラグインを入れました。Controller記事以外にもカスタマイズして作った記事一覧ページをinvalidationしたかったので少しだけプラグインのコードを書き換えました。汎用性のある書き方になおしてプルリクエストを投げようと思っています。脆弱性につながる挙動を減らすためにGET系のリクエストのみ通過させています。POSTが必要なもの(フォーム等)はCyberAgentのコーポレートサイトのフォームを使うなどしてこのサイトに動的なコンテンツを持たせないような交渉をして、改修をしました。WAFファイアウォールです。WAFv2を使っています。新規リリースだったので、厳しい設定にしてから、正常な操作を行ったにも関わらずブロックされるケースはルールを緩和していくようにして設定を詰めていきました。WAFを有効にしたら早速怪しいリクエストをブロックしはじめたのが確認できました。ALBロードバランサです。今回はロードバランサの配下にはサーバは1台しかいませんが、サーバをAutoScalingで構成するのと、ALBの認証連携機能を使うために導入しました。CloudFrontより転送されてきたGET系のリクエストはそのまま通過させ、それ以外は認証を要求するようにしています。X-WP-Secret-Key)を付加し、そのヘッダのvalueに秘密の値を入れ、ALB側で一致するか確認することでCloudFrontから転送されてきたリクエストなのかどうかを判別させています。社内の人間がWordPressの管理画面を開いて記事を投稿する場合はCloudFrontにアクセスするのではなく、ALBのエンドポイントに直接アクセスしてもらい、ALBの認証を通すようにします。認証にはCognitoというサービスをつかいました。Cognito認証やアクセスコントロールの機能を持ったマネージドサービスです。Connectにも対応しています。これにより、社員のみがWordPressの管理画面(ALB)にアクセスできる環境ができました。EC2サーバインスタンスです。NginxとWordPressが動いています。旧ドメインにアクセスがあったときのリダイレクトやURLの書き換えはNginxにルールで書きました。AutoScalingを使って常時1台インスタンスが起動している状態を維持するようにしています。サーバが障害等で落ちると新しいインスタンスが自動で立ち上がります。新しいインスタンスが起動するまでの間はユーザはアクセスできなくなりますが、基本的には頻繁に落ちる物ではないですし、落ちても数分で自動復旧するのと、アクセスの多い記事はCloudFrontのキャッシュに乗っているため全体がダウンとはなりにくいことから、短時間のダウンタイムは許容することにしました。今回の構成だと、公開用のURLと管理画面用のURLはドメインが異なります。WordPressは設定と異なるドメイン宛にきたリクエストはリダイレクトするようで、管理画面にアクセスすると公開用のドメインにリダイレクトされてしまい、困りました。対策として、wp-config.phpのWP_SITEURLとWP_HOMEの変数を固定せずにリクエストの内容からホスト名を取り出して設定を動的に書き換えるようにしました。$_SERVER['HTTP_HOST']);一方で、どんなホスト名でもアクセスしてきたホスト名をそのまま使うとHostヘッダを利用したXSSにつながる可能性があるため、前段のNginxのバーチャルホストの設定で想定していないホスト宛のリクエストはフィルタリングをしています。同様の設定方法を検討される方はご注意ください。AuroraMySQL互換のデータベースです。DBのサーバインスタンスは1台で構成していますが、ストレージレイヤは自動でレプリケーションされているためDBに障害が起きてもデータの損失は発生せず、短時間で自動復旧するのでEC2と同様短時間のダウンタイムは許容してインフラコストを抑えることにしました。バックアップは毎日自動で取得されます。EFSNFS互換のストレージサービスです。EC2インスタンスにマウントして、WordPressのファイルをホスティングします。WordPress自体のphpファイルとユーザがアップロードする画像等のリソースもすべてEFSに置いたため、EC2インスタンスに障害が発生して新しいEC2インスタンスが起動してもファイルは失われません。静的コンテンツをS3にアップロードするプラグインもあるかとは思いますが、WordPressのデザイン等の改修をする方ができるだけ素のWordPressを使っている感覚で作業できるようにEFSを選択しました。今回はCloudFrontが前段のキャッシュとして存在しているので問題ありませんが、キャッシュしない場合は小さいファイルを大量に読み出す速度(レイテンシ)の面で問題があるのでお気をつけください。BackupEFSのバックアップの自動化に使いました。毎日バックアップを作成しています。Insightsでスコアを測定してみました。CloudFrontでキャッシュしているので速度面のパフォーマンスは申し分なさそうです。ロギングも簡単になりました。CloudFrontのアクセスログを有効化して、S3にログが吐き出されるようにするだけでAthenaを使ってSQLでアクセスログを分析できるようになりました。Analyticsを用いればよいのですが、リリース初期でのリンク切れや不具合の検出にはアクセスログが必要で、とても助かりました。IPv4のアクセスとIPv6のアクセスの比率を知るためにこんな感じのクエリを書きました。いまのところは1割くらいがIPv6経由でのアクセスのようですね。CloudFrontでのアクセスログをAthenaで集計する方法はこちらの記事がわかりやすいです。優太2015年新卒入社。Dynalystサーバサイドエンジニア。使う言語はScala。趣味で中古サーバやネットワーク機器を買ってデータセンタに設置して運用しています。