まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:s3

みんな大好き WordPress 。自分もローカルコンテナやクラウド、ホスティングなど色々な形態で活用しています。最近は k8s などのパブリックなコンテナ環境下で使われることも珍しくなくなってきました。

実際に環境構築した経験のある人はわかると思いますが、この WordPress はシングルサーバーのシングルテナント構成(サーバーもインスタンスも1台で、1つの WordPress サイトを作る構成)であれば構築手順は簡単なのですが、負荷分散を考慮して複数サーバーインスタンス化した構成を考慮に入れるととたんにややこしくなります。理由もシンプルではないのですが、最大の問題はメディアストレージと呼ばれる画像などのファイルアップロード空間がファイルシステムを前提としている点にあります。簡単に説明すると、コンテンツ内で使う画像をアップロードすると、その画像はサーバーのファイルシステム上に保存されます。表示される際も当然サーバーのファイルシステム上の画像を参照することになります。サーバーが1台であればこれで問題ないのですが、サーバーが複数台(例えばAとBの2台)あった場合、サーバーAのファイルシステムに画像を保存して、サーバーAから画像を参照すると画像が見えますが、サーバーBのファイルシステムには画像は存在していないので、参照しても見つからない、という結果になってしまいます。負荷分散の仕組みが存在している以上、サーバーAを使うかサーバーBを使うかは毎回変わる可能性があるので、アクセスするたびに画像が見えたり見えなかったりすることになります。サーバーが3台、4台と増えていくと、画像が見える確率はどんどん下がっていきます。これでは使い物になりません。

そのため、WordPress では一般的にメディアストレージには全サーバーから参照可能な共有ストレージをマウントして指定します。こうすることで全サーバーが同じストレージにメディアファイルをアップロードすることになり、全てのサーバーから参照可能になる、というわけです。WordPress 環境構築時によく使う典型的な作業でもあり、この機能に関連した多くのプラグインも提供されています。

で、この WordPress の共有メディアストレージに IBM Cloud の Object Storage を指定する方法を調べたので、自分用メモの意味も込めてまとめました。IBM Cloud の Object Storage はいわゆる「S3互換」のオブジェクトストレージで、一定の条件下で無料利用(しかもクレジットカード不要!)できます。詳しくは後述の説明を参照いただきたいのですが、無料枠でも容量としては 25GB まで使えるので、WordPress の規模としてはそこそこ大きなものでもまかなえる共有ストレージだと思っています。


【WordPress 環境の準備】
まずは WordPress 環境を用意します。具体的には MySQL データベースサーバーと、WordPress が展開された HTTP サーバー。複数サーバーでなければ localhost で構築してもいいですし、ローカルの docker/docker Compose で用意してもいいし、有料/無料のクラウド/ホスティングサーバーを使っても構いません。管理者権限でログイン可能な WordPress 環境を1つ用意してください。この時点ではメディアストレージに特別な設定は不要で、デフォルトのファイルシステムをそのまま使う設定であると仮定します。


【IBM Cloud Object Storage(IBM COS) の準備】
次に上述環境のメディアストレージとなる IBM COS を用意します。IBM Cloud アカウントを所有していない場合はこちらから作成してください(作成後にクレジットカードを登録することでより多くのサービスを利用できるようになりますが、今回紹介している内容をそのまま実行するだけであれば登録しないアカウントでも可能です):
https://cloud.ibm.com/registration


IBM Cloud アカウントでログイン後、ダッシュボード画面から「リソースの作成」ボタンをクリックします:
2021092101


検索ボックスに "object storage" と入力し、見つかった "Object Storage" を選択します:
2021092102


次の画面で料金プランを選択します。料金体系が "Free" と表示されたライトプランが選択されていることを確認してください(ライトプランは無料ですが、Standard プランは有料です)。そして画面右下の「作成」ボタンをクリックします:
2021092103



なお、このライトプランの制約事項は以下のようなものです。ストレージ容量としては 25GB ですが、リクエストの回数やパブリックアウトバウンド容量などに一か月単位の上限が設定されています。また30日間非アクティブな状態が続くと削除されます(このプランのままこの制約を超えて使うことはできませんが、有料プランにアップグレードすることで制約を超えて使うことは可能です)。ご注意ください:
2021092104


Cloud Object Storage サービスが作成され、以下のような画面が表示されます:
2021092105


ではこの Object Storage にデータ(今回は画像)を格納するバケットを作成します。左メニューから「バケット」を選び、「バケットの作成」ボタンをクリックします:
2021092101


