Amazon S3 + CloudFrontによるYumリポジトリにリダイレクトルールを適用する

2015.04.09

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ども、大瀧です。
ソフトウェア配布の手段として、Amazon CloudFrontは非常に強力です。CDNとして世界各地からのアクセスに対して良好なパフォーマンスが期待できますし、多数の同時アクセス負荷を分散させる効果も期待できます。さらにCloudFrontのオリジン(配信元)としてAmazon S3を利用すると、仮想マシンを実行することなくリーズナブルで可用性の高いソフトウェア配信基盤が構成できます。

ただ、S3はWebサーバーとしての機能は一般的なWebサーバーと比べて少ないため、用意されているオプションを理解しうまく活用することが重要です。そこで今回は、S3 Static Website Hostingのリダイレクトルールを利用してYumリポジトリの少し込み入った構成をご紹介します。

構成の概要

まずは、CloudFrontとS3の構成です。Linuxのソフトウェア配布方法としてよく用いられるYumでは、RPMパッケージを配置するYumリポジトリをパッケージの配布元として用意します。Yumリポジトリ自体はXMLファイルなどの静的コンテンツで動作するため、CloudFront + S3でも問題なく動作します。LinuxホストでYumリポジトリの設定をCloudFrontを向くように行いyumコマンドを実行します。CloudFrontでは初回のみS3にパッケージファイル取得のリクエストを発行、キャッシュしつつLinuxホストにパッケージファイルを返送します。

cf-yumrepo01

Yumリポジトリはシンプルなディレクトリごと独立した構成なので、S3バケットの中にディレクトリ(プリフィックス)別の複数Yumリポジトリを配置することもできます。そこで、OSのメジャーバージョン毎にリポジトリを分け、Yumの変数$releaseverを利用してリポジトリの設定内に以下のように記述することがよくあります。

Amazon Linuxの/etc/yum.repos.d/amzn-main.repo

[amzn-main]
name=amzn-main-Base
mirrorlist=http://repo.$awsregion.$awsdomain/$releasever/main/mirror.list
  :(以下略)

ただ、リポジトリによってはOSのバージョンに拠らず同じリポジトリを参照させたいこともあると思います。$releaseverを含めない対応が最もシンプルですが、RHELとAmazon Linuxなど複数ディストリビューションで共通のリポジトリの設定にしたいこともあるでしょう。そういう場合は、特定バージョンのリポジトリを他のバージョンのリポジトリから参照させる方法が考えられます。他のリポジトリへの参照は、大きく分けて以下の2通りがあります。

  • シンボリックリンク
  • HTTPリダイレクト

シンボリックリンクへの追随はWebサーバー側の設定(Apacheの場合はFollowSymlinks)、HTTPリダイレクトはyumコマンドが既定で追ってくれるので特別な対応は要りません。今回リポジトリを構成するS3では、バケット内のファイル(オブジェクト)にシンボリックリンクを設定することはできないため、HTTPリダイレクトを設定することになります。例えば、以下のような構成です。

cf-yumrepo02

RHEL向けの/7ディレクトリにリポジトリのファイルを配置し、Amazon Linux向けの/latest/2015.03などを/7にリダイレクトさせます。

では、順を追って設定していきます。

  • 動作確認環境 : Amazon Linux 2015.03 HVM(東京リージョン : ami-cbf90ecb)

RPMパッケージとYumリポジトリの作成

まずはサンプルのRPMパッケージとYumリポジトリをさくっと作っちゃいます。1ファイル/hoge.txtを含むhogeパッケージをfpmコマンドでパッケージングします。

$ sudo yum groupinstall -y "Development Tools"
$ sudo yum install -y ruby-devel
$ sudo gem install fpm --no-ri --no-rdoc
$ mkdir src
$ echo "Hoge" > src/hoge.txt
$ cat src/hoge.txt
Hoge
$ fpm -s dir -t rpm -n hogehoge -v 0.0.1 -C src -p pkg/hogehoge-0.0.1.rpm .
no value for epoch is set, defaulting to nil {:level=>:warn}
no value for epoch is set, defaulting to nil {:level=>:warn}
Created package {:path=>"pkg/hogehoge-0.0.1.rpm"}
$ rpm -qlp pkg/hogehoge-0.0.1.rpm
/hoge.txt
$

できたhogeパッケージを配置しているpkg/ディレクトリをYumリポジトリのルートとし、createrepoコマンドでYumリポジトリを作成します。

$ sudo yum install -y createrepo
$ createrepo pkg/
Spawning worker 0 with 1 pkgs
Workers Finished
Saving Primary metadata
Saving file lists metadata
Saving other metadata
Generating sqlite DBs
Sqlite DBs complete
$ ls pkg/
hogehoge-0.0.1.rpm  repodata
$

