読者です 読者をやめる 読者になる 読者になる

VCCWを使ってEC2上にWordPress開発環境を構築した

WordPress Vagrant

WordPressをモダンに開発/デプロイしたいと思い調べたところ、VCCWなるものが流行っているらしい。
のですが、公式ページにVagrant/VirtualBoxが必要と書いてある。。
でも、Vagrantvagrant-awsを使えばバックエンドにEC2を使えるはずでしょ!?
僕ちゃんVirtualBoxじゃなくてEC2使いたいの!!

というわけで、四苦八苦の末、表題の通りの環境構築ができたので、
世間は海の日でキャッキャウフフしている中、Google先生につきっきりで夏期講習して頂いた記録を残しておきます。
ちなみに僕は、Vagrantも今回初めて触った初心者なので、的外れな記述もあるかもです。
また、まだ動作が不明な箇所もあるので、ご指摘や情報キボンヌ!!

バージョン

おおまかな流れ

  1. VCCWのGetting Startedを実施
  2. Vagrantfileの修正
  3. vagrant up

で、 http://インスタンスのElasticIP/ でWordPressにアクセスできました。

VCCWのGetting Startedを実施

公式ページの通り、vagrant upする手前まで実施します。
多分、EC2の場合は使えないんじゃないかと思い、vagrant-hostsupdaterは導入しませんでした。

AWS側の設定は他サイトで言及されてるので割愛します。相当めんどかったけど。。

Vagrantfileの修正

変更点は以下。

上記変更箇所の抜粋が以下。

Vagrant.configure(2) do |config|

  # config.vm.box = ENV['wp_box'] || _conf['wp_box']
  config.vm.box = "dummy"
  config.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"

  # config.vm.network :private_network, ip: _conf['ip']

  # config.vm.provider :virtualbox do |vb|
  #   ...
  # end
  config.vm.provider :aws do |aws, override|
    aws.access_key_id     = "..."
    aws.secret_access_key = "..."
    aws.keypair_name      = "vagrant"
    aws.security_groups   = ["sg-2f9df77a"]
    aws.region            = "ap-northeast-1"
    aws.availability_zone = "ap-northeast-1c"
    aws.ami               = "ami-81294380"    # AMIにはCentOSを使う
    aws.instance_type     = "t1.micro"        # AMIにはCentOSを使う
    aws.subnet_id         = "subnet-2510c04c"
    aws.elastic_ip        = true
    aws.tags = {
      "Name" => "vagrant"
    }

    #aws.block_device_mapping = [
    #  {
    #    "DeviceName" => "/dev/sda1",
    #    "Ebs.VolumeSize" => 10,
    #    "Ebs.DeleteOnTermination" => true,
    #    "Ebs.VolumeType" => "standard"
    #  }
    #]

    aws.user_data = <<'EOF'
#!/bin/sh

# sudoでTTYを要求されないようにする
sed -i -e 's/^Defaults[ \t]\+requiretty/#Defaults requiretty/' /etc/sudoers

# パッケージの衝突回避
#yum -y remove postfix

# ユーザを追加
useradd vagrant

# ホスト名を設定
sed -i -e 's/^HOSTNAME=.\+$/HOSTNAME=vccw.dev/' /etc/sysconfig/network

# SSL証明書のチェックをさせない
echo ':ssl_verify_mode: 0' >> ~/.gemrc

# .devのリゾルバ設定を除去
sed -i -e 's/^search \(.*\)\bdev\b\(.*\)/search \1\2/' /etc/resolv.conf
echo 'PEERDNS=no' >> /etc/sysconfig/network-scripts/ifcfg-eth0

# wgetインストール
yum -y install wget

EOF
    
    override.ssh.username         = "root"                     # AMIにはCentOSを使う
    override.ssh.private_key_path = "/path/to/private_key.pem"
  end

end

※ コメントがある箇所は、トラブル対処のために追加/変更が必要になった部分です。
詳しくは、下記の「トラブル対処経緯」を参照して下さい。

※ block_device_mappingを設定してEBSを変更したかったのですが、
なぜかEBSが追加されてしまって期待した動作にならないので、
とりあえずコメントアウトしてあります。

vagrant up