バケットの属性を選択したり、カスタマイズできたりするのですが、今回は定義済みのバケットを使うことにします。「すぐに始める」と書かれたカードの→印部分をクリック:
2021092102


ここでは3ステップでバケットを定義しますが、実質的に最初のここだけがカスタマイズ部分となります。これから作成するバケットの名称を適当に入力します。以下の例では WordPress のメディアストレージ向けということで、自分の名前も使って "kkimura-wordpress-media" と入力しています。ここは皆さんがわかりやすい名前を入力してください。そして「次へ」:
2021092103


次の画面ではそのまま「次へ」:
2021092104


最後の画面も特に変更する必要はありません。そのまま「バケット構成の表示」ボタンをクリックします:
2021092105


すると入力した名称でバケットが作成されます。この時に「ロケーション」欄に表示されている内容は後で使うのでメモしておきます(下図の例だと "jp-tok"):
2021092106


バケットが作成できたら、次はこのバケットを外部から(今回の例だと WordPress から)利用できるようにするための情報を取得します。画面左のメニューで「サービス資格情報」を選択し、「新規資格情報」ボタンをクリックします:
2021092107


資格情報の作成ダイアログが表示されたら「詳細オプション」を開き、役割が「ライター」になっていることを確認した上で、「HMAC 資格情報を含める」をオンにしてから「追加」ボタンをクリックします:
2021092108


いま追加した資格情報が一覧に表示されるので、名称部分をクリックして展開します:
2021092109


以下のように追加したサービス資格情報が表示されます:
2021092110


サービス資格情報は以下のようなフォーマットになっているので、"cos_hmac_keys" の中の "access_key_id" の値と、"secret_access_key" の値をメモしておいてください:
{
  "apikey": "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "cos_hmac_keys": {
    "access_key_id": "xxxxxxxxxxxxxxxxxxxxxxxx",
    "secret_access_key": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  },
  "endpoints": "https://control.cloud-object-storage.cloud.ibm.com/v2/endpoints"
    :
    :
}

※ サービス資格情報に cos_hmac_keys というキーそのものが存在していない場合は、資格情報を作成する際に「HMAC 資格情報を含める」オプションをオンにしていない可能性があります。上述の手順を再度確認してもう一度実行してみてください。


最後にエンドポイントを確認します。画面左メニューから「エンドポイント」を選択し、バケットを作成した時に確認したロケーション情報( Regional の jp-tok)に合わせて「回復力」と「ロケーション」を設定し、そこで表示されるパブリック URL の内容をメモしておきます:
2021092111


これで IBM COS 側の設定と準備も完了です。改めて、この時点で  IBM COS に関する以下の情報が入手できていることを確認してください。これらがすべてわかっていれば WordPress のメディアストレージとしてマウントできるようになります(手順は後述します):
取得・確認方法
バケット名バケット作成時に指定した名前
access_key_idサービス資格情報内
secret_access_keyサービス資格情報内
エンドポイント作成したバケットのロケーション情報に合わせて取得したパブリック URL


【Media Cloud プラグインのインストールと設定】
ここまでの手順が正しく実施できて、上述の4つの情報が取得できていれば WordPress に IBM COS のバケットをメディアストレージとしてマウントできる準備が整ったことになります。以下では実際にマウントする手順を紹介します。

まず WordPress の管理機能にアクセスできるアカウントでログインし、管理画面に移動します。まずObject Storage をメディアストレージとしてマウントするための Media Cloud プラグインをインストールします。画面左のメニューから「プラグイン」を選び、「新規追加」ボタンをクリックします:
2021092201


キーワード検索ボックスに "Media Cloud" と入力します:
2021092202


候補がいくつか見つかりますが、その中に以下のような "Media Cloud for Amazon S3, ..." というプラグインが見つかります。ここの「今すぐインストール」をクリックしてインストールします:
2021092203


インストールに成功すると「有効化」というボタンに変わります。このボタンもクリックしてプラグインを有効にします:
2021092204


更新通知機能をオプトインするかどうかを聞かれます。オプトインする場合は「許可して続ける」、したくない場合は「スキップ」のいずれかを選んで先へ進みます:
2021092205


Media Cloud のセットアップウィザードが起動します。まずは Next をクリック:
2021092206


最初に Object Storage のプロバイダーを選択します。IBM COS の場合は "S3 Compatible" を選択します:
2021092207


S3 互換ストレージの設定が開始されます。"Next" をクリック:
2021092201


