WEARにおける画像配信のリプレイス戦略とAkamai Image & Video Managerの導入

OGP

こんにちは、WEAR部の繁谷です。SREとしてWEARの運用・保守・開発をしています。

WEARでは、以前の記事で説明した通り、画像配信のリプレイスを行ってきました。本記事ではSRE観点で画像配信のリプレイスやAkamai Image & Video Manager(以下、Image Manager)を利用した画像リサイズの導入の事例を説明します。

techblog.zozo.com

WEARにおける画像配信の課題

前述の記事でも紹介している通り、リプレイス前のWEARの画像配信は下図の構成でした。コーディネート投稿時などのタイミングでIISのAPIを叩き、オリジナル画像をS3に保存します。その書き込みをフックとし、オリジナル画像をリサイズするAWS Lambdaが実行され、派生画像を作成します。そして、作成された派生画像をCDNで配信します。

リプレイス前環境

図1 : リプレイス前の構成図

しかし、この構成は下記の諸々の課題を抱えていました。

  • 画像アップロードのアプリケーションがメンテナンスできないIISやVBScriptで稼働している
  • IaC(Infrastructure as Code)されていないAWSのリソースがある
  • 画像のリサイズを行うLambdaアプリケーションが古いNode.jsで書かれている
  • 膨大なオリジナル画像と、それらをリサイズした派生画像によりS3のコストが増加している

上記の課題のうち、上の2つは前回の記事で、APIのリプレイス、新しいAWSアカウントへの移行によってそれぞれ解決できました。本記事では、主に下の2つの課題に対するアプローチを紹介します。

リプレイス戦略

本章では、前章同様に前回の記事の再掲を含みますが、上記の課題を解決するためのリプレイス戦略を説明します。

リプレイスのゴール

まず始めに、リプレイスで目指す完成形を紹介します。

リプレイス後環境

図2 : リプレイス後の構成図

図1で示したリプレイス前の構成と比較すると、非常にシンプルな構成になっています。以下が変更点です。

  • AWSのリソースをIaCされた新アカウントへ移行
  • 画像アップロードAPIをECS上のRuby on Railsアプリケーションへリプレイス
  • CDNをAkamaiへ変更
  • LambdaによるリサイズをImage Managerに変更し、動的に画像リサイズを行うことで派生画像が削除可能な構成に変更

なお、このゴールを目指すなかで、以下の制約も存在していました。

  • ダウンタイムをなるべくなくす
  • 画像のURLは変更しない

前者のダウンタイムを短くすることは当たり前のことです。それに加え、リプレイスによりURLのドメインやパスを変更してしまうとアプリケーションコードを変更しなければならないため、後者の制約も課しています。これらの制約をクリアしつつ、リリースを4つのフェーズに分けてリプレイスを進めていきます。

各フェーズの内容を順に説明します。

フェーズ1 : アップロードAPIのリプレイス

本フェーズの内容は、前述の過去記事で詳しく説明しているため、詳細は割愛します。下図に示す通り、新しいAWSのリソースを作成し、新規のアップロードは新しいAPIで行うようにしました。

フェーズ1

図3 : フェーズ1の構成図

フェーズ2 : 旧環境のデータ移行

フェーズ2では、以下の2点を行います。Image Managerを使う前準備として新環境にAkamaiを導入することと、旧環境のAWS S3にある膨大な画像データを新環境に移行することです。

フェーズ2

図4 : フェーズ2の構成図

Akamaiの導入手順を簡単に説明します。Amazon Route 53で、AレコードによってCloudFrontに向いている画像配信用のドメインを、CNAMEでAkamaiのProperty Managerで得られたホストに向けます。なお、AWS CloudFormationからは、ダウンタイムなしでAレコードからCNAMEへの変更ができないのため、CLIを使って実施します。

下記のコマンドを試してみましょう。

