Home > アーカイブ > 2014-10

2014-10

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

この記事の所要時間: 315

2014/10/11 に開催された PHPカンファレンス にて、「Ansibleではじめるサーバ作業の自動化」という発表を行ってきました。

th_ansible_logo_black_square

午前中のセッションだったのですが、多くの方にご参加頂き、ありがとうございました。

発表資料

発表資料をslideshareに公開しました。

Ansible ではじめるサーバ作業の自動化 from Masashi Shinbara

今回は、これからAnsibleを使ってみようという方を対象として、Ansibleの基本的な内容をメインにしました。また、実際に私自身がPHPプロジェクトで採用した際のユースケースを紹介しています。

発表後、「Ansibleをやってみます!」という意見を頂けたので、このセッションの目的は達成することができました:D

このセッションのフィードバックは、joind.in にて受けて付けています。すでにいくつか好評価を頂いていて安心していますが、もし良かったらお願いします。

https://joind.in/talk/view/12035

アプリケーションエンジニアが使う自動化ツール

セッションの最後にお話しましたが、Ansible の良さは仕組みが単純であり、豊富なモジュールがあるおかげで、適用範囲が広いということです。

構成管理はもちろんのこと、デプロイやクラウドオーケストレーション、そしてアドホックなメンテナンスなど、PHPアプリケーションの動作環境を構築して、運用していくための多くのタスクを自動化することができます。

もちろん、それぞれのタスクには特化したツールがあり、それらを使う方がより深い機能を使うことができます。ただ、別のツールを習得するには、それなりの学習コストを払う必要があります。

PHP エンジニアの中には、自分が開発したアプリケーションを動かすためにインフラも見るという人が多いと思うのですが、そういった人には、学習コストが低く、一つのツールで幅広いタスクをこなすことができる Ansible は、相性が良いように思います。

はじめは、Ansible の使い方を学習する必要はありますが、その効果を考えると、悪くない投資です。

これからAnsibleをはじめるなら

当日、時間の関係で入れられなかったのですが、これから Ansible を使う人に参考になるリンクを資料に入れています。

  • Ansible Documentation Ansible 公式ドキュメントです。何度もお世話になります。Dash に docset があるので、Dash ユーザの方はそちらも便利です。
  • Phansible PHP の開発環境を構築する Vagranfile を生成します。Ansible でプロビジョンを行うので、Playbook の書き方など参考になります。
  • Ansible Galaxy Role が公開されいるサイトです。ansible-galaxy コマンドで取り込んでも良いですし、他の人の書き方が参考になります。
  • ansible-examples Ansible 公式の Playbook サンプルです。LAMP や tomcat など様々なサンプルがあり、参考になります。
  • 入門Ansible 日本語で書かれた電子書籍です。分かりやすくまとまっていて、Ansible はじめる人はまず読んでおくと良いです。

さいごに

今回は午前中の発表ということで、午後からは気楽に過ごすことができました。見たいセッション続出で右往左往したりはしましたが、いくつかのセッションを楽しむことができました。

なぜか最後の懇親会で司会したりしてましたが、来年はスタッフの中から手を上げる人が出るといいと思います!(あとやっぱり、PIO でやる懇親会は良いですね。)

