Home > cloud > AWS

AWS Archive

AWS で請求金額にビックリしないようにやっておくべきこと

  • 2015-03-13 (金)
  • AWS
この記事の所要時間: 315

AWS は、従量課金なので、他者からの不正利用(本来無いことですが)や想定外の利用で、翌月の請求が来て、ビックリということがあります。

logo_aws

私自身も関わっているプロジェクトで、ある月に平時の数倍の請求が来て、原因調査を行ったという経験がありました。

転ばぬ先の杖ということで、先にやっておくべきことについてまとめておきます。

1. AWSアカウントの不正利用を防ぐ

まず、考えられるのが、アカウントを乗っ取られての不正利用です。もちろん、不正利用は、請求だけでなく、システムやリソースを守るという点でも防ぐべきことです。

そこで、AWS アカウントは、2要素認証(2段階認証 / 2 Factor authentication / 2FA)を設定しておきます。

手順は、下記のエントリがまとまっています。

AWSアカウント作ったらこれだけはやっとけ!IAMユーザーとAuthyを使ったMFAで2段階認証 – Qiita

私は、以前は、Google Authenticator を使っていたのですが、Authy に変えました。単純に見やすいですし、バックアップ機能もあり、スマートフォン買い替えなどで別デバイスへ移行する際も便利なので、おすすめです。

2. アクセスキーを適切に管理する

AWS アカウントの不正利用を防いだところで、アクセスキーの管理がずさんだと、結局は不正利用されてしまいます。

そこで、アクセスキーを適切に管理する方法を知っておきます。

これについては、AWS のドキュメントに、良い資料があるので、こちらを参考にすると良いでしょう。

AWS アクセスキーを管理するためのベストプラクティス – アマゾン ウェブ サービス

3. 請求金額を監視する

これで、不正利用は防げて安心、というなるところなのですが、正規な利用を行っていても、驚きの請求が来ることがあります。

私が、遭遇したケースは、まさにこれでした。

某Webサイトでの出来事だったのですが、アクセス数はそれほど変わらないのに、転送量が平時の月より大幅に増えて、それにより予想外の請求が来ていました。よくよく調べてみると、このサイトでは動画ファイルを公開していたのですが、動画ファイルの容量が大きく、これが原因で転送量が増加していました。確認してみると、動画ファイルを更新した時期と、請求額が大きく増えた月が一致していました。

このように、不正利用では無くとも、通常の運用でも、請求額が大きく増える可能性は十分にあります。

運用を気をつけるというのはもちろんなのですが、Billing Alerts で、請求額を監視しておくと安心です。

CloudWatch_Management_Console

アラートと通知で請求額を監視 – AWS 請求情報とコスト管理

Billing Alerts は、月ごとの請求額を監視して、設定した値を超えれば、アラートを送るというものです。

私の場合、下記の 2 パターンでアラートが来る用意設定しています。

  • $10 を超えたら、アラート通知
  • 平時請求額 * 3 を超えたら、アラート通知

前者は、ちゃんとアラートが飛んでくるか確認するためです。監視にありがちな「頼りがないのは良い知らせ」と思って、安心してたら、実はちゃんと監視できていない( or アラート設定が間違っていた)を防ぐためです。

後者が、想定外の請求を監視するもので、これが飛んできたら、請求内容を確認して、想定外のリソースが使われていないかを確認します。

さいごに

AWS は、従量課金でかつプログラマブルにリソースを操作できるので、想定外なリソース利用によって、請求額が増加する可能性があります。ただ、請求金額すら、リソースと同じように監視して、アラートが出せるというのが AWS らしくて良いですね。

突然の請求に驚かないように、今一度、確認しておきましょう。

  • コメント (Close): 0
  • トラックバック (Close): 0

2014 年に発表したセッションと資料まとめ

この記事の所要時間: 648

2014 年も残すは、あと 1 週間になりました。今年も様々なイベントで登壇しましたので、発表したセッションと資料をまとめてみます。

phpcon_kansai_2014
写真提供:久岡写真事務所

登壇イベント

2014/04/04 「わかってるフレームワーク Laravel」Laravel勉強会福岡

「わかってるフレームワーク Laravel」とうタイトルで発表しました。

Laravel で、とあるプロジェクトの開発が終わった後だったので、Laravel への良さを主観たっぷりでお話しました。

翌日の Laravel Meetup Tokyo と合わせて、一人 Laravel Japan ツアーでした:D

2014/04/05 「知っておくべき Auth オートログイン」 Laravel Meetup Tokyo vol.3

Laravel 4.1.25 以前にあった Auth フィルタ利用時のオートログインの問題点についてお話しました。

いくつかの前提条件は必要ですが、影響度が大きいので、「これはやばい」というのが伝わっていました。

なお、この問題は、4.1.26 にて修正されたので、現在は問題ありません。

Laravel ユーザなら知っておくべきAuthオートログインのこと

2014/04/12 「Vagrant ユーザのための Docker 入門」 第3回コンテナ型仮想化の情報交換会@大阪

Docker が盛り上がってきた時だったので、Vagrant ユーザを対象に Docker 入門をお話しました。

セッション途中でも活発に質問が飛び込んできたり、デモでコンテナ起動の速さに驚きの声があがったりで、盛り上がったのを覚えています。

「VagrantユーザのためのDocker入門」を発表してきました

2014/04/19 「最近なんだか、はてブがおかしい」俺聞け8 in Tokyo

資料未公開

当初は「Webエンジンアとしてご飯を食べていく」という内容を考えていたのですが、事前に、主催の @msng さんから「ブログに関する発表が多くて嬉しい」というコメントがあったので、ブロブに寄せようと内容を変えました:)

会場には、著名なブロガーの方が多く、みなさん同じようなことを感じているようで、発表後の情報交換が捗りました。

2014/04/24 「Vagrant 体験入門」DevLove関西

これから Vagrant を学ぶ方向けに、Vagrant 概要についての発表と体験ハンズオンを行いました。

Vagrant ハンズオンでは、みんなで同一拠点から一斉にプロビジョンを行うので、遅延やエラーが起こったり、環境の違い(Vagrant + VirtualBox が起動するまでの)でトラブルが発生したりで、毎回発見があります。

ハンズオンの資料は Qiita に公開しています。

Vagrant体験入門ハンズオン手順 – 2014/04/24 DevLove関西

Vagrant体験入門ハンズオンの資料を公開します

2014/06/19 「Heroku で作るスケーラブルな PHP アプリケーション」第16回関西PHP勉強会

Heroku で PHP が正式サポートされたので、スケーラブルな構成をどう組むかという内容でお話しました。

その後、いくつかのプロジェクトで Heroku + PHP を使っているのですが、やはり PaaS として良くできていますね。まだ掴みきれていない部分もあるので、引き続き追いかけていきます。

Heroku で作るスケーラブルな PHP アプリケーション

2014/06/28 「PHPコードではなく PHPコードの「書き方」を知る」PHPカンファレンス関西2014

PHPカンファレンス関西の初心者向けセッションということで、FizzBuzz を題材に、関数化、クラス化、そして自動テストを書くという流れをお話しました。

「PHPコードではなくPHPコードの「書き方」を知る」を発表してきました

2014/07/05 「開発現場で活用する Vagrant」夏の JAWS-UG 三都物語 2014

関西での JAWS-UG イベント、三都物語でのセッションでした。JAWS-UG では久しぶりの発表になりました。

Vagrant を実際に使う例として、デモで実演しながらセッションを進めました。

会場がフランクな雰囲気で、話しやすかったのが印象的でした。あと Yo を使って、バーチャル拍手というかうなずきを送ってもらったりもしましたね。

「開発現場で活用するVagrant」を発表しました

2014/08/23 「Vagrant 心得 5 ヶ条」DevLove 甲子園 2014 西日本大会

資料未公開

DevLove 甲子園にて、Vagrant についてお話しました。ここでは、Vagrant を活用する上で、気をつけておくと良いことを 5 つにまとめました。

内容は、いずれ blog に書きたいと思います。

2014/10/11 「Ansible ではじめるサーバ作業の自動化」PHPカンファレンス 2014

PHP カンファレンスで、Ansible についてお話しました。発表を聴いた方からは、好意的なフィードバックが多く、「Chef を使っていましたが、Ansible 使ってみます!」という意見もあり、良かったです。