次の画面で先程準備した IBM COS の情報を入力します。入力内容は以下のようにします:
項目名入力する値
ACCESS KEYaccess_key_id の値
SECRETsecret_access_key の値
BUCKET作成したバケット名
REGION(Automatic のまま)
CUSTOM ENDPOINTエンドポイント URL

最後に "Next" をクリック:
2021092202


入力した値が正しく利用できるかどうかを確認するいくつかのテストを行います。"START TESTS" をクリック:
2021092203


実際にバケットに対してファイルをアップロードして、アップロードできていることを確認して、削除して・・・といったテストが行われます。すべて成功すると下図のように5つのグリーンでチェックマークが表示され、正しく利用できる状態であることが確認されました。"Next" をクリック:
2021092204


これで Media Cloud を利用できる状態になりました。"FINISH & EXIT WIZARD" をクリックして設定ウィザードを終了します:
2021092205


WordPress の管理画面に戻り、"Media Cloud" メニュー内の "Enable Cloud Storage" がオンに設定されていることを確認します:
2021092206


ちなみに、ここで設定した値は MySQL データベースの wp_options テーブル内に格納されているようです。なので、この状態で(データベースへの接続情報が含まれた状態で)サーバーの内容をコンテナイメージ化すれば、コンテナ環境でも動く状態が作れる、と思います:
2021092201



最後にメディアストレージが Object Storage に切り替わっていることを WordPress 内からも確認しておきましょう。管理画面の「メディア」を選択し、メディアライブラリの「新規追加」で適当な画像ファイルを選択して追加します:
2021092207


試しにこんな感じで1つ画像をアップロードしてみました(この画像は WordPress のコンテンツとして利用することができず状態になっています):
2021092208


改めて IBM Cloud のダッシュボードに戻り、IBM Cloud Object Storage のバケット内を表示してみると、画像ファイルが追加されているはずです(2つ追加されているのは、1つのアップロードに対して元画像とサムネイル用の2つの画像が追加されているからのようです):
2021092209


画像を1つ選択すると右にウィンドウが表示され、ここからダウンロードすることができます:
2021092201


実際にダウンロードして表示し、WordPress 画面からアップロードした画像が Object Storage に格納されていることを確認します:
2021092202


WordPress のメディアストレージとして IBM Cloud の Object Storage を利用できることが確認できました。IBM Cloud の Cloud Object Storage を使うことである程度の規模まで無料でこの環境での運用ができるので、バケットを複数用意して使うケースも含めて、実運用前の構築段階ではとても便利に使うことができそうです。

このエントリが特定の個人を揶揄する目的で作ったものではないことを最初にお断りしておきます。


ちょうど今(2016/Mar/24)話題になっている某氏の謝罪ウェブサイトを見ていて、あることに気付きました:
2016032400


このページの内容自体にどうこう言うつもりはありません。問題はこのページの URL です。http://ototake.com/ にアクセスするとこのページが表示されるようになっています。もともとはこの人のウェブページ用のサーバーだったはずだけど、トップページだけ作り変えたのでしょうか?


ではプロフィール紹介用のページ http://ototake.com/profile/ はどうなっているのか、と思ってアクセスすると、404 エラー(ページが見つからない)になりました:
2016032402


ちなみに(グーグルのキャッシュによると)以前はこんなページだったはず:
2016032403


トップページを変えただけでなく、プロフィールページも消したのか・・・ いや違う。このエラーページの内容は単なる「ページが見つからない」ではなく、"Code: NoSuchKey" とか、 "Key: profile" とか、何かをシステマチックに探した上で見つからない、というエラーに見えます。単にページ内容を入れ替えたものではなさそうです。


この謎はアドレスを逆引きして分かりました:
2016032401


なるほど、Amazon S3静的ウェブホスティング機能を使って作られたページだったようです。ということはどこかに元のページも残しつつ、DNS の切り替えだけでこの謝罪ページに飛ぶよう設定されていた、ということです。

なかなかうまい方法だと思いました。まず今回のような謝罪ページは一時的にアクセスが集中する可能性があるので、今まで使っていたウェブサーバーの中身を置き換えただけではアクセスを捌ききれる保証はありません。そこを S3 の静的ウェブホスティングにすれば比較的安価に(アカウントを新規に作れば1年間は無料で)それなりの可用性が保証されたこのページを作ることができます。 そして DNS の切り替えでこの新ページを運用しているとすれば、謝罪終了(?)後に元のページへ戻す作業も DNS を切り替え直すだけで簡単に済みますし、その後は謝罪ページも消してしまえば、それ以降の料金はかかりません。 ということは現在のサーバーを落とす必要もないので、再切り替え時の手間やトラブルも少なく済みそう、と推測されます。