これで、vagrant up すればOKなはずなのですが、
僕の環境では、上記Vagrantfileのaws.user_dataがどうも実行されていないようで、
しょうがないので、以下のようにしました。

  1. vagrant up --provider=aws
  2. エラーになった後、 vagrant ssh して上記Vagrantfileのaws.user_dataの部分を手動実行
  3. exitして、 vagrant reload --provision

※ 他サイトでは、aws.user_dataの実行を待たずにprovisionするから最初エラーになるけど、
再度 vagrant provision すればイケるよって書いてあったんですが、僕の環境ではダメでした。

※ 上記Vagrantfileのaws.user_dataの「パッケージの衝突回避」の対処は、
最初に実施すると、また別のエラーが発生してしまうため、コメントアウトしてます。
該当のエラーが起きたら、 vagrant ssh して対処して、 vagrant reload --provision すると。
詳しくは、下記の「トラブル対処経緯」を参照して下さい。

トラブル対処経緯

以下に、遭遇したエラーと、その対処の経緯を、上記Vagrantfileのコメント毎に記載しています。
長いっす。

AMIにはCentOSを使う

当初、Amazon Linuxを使用しようとしましたが、以下のエラーに遭遇しました。

Could not retrieve mirrorlist http://rpms.famillecollet.com/enterprise/2015/remi/mirror error was 14: PYCURL ERROR 22 - "The requested URL returned error: 404 Not Found"

VCCWのドキュメントに、RHELの5or6に相当するOSでないと動作しない旨のような記述があったので、
CentOS6.5のAMIを使用することにしました。
公式から配布されているCentOSのAMIを使うと、インスタンスはt2.microでなくt1.micro、ユーザはrootになります。

※ 上記VagrantfileではVPC関連の設定がしてありますが、不要っぽいです。
VPCAmazon Linuxかt2.microを使うのに必要なはずなのですが、CentOSでt1.micro使うことにしたので。

sudoでTTYを要求されないようにする

sudo: sorry, you must have a tty to run sudo

調べると、たくさんのサイトで色々な対処方法が言及されてましたが、
僕は開発環境なのでTTY要求自体無効で良いかなと。

vagrant up したらエラー「sudo: sorry, you must have a tty to run sudo」が出たときの対処方法 - 彼女からは、おいちゃんと呼ばれています

パッケージの衝突回避

package[php-mysql] (php::package line 22) had an error: Chef::Exceptions::Exec:  returned 1, expected 0
ERROR with rpm_check_debug vs depsolve

よくわかりませんでしたが、以下を参考に yum -y remove postfix したらいけました。

vagrant - rpm_check_debug vs depsolveがでたぞ - Qiita

postfixは、後で再度インストールできました。

ユーザ追加

template[/home/vagrant/.wp-cli/config.yml] (wpcli::default line 44) had an error: Chef::Exceptions::UserIDNotFound: cannot determine user id for 'vagrant', does the user exist on this system?

どうやら、VCCWのChefの処理の中で、vagrantユーザが必要なようです。

ホスト名を設定

Chef::Exceptions::MultipleFailures: Chef::Exceptions::MultipleFailures

全然意味わかんねーよ。。と思ったけど、エラーが出る前のログが
Apacheのサービス再起動しようとしてる感じだったので、以下のようにしてみたら、
ServerNameが設定されてなくてエラーになってました。

$ /sbin/service httpd status
httpd is stopped
$ /sbin/service httpd start
Starting httpd: Syntax error on line 2 of /etc/httpd/sites-enabled/wordpress.conf:
ServerName takes one argument, The hostname and port of the server
$ head /etc/httpd/sites-enabled/wordpress.conf
<VirtualHost *:80>
  ServerName 
  DocumentRoot /var/www/wordpress

  EnableSendfile off

  <Directory /var/www/wordpress>
    Options FollowSymLinks
    AllowOverride FileInfo Options Limit
    Order allow,deny

VCCWのcookbookを調べると、 node[:fqdn] の値を設定しているようでした。
Chefについても初心者なので、どうやって値を取得しているのかわからず、右往左往。
ようやく以下のページが。

chef の node.name が fqdn に設定している行を探る。 - Qiita

ここから辿ると、CentOSでは node[:fqdn] は、 hostname -f の値であるらしいとわかり、
その設定は /etc/sysconfig/network のHOSTNAMEで行うとのこと。