準備している時は、話したいことをどう上手くおさめるかを苦心したので、普段スピーカーをしているコミュニティの仲間から「うまくまとまっていましたね」と言ってもらえ、やはり見ている人には分かるんだなあと感じたりもしました。

このセッションを見た方から、別のイベントでの登壇についてお誘いがあったり、次につながったセッションでもありました。

「Ansibleではじめるサーバ作業の自動化」を発表してきました

2014/12/19 「ビルドサーバで使う Docker」DevLove 関西

年内最後の発表は、やはり Docker でした。今年は、ほんと Docker が躍進した一年でしたね。

Jenkins サーバでの活用例から、導入のポイントや設定方法などをお話しました。

「Jenkinsサーバで使う Docker」を発表してきました

ロクナナワークショップ 「Laravel で学ぶモダン PHP 開発講座」

11 月から、ロクナナワークショップさんにて「Laravel で学ぶモダン PHP 開発講座」という講座を行っています。

みっちり 1 日で、Vagrant や Composer の使い方、Laravel を使った REST API の実装、そして、その自動テストを書くという内容です。

すでに 2 回開催しているのですが、参加された方は熱心に課題に取り組まれていて、講師としても勉強になることが多いです。まとまった時間でじっくり課題をこなしていくので、これから学んでいこうという方にはおすすめです。

次回は 2015/02/17 に開催予定ですので、もし興味がある方は、ご参加下さい。

新原雅司のLaravel で学ぶモダン PHP 開発講座

さいごに

今年を振り返ってみると、自分で名乗り出るよりも、お声がけ頂いて、登壇するという機会が増えました。お声がけ頂けるのは嬉しく、スケジュールやタイミングが許せば、できるだけお引き受けしたいです。

人前で話すというのは、準備も大変ですし、いつも緊張しますが、毎回色々な発見があり、また、終わった後は何ともいえない解放感というか充実感を感じることができます。聴いて頂いた方からのフィードバックも嬉しいものです。

今年も、セッションに参加して頂いた方、イベントにお声がけ頂いた方、本当にありがとうございました。

2015 年は、年始の 1/16 に GoAzure 2015 で登壇する予定です。Websites でスケーラブルな PHP アプリケーションを作るという内容ですので、ご参加お待ちしています!

  • コメント (Close): 0
  • トラックバック (Close): 0

Ansible で EC2 インスタンスを起動して、Route53 に Public DNS を登録する

この記事の所要時間: 1452

Ansible は、構成管理ツールとして認知されていますが、AWS 関連のモジュールが多数実装されており、各コンポーネントの起動や設定ができます。

th_ansible_logo_black_square

このエントリでは、Ansible で、検証環境用の EC2 インスタンスを起動して、その Public DNS をRoute 53 に登録してみます。

以前書いたこのエントリの内容 を Ansible で自動化するイメージですね。

準備

今回は、AWS を操作するので、Python の AWS SDK である boto をインストールしておきます。boto は、pip なり、yum なりでインストールできます。

  • OSX
$ pip install boto
  • RHEL / CentOS
$ rpm -ivh http://ftp.riken.jp/Linux/fedora/epel/6/i386/epel-release-6-8.noarch.rpm
$ yum -y install python-boto

AWS 認証情報

AWS 認証情報を設定します。

playbook に直接記載する方法もあるのですが、ここでは、boto の設定ファイルである ~/.boto に記述をします。こうしておけば、playbook では、認証情報を指定する必要がありません。

[Credentials]
aws_access_key_id = xxxxxxxxxxxxxxx
aws_secret_access_key = xxxxxxxxxxxxxxx

EC2 インスタンスの起動

Ansible で EC2 インスタンスを起動するには、ec2 モジュールを使います。

AWS 関連のモジュールを使う場合、対象のインベントリが指定できない場合がある(対象のホストをこのタスクで生成するので)ので、local connection として実行します。

ec2 モジュールには、EC2 インスタンスを起動するためのパラメータを指定します。下記では、VPC で、t2.micro インスタンスを指定しています。各パラメータについては、EC2 インスタンスを起動する際は、お馴染みのものなので、値を指定していきます。あとで識別できるように Name タグに ansible1 を設定しておきます。

ここで起動したインスタンスの Public DNS を、Route 53 に登録するので、register を使って、処理結果をec2という変数に格納しておきます。

- hosts: localhost
  gather_facts: no
  connection: local
  tasks:
    - name: Create ec2 instanse
      ec2:
        key_name: keyA
        instance_type: t2.micro
        image: ami-0xxxxx
        monitoring: yes
        wait: yes
        region: ap-northeast-1
        group_id: sg-xxxxxx
        vpc_subnet_id: subnet-xxxxx
        assign_public_ip: yes
        instance_tags: 
          Name: ansible1
      register: ec2

Route 53 に Public DNS を CNAME に登録

あらかじめ決められた FQDN でアクセスできるように、先ほど起動したインスタンスの Public DNS を CNAME として Route 53 に登録します。

Route 53 の操作には、route53 モジュールを使います。

EC2 インスタンスの情報は、ec2.instances に格納されているので、これを利用します。下記では、ansible1.dev.example.com という FQDN に対して、ec2 の Public DNS を CNAME で割り当てています。

    - name: Set Public DNS to CNAME in Route53
      route53:
        command: create
        zone: dev.example.com
        type: CNAME
        value: "{{ item.public_dns_name }}"
        overwrite: yes
        record: ansible1.dev.example.com
        ttl: 300
      with_items: ec2.instances

playbook の実行

この playbook を ansible-playbook コマンドで実行します。

local connection を使うのですが、インベントリファイルが必要になるので、作成しておきます。

$ cat > hosts <EOF
127.0.0.1
EOF

では、実行してみましょう。ansible-playbook コマンドを実行すると、2 つのタスクが処理されました。

$ ansible-playbook -i hosts aws.yml

PLAY [localhost] **************************************************************

TASK: [Create ec2 instanse] ***************************************************
changed: [localhost]

TASK: [Set Public DNS to CNAME in Route53] *********************************************
changed: [localhost] => (item={......})

PLAY RECAP ********************************************************************
localhost                  : ok=2    changed=2    unreachable=0    failed=0

AWS の Management Console を確認すると、Name タグに ansible1 が設定されたインスタンスが生成されていました。

ansible-aws-ec2

Route 53 を見ると、想定したいた FQDN の CNAME に EC2 インスタンスの Public DNS が設定されていました。

ansible-aws-route53

起動済の EC2 を破棄

EC2 インスタンスを起動して、Route 53 に登録するという流れはできました。

ただ、このままだと、この playbook を実行する度に新しいインスタンスが作成されるので、不要なインスタンスが残り続けます。そこで、今回は検証環境ということで、古いインスタンスは破棄した後に、新しいインスタンスを作るという流れにします。

起動済のインスタンスを破棄するには、稼働中のインスタンス ID を取得する必要があります。インスタンス ID はec2_factsモジュールを実行します。このモジュールは、インスタンス内で実行するので、インスタンスをインベントリファイルに追加する必要があります。

これを手で行うと、インスタンスを起動するたびにインベントリファイルを書き換えることになるので、Dynamic Inventory を利用します。Dynamic Inventory は、インベントリ情報をスクリプト等で動的に生成することができる仕組みです。これを使うことで、AWS から稼働中のインスタンス情報を取得して、各インスタンスをインベントリとして、タスクを実行することができます。

Ansible のソースコードには、稼働中の EC2 インスタンス情報を取得するスクリプト(plugins/inventory/ec2.py, plugins/inventory/ec2.ini)が含まれているので、これを利用します。

https://github.com/ansible/ansible/blob/devel/plugins/inventory/ec2.py
https://github.com/ansible/ansible/blob/devel/plugins/inventory/ec2.ini

ec2.py はインベントリを取得するスクリプトで、ec2.ini がその設定ファイルです。

まず、ec2.ini の設定を変更します。ec2.py は、デフォルトでは取得した情報をキャッシュ仕組みになっているのですが、今回は実行時に最新の情報を取得したいので、このキャッシュを無効にします。

$ vim ec2.ini
cache_max_age = 300 # デフォルトは 300 秒なので、0 にする
↓
cache_max_age = 0

次に、playbook にインスタンス情報を取得するタスクを追加します。このタスクは、先頭に記述しておきます。hosts には、tag_Name_ansible1を指定しています。これは ec2.py で動的に取得したインベントリの内、タグ Name の値が ansible1 のホストを対象にするということです。このように ec2.py では稼働中の全インスタンスを利用するだけでなく、タグやインスタンスタイプなど様々な切り口でインベントリを絞り込むことができます。