このやり方はうまいなあ、と思いました。DNS の切り替えにかかるタイムラグや、各種キャッシュの切り替わりを意識する必要はあるにせよ、コスパのいい謝罪ページ運用だと感心してしまいました。もちろん謝罪用だけでなく、何らかの事情で一時的に異なるページを表示する必要が生じた場合の方策と考えても使えると思います。

S3 互換のオブジェクトストレージサービスを運用している会社にとってはビジネスの参考になります(苦笑)。


AWS(Amazon Web Services) のストレージサービスである S3。特定条件の中で利用する限りは無料になるし、容量1GBに付き月10円弱で使えるし、これ単体で静的なウェブホスティングにも使えるので、ちょっとしたファイル置き場以上の便利さがあります。

最近、この S3 をバケット単位でマウントできるという s3fs というツールの存在を知りました。その紹介です。

そもそも S3 をマウントできると何がうれしいのか?単なるファイル置き場というだけでなく、自分が最近使う機会の多い WordPress をクラスタリング環境にする際にネットワークマウントは必須になっている、という背景もあり、自分の場合にはそういったネットワークマウントのできるパブリックなクラウドストレージは WordPress と併用する環境としても魅力的なのでした。


ここでちょっとだけ脱線を。WordPress 自体はデータを RDB(一般的には MySQL)内に格納するので、クラスタリング環境を構築する上で特別意識することはないように思えます。ただし、ファイルをアップロードして利用する場合だけは注意が必要です。WordPress のファイルアップロード(メディアアップロード)では、アップロードされたファイルはファイルシステム上に移動されて、WordPress 自身はそのファイルパスの情報だけを格li納します(つまりバイナリの情報はDBには格納しません)。

この挙動は WordPress が1台の HTTP サーバー環境で稼働する場合は大きな問題にはなりにくいと思っていますが、例えば2台の HTTP サーバー(A, B) でクラスタリング環境を構成していた場合で考えると問題が浮き彫りになります。

仮に2台のうちのサーバーA上で、このメディアアップロードが実行されたと仮定します。サーバーA はアップロードされたファイルを自分自身の /var/www/html/wordpress/wp-content/uploads/ 以下に移動します。仮にそのファイル名が /var/www/html/wordpress/wp-content/uploads/aaa.jpg となったとします。

上記のように WordPress ではバイナリの情報は DB に格納せず、そのファイルパス情報だけを DB に格納します。つまりアップロードされたファイルは /var/www/html/wordpress/wp-content/uploads/aaa.jpg に存在する、という情報だけを DB に記憶することになります。サーバーA 内ではこれで問題になることはありません。

ところがクラスタリングのもう一台であるサーバーBも同じDBを参照しているので、サーバーBからも「該当ファイルは /var/www/html/wordpress/wp-content/uploads/aaa.jpg に存在する」と見えてしまします。このファイルはサーバーA のファイルシステムには保存されていますが、サーバーB には存在していません。したがって例えばサーバーB 上の処理でこの画像を表示させようとすると「ファイルが存在しない」ことになってしまいます。クラスタリングの振り分けはユーザーがコントロールできるわけではないので、ユーザーによってファイルが見えたり見えなかったり、ということが起きてしまいます。

これを解決するにはディレクトリを共有するしかありません。上記例であれば /var/www/html/wordpress/wp-content/uploads/ 以下が実際にはネットワークフォルダになっていて、その同じ箇所をサーバーA/B 双方からマウントして参照する、という構成になっている必要があるのでした。そしてそのようなネットワークフォルダをどうやって用意・調達するか、という問題に直面することになるのでした。


少し脱線しましたが、こんな背景の中で「無料でも使える AWS S3 がマウントできる」というのはかなり魅力的な情報なのでした。早速試してみたので以下にその手順を紹介します:

まずは S3 側の準備をします。仮に "awsuser1" という名前のバケットが S3 上に作成済みであると仮定し、このバケットを共有する前提で紹介します:
2014031201


必要な設定は、このバケットに接続するための認証ユーザーの作成です。既に別の AWS サービス用などにユーザーを作成済みであればそのユーザーを流用しても構いませんが、ここでは S3 アクセス用のフル権限を持ったユーザーを新規に作成することにします。

AWS のサービス一覧から IAM を選択します:
2014031202


左ペインで Users を選択し、"Create New Users" ボタンをクリックします:
2014031203


(名前自体はあまり重要ではないので)適当な名前のユーザーを作成します:
2014031204