Yumリポジトリのメタデータはrepodata/配下にXMLファイルといくつかのファイルで構成されます。これでYumリポジトリのファイル作成はOKです。

念のためデバッグしてみましょう。Yumリポジトリの設定ファイル(/etc/yum.repos.d/hoge.repo)を作成し、リポジトリのディレクトリを絶対パスで記述します。

/etc/yum.repos.d/hoge.repo

[hoge]
baseurl=file:///home/ec2-user/pkg/
enable=yes
gogpcheck=no

では、yumコマンドでYumリポジトリが動作するか確認してみます。

$ yum info hoge
読み込んだプラグイン:priorities, update-motd, upgrade-helper
リポジトリー 'hoge' は構成中に名前がありませんので ID を使います
hoge                                                                                                                                            | 2.9 kB     00:00
hoge/primary_db                                                                                                                                 | 1.6 kB     00:00
利用可能なパッケージ
名前                : hogehoge
アーキテクチャー    : x86_64
バージョン          : 0.0.1
リリース            : 1
容量                : 1.8 k
リポジトリー        : hoge
要約                : no description given
URL                 : http://example.com/no-uri-given
ライセンス          : unknown
説明                : no description given
$

きちんとyumコマンドでパッケージが読めていますね!

S3 Static Website Hostingの設定

YumリポジトリのファイルをS3にアップロードします。あらかじめ任意のS3バケット *1を作成します。リダイレクトを動作させるためにはStatic Website Hosting機能を有効にし、リダイレクトルールを記述します。

cf-yumrepo04

  • バケットの[Properties]ボタンをクリックし、[Static Website Hosting]のアコーディオンメニューを開く
  • [Enable website hosting]のラジオボタンをクリック
  • [Index Document]は任意のファイル名を入力(yumコマンドはindex.htmlを読まないので動作には影響なし)
  • [Edit Redirection Rules]をクリックし、テキストエリアに以下を入力 *2
<RoutingRules>
    <RoutingRule>
        <Condition>
            <KeyPrefixEquals>latest/</KeyPrefixEquals>
        </Condition>
        <Redirect>
            <ReplaceKeyPrefixWith>7/</ReplaceKeyPrefixWith>
        </Redirect>
    </RoutingRule>
    <RoutingRule>
        <Condition>
            <KeyPrefixEquals>2014.09/</KeyPrefixEquals>
        </Condition>
        <Redirect>
            <ReplaceKeyPrefixWith>7/</ReplaceKeyPrefixWith>
        </Redirect>
    </RoutingRule>
    <RoutingRule>
        <Condition>
            <KeyPrefixEquals>2015.03/</KeyPrefixEquals>
        </Condition>
        <Redirect>
            <ReplaceKeyPrefixWith>7/</ReplaceKeyPrefixWith>
        </Redirect>
    </RoutingRule>
</RoutingRules>

入力後は画面下方の[Save]ボタンのクリックを忘れずに!続いて、AWS CLIなどでYumリポジトリのディレクトリ以下のすべてのファイルをアップロードします。awsコマンドを実行するマシンでは、あらかじめS3にアクセスできるようIAMロールもしくはAPIキーの設定を済ませておきます。

$ aws s3 cp --recursive --acl public-read pkg/ s3://takipone-repotest/7/
upload: pkg/repodata/2211fa11fd76daa7aceabf19418bf8294bf51bb8b57e2e1095a6761a3a38c91b-primary.sqlite.bz2 to s3://takipone-repotest/7/repodata/2211fa11fd76daa7aceabf19418bf8294bf51bb8b57e2e1095a6761a3a38c91b-primary.sqlite.bz2
upload: pkg/repodata/61235ed0c793230e12ceb017cea85ae2ba60c058357ef8ae608d779b2aa0e308-other.sqlite.bz2 to s3://takipone-repotest/7/repodata/61235ed0c793230e12ceb017cea85ae2ba60c058357ef8ae608d779b2aa0e308-other.sqlite.bz2
upload: pkg/repodata/704ef5cd32e4ec64f3f7d85b093ef3d0ac64de8674dc38f9af1b428415b07f0e-other.xml.gz to s3://takipone-repotest/7/repodata/704ef5cd32e4ec64f3f7d85b093ef3d0ac64de8674dc38f9af1b428415b07f0e-other.xml.gz
upload: pkg/repodata/repomd.xml to s3://takipone-repotest/7/repodata/repomd.xml
upload: pkg/repodata/d1f86b89886bda187279e38780d28a20ac3669523e467d1df057a91d7047738c-filelists.sqlite.bz2 to s3://takipone-repotest/7/repodata/d1f86b89886bda187279e38780d28a20ac3669523e467d1df057a91d7047738c-filelists.sqlite.bz2
upload: pkg/hogehoge-0.0.1.rpm to s3://takipone-repotest/7/hogehoge-0.0.1.rpm
upload: pkg/repodata/640c555807796f5b6b10a04a001ee48a7cc17cfdaf5496c7f710e1ecb33364cf-filelists.xml.gz to s3://takipone-repotest/7/repodata/640c555807796f5b6b10a04a001ee48a7cc17cfdaf5496c7f710e1ecb33364cf-filelists.xml.gz
upload: pkg/repodata/95753241725d3d8dd859d45447001cbc03b4988ac5c86e0bd85acd2391f87495-primary.xml.gz to s3://takipone-repotest/7/repodata/95753241725d3d8dd859d45447001cbc03b4988ac5c86e0bd85acd2391f87495-primary.xml.gz
$