aws route53 change-resource-record-sets --hosted-zone-id [ホストゾーンID] --change-batch file://example.json
{
  "Comment": "example",
  "Changes": [
    {
      "Action": "DELETE",
      "ResourceRecordSet": {
        "Name": "example.com",
        "Type": "A",
        "ResourceRecords": [
          {
            "Value": "exmaple.cloudfront.net."
          }
        ]
      }
    },
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "exmaple.com",
        "Type": "CNAME",
        "ResourceRecords": [
          {
            "Value": "exmaple.akamaized.net"
          }
        ]
      }
    }
  ]
}

コマンドを実行してみたところ、以下のエラーにより更新できません。

An error occurred (InvalidChangeBatch) when calling the ChangeResourceRecordSets operation: [Tried to delete resource record set [name='[ドメイン名]', type='A'] but the rdata provided is invalid, RRSet of type CNAME with DNS name [ドメイン名]. is not permitted as it conflicts with other records with the same DNS name in zone [ゾーン]]

これはRFC1912の制約に引っかかるためです。よって、この場合のみ、メンテナンスで変更しています。

データ移行をするためにはクロスアカウントのS3間のデータコピーが必要です。また、旧環境のS3バケットへ書き込みのあるAPIがまだ残っているため、それらのAPIで書き込まれたデータを随時新環境にコピーする必要もあります。

まず検討したのはAmazon S3 バッチオペレーションで全データをコピーし、旧環境に書き込まれる新しいデータはS3のレプリケーションによってコピーする方法です。試してみたところ、バッチオペレーションは大量のデータを簡単にコピーできました。しかし、レプリケーションは想定通りにいきませんでした。我々の場合、レプリケーション時に下記のように送信先のパスを指定する必要がありましたが、レプリケーションでは送信先のパスを指定できないことが判明したためです。

 s3://src-bucket/images -> s3://dist-bucket/dist/images

その他にも、マネージドな方法として考えられるのがAWS DataSyncです。ところが、これも要件にマッチしませんでした。DataSyncで扱えるオブジェクト数には5000万の上限が存在しますが、15億ほどある我々のオブジェクト数では、はるかにその上限を超えているためです。
結局、旧環境で画像が書き込まれた際にリサイズするLambdaで、同時に新環境にも対象の画像を書き込むようにコードを追記することで解決しました。

フェーズ3 : Image Managerの導入

この段階で、ようやくImage Managerを導入する準備が整いました。導入方法を説明する前に、Image Managerの特徴を紹介します。

Image & Video Manager

Image & Video ManagerはAkamaiのCDN Platform上で動作するモジュールです。このサービスは、画像や動画に様々な最適化をポリシーベースで行うことができます。類似サービスには、FastlyのImage Optimizerが挙げられます。

Image Managerの選定理由

弊社の技術スタックから、候補はImage ManagerとFastlyのImage Optimizerに絞られました。そして、下記の観点で比較しながら、最終的に採用するサービスを選定していきます。

  • 設定の柔軟性
  • 料金
  • IaC

設定の柔軟性は、前述の「画像のURLは変更しない」という制約を守れるかどうかに着目します。

WEARでは、下記の例のようなURLで画像を配信しています。オリジナル画像のファイル名のサフィックスとして横幅のサイズを数値で指定し、リサイズされた画像を参照します。

オリジナル画像 : https://example.com/path/filename.jpg
横幅500pxでリサイズされた画像 : https://example.com/path/filename_500.jpg

そのため、 filename_500.jpg といったファイル名から、横幅を抽出してリサイズされた画像を作成可能な設定が必要です。両サービスとも、先方にヒアリングを行った結果、どちらも柔軟に設定できることが判明しました。なお、Image Managerにおける設定方法は後述します。

次に料金の観点です。両社に今回の用途を伝えながら見積もりを依頼したところ、Image Managerの方が大幅に安価で提供頂けることが判明しました。

3つ目の観点のIaCです。AkamaiではTerraformのproviderが提供されており、ほとんどの設定がTerraform上で管理可能です。ただし、Image ManagerのCustom Policyは、Terraformは対応していません。一方、Image Optimizerは、VCLで管理できます。