---
- hosts: tag_Name_ansible1
  gather_facts: no
  user: root
  tasks:
    - ec2_facts:

つづいて、取得したインスタンス情報を使って、インスタンスを破棄します。インスタンスの破棄には ec2 モジュールを利用します。state=absentを指定することで、instance_idsで指定したインスタンスが破棄されます。

下記では、with_items で、インスタンスID を指定しているので、タグ名が ansible1 のインスタンスは全て破棄されます。

- hosts: tag_Name_ansible1
  gather_facts: no
  connection: local
  tasks:
    - name: Remove ec2 previous instances
      ec2: state=absent
           region=ap-northeast-1
           instance_ids={{ item }}
           wait=true
      with_items: ansible_ec2_instance_id

完成した playbook の実行

playbook が完成しました。実行してみましょう。

-iオプションで、ec2.py を指定して、下記のように実行します。

実行すると下記の流れでタスクが実行されていきます。これで、何度実行しても起動しているインスタンスは一つのみになりました。

  1. タグ名=ansible1 の EC2 インスタンス情報取得
  2. 1 で取得した EC2 インスタンスを破棄
  3. EC2 インスタンス作成
  4. 3 で作成したインスタンスの Public DNS を Route 53 に登録
$ ansible-playbook -i ec2.py aws.yml

PLAY [tag_Name_ansible1] ******************************************************

TASK: [ec2_facts ] ************************************************************
ok: [xxx.xxx.xxx.xxx]

PLAY [tag_Name_ansible1] ******************************************************

TASK: [Remove ec2 previous instances] *****************************************
changed: [xxx.xxx.xxx.xxx] => (item=i-xxxxxx)

PLAY [localhost] **************************************************************

TASK: [Create ec2 instanse] ***************************************************
changed: [localhost]

TASK: [Set Public DNS to CNAME in Route53] *********************************************
changed: [localhost] => (item={...})

PLAY RECAP ********************************************************************
xxx.xxx.xxx.xxx            : ok=2    changed=1    unreachable=0    failed=0
localhost                  : ok=2    changed=2    unreachable=0    failed=0

最終的な playbook は以下です。

---
- hosts: tag_Name_ansible1
  gather_facts: no
  user: root
  tasks:
    - ec2_facts:

- hosts: tag_Name_ansible1
  gather_facts: no
  connection: local
  tasks:
    - name: Remove ec2 previous instances
      ec2: state=absent
           region=ap-northeast-1
           instance_ids={{ item }}
           wait=true
      with_items: ansible_ec2_instance_id

- hosts: localhost
  gather_facts: no
  connection: local
  tasks:
    - name: Create ec2 instanse
      ec2:
        key_name: keyA
        instance_type: t2.micro
        image: ami-0xxxxx
        monitoring: yes
        wait: yes
        region: ap-northeast-1
        group_id: sg-xxxxxx
        vpc_subnet_id: subnet-xxxxx
        assign_public_ip: yes
        instance_tags: 
          Name: ansible1
      register: ec2

    - name: Set Public DNS to CNAME in Route53
      route53:
        command: create
        zone: dev.example.com
        type: CNAME
        value: "{{ item.public_dns_name }}"
        overwrite: yes
        record: ansible1.dev.example.com
        ttl: 300
      with_items: ec2.instances

さいごに

Ansible で AWS を操作してみました。

インスタンス情報の取得やその情報の利用(インスタンス破棄)などは少しコツが必要ですが、それさえ分かれば、思ったとおりに動作しました。はじめは同じことを Terraform で行っていたのですが、プロビジョンには Ansible を使っていたので、どうせなら Ansible で完結させようと思い、試してみました。

このエントリでは、AWS の操作のみ行っていますが、実際は、インスタンス生成後にプロビジョンやデプロイを行う playbook を挟む形になります。こうすれば、EC2 インスタンス生成、プロビジョン、デプロイが Ansible だけで行うことができます。

  • コメント (Close): 0
  • トラックバック (Close): 0

AWS EC2 インスタンス間の名前解決に Route 53 を使う

  • 2014-09-05 (金)
  • AWS
この記事の所要時間: 638

Route 53 に EC2 インスタンスの Public DNS を CNAME で登録して、それを EC2 インスタンス間での通信でも利用するという話です。

1. 前提

  • EC2-Classic 環境
  • EC2 インスタンスの接続情報(FQDN なり IP なり)は、AWS のメンテナンスによる再起動などで変更される。
  • アプリケーションやミドルウェアで、別インスタンスに接続している場合、AWS から割り当てられる Public DNS や IP を設定ファイルなどに記述していると、変更の度に修正が必要になる。
  • DNSサーバを立てようとしたが、そこまで変更の頻度は多くない(日常的にインスタンス数が増減するわけではない)ので、正直わざわざ立てるほどでも無い。また、DNS サーバの面倒も見たくない。