これでOKです!

CloudFrontの設定

設定したS3バケットをオリジンとするCloudFrontディストリビューションを作成します。一般的なディストリビューション作成と特に変わりませんが、HTTPリダイレクトを動作させるために[Origin Domain Name]にはオートコンプリートの候補に出てくる通常のS3バケットのURLではなく、Static Website HostingのURL((バケット名).s3-website-(リージョン名).amazonaws.com)を指定することに注意しましょう。

cf-yumrepo05

これでOKです! *3

動作確認

では、先ほどのYumリポジトリの設定ファイルにあるリポジトリURLをCloudFrontに変更し、yumコマンドを実行してみます。

/etc/yum.repos.d/hoge.repo

[hoge]
baseurl=http://XXXXXXXXXXXXX.cloudfront.net/$releasever/
enable=yes
gogpcheck=no

Amazon Linuxの既定では、/etc/yum.confの以下の設定によって$releaseverは「latest」になります。

/etc/yum.conf

# by default the yum configuration will point to the latest release
# of Amazon Linux AMI. If you prefer not to automatically move to
# new releases, comment out this line.
releasever=latest

CloudFront→S3に来たところで、リダイレクトルールによって/latestのアクセスは/7にリダイレクト、今回配置したリポジトリが参照できるはずです。

$ sudo yum clean all
読み込んだプラグイン:priorities, update-motd, upgrade-helper
リポジトリー 'hoge' は構成中に名前がありませんので ID を使います
リポジトリーを清掃しています: amzn-main amzn-updates hoge
Cleaning up everything
$ sudo yum info hogehoge
読み込んだプラグイン:priorities, update-motd, upgrade-helper
リポジトリー 'hoge' は構成中に名前がありませんので ID を使います
amzn-main/latest                                                                                                                                | 2.1 kB     00:00
amzn-main/latest/group                                                                                                                          |  35 kB     00:00
amzn-main/latest/primary_db                                                                                                                     | 3.3 MB     00:00
amzn-updates/latest                                                                                                                             | 2.3 kB     00:00
amzn-updates/latest/group                                                                                                                       |  35 kB     00:00
amzn-updates/latest/updateinfo                                                                                                                  | 218 kB     00:00
amzn-updates/latest/primary_db                                                                                                                  |  81 kB     00:00
hoge/latest                                                                                                                                     | 2.9 kB     00:00
hoge/latest/primary_db                                                                                                                          | 1.6 kB     00:00
利用可能なパッケージ
名前                : hogehoge
アーキテクチャー    : x86_64
バージョン          : 0.0.1
リリース            : 1
容量                : 1.8 k
リポジトリー        : hoge/latest
要約                : no description given
URL                 : http://example.com/no-uri-given
ライセンス          : unknown
説明                : no description given
$

CloudFront経由でパッケージ情報が取得できました!

まとめ

YumリポジトリをS3とCloudFrontで配信する構成と、S3のリダイレクト設定についてご紹介しました。実際の運用にはリポジトリメタデータをパッケージ更新に合わせて更新する必要があるため、メタデータのHTTPヘッダを変更してキャッシュ保持期間を短めに設定するなどのチューニングが推奨されます。以下の記事が参考になると思います。(みんな悩んでるんですねぇw)

参考URL

脚注

  1. CloudFrontに独自ドメインを設定する場合にはドメイン名と同一名のバケットを作成します
  2. リダイレクト先のURLはS3 Static Website Hostingのドメインになるため、独自ドメインの場合は<Redirect>要素に<HostName>要素でドメインを指定する必要があります。
  3. 独自ドメインをCloudFrontに設定する部分も特に通常通り[Distribution Settings] - [Alternate Domain Names(CNAMEs)]に入力すればOKです。