SSL証明書のチェックをさせない

ERROR:  While executing gem ... (Gem::RemoteFetcher::FetchError)
SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: unknown protocol (https://your-dns-needs-immediate-attention.dev/quick/Marshal.4.8/colored-1.2.gemspec.rz)

または、

ERROR:  While executing gem ... (Gem::RemoteFetcher::FetchError)
SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (https://your-dns-needs-immediate-attention.dev/quick/Marshal.4.8/colored-1.2.gemspec.rz)

というエラーが出て、gemのインストールに失敗しました。
SSL証明書関連のエラーということなので、rubyやchefのSSL関連の設定チェック方法を調べ、
以下を実行してみました。

$ knife ssl check
WARNING: No knife configuration file found
Connecting to host localhost:443
ERROR: The SSL certificate of localhost could not be verified
Certificate issuer data: /C=JP/ST=Wakayama/L=Kushimoto/O=My Corporate/CN=vccw.dev

Configuration Info:

OpenSSL Configuration:
* Version: OpenSSL 1.0.1m 19 Mar 2015
* Certificate file: /opt/chef/embedded/ssl/cert.pem
* Certificate directory: /opt/chef/embedded/ssl/certs
Chef SSL Configuration:
* ssl_ca_path: nil
* ssl_ca_file: nil
* trusted_certs_dir: nil

...

$ ruby -r openssl -e 'p OpenSSL::X509::DEFAULT_CERT_FILE'
"/etc/pki/tls/cert.pem"

/opt/chef/embedded/ssl/cert.pem も /etc/pki/tls/cert.pem も
存在はしていましたが、ファイル内容は異なっていました。
また、wgetで適当なhttpsなページを取得することには成功したので、
gemインストールにおけるSSL通信のみの問題なようでした。

そして、/etc/pki/tls/cert.pemはEC2組み込みの証明書という情報が見つかったので、
多分、chefからgemインストールの処理が走る時、/etc/pki/tls/cert.pemでなく、
/opt/chef/embedded/ssl/cert.pemが使われるため、エラーになっているのではと思いました。

なので、/etc/pki/tls/cert.pemを/opt/chef/embedded/ssl/cert.pemに上書きしてみたのですが、
vagrant reload --provision すると、/opt/chef/embedded/ssl/cert.pemが再度作成されるらしく、
元のファイルに戻ってしまいました。

そのため、しょうがなくgemでSSL証明書のチェックを行わないように設定することで対処しました。

.devのリゾルバ設定を除去

ERROR:  While executing gem ... (Gem::RemoteFetcher::FetchError)
bad response Not Found 404 (https://your-dns-needs-immediate-attention.dev/quick/Marshal.4.8/colored-1.2.gemspec.rz)

.dev で終わる hostname のとき gem install が失敗するようになった - ヤルキデナイズド

devというTLDが新設されたから、自前で名前解決してる場合に正しく名前解決されなくなるかもってことか。
確認してみると、正に。EC2では.devは内部解決しようとしているらしい。

$ cat /etc/resolv.conf 
; generated by /sbin/dhclient-script
search ap-northeast-1.compute.internal dev
nameserver 172.30.0.2

なので、devは内部解決しないようにresolv.confのエントリから除去しました。
のに、vagrant reload --provision すると元に戻ってしまう...
から、以下のページのように設定。

Amazon EC2(Linux)のネットワーク設定でハマったときに見るメモ | Developers.IO

wgetインストール

execute[wp-test-install] (vccw::default line 98) had an error: Mixlib::ShellOut::ShellCommandFailed: Expected process to exit with [0], but received '127'
...
/usr/bin/wp-test-install: line 39: wget: command not found

wgetが要るってさ。

ちなみに、他にもエラー出たんだ

ERROR:  While executing gem ... (Gem::RemoteFetcher::FetchError)
bad response Service Unavailable 503 

何だ?と思ったけど、再度やったらうまくいった。
多分タイミング悪く、接続先サーバが調子悪かったんじゃまいか。
どんだけ、エラー引くのよ。勘弁してよ。

あぁ〜〜〜 はらたつのり〜〜〜〜〜〜〜〜