2. やりたいこと

  • Route 53 で各ホストの接続情報を管理すれば、一元管理できるし、修正も一箇所で済む。
  • DNS サーバの面倒を見る必要が無いし、自分で運用するより安心。(Route53 は、SLA 100%
  • EC2 インスタンスごとに FQDN を割り当てて、CNAME として EC2 インスタンスの Public DNS を設定する。
  • Public DNS を設定するのは、同じ FQDN で、AWS 外部からはグローバル IP、内部ではプライベート IP を返せるようにするため。
  • 外部からのアクセスは、Security Group で制限する。

3. 設定

3-1. Route 53 で、サブドメインを作る

まず、EC2 インスタンス用のサブドメインを作成します。これは FQDN の管理の都合上だけなので、すでに存在してるドメインに、CNAME レコードを追加しても問題無いです。

ここでは、example.com を保持しているとして、サブドメインとして aws.example.com を作成します。EC2 インスタンスは、web1.aws.example.com や db-master.aws.example.com などにします。

まず、Route 53 の画面で、「Create Hosted Zone」をクリックして、新しいゾーンを作成します。Domain Nameには今回作成するサブドメインを記述します。

route53_create_zone

ゾーンを作成すると、Delegation Set が割り当てられます。これは後で、委譲先として設定するのでコピーしておきます。

route53_delegation_set

aws.example.com をサブドメインとして設定します。ここでは、example.com ドメインを Route 53 で管理している想定なので、それ以外の場合は、それぞれ適時設定して下さい。

すでにある exaple.com ゾーンを開いて、「Create Record Set」をクリックして、新しいレコードセットを作成します。画面右側のフォームで、「Nameaws を、TypeNS - Name server を入力します。Value には、先ほどコピーしておいた aws.example.com ゾーンの Delegation Set の内容をペーストします。

route53_ns_record

これで aws.example.com の設定ができました。

3-2. Route 53 で、EC2 インスタンスの FQDN を設定する

あとは、作成した aws.example.com に、レコードセットを追加して、EC2 インスタンスの Public DNS を CNAME として登録していくだけです。

ここでは、Web サーバとして使っている EC2 インスタンスの Public DNS を、web1.aws.example.com に割り当てます。

まず、EC2 の Public DNS を確認します。Management Console では下記のように表示されているので、これをコピーしておきます。

ec2_public_dns.png

次に、Route 53 で、aws.example.com ゾーンを選択して、「Create Record Set」をクリックします。フォームには、以下のように、Nameweb1TypeCANE - Canonical nameValue に先ほどコピーした EC2 インスタンスの Public DNS を設定します。

ec2_public_dns

これで設定は完了です。

3-3. 動作確認

設定した FQDN が引けるかどうか確認します。(実際は、実在の FQDN で実行してますが、ここでは例示のため、exmaple.com ドメインとしています。)

まず、EC2 インスタンス内で引いてみます。こちらでは、10.0.yyy.yyy というローカル IP が引けました。

[ec2-user@ip-10-xxx-xxx-xxx]$ dig web1.aws.example.com
;; ANSWER SECTION:
web1.aws.example.com.    300     IN      CNAME   ec2-54-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com.
ec2-54-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com. 60 IN A 10.0.yyy.yyy

次に、AWS の外部で引いてみます。54.yyy.yyy.yyy というグローバル IP が引けました。

$ dig web1.aws.example.com
(snip)
;; ANSWER SECTION:
web1.aws.example.com.    300     IN      CNAME   ec2-54-xxx-xxx-x.ap-northeast-1.compute.amazonaws.com.
ec2-54-xxx-xxx-x.ap-northeast-1.compute.amazonaws.com. 604800 IN A 54.yyy.yyy.yyy

どちらも正常に動作していることが確認できました。

4. 利用

アプリケーションやミドルウェアなどで、EC2 インスタンスへ接続する場合は、今回設定した web1.aws.example.com を設定します。AWS 内部であれば、ローカル IP が引けるので、内部ネットワークで接続できます。

動作確認などで、外部から接続する場合も同じく web1.aws.example.com へ接続します。AWS 外部であれば、グローバル IP が引けるので、該当インスタンスへ接続することができます。

5. Public DNS が変更した場合

EC2 インスタンスの再起動などで、Public DNS が変更になった場合は、Route 53 にて、web1.aws.example.com の Value を新しいインスタンスの Public DNS に設定するだけです。

さいごに

Route 53 で、EC2 インスタンスの Public DNS を設定する方法を見てきました。

ここでは、EC2 インスタンスの話を書いていますが、RDS や ElastiCache などのエンドポイントも同じように Route 53 で FQDN を割り当てておくと、もしエンドポイントが変更になった際も変更箇所が限定されているので楽です。

ただ、Route 53 に登録するということは、当然ながら、誰もが Public DNS を知ることができるという点は留意しておく必要があります。(もちろん、FQDN も知る必要がありますが)個人的には、Security Group で接続制限をかけていれば問題は無いと思いますが、これまずいんじゃない?というのがあれば、教えて下さい m(_ _)m

  • コメント (Close): 0
  • トラックバック (Close): 0

Laravel の Queue で非同期処理を実装する(beanstalkd / IronMQ / SQS)

この記事の所要時間: 1654

Laravel で実装されている Queue について見てみました。

laravel

Laravel では Queue を使うことで、時間がかかる処理や、時間差で実行したい処理を非同期で実行することができます。

Laravel 4.2 の Queue では、以下の 5 つのキュードライバをサポートしています。

  • sync
  • Beanstalkd
  • Amazon SQS
  • IronMQ
  • Redis

ここでは、sync、Beanstalkd、IronMQ、Amazon SQS について試してみました。

Laravel での設定

Laravel で Queue を使うには、app/config/queue.phpにて、利用するキューエンジンの選択、設定を行います。

もちろん他の設定と同じく、app/config/local/queue.phpapp/config/production/queue.phpなど、環境に応じて設定を切り替えることも可能です。

下記が設定例です。defaultでは利用するキュードライバを指定します。指定できる値は、sync, beanstalkd, sqs, iron, redis の 5 種類です。

connectionsキーでは、それぞれのドライバについて接続情報を指定します。下記では、beanstalkdの接続情報を指定しています。

return [
    'default' => 'beanstalkd',
    'connections' => [
        'beanstalkd' => [
            'driver' => 'beanstalkd',
            'host' => 'localhost',
            'queue' => 'default',
            'ttr' => 60,
        ],
    ],
];

キューへジョブを登録

キューへのジョブを登録するには、Queueクラスのpushメソッドを使います。

第一引数にはジョブを実行するワーカーのクラス名を、第二引数にはワーカーに渡すパラメータを指定します。

use CarbonCarbon;

Queue::push('MyWorker', ['message' => 'Hello!', 'date' => Carbon::now()]);

ここでは、ワーカーのクラス名のみを指定しているため、ジョブを実行する際はfireメソッドが呼ばれます。他にもMyWorker@doJobとすることで任意のメソッドを実行したり、クロージャを渡して、そのクロージャをワーカーとして実行したりできます。

詳しくはドキュメントを参照してください。

http://laravel.com/docs/queues
http://laravel4.kore1server.com/docs/42/queues

ワーカーの実装

ジョブを処理するワーカーとしてMyWorkerクラスを実装します。ワーカーは特定のクラスを継承する必要はなく、 POPO(Plain Old PHP Object)で良いです。

MyWorkerクラスにはfireメソッドを実装します。ジョブがキューに登録されると、リスナーからこのメソッドが呼ばれます。

第一引数にはジョブインスタンス、第二引数では、Queue::push()の第二引数で指定したパラメータが渡されます。ただ、このパラメータはジョブに入る時にjson_encode()されるので、オブジェクトのインスタンスはプロパティの連想配列となります。

下記の実装では、渡されたパラメータを元に文字列を生成して、echoで標準出力へ出力しているだけです。

ジョブが正常に完了したら、delete()メソッドで、ジョブを削除しておきます。これを行わないと同じジョブが何度も実行されています。

<?php
use CarbonCarbon;
use IlluminateQueueJobsJob;

class MyWorker
{
    /**
     * @param Job $job
     * @param array $data
     */
    public function fire(Job $job, array $data)
    {
        echo sprintf('[%s] %s at %s', Carbon::now(), $data['message'], $data['date']['date']) . PHP_EOL;
        $job->delete();
    }
}

キューの監視

キューを監視してワーカーを起動するリスナーを起動します。

Laravel では artisan コマンドですでに用意されているのでこれを利用します。

php artisan queue:listenコマンドを実行すると、キューを監視状態になります。この状態でキューにジョブが登録されていると、自動でワーカーが起動して処理が実行されます。

$ php artisan queue:listen

この状態でジョブが登録されると下記のように出力されます。

$ php artisan queue:listen
[2014-08-14 16:52:35] Hello! at 2014-08-14 16:52:34.000000
Processed: MyWorker

このプロセスが終了しているとキューにジョブが登録されても実行されないので、supervisor や monit などで常時起動するように設定しておくと良いでしょう。

一定時間後に実行するジョブ

Queue::push()で登録したジョブは、リスナーが感知するとワーカーが起動して実行されます。

それとは別に、Queue::later()というメソッドを使うと、一定時間経過後に実行するジョブを登録することができます。

第一引数には、ジョブの実行を開始する時間を指定します。数値を渡すと秒数として認識され、その秒数が経過した際にジョブが実行されます。Carbonクラスのインスタンスを渡すとCarbonクラスで指定された日時に実行されるジョブとして登録されます。

第二引数と第三引数は、Queue::push()の第一引数と第二引数と同じです。

下記の例では、10秒後に実行されるジョブを登録しています。

Queue::later(10, 'MyWorker', ['message' => 'Delayed', 'date' => Carbon::now()]);

リスナー側では下記のような出力になります。[]内の日時と、atの後ろの日時で 10 秒ずれていることが分かります。

$ php artisan queue:listen
[2014-08-14 16:52:45] Delayed at 2014-08-14 16:52:34.000000
Processed: MyWorker

これはローカルの beanstalkd での実行なのでずれが無いですが、IronMQ を利用した際は、数秒のずれがありました。多少のずれは発生するので、それを認識した上で利用すると良いでしょう。

サポートしているキュードライバ

Laravel でサポートしているキュードライバ(Redisを除く)を見てみましょう。

sync

デフォルトで指定されているドライバです。

仕組みとしてはキュー、ワーカーの流れを通るのですが、ジョブが登録されると、即時にワーカーが実行されます。

非同期処理にはならないので、実際にキューを使う場面では、他のドライバを利用する必要があります。

Beanstalkd

Beanstalkd は、オープンソースのキューイングシステムです。

利用するには、Beanstalkd 自体のインストールが必要になります。

Beanstalkd は、yum などパッケージでも公開されているので、利用するプラットフォームごとに選択してインストールすると良いです。

ここでは OSX 環境を想定して、Homebrew でインストールします。

$ brew install beanstalkd

beanstalkd を起動します。デフォルトではポート11300で待ち受けます。

$ beanstalkd

なお、beanstalkd は、デフォルトではキューの情報を永続化しません。このままだと beanstalkd が落ちるとキューの情報が消えてしまうので、本番環境などで運用する際は、永続化するように設定を行うのが良いです。

http://kr.github.io/beanstalkd/

Laravel で利用する際は、composer で下記のパッケージを追加しておきます。pda/pheanstalk は、3.x がリリースされていますが、Laravel 4.2 は、2.x 系にしか対応していないので、バージョン番号に注意して下さい。

"require": {
  "pda/pheanstalk": "~2.1.0"
}

IronMQ

Iron.io が提供しているメッセージキューサービスです。

ブラウザから登録するだけで利用することができます。基本は有償サービスなのですが、無料プランが用意されており、1,000,000APIリクエスト/月まで利用することができます。

グラフィカルな管理画面が用意されており、キューの状況などが分かりやすいのが良いです。

Heroku の Addon としても提供されているので、Heroku へデプロイするなら簡単に連携することができます。

Laravel で利用する際は、composer で下記のパッケージを追加しておきます。

"require": {
  "iron-io/iron_mq": "~1.5.1"
}

下記が Heroku 環境で IronMQ を利用する際の設定例です。Heroku では、接続情報が環境変数で提供されてるので、それらをtokenprojectに設定しています。

return [
    'default' => 'iron',
    'connections' => [
        'iron' => [
            'driver' => 'iron',
            'host' => 'mq-aws-us-east-1.iron.io',
            'token' =>  getenv('IRON_MQ_TOKEN'),
            'project' => getenv('IRON_MQ_PROJECT_ID'),
            'queue' => 'sample',
            'encrypt' => true,
        ],
    ],
];

AWS US-EastAWS EU-WestRackspace ORDRackspace LONのインスタンスを利用することができます。日本国内のインスタンスは存在しないので、国内のアプリケーションからキューを登録する場合はレイテンシが気になるかもしれません。

http://www.iron.io/

SQS

AWS のメッセージキューサービスです。

こちらも管理画面からキューを作成するだけで利用することができます。有償サービスですが、無料枠が用意されており、100万件キューイングリクエスト/月まで無料で利用することができます。

東京リージョンを利用できるので、アプリケーションサーバが国内にあるなら利用しやすいですね。

Laravel で利用する際は、composer で下記のパッケージを追加しておきます。

"require": {
  "aws/aws-sdk-php-laravel": "1.*"
}

設定例は下記です。ここでは、アクセスキーやシークレット、エンドポイントURL を環境変数で渡しています。AWS ではおなじみですが、regionにキューを作成したリージョンを指定するのを忘れないようにしましょう。

    'default' => 'sqs',
    'connections' => [
        'sqs' => [
            'driver' => 'sqs',
            'key' => getenv('AWS_ACCESS_KEY_ID'),
            'secret' => getenv('AWS_SECRET_ACCESS_KEY'),
            'queue' => getenv('AWS_SQS_URL'),
            'region' => 'ap-northeast-1',
        ],
    ],

http://aws.amazon.com/jp/sqs/

ユニットテスト

キューにジョブを登録する側のテストについてです。

QueueクラスをshouldReceiveメソッドでモック化して、テストするのが手軽です。

<?php
use CarbonCarbon;

/**
 * Class QueueTest
 */
class QueueTest extends TestCase
{
    /**
     * @test
     */
    public function queuePush()
    {
        $now = Carbon::create(2014, 8, 13, 12, 34, 56);
        Carbon::setTestNow($now);

        Queue::shouldReceive('connected')->once();
        Queue::shouldReceive('push')->once()->with('MyWorker', ['message' => 'Hello!', 'date' => $now]);
        Queue::shouldReceive('later')->once()->with(10, 'MyWorker', ['message' => 'Delayed', 'date' => $now]);

        $this->client->request('GET', '/queue/push');

        $this->assertTrue($this->client->getResponse()->isOk());
    }
}

サンプルアプリケーション(Heroku)

このエントリの内容を実装したサンプルアプリケーションを github に公開しています。

コード自体はシンプルで、http://localhost/quque/push にアクセスするとジョブがキューに登録されます。あとは php artisan queue:listen コマンドでジョブが実行されます。

Heroku で試せるように、heroku_create というシェルスクリプトで、heroku 関連のコマンドを記述しています。このコマンドを流せば、Heroku アプリケーションが構築されます。

Heroku でのポイントは、`Procfile`で、ワーカープロセスとしてリスナーを起動するという点です。

web: vendor/bin/heroku-php-apache2 public/
worker: php artisan queue:listen

このアプリケーションを Heroku にデプロイすると、web(ジョブをキューに登録する側)、worker(リスナー)の Dyno が構築されます。

あとは Heroku の管理画面で worker の Dyno 数を 1 にすると、web 経由で登録したジョブが worker によって実行されるようになります。

https://github.com/shin1x1/laravel-queue-sample

さいごに

Laravel の Queue について見てきました。

最後に、どのドライバを使うかについてですが、開発環境では beanstalkd を利用するのが手軽で良いでしょう。ローカルにインストールするので動作も速いです。

本番環境では、要件によりけりですが、国内にアプリケーションサーバがあるなら SQS、Heroku など US リージョンを利用するなら IronMQ が良さそうです。

もちろん、自前で beantalkd や Redis を立てるのも良いですが、利用できるなら、ありものを利用するのが楽ですね。

このように、開発環境と本番環境とでドライバを変えても、コード側は一切変更する必要が無いというのは、よく出来ていますね。

参考

blog.ISHINAO.net | Laravel 4でキューを使ってみる
laravel – キュードライバにbeanstalkdを使用する – Qiita

  • コメント (Close): 0
  • トラックバック (Close): 0

CentOS 5, 6 / Amazon Linux で PHP をパッケージインストールする方法まとめ

この記事の所要時間: 1251

Shin x blog Advent Calendar 2013 の 15 日目です。

php-logo

Cent OS 5, 6 / Amazon Linux にて、PHP の各バージョンを yum でインストールする方法をまとめてみました。

CentOS 6

PHP 5.3

CentOS 6 では、公式パッケージが PHP 5.3.3 なので、公式のリポジトリからインストールできます。

$ sudo yum -y install php
(snip)

$ php -v
PHP 5.3.3 (cli) (built: Dec 11 2013 03:29:57)

パッケージバージョンは 5.3.3–27 となっています。これは主にセキュリティ上の問題が発生した場合にパッチが提供されているためで、最新のビルドは、2013/12/10 になっています。

$ sudo rpm -qi php
Name        : php                          Relocations: (not relocatable)
  Version     : 5.3.3                             Vendor: CentOS
  Release     : 27.el6_5                      Build Date: Tue Dec 10 22:38:18 2013
  Install Date: Sat Dec 14 22:01:49 2013         Build Host: c6b10.bsys.dev.centos.org
  Group       : Development/Languages         Source RPM: php-5.3.3-27.el6_5.src.rpm
  Size        : 3702221                          License: PHP
  Signature   : RSA/SHA1, Wed Dec 11 04:24:11 2013, Key ID 0946fca2c105b9de
  Packager    : CentOS BuildSystem 
  URL         : http://www.php.net/
  Summary     : PHP scripting language for creating dynamic web sites

PHP 5.4

CentOS のリポジトリでは PHP 5.4 は提供されていないので、外部のリポジトリからインストールします。

ここでは、PHP 5.4 を提供しているリポジトリのうち、remi / IUS を利用します。

remi

remi リポジトリは、Fedora プロジェクトのコントリビュータでもある Remi Collet 氏が運営しているリポジトリです。

PHP の新バージョンがリリースされるごとに該当バージョンの RPM を作成し、配布しています。旧 php.net サイトから、外部リポジトリとしてリンクされていたので、PHP ユーザにはお馴染みですね。

まず、remi リポジトリを有効にするために RPM をインストールします。remi リポジトリには epel リポジトリが必要なので、こちらもインストールしておきます。

$ sudo rpm -Uvh http://ftp.jaist.ac.jp/pub/Linux/Fedora/epel/6/i386/epel-release-6-8.noarch.rpm
$ sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

PHP 5.4 を remi リポジトリからインストールします。パッケージ名は php です。remi リポジトリはデフォルトでは有効にならないので、–enablerepo オプションで指定します。

リリースされたばかりの PHP 5.4.23 がインストールされました。ビルド日時は、2013/12/11 となっています。

$ sudo yum -y install php --enablerepo=remi
(snip)

$ php -v
PHP 5.4.23 (cli) (built: Dec 11 2013 06:48:07)

IUS

IUS は、Rackspace が運営しているリポジトリです。

「Rackspace RPM の Fedora」と書かれているとおり、新しいパッケージは、まず IUS で公開し、プロダクション環境での利用が検証できた後に、Rackspace 顧客用のエンタープライズパッケージとして提供しているようです。

IUS リポジトリを利用するために ius-releaseepel-release パッケージをインストールします。

$ sudo rpm -Uvh http://dl.iuscommunity.org/pub/ius/stable/CentOS/6/x86_64/epel-release-6-5.noarch.rpm
$ sudo rpm -Uvh http://dl.iuscommunity.org/pub/ius/stable/CentOS/6/x86_64/ius-release-1.0-11.ius.centos6.noarch.rpm

PHP 5.4 を IUS リポジトリからインストールします。パッケージ名は php54 です。IUS リポジトリはデフォルトでは有効にならないので、–enablerepo オプションで指定します。

最新版の 5.4.23 ではなく、5.4.22 がインストールされました。ビルド日時は、2013/11/15 となっています。

$ yum -y install php54 --enablerepo=ius
(snip)

$ php -v
PHP 5.4.22 (cli) (built: Nov 15 2013 10:13:25)

IUS では、新しいパッケージは、まず ius-testing リポジトリで検証を行い、その後 ius リポジトリへ展開される流れになっているので、isu-testing リポジトリを見てみると、最新の 5.4.23 が公開されていました。検証環境などで、すぐに新しいバージョンを使いたい場合は、ius-testing を利用すると良いでしょう。

$ sudo yum info php54 --enablerepo=ius-testing
(snip)
Available Packages
Name        : php54
Arch        : x86_64
Version     : 5.4.23
Release     : 3.ius.centos6
Size        : 2.7 M
Repo        : ius-testing
(snip)

PHP 5.5

PHP 5.5 も公式リポジトリでは提供されていないので、remi / IUS からインストールします。

remi

remi の PHP 5.5 は、remi-php55 というリポジトリにて提供されていますので、–enablerepo では、remi-php55 を指定します。パッケージ名は php になります。

最新版の 5.5.7 がインストールされました。ビルド日時は、2013/12/11 です。

$ sudo yum -y install php --enablerepo=remi-php55
(snip)

$ php -v
PHP 5.5.7 (cli) (built: Dec 11 2013 07:13:20)

IUS

IUS では、ius リポジトリにて PHP 5.5 が提供されているので、パッケージ名を php55u に変更します。

最新版から一つ前の 5.5.6 がインストールされました。ビルド日時は、2013/12/04 です。

$ sudo yum -y isntall php55u --enablerepo=ius
(snip)

$ php -v
PHP 5.5.6 (cli) (built: Dec  4 2013 17:19:08)

なお、5.4 と同じく ius-testing リポジトリを見ると、最新版の 5.5.7 が提供されていました。

$ sudo yum info php55u --enablerepo=ius-testing
(snip)
Name        : php55u
Arch        : x86_64
Version     : 5.5.7
Release     : 1.ius.centos6
Size        : 2.6 M
Repo        : ius-testing
(snip)

CentOS 5

PHP 5.1

CentOS 5 では、ベンダー提供の標準 RPM が、PHP 5.1.6 なので、公式 yum リポジトリから yum install でインストールできます。

5.1.6 はかなり古いバージョンですが、現在もパッチの提供が続けられています。最新ビルドは、2013/12/10 となっていました。

$ sudo yum -y install php
(snip)

$ php -v
PHP 5.1.6 (cli) (built: Dec 10 2013 22:08:48)

PHP 5.3

公式リポジトリにて PHP 5.3 パッケージも配布されています。パッケージ名は php53 となっています。

CentOS 6 と同じく、PHP 5.3.3 がインストールされます。ビルド日時は、2013/12/10 です。

$ sudo yum -y install php53
(snip)

$ php -v
PHP 5.3.3 (cli) (built: Dec 10 2013 22:12:52)

PHP 5.4, 5.5

CentOS 6 と同じく、外部リポジトリを利用してインストールします。

remi / IUS 共に、CentOS 5 用の release パッケージが提供されていますので、こちらをインストールします。各 PHP のインストールは、CentOS 6 と同じです。

remi

epel-releaseremi-release パッケージをインストールします。

$ sudo rpm -Uvh http://ftp.jaist.ac.jp/pub/Linux/Fedora/epel/6/i386/epel-release-6-8.noarch.rpm
$ sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-5.rpm

IUS

epel-releaseius-release パッケージをインストールします。なお IUS では、PHP 5.4 は提供されていますが、PHP 5.5 は提供されていませんでした。

$ sudo rpm -Uvh http://dl.iuscommunity.org/pub/ius/stable/CentOS/5/x86_64/epel-release-5-4.noarch.rpm
$ sudo rpm -Uvh http://dl.iuscommunity.org/pub/ius/stable/CentOS/5/x86_64/ius-release-1.0-11.ius.centos5.noarch.rpm

Amazon Linux

Amazon Linux では、公式リポジトリにて、PHP 5.3, 5.4, 5.5 が提供されています。

同じリポジトリで提供されているので、パッケージ名にてインストールするバージョンを指定します。

PHP 5.3

パッケージ名を php でインストールします。最新版一つ前の 5.3.27 が提供されています。ビルド日時は、2013/07/12 です。

$ sudo yum -y install php
(snip)

$ php -v
PHP 5.3.27 (cli) (built: Jul 12 2013 22:04:28)

PHP 5.4

パッケージ名を php54 でインストールします。最新版一つ前の 5.4.22 が提供されています。ビルド日時は、2013/12/09 です。

$ sudo yum -y install php54
(snip)

$ php -v
PHP 5.4.22 (cli) (built: Dec  9 2013 18:19:32)

PHP 5.5

パッケージ名を php55 でインストールします。最新版一つ前の 5.5.6 が提供されています。ビルド日時は、2013/12/09 です。

$ sudo yum -y install php55
(snip)

$ php -v
PHP 5.5.6 (cli) (built: Dec  9 2013 18:09:49)

さいごに

CentOS / Amazon Linux にて PHP を yum でインストールする方法を見てきました。現在は、PHP 5.3, 5.4, 5.5 どのバージョンにおいても yum でインストールすることが可能です。

検証は、CentOS 6 は Vagrant + VirtualBox + Docker 、CentOS 5 は Vagrant + VirtualBox で、Amazon Linux は AWS で行いました。こういった類の検証では、Docker コンテナの起動の速さは便利ですね。Vagrant ですら昨年の今頃はまだ触った程度だったのに、ここ一年の進化は早いものです。

参考

  • コメント (Close): 0
  • トラックバック (Close): 0

とある CMS を使ったサイトに Varnish を導入した話

この記事の所要時間: 741

Shin x blog Advent Calendar 2013 の 6 日目です。

varnishcache-logo

とあるサイトに、Varnish をリバースプロキシとして導入して、半年が経過しました。

導入した経緯やその効果など書いてみたいと思います。

Varnish とは

Varnish は、HTTP アクセラレータです。Web サーバのリバースプロキシとして動作し、キャッシュを生かして高いパフォーマンスを発揮するのが特徴です。また、VCL という独自の設定言語を持ち、これにより状況に応じた設定を柔軟に行うことができます。

導入の経緯

このサイトでは LAMP 構成の CMS を利用しており、インフラには AWS を利用しています。基本、閲覧が中心なのですが、イベント時に多数のアクセスがあります。S3 や CloudFront も検討したのですが、コンテンツを数分おきに更新する必要があるので今回は採用しませんでした。

下記が構成のイメージです。なお図はかなり簡略化しており、実際の構成とは異なります。

before

こちらでパフォーマンスの問題が発生したので、CMS が生成したページ全体をキャッシュとして高速に返すよう Varnish Cache を導入しました。

after

当初、nginx の proxy_cache を試したのですが、同一 URL へ多数のリクエストが来ている状況でキャッシュのライフタイムが切れると、バックエンドへ同じ URL に対して複数のリクエストが飛んでしまい、PHP アプリケーション側に負荷がかかるという現象があったので、今回は取りやめました。

Varnish では、同一 URL に対して複数のリクエストがあっても、バックエンドへは 1 リクエストしか飛ばないようになっています。

導入

Varnish Cache は、m1.large インスタンスの Amazon Linux サーバに yum からインストールしました。

$ sudo rpm --nosignature -ivh http://repo.varnish-cache.org/redhat/varnish-3.0/el6/noarch/varnish-release/varnish-release-3.0-1.el6.noarch.rpm
$ sudo yum -y install varnish

もし varnish のプロセスが落ちた場合に自動で再起動するように monit も入れています。varnish は、monit から起動しています。

$ sudo yum install monit
$ sudo chkconfig monit on

$ sudo vim /etc/monit.d/varnish
check process varnish with pidfile /var/run/varnishd.pid
start program = "/etc/init.d/varnish start"
stop program = "/etc/init.d/varnish stop"

$ sudo service monit start

監視

死活、性能監視として Zabbix を採用していたので、Varnish サーバも Zabbix で監視しています。

Zabbix のテンプレートは下記を利用しています。

rdvn / zabbix-templates

効果

Varnish 導入の効果はてきめんでした。

ELB 経由で来たリクエストは全て Varnish を経由しており、キャッシュが有効な期間(3分で設定しています)は、キャッシュを返すだけなので非常に高速です。

またキャッシュが切れた場合も、バックエンドへは 1 URL に対して 1 リクエストしか来ないため、バックエンドへの大きな負荷にはなりません。(ある特定の数ページのみが際立ってアクセスされるサイトなので)

導入前は、ピーク時にはバックエンドの Web サーバが応答を返せない場合があったのですが、それも一切無くなりました。

はっきりいって、下手に CMS を細々チューニングするよりも遥かに効果があります。導入後も安定して動いており、Varnish 起因の問題も発生していません。

参考の数値として、270,000 req/m のリクエストが来た時(Varnish 上位にある ELB の RequestCount)、Varnishサーバ(m1.large)の CPU 利用率は 56% 程度でした。その際の Client requests received(client_req)は 5,000 弱でした。外部からの閲覧に関して遅延など異常はありませんでした。

VCL

Varnish の特徴として挙げられるのが VCL = Varnish configuation Language による設定です。

VCL は小さな DSL となっており、プログラミングのように設定を書くことができます。イメージとしては nginx の設定をよりコードっぽくした感じですね。

例えば、下記は UserAgent を見て、iPhone が含まれていたら、http://sp.example.com/ へリダイレクトさせる VCL です。

if (req.url == "/") {
  if (req.http.user-agent ~ "(?i)iPhone") {
    error 750 "Moved Temporarily";
  }
}

sub vcl_error {
  if (obj.status == 750) {
    set obj.http.location = "http://sp.example.com/";
    set obj.status = 302;
    return (deliver);
  }
}

参考

構築にあたって参考にしたサイトです。柔軟に設定できるので、色々と調べながらの調整になりました。

さいごに

Varnish は、手軽に導入できるわりに簡単にパフォーマンスを向上させることができます。とくに CMS のような閲覧が中心となるアプリケーションには大きな効果を発揮します。

CMS 自体にもキャッシュ機構などは付いていますが、それよりの上位でキャッシュできるので、バックエンドが負荷に耐えられない構成でもうまく吸収することができます。

個人的には VCL がプログラムっぽく書けるのが設定しやすくて好きです。

アクセス過多でパフォーマンスに問題が出た際に使える切り札として覚えておくと、いつか役立つ日が来るやもしれません。

公式サイトのドキュメントが英語なので、日本語でのまとまった情報があればと思うのですが、詳しい方(チラチラッ、Kindle とかでどうでしょうか 😀

おまけ Vagrantfile

簡単に Varnish を試せるように Vagrantfile を作りました。

vagrant up して、http://192.168.33.50/sample.php にアクセスすると現在日時が表示されます。こちらがバックエンドアプリケーションの想定ですので、リロードする度に表示される日時は変わっていきます。

Varnish は 6081 port で待ち受けているので、http://192.168.33.50:6081/sample.php にアクセスするとその時点でのページがキャッシュされます。リロードするとキャッシュが返され、日時が変更されていないことが分かるでしょう。

shin1x1/vagrant-varnish

$ git clone https://github.com/shin1x1/vagrant-varnish
$ vagrant up
  • コメント (Close): 0
  • トラックバック (Close): 0

関西PHP勉強会で「いまどきのPHP」を発表してきました( in JAWS FESTA Kansai 2013 )

この記事の所要時間: 325

9/28に京セラドームで開催されたJAWS FESTA Kansaiの1トラックとして、関西PHP勉強会を開催しました。

Untitled
Photo by omoon.

午前のセッションにも関わらず、多数の方に参加頂き、ありがとうございました。

いまどきのPHP

今回の勉強会では、3セッションを行ったのですが、私のセッションでは「いまどきのPHP」について発表しました。

いまどきのPHP from Masashi Shinbara

いつもの勉強会とは違い、JAWS FESTA Kansai の中で開催したので、PHPユーザ以外の方(普段は別の言語で開発している、以前は書いていたけど最近の動向は知らない)が参加されるかもと思い、いま多くの言語で行われているオブジェクト指向開発がPHPでもきるんだよということを伝えたくて、PHPのオブジェクト指向機能をメインにしました。

結果としては、ほとんどの方がPHPをメインで使われているとのことだった(まあ、PHP勉強会なので当たり前になのですが:))ので、おさらい程度の内容だったと思うのですが、熱心に聴いて下さる方もいたので、話して良かったです。

じゃんけん大会

勉強会の終わりには、「PHPエンジニア養成読本」をかけたじゃんけん大会を行いました。

ちょうど隣の WordBench 大阪のセッションが終わった頃だったので、多数の方に参加頂いて、盛り上がりました:D 獲得された方は、簡単な内容で良いので、レビューなど書いて頂ければ嬉しいですm(_ _)m

blog を書くまでが勉強会

数年前の勉強会では良く言われていたフレーズです。私自身の開催する勉強会では必ずこの話をしていたのですが、TwitterやFacebookなど気軽に短文を投稿できるメディアが広がってからはあまり聞かなくなりました。

その頃から、勉強会やカンファレンスなどのイベントへの参加blog記事が少なくなってきたような気がします。私自身も以前は書いていた参加エントリも書かなくなりました。(一時期はスライドすら公開しないことも><)

今回は初心に戻って、勉強会の最初と最後で伝えたのですが、すると早速いくつかのエントリを書いて頂けました!一時期に比べるとblogを書く人が減っているのはあるとは思うのですが、きちんと伝えれば反応してくれる人はいるのだとあらためて思いました。

勉強会の運営やセッションでの発表などは一方通行のものではなく、参加した人との相互作用で成り立つものだと思います。その場でお話するのももちろん良いのですが、できればblogなどでのフィードバックがあると今後の参考になりますし、なにより「開催して良かった」「次はこうしよう」など今後へのモチベーションにもなりますので、可能な範囲で書いて頂けると嬉しいです。(自戒も込めて)

発表資料や参加エントリはKansai PHP Users Group の Facebook グループにて。

Kansai PHP Users Group として別イベントへの参加

Kansai PHP Users Group として活動してから、3 年以上が経つのですが、ようやく別のイベントにコミュニティとして参加する機会が増えてきました。

8 月には WordBench 大阪にてセッションを行いました。今回は JAWS FESTA Kansai にて勉強会を開催しました。これまで参加したいとは思いつつ、タイミングが合わず実現していなかったのですが、ここ最近はそれが一気に来ました。

実は、10 月にはInnovation EGG、そして11月にはKOFへの参加を予定しています。

関西の中で、それぞれのコミュニティが分断しているのではなく、一緒に何かやりたいというのは以前から頭にはあったのですが、色々な人の出会いのおかげで、それが少しづつ形になってきています。今後もこういったコラボレーションを行っていきたいですね。

  • コメント (Close): 0
  • トラックバック (Close): 0

Amazon S3 stream wrapper で S3 を操作する

この記事の所要時間: 038

AWS SDK for PHP2 に実装されている Amazon S3 stream wrapper で S3 を操作してみました。

Amazon S3 stream wrapper を使うと「s3://bucket/foo/bar.txt」といったパスで mkdir() や file_get_contents() などの標準関数から S3 を操作することができます。

Amazon S3 stream wrapper の使い方

Amazon S3 stream wrapper は AWS SDK for PHP2 に含まれているので、SDK をインストールしておきます。インストール方法などは下記をどうぞ。

AWS SDK for PHP 2 をインストールして AutoScaling の設定を行う

Aws\S3\S3Client の registerStreamWrapper メソッドを実行すると「s3」というプロトコルが有効となります。
あとは通常のファイル操作と同じように mkdir() や file_get_contents() 関数にて操作対象の S3 オブジェクトを操作します。

パス名は以下の形式で指定します。

s3://バケット名/キー(パス)

たとえば bucket1 というバケットの /folder/foo.txt であれば下記のようになります。

s3://bucket1/folder/foo.txt

以下のサンプルでは、東京リージョンに存在するバケットに対して、dir1/dir2 というフォルダを作成して、file1, file2, file3 というファイルをアップロードしています。さらに dir1/dir2 の内容を読み込んで echo しています。

これを実行すると以下のように出力されます。

$ php s3_stream_wrapper.php
s3://shin1x1-tokyo/dir1/dir2/file1.txt = file1
s3://shin1x1-tokyo/dir1/dir2/file2.txt = file2
s3://shin1x1-tokyo/dir1/dir2/file3.txt = file3

Management Console でも S3 にオブジェクトが作成されていることが分かります。

s3_stream_wrapper

Amazon S3 stream wrapper を使う利点

stream wrapper で S3 を操作する利点ですが、まず普段ファイルを操作するのと同じ方法で操作できるのが便利です。

また、スキーマを変更するだけで別のプロトコルで処理ができるので、ユニットテストが書きやすくなります。

具体的には、「s3://」といったパスを引数で渡して処理を実行するように実装しておきます。すると、テスト時は vfsStream を使って「vfs://」からはじまるパス名に渡すように変更すれば、S3 へ通信させることなくテストを実行することができます。

SDK の API を実行するよりも簡単にS3 を操作できるのでおすすめです。

参考

  • コメント (Close): 0
  • トラックバック (Close): 0

AWS SDK for PHP 2 をインストールして AutoScaling の設定を行う

この記事の所要時間: 1053

PHP から AWS を操作するためのライブラリ「AWS SDK for PHP」の新バージョン「AWS SDK for PHP 2」を触ってみました。

AWS SDK for PHP 2 リリース直後は対応サービスが少なかったのですが、現在は主要なサービスは網羅しているようです。

AWS SDK for PHP 2 の主な特徴

https://github.com/aws/aws-sdk-php

  • PHP5.3.3以降
  • PSR-0, PSR-1, PSR-2対応
  • Composer, PEAR でのインストール、phar ファイルの配布
  • Guzzleベース
  • namespace, Iterators, Waiters, Enums, レスポンスモデル, 例外など、いまどきの実装に対応

AWS SDK for PHP 2 のインストール

AWS SWK for PHP 2 は、phar ファイル、Composer 、PEAR のいずかれの方法でインストールすることができます。
phar ファイルが一番お手軽(ダウンロードするだけ)なのですが、ソースが読みづらいのと、APC が効かないという話もあるので、ここでは Composer でインストールします。

  • まず composer.json を作成します。
    $ vim composer.json
    {
      "require": {
        "aws/aws-sdk-php": "2.*"
      }
    }
    

  • 次に Composer をインストールします。
    $ curl -s "http://getcomposer.org/installer" | php
    #!/usr/bin/env php
    All settings correct for using Composer
    Downloading...
    
    Composer successfully installed to: /path/to/composer.phar
    Use it: php composer.phar
    

  • Composer で AWS SDK for PHP 2 をインストールします。依存ライブラリもダウンロードするので時間がかかる場合があります。
    $ php composer.phar install
    Loading composer repositories with package information
    Installing dependencies
      - Installing symfony/event-dispatcher (v2.2.1)
          Loading from cache
    
            - Installing guzzle/guzzle (v3.3.1)
          Loading from cache
    
            - Installing aws/aws-sdk-php (2.2.1)
          Loading from cache
    
          symfony/event-dispatcher suggests installing symfony/dependency-injection (2.2.*)
      symfony/event-dispatcher suggests installing symfony/http-kernel (2.2.*)
      aws/aws-sdk-php suggests installing doctrine/cache (Adds support for caching of credentials and responses)
      aws/aws-sdk-php suggests installing monolog/monolog (Adds support for logging HTTP requests and responses)
      aws/aws-sdk-php suggests installing symfony/yaml (Eases the ability to write manifests for creating jobs in AWS Import/Export)
      Writing lock file
      Generating autoload files
    

    インストールが完了すると以下のようなファイル、ディレクトリが存在します。

    $ ls
    composer.json composer.lock composer.phar vendor
    

    AWS SDK for PHP 2 の参考情報

    • github

    基本的な情報が README.md にあります。下記の User Guide や API リファレンスなどへのリンクもあります。

    https://github.com/aws/aws-sdk-php/

    • User Guide

    AWS SDK for PHP 2 の情報ならこれが一番分かりやすいです。SDK にも aws/aws-sdk-php/docs 以下に含まれていますが、下記サイトからも参照できます。
    インストール方法やサンプルソース、アーキテクチャ、パフォーマンスガイド、旧バージョンからのマイグレーションなど充実しています。

    AWS SDK for PHP 2 — AWS SDK for PHP 2.2.1 documentation

    Auto Scaling の設定

    現行は API でしか操作できない Auto Scaling の設定を AWS SDK for PHP 2 でやってみましょう。
    ELB 配下に立てる Web サーバのインスタンスを Auto Scaling で起動するイメージです。
    必要な ELB と Web サーバの AMI はあらかじめ用意しておきます。

    Auto Scaling の設定

    Auto Scaling の設定を行います。
    AWS SDK for PHP 2 の書き方としては、AWS の API へのパラメータを連想配列で渡す形になります。基本は全てのパラメータを連想配列で渡すだけなので分かりやすいですね。(このあたりは CakePHP っぽい)

    Auto Scaling 設定内容を確認

    Auto Scaling の内容は Management Console では確認できないので、API で確認します。

    実行すると以下のように設定された AutoScaling が確認できます。

    array(2) {
      'AutoScalingGroups' =>
      array(1) {
        [0] =>
        array(18) {
          'Tags' =>
          array(0) {
          }
          'SuspendedProcesses' =>
          array(0) {
          }
          'AutoScalingGroupName' =>
          string(2) "as"
          'HealthCheckType' =>
          string(3) "ELB"
          'CreatedTime' =>
          string(24) "2013-04-16T15:10:20.753Z"
          'EnabledMetrics' =>
          array(0) {
          }
          'LaunchConfigurationName' =>
          string(7) "as_conf"
          'Instances' =>
          array(2) {
            [0] =>
            array(5) {
              'HealthStatus' =>
              string(7) "Healthy"
              'AvailabilityZone' =>
              string(15) "ap-northeast-1c"
              'InstanceId' =>
              string(10) "xxxxxxxxxxxx"
              'LaunchConfigurationName' =>
              string(7) "as_conf"
              'LifecycleState' =>
              string(9) "InService"
            }
            [1] =>
            array(5) {
              'HealthStatus' =>
              string(7) "Healthy"
              'AvailabilityZone' =>
              string(15) "ap-northeast-1c"
              'InstanceId' =>
              string(10) "xxxxxxxxxxxx"
              'LaunchConfigurationName' =>
              string(7) "as_conf"
              'LifecycleState' =>
              string(9) "InService"
            }
          }
          'DesiredCapacity' =>
          string(1) "2"
          'AvailabilityZones' =>
          array(1) {
            [0] =>
            string(15) "ap-northeast-1c"
          }
          'LoadBalancerNames' =>
          array(1) {
            [0] =>
            string(2) "as"
          }
          'MinSize' =>
          string(1) "2"
          'VPCZoneIdentifier' =>
          array(0) {
          }
          'HealthCheckGracePeriod' =>
          string(3) "200"
          'DefaultCooldown' =>
          string(3) "300"
          'AutoScalingGroupARN' =>
          string(125) "arn:aws:autoscaling:ap-northeast-1:xxxxxxxxxxxxxxxxxxxxxxxxx"
          'TerminationPolicies' =>
          array(1) {
            [0] =>
            string(7) "Default"
          }
          'MaxSize' =>
          string(1) "5"
        }
      }
      'ResponseMetadata' =>
      array(1) {
        'RequestId' =>
        string(36) "xxxx"
      }
    }
    

    Auto Scaling を停止、削除

    Auto Scaling をそのままにしておくとインスタンスを停止しても、また起動してしまうので、停止、削除を行います。この処理を行うと Auto Scaling で起動したインスタンスも停止します。

    Auto Scaling の 注意点

    • HealthCheckType=ELB の時は、HealthCheckGracePeriod の指定が必要。
    • HealthCheckGracePeriod が短すぎると、インスタンス起動してELBのヘルスチェックが通るまでに異常とみなされて、インスタンスが終了する。
      => インスタンスが MinSize に足りなければ、起動->終了を繰り返して課金だけされる恐れがある。(EC2 インスタンスは一度起動すると最低 1 時間分は課金される。)
    • ヘルスチェックで異常とみなされたインスタンスは強制的に Terminate される。
    • 試した後は Auto Scaling を止めておく。
    • コメント (Close): 0
    • トラックバック (Close): 0

    ホーム > cloud > AWS

    検索
    フィード
    メタ情報

    Return to page top