以上の比較結果を踏まえ、両者の違いをまとめたものが下表です。料金の優位性が高いと判断し、Image Managerを選定しました。

観点 Image Manager Image Optimizer
設定の柔軟性
料金
IaC

Image Managerの設定

次に、選定したImage Managerの設定方法を説明します。Image Managerでリサイズをするには、以下の処理が必要です。

  1. 横幅が指定されたURLからオリジナル画像の特定
  2. URLからリサイズ後の横幅の抽出
  3. Image Managerの適用
  4. 1, 2を元にリサイズを行うCustom Policyの作成

1. 横幅が指定されたURLからオリジナル画像の特定

前述の通り、リクエストはオリジナル画像のファイル名にリサイズ後の横幅が付随した形式で送られます。

https://example.com/path/filename_500.jpg

filename_500.jpg という画像は存在せず、 filename.jpg というオリジナル画像のみ存在します。そのため、CDNからオリジンへリクエストする際には、パスを書き換える必要があります。

AkamaiのProperty Managerは、リクエストに対して様々な条件(Criteria)と動作(Behaviors)を定義できます。今回は、 Modify outgoing request path というBehaviorで正規表現によってパスを置換することで要件をクリアしました。下図の例では、パスの _[横幅](.拡張子) に当たる部分を Perl Compatible Regular ExpressionReplacement(.拡張子) に置換しています。

Modify outgoing request path

図5 : Modify outgoing request path

2. URLからリサイズ後の横幅の抽出

このステップでも、Property ManagerのBehaviorで、ファイル名から正規表現で抽出した値を変数として管理して対応しています。下図の例では、ファイル名に対して RegexReplacement_ の後の横幅を抽出し、 PMUSER_WIDTH という変数で管理しています。

Set Variable

図6 : Set Variable

3. Image Managerの適用

Image Managerの適用の仕方は、ドキュメントの通りなため、本記事では省略します。

4. 1, 2を元にリサイズを行うCustom Policyの作成

Custom Policyの設定も、ドキュメントに沿って設定しています。

Image Managerは、デフォルトではクエリパラメータによって横幅などの値を受け取り最適化しています。しかし、前述のようにProperty Managerを組み合わせることで、柔軟に対応できることがわかりました。

AkamaiのIaC

前述の通り、Akamai社がTerraformのproviderを提供しているため、Property Managerなどの設定はコードで管理できます。

しかし、今回は初期構築で複雑な設定をする必要があるため、コンソールから設定したあとにimportする方が適切でした。そのため、Akamai社から提供されているDockerを使い、その開発環境でimportします。

github.com

Akamaiの認証情報を記載した .edgerc を用意し、下記のコマンドでコンテナを立ち上げると akamai terraform などが使えるシェルが起動します。

docker run --rm -it -v $HOME/.edgerc:/root/.edgerc:ro akamai/shell

Property Managerをimportする場合は、下記のように実行すると terraform apply に必要な全ての設定を生成できます。

akamai terraform create-property [property name]

akamai terraform に関する情報は、以下のリポジトリでマニュアルとして公開されています。

github.com

以上でAkamiのImage Managerによる画像のリサイズの仕組みを導入できました。構成は下図の通りです。

フェーズ3

図7 : フェーズ3の構成図

フェーズ4 : ドメインの切り替え

最後に旧環境への書き込みがなくなったことを確認し、旧環境を指しているドメインを新環境に切り替えます。その後、不要なリソースを削除してリプレイスは完了です。

フェーズ4

図8 : フェーズ4の構成図

おわりに

WEARにおける画像配信のリプレイス戦略とAkamai Image & Video Managerの導入事例を紹介しました。 Akamai Image & Video Managerの導入に関心のある皆さんの参考になれば幸いです。

ZOZOでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。

corp.zozo.com

hrmos.co

カテゴリー