今年も楽しいカンファレンスをありがとうございました。

  • コメント (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

[書評] CakePHPで学ぶ継続的インテグレーション

この記事の所要時間: 939

著者の @kaz_29 さんから「CakePHPで学ぶ継続的インテグレーション」を献本して頂きました。日頃から関心のある分野なので、早速読ませて頂きました。

PHP で学ぶ継続的インテグレーション

本書のタイトルは「CakePHPで学ぶ継続的インテグレーション」です。実際、本書の中では、CakePHPアプリケーションを題材に継続的インテグレーションを行う手法が解説されています。

ただ、ここで紹介されている継続的インテグレーションの手法は、CakePHP 固有のものではなく、他のフレームワークでも転用可能なものです。

勝手なお世話ですが、書籍のタイトルとしては、「PHPで学ぶ継続的インテグレーション」の方が、良かったかもしれませんね:D

分散された情報がこの一冊に

継続的インテグレーション(CI)を行うには、あるツールさえ入れておけばできるというものではなく、多くのツールを組み合わせる必要があります。

数年前、自社で CI 環境を構築した際は、Jenkins のインストールからはじまり、PHP向けのビルドタスクの組み込み、Git リポジトリの連携、自動テストの実行、結果レポートの出力、検証など、多くの手間がかかりました。一つ一つのツールについては、公式サイトのドキュメントなどで情報はあるのですが、それらを組み合わせて、自分達の開発プロセスに合うように一つのビルドプロセスとして、インテグレートするのが大変でした。

特に、PHP プロジェクトで CI を行う際に参考となる情報が少なく、Template for Jenkins Jobs for PHP Projects が、数少ないお手本というような状況でした。

本書では、こうした CI 環境を構築するのに必要なツール群について多くの解説があります。ざっと書きだしただけで、下記のようなツールに触れられています。

  • Vagrant
  • VirtualBox
  • Chef
  • CakePHP
  • Jenkins
  • Behat
  • PHPUnit
  • PHP_CodeSniffer
  • PHPCPD
  • PHPMD
  • PHP_CodeCoverage
  • phpDocumentor
  • Composer
  • Phing
  • Capistrano

さらに加えて、CakePHP のプラグインもいくつか紹介されています。これらは、単にインストールして動かすということではなく、CI の流れで、それぞれのツールをどのように使うか、という視点で書かれています。

これまで、自分で細切れになった情報をかき集めて、ビルドプロセスを組み上げていく必要があったのですが、本書では、こうしたインテグレーションの一つの解法が記載されており、これから PHP プロジェクトで CI を行うには大いに参考になります。

すでに CI 環境を構築している場合も、それらを振り返り、改善していくための一つのパターンとして本書を参考にすることができます。

紹介されているツールを眺めてみるのも一つの面白さで、私は vagrant-chachier プラグイン をこの本を読んで使ってみようと思いました。

自分で CI 環境を作って、開発プロセスを実践

本書では、Vagrant を使って、自分の PC の中に仮想ホストを 3 つ、そして Github をアプリケーションコードのリポジトリとして利用するようになっています。

こうした環境構築では、実践する環境を作るのに手間がかかっていたのですが、Vagrant のおかげで仮想環境が楽に使えるようになったので、手軽に書籍の内容が実践できるようになりました。良い時代です。

仮想ホストは、開発環境(develp)、CI サーバ(ci)、本番環境(deploy)とそれぞれ役割が割り当てられていて、それぞれが Github のリポジトリをハブにして、アプリケーションのビルドやデプロイを行うようになっています。

全く同じ構成で良ければ、実際のプロジェクトにそのまま生かすこともできるでしょう。また、異なる構成でも CI として大まかな流れは似たものになるでしょうから、本書で得たノウハウを持って、自分のプロジェクトに CI を導入することができます。

実際に自分で手を動かして、CI 環境の構築、実践を行うことで、各ツールの役割や動きなどが実感として知ることができます。昨今は、Travis など SaaS のビルドサービスを使う場合も多いですが、自分で環境を作ってみることで、こうしたサービスもより理解が深まるのではないでしょうか。

サンプルコードの動かし方

書籍を読んで、記載されている手順を順に試すことで、CI 環境を構築することができます。はじめて、こうした環境を作るという方は、順に読み進めていくのが良いでしょう。

すでに CI 環境を利用している人は、公開されているサンプルコードを利用して環境構築を行うこともできます。私は、公開されているサンプルコードを使って、環境構築を行ないました。手順を記載しておきますので、参考まで。

事前準備

必要なツールです。以下は最低限必要になります。

  • Vagrant
  • vagrant-omnibus
  • VirtualBox

ChefDk インストール

Berkshelf を使うために、ChefDk をインストールしました。これは、Berkshelf や Knife など Chef 関連のツール群をパッケージングしているツールで、ダウンロードして、パッケージをインストールするだけでツールを使うことができます。Berkshelf を gem で入れると、すんなり行けば良いのですが、環境によってエラーが発生したりするので、こうした手間を省くために利用しました。

OSX であれば、brew cask でインストールすることができます。

$ brew cask install chefdk

サンプルコード取得

サンプルコードは、アプリケーションと環境構築でリポジトリが分かれています。

はじめに、自分で push できるように両リポジトリを fork します。

そして、環境構築のリポジトリを cakephp_ci ディレクトリに git clone します。cakephp_ci ディレクトリに移動して、アプリケーションのコードをリポジトリから、application ディレクトリに展開します。

$ git clone 環境構築リポジトリ cakephp_ci
$ cd cakephp_ci
$ git clone アプリケーションリポジトリ application

Berkshelf でクックブック取得

Berkchelf でクックブックを取得します。下記は、brew cask でインストールした ChefDk に含まれる berks コマンドを利用しています。

$ /opt/chefdk/bin/berks vendor cookbooks

vagrant up で仮想マシンを起動

cakephp_ci ディレクトリには、Vagrantfile があるので、vagrant upで起動します。3 つのホストについて、起動、プロビジョンを行うので、しばらく待ちましょう。

$ vagrant up
Bringing machine 'develop' up with 'virtualbox' provider...
Bringing machine 'ci' up with 'virtualbox' provider...
Bringing machine 'deploy' up with 'virtualbox' provider...

Composer の実行

develop にログインして、composer install を実行します。

$ vagrant ssh develop
vagrant@develop: cd /var/www/application/current/app
vagrant@develop: composer install

データベースの構築

各ホストにログインして、データベースとユーザを作成します。構築手順は、書籍の「4-3-2. データベースの作成」に記載があります。

vagrant@develop: mysql -uroot -ppassword

GRANT ALL PRIVILEGES ON *.* TO 'webapp'@'%' identified by 'passw0rd' WITH GRANT OPTION;
FLUSH PRIVILEGES;
CREATE DATABASE blog default character set utf8;
CREATE DATABASE test_blog default character set utf8;

データベーススキーマの構築

データベーススキーマは、CakePHP のプラグイン「CakeDC Migrations Plugin」を使って、構築します。マイグレーションファイルは、用意されているので、下記のように実行します。

vagrant@develop: cd /var/www/application/current
vagrant@develop: ./app/Console/cake migrations.migration run all

これで、delvelop ホストで、フィーチャのテストとユニットテストが通るようになります。

vagrant@develop: cd /var/www/application/current
vagrant@develop: ./app/Console/cake Bdd.story
vagrant@develop: ./app/Console/cake test app

さいごに

継続的インテグレーションの環境を構築して運用していくには、それなりにノウハウが必要です。これまで自力で何とかするしかなかったのですが、本書があれば、まずベーシックな構成については、構築することができます。正直、これから CI 環境を構築する人は、羨ましいです:D

できれば、データベースの構築などもプロビジョンで行うようになっていると、より自動化できて良いと思いましたが、これは読者への課題ということなのでしょう。

また、PHPCPD や PHPMD で算出される数値をベースにコードを改善していく内容がもっとあると嬉しかったです。(やや本書の範囲からはずれていきますが)

読んでいくにあたっては、その内容がどのホストで実行すべきものなのかをイメージしながら進むようにしましょう。これは実際の現場でも同じで、このタスクはどこでやるべきことなのかは常に意識する必要があります。

CI を実践するにあたって必要な情報が、ぎゅっと、まとまった 1 冊です。CakePHP に限らず、PHP プロジェクトで継続的インテグレーションを行うなら、ぜひ一度手にとってみて下さい。

「CakePHPで学ぶ継続的インテグレーション」ハンズオン

2014/11/01 に大阪で本書を題材にしたハンズオンが開催されます。講師には、著者の @kaz_29 さんにお願いしています。私もヘルプで入るつもりなので、みんなで CI を体験してみましょう。

http://devlove-kansai.doorkeeper.jp/events/15073

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

Home > アーカイブ > 2014-10

検索
フィード
メタ情報

Return to page top