作成直後のダイアログの "Show User Security Credentials" をクリックして展開します:
2014031205


展開後に表示される "Access Key ID" と "Secret Access Key" 両方の値をメモするかダウンロードして、後から参照できるようにしておきます。記録できたら "Close Window" でこのダイアログを閉じます:
2014031206


次にこのユーザーに S3 へのアクセス権を付与します。左ペインで Users が選択された状態に戻ります。ここで作成したユーザーを選択し、右下のユーザー詳細情報ペインでは "Permissions" タブを選択します。その中の "Attach User Policy" ボタンをクリックします:
2014031207


アクセス権指定のダイアログが表示されます。Select Policy Template と書かれたリストの下の方に "Amazon S3 Full Access" という列があるので、この右の "Select" ボタンをクリックします:
2014031208


確認画面になるので "Apply Policy" をクリックします。これでこのユーザーは S3 へのフルアクセス権を持ったことになります:
2014031209




次はマウント元側の設定です。今作成した(S3 へのフルアクセス権を持った)ユーザーでマウントするための設定を行います。まずインターネットに接続された Linux を用意します。以下 CentOS を使っている前提で紹介しますが、ディストリビューションによる可不可は特にないと思っています(AWS のインスタンスでも、そうでなくてもできます)。

まず事前準備として必要そうなライブラリを導入しておきます:
# yum groupinstall "Development Tools"  (C/C++ コンパイル環境を導入)
# yum install openssl-devel (libcrypt 0.9 を導入) # yum install libcurl-devel (libcurl 7.0 を導入) # yum install libxml2-devel (libxml-2.0.2.6 を導入)

上記3ライブラリに加えて fuse 2.8.5 が必要になります。AWS の EC2 インスタンスからは普通に yum でインストールすることもできます(yum install fuse fuse-devel)が、yum でインストールできないケースも多いのでビルド手順を紹介します。
# cd /usr/local/src
# wget http://sourceforge.net/projects/fuse/files/fuse-2.X/2.8.5/fuse-2.8.5.tar.gz
# tar xzvf fuse-2.8.5.tar.gz
# cd fuse-2.8.5
# ./configure --prefix=/usr
# make
# make install
# ldconfig
# modprobe fuse

fuse までが導入できると s3fs のビルド条件がそろったことになります。以下の手順で s3fs をビルドします:
# cd /usr/local/src
# wget http://s3fs.googlecode.com/files/s3fs-1.61.tar.gz
# tar xzvf s3fs-1.61.tar.gz
# cd s3fs-1.61
# export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/lib64/pkgconfig/
# ./configure --prefix=/usr
# make
# make install

これで s3fs のインストールが完了しました。最後に S3 へアクセスするためのユーザーの設定を行います。/etc/passwd-s3fs というファイルを、上記ユーザー作成時にメモした Access Key ID と Secret Access Key を使って、以下のような内容で新規に作成します(カッコは不要です):
# echo '(Access Key ID):(Secret Access Key)' > /etc/passwd-s3fs

仮に Access Key ID が ABCD で Secret Access Key が wxyz だった場合、/etc/passwd-s3fs の中身は以下の一行になります:
ABCD:wxyz

このファイルは他者から参照できないようにする必要があるため、ファイルパーミッションを変更します:
# chmod 640 /etc/passwd-s3fs

マウント先のディレクトリを用意します。ここでは /mnt/s3 というディレクトリに S3 をマウントすることにします:
# mkdir /mnt/s3

これで全ての準備が整いました。S3 の awsuser1 というバケットを /mnt/s3/ にマウントするには以下のようなコマンドを実行します。バケット名やマウント先は環境に合わせて適宜変更してください:
# s3fs awsuser1 /mnt/s3/ -o allow_other,default_acl=public_read

結果はこんな感じになりました。S3 って容量としては 256TB も用意されてるんですねw:
2014031210


再起動時にもこのマウントを有効にするには、同じコマンドを手動で再発行するのではなく、 /etc/fstab に以下の1行を追加記述するのがいいと思います。これもバケット名やマウント先は環境に合わせて適宜変更してください:
s3fs#awsuser1 /mnt/s3 fuse allow_other,default_acl=public-read 0 0


こんな感じで S3 をファイルシステムにマウントできることがわかりました。後は WordPress をクラスタ環境で使う場合は、メディアアップロードのディレクトリをこのマウント先にしておけば、同じイメージをクローンしてもクローン先でも同じ S3 を参照することになるので上述のような問題を回避できることになります、たぶん。





 

このページのトップヘ