終電23時11分って早くね?

都内のIT企業で働くカラオケ大好きエンジニアの雑記

PHP CodeSnifferでtestsディレクトリにだけ除外ルールを追加する

最近はPSR-2の規約に沿ってコードを書くことを意識しています。

www.php-fig.org

特にチームで開発している状況でコーディングスタイルのルールが明確に決まってないと、
A「インデントはスペース2つ!」
B「いや、スペース4つ!!」
C「タブやろ」
みたいな細かい話になりがちだと思います。
(PSR-2ではスペース4つのルール)

そんなときにPSR-2のようなコーディングスタイルガイドに寄り添っていくのはとてもいいなーと感じています。
(自分が今まで書いてきたルールと違う部分は慣れるまでちょっと気持ち悪いですが)

なぜtestsディレクトリだけに除外ルールを追加したかったか?

プロジェクトのコード全体をPSR-2に沿って書くようにしてたなかで、
テストを書く際に2つ困ったことがあったからです。

  • テスト名を日本語にした場合にエラーになる
  • 抽象クラス(abstract)のテストの場合にエラーになる

テスト名を日本語にした場合にエラーになる

PHP CODE SNIFFER VIOLATION SOURCE SUMMARY
----------------------------------------------------------------------
SOURCE                                                           COUNT
----------------------------------------------------------------------
PSR1.Methods.CamelCapsMethodName.NotCamelCaps                    9
----------------------------------------------------------------------
A TOTAL OF 9 SNIFF VIOLATIONS WERE FOUND IN 1 SOURCE
----------------------------------------------------------------------

「メソッドがキャメルケースではないよ!」というエラーになります。

/**
 * @test
 */
public function 保存ができること()
{
    $this->todo->addItem('アイテム1');
    $this->assertTrue($this->todo->save());
}

public function test取得ができること()
{
    $this->todo->addItem('アイテム1');
    $this->assertTrue($this->todo->save());
}

PHP@testアノテーションをつけることで、日本語だけの関数名でテストを書けます。
(下のようにtestをプレフィックスにつけても日本語で書けます。)

日本語なのでエラーになるのは当然ですね。
英語が苦手なメンバーがいたり、日本語のほうがテスト内容が分かりやすかったりはするのでたまに日本語でテストを書いたりしています。

でもアプリケーションのコードでは関数は日本語で書いていない。
全体の除外ルールとしてしまうこともできますが、アプリケーションのコードのほうで、もしキャメルケースで書かれていない場合はエラーとして拾えなくなってしまいます。

抽象クラス(abstract)のテストの場合にエラーになる

PHP CODE SNIFFER VIOLATION SOURCE SUMMARY
----------------------------------------------------------------------
SOURCE                                                           COUNT
----------------------------------------------------------------------
PSR1.Classes.ClassDeclaration.MultipleClasses                    2
----------------------------------------------------------------------
A TOTAL OF 2 SNIFF VIOLATIONS WERE FOUND IN 1 SOURCE
----------------------------------------------------------------------

「1つのファイルに複数クラスの定義があるよ!」というエラーになります。

抽象クラスのテストをしたいときは、テストのクラスのなかにもう1つクラスを書いています。

class FugaTest extends \PHPUnit\Framework\TestCase
{
    public function testReturnFuga()
    {
        $fuga = new Fuga();
        $this->assertSame('fuga', $fuga->get());
    }
}

class Fuga extends Hoge
{
}

めちゃくちゃ適当ですがこんな感じ。

2つのルールをtestsディレクトリで除外するphpcs.xmlの書き方

PSR1.Methods.CamelCapsMethodName.NotCamelCaps
PSR1.Classes.ClassDeclaration.MultipleClasses

この2つのルールをtestsディレクトリ以下のみ除外するには下記のように設定すればOKでした。

<rule ref="PSR1.Methods.CamelCapsMethodName.NotCamelCaps">
    <exclude-pattern>*/tests/*</exclude-pattern>
</rule>
<rule ref="PSR1.Classes.ClassDeclaration.MultipleClasses">
    <exclude-pattern>*/tests/*</exclude-pattern>
</rule>

それぞれのルールに対して除外ディレクトリを設定してあげればOKです。
全体としてはこんな感じ。

<?xml version="1.0"?>
<ruleset name="Custom_PSR2">
  <description>Custom ruleset Based on PSR2</description>
  <exclude-pattern>*/vendor/*</exclude-pattern>
  <exclude-pattern>*/bootstrap/cache/*</exclude-pattern>
  <exclude-pattern>*/database/*</exclude-pattern>
  <exclude-pattern>*/node_modules/*</exclude-pattern>
  <exclude-pattern>*/public/*</exclude-pattern>
  <exclude-pattern>*/resources/*</exclude-pattern>
  <exclude-pattern>*/storage/*</exclude-pattern>
  <rule ref="PSR2">
    <exclude name="Generic.Files.LineLength.TooLong" />
  </rule>
  <rule ref="PSR1.Methods.CamelCapsMethodName.NotCamelCaps">
    <exclude-pattern>*/tests/*</exclude-pattern>
  </rule>
  <rule ref="PSR1.Classes.ClassDeclaration.MultipleClasses">
    <exclude-pattern>*/tests/*</exclude-pattern>
  </rule>
</ruleset>

※メソッド名が長くなりがちなので全体のルールにGeneric.Files.LineLength.TooLongも設定してます

ちょっと場所が分かりづらいですが、PHP CodeSnifferのWikiにこのやり方で書いてあります。
github.com

MySQL5.5.6(以下?)でSupersetがうまく動かない(場合がある)

f:id:blue_goheimochi:20170210100609p:plain

AirbnbによるオープンソースのBIツールのSuperset

github.com

Re:dashもちょろちょろ触っているのですが、
ダッシュボードのカスタマイズが柔軟そうだなー
と思いSupersetの環境を作ってみたのですがデモは動くんだけど、
手元のDBに接続してみるとうまくいかない・・・となりました。

原因

おそらくMySQL5.5.6(以下?)で発生するSTR_TO_DATEをWHERE句に使うことによるバグ。
MySQL Bugs: #56271: STR_TO_DATE in date compare incorrect results

Supersetが内部でdateのフォーマットを整形した形でSQLを発行しているのですが、
その部分でSTR_TO_DATEが使われているためだと思われます。

if target_type.upper() in ('DATETIME', 'DATE'):
    return "STR_TO_DATE('{}', '%Y-%m-%d %H:%i:%s')".format(
        dttm.strftime('%Y-%m-%d %H:%M:%S'))
return "'{}'".format(dttm.strftime('%Y-%m-%d %H:%M:%S'))

superset/db_engine_specs.py at 37fb56c61ceb339079ff117971fc91bdd678db80 · airbnb/superset · GitHub
ifの条件にはまらなければ(DATETIME、DATEのカラムじゃなければ)大丈夫なのかな。

どんなSQLが発行されるか?

こんな。

mysql> SELECT COUNT(*) AS count
    -> FROM items
    -> WHERE created_at >= STR_TO_DATE('2000-01-01 00:00:00', '%Y-%m-%d %H:%i:%s')
    -> AND created_at <= STR_TO_DATE('2017-12-31 23:59:59', '%Y-%m-%d %H:%i:%s');

一見正しそうに見える。

STR_TO_DATEの結果

mysql> SELECT STR_TO_DATE('2000-01-01 00:00:00', '%Y-%m-%d %H:%i:%s');
+---------------------------------------------------------+
| STR_TO_DATE('2000-01-01 00:00:00', '%Y-%m-%d %H:%i:%s') |
+---------------------------------------------------------+
| 2000-01-01 00:00:00                                     |
+---------------------------------------------------------+

mysql> SELECT STR_TO_DATE('2017-12-31 23:59:59', '%Y-%m-%d %H:%i:%s');
+---------------------------------------------------------+
| STR_TO_DATE('2017-12-31 23:59:59', '%Y-%m-%d %H:%i:%s') |
+---------------------------------------------------------+
| 2017-12-31 23:59:59                                     |
+---------------------------------------------------------+

たぶん大丈夫。

SQLの結果

mysql> SELECT COUNT(*) AS count
    -> FROM items
    -> WHERE created_at >= STR_TO_DATE('2000-01-01 00:00:00', '%Y-%m-%d %H:%i:%s')
    -> AND created_at <= STR_TO_DATE('2017-12-31 23:59:59', '%Y-%m-%d %H:%i:%s');
+-------+
| count |
+-------+
|     0 |
+-------+

0件・・・・・

STR_TO_DATEを使わないで直接指定してみる

mysql> SELECT COUNT(*) AS count
    -> FROM items
    -> WHERE created_at >= '2000-01-01 00:00:00'
    -> AND created_at <= '2017-12-31 23:59:59';
+-------+
| count |
+-------+
|   999 |
+-------+

カウントがちゃんと取れる・・・・。

MySQLのバージョン確認

mysql> SELECT version();
+--------------+
| version()    |
+--------------+
| 5.5.6-rc-log |
+--------------+

MySQLの別のバージョンで試す

mysql> SELECT version();
+-------------------+
| version()         |
+-------------------+
| 5.7.12-0ubuntu1.1 |
+-------------------+

mysql> SELECT COUNT(*) AS count
    -> FROM items
    -> WHERE created_at >= STR_TO_DATE('2000-01-01 00:00:00', '%Y-%m-%d %H:%i:%s')
    -> AND created_at <= STR_TO_DATE('2017-12-31 23:59:59', '%Y-%m-%d %H:%i:%s');
+-------+
| count |
+-------+
|   999 |
+-------+

>|abc|
mysql> SELECT COUNT(*) AS count
    -> FROM items
    -> WHERE created_at >= '2000-01-01 00:00:00'
    -> AND created_at <= '2017-12-31 23:59:59';
+-------+
| count |
+-------+
|   999 |
+-------+

どっちも取れる・・・!!!!

MySQLのリリースノートをあさったり

MySQL 5.5 Release Notes

MySQL Bugs: #56271: STR_TO_DATE in date compare incorrect results
これだ!

51 Changes in MySQL 5.5.7 (2010-10-14, Release Candidate)

Comparison of one STR_TO_DATE() result with another could return incorrect results. (Bug #56271)

5.5.7で直ったっぽい!!!!

まとめ

ということで、5.5.7以上を使っていればたぶん大丈夫だと思われます。
5.5.6以下でもうまく行くケースはたぶんある。(TIMESTAMPとかのカラムをTime Columnに設定すればたぶん大丈夫)
strftimeで変換したあともう一度STR_TO_DATEする必要あるのか・・な・・?

【Laravel Practice04】AnsibleでNTPサーバーを構築

f:id:blue_goheimochi:20160629162151p:plain

デプロイサーバーにNTPサーバーをAnsibleで構築してみます。
今回、仮想環境にはCentOS7を使っているので、chronyをインストールしてみます。

ntpdとchronyの違い

CentOS6まではデフォルトのNTPサーバーはntpdだったようですが、
CentOS7ではchronyが標準となっているようです。

大きな違いとしては

ntpd と chronyd の大きな違いの 1 つは、コンピューターのクロックを管理するために使われるアルゴリズムにあります。

とのことで、システムクロックをntpdより迅速に調整することが可能らしいです。

[参考]
第15章 chrony スイートを使用した NTP 設定

yumモジュールでchronyをインストール

今回作業したところは、以下のコミットログにまとまっていますのでご参照ください。
github.com
今回は、ansible/roles/chrony/tasks/main.ymlの1ファイルのみ追加しています。

- name: install chrony
  yum: name=chrony state=latest

Ansibleのyumモジュールでchronyをインストールする際の記述です。

$ sudo yum install -y chrony

と同等の処理が行われます。

Ansible yumモジュールのドキュメント
yum - Manages packages with the yum package manager — Ansible Documentation

他のパッケージをインストールしたい場合は、
たとえばhttpdであれば

- name: install httpd
  yum: name=httpd state=latest

と書けばOKです!簡単ですね。

デフォルトで設定されているNTPサーバーを無効にする

デフォルトで設定されているNTPサーバーを無効にします。
pool.ntp.orgのサーバーは世界中すべてのタイムサーバーを指定しているそうで、
時刻を精度よく保つためには近いゾーンのものを設定するのがよいみたい。
(あとで設定します)

[参考]
pool.ntp.org: プールを利用するためにNTPを設定する方法は?

chronyの設定ファイルは/etc/chrony.confに作成されていると思うので、これを今回はAnsibleのreplaceモジュールで操作してみます。

Ansible replaceモジュールのドキュメント
replace - Replace all instances of a particular string in a file using a back-referenced regular expression. — Ansible Documentation

- name: disable servers
  replace: >
    dest=/etc/chrony.conf
    regexp='^(server \d+.centos.pool.ntp.org iburst)'
    replace='# \1'

destで対象のファイルを指定して、
regexpでファイル内の変更したい箇所を正規表現で指定できます。
replaceは変換後の文字列ですね。

今回は、regexpでマッチする行の先頭に#がつくようにタスクを書いてみました。
2回目以降のAnsible実行の際は、正規表現に当てはまらなくなるので、変更はされません。
changedになってしまう場合は正規表現の書き方を変えてみるとよいと思われます。

日本のタイムゾーンのNTPサーバーを追加する

先述した通り、最も近い日本のタイムゾーンのNTPサーバーを設定します。

- name: add servers
  blockinfile:
    dest: /etc/chrony.conf
    state: present
    content: |

      # ntp servers
      server ntp.jst.mfeed.ad.jp iburst
      server ntp.nict.jp iburst

Ansible blockinfileモジュールのドキュメント
blockinfile - Insert/update/remove a text block surrounded by marker lines. — Ansible Documentation

blockinfileはAnsible 2.0から追加されたモジュールです。
複数行を追加したいときなんかに使います。

insertafter: '[対象の文字列(正規表現可)]'を指定すると対象の行の後に追加したりできますが、今回はファイルの一番最後に、NTPサーバーの設定を追記するようにしています。
詳しい書き方はAnsibleのドキュメントをご参照ください。

ntp.jst.mfeed.ad.jpntp.nict.jpの2つのNTPサーバーが日本標準時を提供してくれているのでそちらを指定させていただきました。

時刻同期を内部から許可する設定を追加

ローカルネットワークからのアクセスを許可する設定を追加します。

- name: add allow ntp client
  lineinfile: >
    dest=/etc/chrony.conf
    insertafter="#allow 192.168/16"
    line="allow 192.168.1.0/24"

Ansible lineinfileモジュールのドキュメント
lineinfile - Ensure a particular line is in a file, or replace an existing line using a back-referenced regular expression. — Ansible Documentation

今度はlineinfileモジュールを使ってみました。
1行の行追加の場合、こちらのモジュールを使うとよさそう。
#allow 192.168/16の下の行にallow 192.168.1.0/24を追加するタスクです。

サービスの起動と自動起動の設定

- name: chrony start and enable
  service: name=chronyd state=started enabled=yes

serviceモジュールを使って、chronydのスタートと自動起動の設定ができます。

Ansible serviceモジュールのドキュメント
service - Manage services. — Ansible Documentation

$ systemctl start chronyd
$ systemctl enable chronyd

のコマンドの実行と同様のタスクになります。
nameに対象のサービスを指定することで別のサービスに対しても実行可能です。

手動での時刻あわせ

手動での時刻あわせのコマンドを実行します。

- name: adjust the time
  shell: chronyc -a makestep
  changed_when: false

shellモジュールはその名前の通り、シェルコマンドを実行できるモジュールです。

Ansible shellモジュールのドキュメント
shell - Execute commands in nodes. — Ansible Documentation

shellモジュールを利用する場合、冪統制は自分で担保する必要があります。(と思います。。)
特に先述のファイルに何かを追加するような処理をshellモジュールで書くと、実行するたびに同様の記述がファイルに書き込まれてしまいます。

例)

- name: add hoge
  shell: echo 'hoge' >> /tmp/text.txt

このような場合実行するたびにhoge/tmp/text.txtに追記されてしまい、そのつど、changedのステータスになってしまいます。
Ansibleのモジュールにはそういう冪統制を担保してくれるものが多いと思うので、可能な限りAnsibleのモジュールに頼ったほうがよいでしょう。
様々なモジュールがあるのでぜひドキュメントを眺めてみてください。

今回の場合は、手動の時刻あわせのコマンドを実行することになりますが、これは毎回実行されても影響はないと考えます。(ファイルの書き込みとかは起こらないと思うので)
こういう場合は、changed_when: falseを指定しておくと必ず、okのステータスになりますので指定してみました。
changed_when: [条件]という風な指定で、条件に合致したときだけchangedとできるので、特定の条件がある場合はそのように記述しましょう。

以上、NTPサーバーを構築するときのAnsibleのタスクを説明してみました!
内容はボリューミーですが、Ansibleの基本っぽい部分が分かるのではないかなぁと思います。

Ansibleはドキュメントもしっかりしていて、日本語の情報も結構あるので、
「このコマンドに対応するモジュールはあるかな?」と思ったら検索してみてください!
大体あります。笑

まとめ

  • CentOS7はchronyが標準のNTPサーバー
  • ntpdよりchronydのほうが時間調整が早いらしい
  • Ansible yumモジュールの簡単な使い方
  • Ansible replaceモジュールの簡単な使い方
  • NTPサーバーはタイムゾーンが近いところを設定する
  • Ansible lineinfileモジュールの簡単な使い方
  • Ansible serviceモジュールの簡単な使い方
  • Ansible shellモジュールの簡単な使い方
  • shellモジュールを使うときは冪統制は自分で考えなきゃいけないから可能な限りAnsibleのモジュールを使うと楽
  • Ansibleはドキュメントがしっかりしてるので見るとはかどる

次回もAnsibleを使ってさらにデプロイサーバーの環境を整えます!
ユーザー追加とかを想定中。

ツッコミお待ちしております!!

初めてのAnsible

初めてのAnsible

【Laravel Practice03】デプロイサーバーにAnsibleを実行する

f:id:blue_goheimochi:20160624231936p:plain

まずはAnsibleをデプロイサーバーに向けて実行してみます。
AnsibleがインストールされているPC自身にプロビジョニングができるので、
Macの環境構築なんかもAnsibleでできるみたいです!

blog.shin1x1.com

ところでAnsibleとは?

ChefやPuppetやItamaeと同列に扱われる、構成管理ツールの1つです。
エージェントレスでシンプルなところが特徴とされています。

エージェントレス?

Chefなど一部の構成管理ツールは、対象のサーバーにもChefがインストールされている必要があったりします。
Ansibleは対象のサーバーにsshで接続できれば、対象のサーバーに特別な準備はいりません。

Ansibleについての説明はしますが、最小限な感じになると思うので、
分からない場合は、コメントいただいたり、ググったり、下の本を読んでみたりしてください・・・!

初めてのAnsible

初めてのAnsible

とりあえずコマンドを実行してみる

とりあえずエラーが発生しますが、コマンドを打ってみます。

まずは

$ vagrant ssh deploy

で、デプロイサーバーにログイン。

$ sudo ansible-playbook -i /vagrant/hosts -l deploy -c local /vagrant/ansible/deploy.yml
ERROR! the playbook: /vagrant/ansible/deploy.yml could not be found

はい、エラーになりましたね。
/vagrant/ansible/deploy.ymlというPlaybookはありません!とのことです。
ひとつずつ解決していきます。

プレイブック?

プレイブックとは作業手順書と置き換えて考えていただければいいと思います。
サーバを構築するための作業手順書です。

構成管理ツールがない時代は、秘伝のテキストファイルにサーバーの構成方法のメモ書きが残されていたりしていたそうですが、
そのような手順を「YAML」という形式で記述したものがプレイブックになります。

デプロイサーバー用のプレイブックということでdeploy.ymlという名前にしてみました。

deploy.yml

- hosts: deploy
  become: yes
  roles:
    - common

こんな感じのファイルになります。

1行目ではhosts: deployとして、対象のホストを指定しています。

勘のいいかたはお気づきかもしれませんが、最初に打ったコマンドでhostsのファイルをしております。

-i /vagrant/hostsでhostsのファイルを指定できます。
デフォルトでは/etc/ansible/hostsのファイルが参照されます。

hostsファイル

[deploy]
127.0.0.1

こんな感じでhostsは設定します。ローカル環境を示す127.0.0.1またはlocalhostを指定します。

2行目のbecome: yessudoで実行する設定です。
実行するユーザーを切り替える際にはbecome_user: deployのような感じでユーザー名を指定します。

3-4行目ではrole(ロール)を指定しています。

laravel-servers
  └─ansible
      └─roles
          └─common
              └─tasks
              │   └─main.yml
              └─vars
                   └─main.yml

こんな感じのディレクトリ構造になっていて、rolesのディレクトリの中にcommonディレクトリを配置するような構造です。
ロールで管理しなくてもプレイブックに直接記述する方法でもOKなのですが、役割が分かりやすくなるので、この形が自分の好みです。

tasksディレクトリの中のmain.ymlに実際にサーバーに対して実行したい処理を書いていきます。

main.yml

github.com

上記のファイルをご参照ください。
たくさん色々書いてあります・・・!笑

name: XXXXXXXXXXで書かれている1つ1つタスクと呼ばれる部分です。
名前は分かりやすい名前をつけてあげましょう。

yum:service:shellなどはAnsibleが用意しているモジュールです。

All Modules — Ansible Documentation

http://docs.ansible.com/ansible/list_of_all_modules.html

すごくたくさんもモジュールが用意してあります。
shellcommandのモジュールを使えば、通常のコマンドとしてもかけます。
が、モジュールを使えば、たとえばyumであれば、

- name: install yum-cron
  yum: name=yum-cron state=latest

と書くことで、インストールされてなければインストール、すでにインストールされていなければ何もしないというような冪統制を考慮してくれるので、書ける方法があればモジュール経由で書くのがいいかと思います。

各モジュールはドキュメントやグーグル先生に聞いて調べてみてください。。笑

varsディレクトリのmain.yml

vars/main.yml
timezone: Asia/Tokyo

ロール用の変数を宣言する事ができます。

role/main.yml
- name: set timezone
  shell: timedatectl set-timezone "{{ timezone }}"

という感じで、{{}}で囲って変数を使用します。

commonロールのタスク

下記が今回実行するタスクです

以上が実行されます。

ここまでの作業のコミットは以下になります。
github.com

次から再度コマンド実行していきますので、上のファイルと同じ構成で各ファイルを配置してみてください。

再度コマンドを実行

今度はコマンドを実行してもエラーがなく進むと思います。完了するまでにちょっと時間がかかります。

$ sudo ansible-playbook -i /vagrant/hosts -l deploy -c local /vagrant/ansible/deploy.yml
PLAY [deploy] ******************************************************************

TASK [setup] *******************************************************************
ok: [127.0.0.1]

TASK [common : install epel repository] ****************************************
changed: [127.0.0.1]

~~~~~~~~~~~~~~~~~

PLAY RECAP *********************************************************************
127.0.0.1                  : ok=13   changed=10   unreachable=0    failed=0

ok:は実行されたタスク
changed:は今回の実行で変更が行われたタスク
というようなイメージです。

13個が実行さで10個のタスクで今回変更があったということになります。

もう一度同じコマンドを打ってみましょう。

$ sudo ansible-playbook -i /vagrant/hosts -l deploy -c local /vagrant/ansible/deploy.yml
PLAY [deploy] ******************************************************************

TASK [setup] *******************************************************************
ok: [127.0.0.1]

TASK [common : install epel repository] ****************************************
ok: [127.0.0.1]

~~~~~~~~~~~~~~~~~

PLAY RECAP *********************************************************************
127.0.0.1                  : ok=12   changed=0    unreachable=0    failed=0

前回より早く終わったかと思います。
12個が実行さで今回変更はありませんでした。
数が1つ減っているのは、skippingになっているためです。
指定の条件に合致しない場合は実行されないタスクがあるので、これはこれで正常な動作になります。
気になる人はset timezoneのタスクを見てみてくださいね。

補足ですが-c localのオプションはAnsibleをローカルモードで実行したい場合のオプションになります。

まとめ

  • AnsibleはMacの開発環境構築にも使える!
  • Ansibleとはエージェントレスでシンプルな構成管理ツールの1つである
  • 同様の構成管理ツールにはChef、Puppet、Itamaeなどがある
  • プレイブックに構築手順を「YAML」形式で書く
  • hostsは適切に設定しましょう
  • ロールに切り出すと役割ごとにタスクを管理しやすいと思う
  • Ansibleのモジュールはたくさんあるのでドキュメントを見る
  • ロール用に変数も定義できる
  • ローカルモードで実行したい場合は-c localのオプションをつける

次回はAnsibleを使ってさらにデプロイサーバーの環境を整えていきます・・!

次の記事はこちら!
【Laravel Practice04】AnsibleでNTPサーバーを構築 - 終電23時15分って早くね?

【Laravel Practice02】デプロイサーバーにAnsibleをインストール

f:id:blue_goheimochi:20160624022454p:plain

デプロイサーバーにAnsibleをインストールします。

前回はこちら
【Laravel Practice01】デプロイサーバー、Webサーバー、DBサーバーの準備 - 終電23時15分って早くね?

前回も言いましたが本当はたぶんデプロイサーバーに向けてAnsibleをホストOSから実行すればよいです。
が、Windows環境で(面倒なので)ローカルからAnsibleを実行するのではなくデプロイサーバーにインストールしてみます。

デプロイサーバーにログイン

手順どおりにいけばlaravel-serversディレクトリにいると思いますのでそこで、

$ vagrant ssh deploy

というコマンドでデプロイサーバーにログインします。
複数の仮想サーバーがある場合はvagrant ssh [名前]SSHで対象サーバーにログインできます。
仮想サーバーが1つしかない場合は、名前を明示せずvagrant upだけでOKです。

EPELリポジトリの導入

エンタープライズ Linux 用の拡張パッケージ(EPEL) は、 Red Hat Enterprise Linux (RHEL) 向けの高品質なアドオンパッケージであり、CentOSScientific Linux (SL) のような RHEL からスピンオフしたディストリビューションと互換性のある、Fedora プロジェクトで有志によって作成されたパッケージになります。FedoraRHEL のアップストリームであり、EPEL のアドオンパッケージは主に RHEL 向けにビルドされた Fedora リポジトリをソースとしています。

https://fedoraproject.org/wiki/EPEL/ja

CentOSの標準パッケージには含まれないパッケージをyumでインストールするためにEPELリポジトリを導入します。
Ansibleはこちらのリポジトリからインストールするような想定です。

$ sudo yum install -y epel-release

デプロイサーバのコンソールから上記コマンドで、EPELリポジトリのインストールができます。

Ansibleのインストール

今回利用しているCentOSyumUbuntuのaptなどのパッケージ管理システムを使えば、
ソースコードを落としてきて個別にインストールする必要がないので楽ですね。

最新版が使いたい!となると、パッケージとして提供されてないケースがあるのでそういう場合は手動で最新版をインストールする方法をぐぐって試してみてください。

$ sudo yum install -y ansible

と、yumでさくっとインストールすると、

$ ansible --version
ansible 2.1.0.0

という感じでAnsibleのバージョン2.1がインストールできました。

vagrat up 時に自動でEPELリポジトリとAnsibleをインストールするようにしてみる

前項まででいったん、今回の目的である「デプロイサーバーにAnsibleをインストールする」というのは完了です。
が、せっかくなのでVagrantの機能を使って、vagrant upした際に自動的にデプロイサーバーにEPELリポジトリとAnsibleをインストールしてみます。

Vagrantのプロビジョニングの機能

vagrant upで仮想環境を起動したあとに実行する処理を指定できるのが、Vagrantのプロビジョニングの機能です。

www.vagrantup.com

仮想環境起動後に実行可能な詳しい処理は公式サイトをご確認ください。
ChefやPuppet、Ansibleやシェルスクリプトなどなどで処理を指定する事が可能ですが、
今回はシェルスクリプトでやります。

Vagrantfileの記述

github.com

とても簡単!

server.vm.provision "shell", :path => "provision.sh"

shellの部分でプロビジョニングの方法(chefとかansibleとか)を指定し、
シェルスクリプトの場合は実行するファイルを指定します。

provision.shの記述

github.com


こちらも簡単ですね。

冪等性を意識するために、if文なんかを書いてみました。

yumでインストールしたEPELリポジトリrpmコマンドとgrepを使ってチェックしています。

if [ -n "`rpm -q epel-release | grep -w 'not installed'`" ]; then
  sudo yum install -y epel-release
fi

rpm -qはパッケージの詳細を表示するコマンドです。

インストールされている場合は

$ rpm -q epel-release
epel-release-7-6.noarch

インストールされていない場合は

$ rpm -q epel-release
package epel-release is not installed

のような結果になるので、grep -w 'not installed'でワード検索し、
インストールされていない場合のみインストールするような感じです。
たぶん他のパッケージでも応用して使える気がします。

Ansibleはwhichを使ってチェックしています

if [ ! `which ansible` ]; then
  sudo yum install -y ansible
fi

whichはコマンドを探してくれます。
コマンドがある場合はそのパスとともに結果が返ってきます。

$ which ansible
/usr/bin/ansible

ない場合は、

$ which ansible
/usr/bin/which: no ansible in (/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/.local/bin:/home/vagrant/bin)

no ansibleと出力されていてコマンドが存在しないことが分かります。

whichコマンドの終了ステータス(成功したら 0、失敗したら 1)で判定して、Ansibleがインストールされていない場合のみインストールを実行します。

デプロイサーバーを一度破棄する

$ vagrant destroy -f deploy

上記のコマンドで一度、デプロイサーバーを破棄します。仮想環境を削除できます。
-fのオプションは強制的に削除するオプションで、これをつけないと削除するかどうかを確認されるので、「Y」を応答して削除しましょう。

デプロイサーバーを再構築する

$ vagrant up deplo

前回すでに打ったコマンドと同じですが、再度デプロイサーバーを構築するためにvagrant upを実行します。
そしたらしばらくコンソールを眺めてみましょう。

==> deploy: Running provisioner: shell...
    deploy: Running: C:/Users/HOGEHOGE/AppData/Local/Temp/vagrant-XXXXXXXXXX.sh


のようなログが出てきたらシェルでのプロビジョニングがはじまります。

デプロイサーバーにログインして、EPELとAnsibleを確認する

$ vagrant ssh deploy

でログインし、

$ rpm -q epel-release
epel-release-7-6.noarch
$ which ansible
/usr/bin/ansible
$ ansible --version
ansible 2.1.0.0

となれば無事Vagrantでの自動のプロビジョニングは完了です!

まとめ

  • EPELリポジトリをインストールする
  • EPELリポジトリCentOSの標準パッケージに含まれないパッケージを提供してくれる
  • AnsibleはEPELリポジトリからインストールする
  • yumでインストールできるから簡単ですね!
  • ubuntuの場合はapt-getでインストールできる
  • Vagrantfileにシェルでのプロビジョニングを自動実行するように追加
  • シェルスクリプト以外でもChefやAnsibleなどが起動完了後に実行できる
  • 冪統制をシェルスクリプトでも考えてみると楽しい
  • Ansibleなどの構成管理ツールはそんな冪統制をよしなにしてくれたりもするよ

次は、デプロイサーバーでAnsibleをデプロイサーバー自身に実行してみたいと思います。

次の記事はこちら!
【Laravel Practice03】デプロイサーバーにAnsibleを実行する - 終電23時15分って早くね?


初めてのAnsible

初めてのAnsible

【Laravel Practice01】デプロイサーバー、Webサーバー、DBサーバーの準備

f:id:blue_goheimochi:20160622231431p:plain

Laravelを勉強するにあたって、色々な方面にも興味が出てしまったので、
Laravelアプリケーションを動かすためのサーバー環境構築とか含めて色々やってみようと思ったのでログとして残してみます。

今のところですが、画像のような感じで、

  • デプロイサーバー
  • Webサーバー
  • DBサーバー

を用意して、

  • 各サーバーはAnsibleでプロビジョニングする
  • デプロイサーバーからlaravel/envoyでデプロイする
  • サンプルのLaravelアプリケーションを作る

っていうところまではできたらいいなと思っています。
デプロイは他のツールも試してみたいなぁ。
とりあえずローカルにVirtualBoxVagrantで仮想環境を立ててやってみます。

デプロイサーバー、Webサーバー、DBサーバーの準備

ローカルにVirtualBoxVagrantでCentOS7の仮想環境を3台用意します。
VirtualboxVagrantは各自ご用意ください。
ちなみに私はWindows環境ですが、Chocolateyというソフト(Macでいうbrewみたいなやつ)でインストールしてます。簡単。

Vagrantfile

github.com

こちらのコミットをご覧ください。
3つのサーバーを起動するだけのVagrantfileになっております。
README.mdにも書きましたが、

$ git clone https://github.com/blue-goheimochi/laravel-servers.git
$ cd laravel-server
$ vagrant up

で、3つのサーバーをすべて起動する事ができます。

サーバーの定義
config.vm.define "deploy" do |server|
~~~~~~
end

config.vm.define "web" do |server|
~~~~~~
end

config.vm.define "db" do |server|
~~~~~~
end

と、Vagrantfileに記述することで複数のサーバーを定義できます。
deploywebdbという名前を設定しています。

個別にサーバーを起動したい場合は、

$ vagrant up deploy

のように、定義した名前をvagrant up [名前]とつけることで個別に起動できます。

Boxファイルの指定

各サーバーで同じBoxファイルを指定しています。

今回はbento/centos-7.1というBoxを使います。
CentOS7のBoxファイルです。

server.vm.box = "bento/centos-7.1"

【参考】bentoプロジェクトのBoxファイル一覧
bento | Atlas by HashiCorp
chef社が正式にサポートしているbentoというプロジェクトのBoxのようです。
多分安心して使っていいはず・・・!
色々なディストリビューションがそろってます。

IPアドレスの指定

IPアドレスは各サーバー別々のものを指定します。
すでに仮想サーバーがローカルに存在する場合は、それともかぶらないIPアドレスを指定しましょう。

server.vm.network "private_network", ip: "192.168.33.70"
vagrant-vbguestプラグインの自動アップデートを無効にする

vagrant-vbguestの自動アップデートを無効にします。

if defined?(server.vbguest)
  server.vbguest.auto_update = false
end

boxファイルが作成されたときのVirtualBoxのバージョンと自分がインストールしているVirtualBoxのバージョンが違う際に、
VirtualBox Guest Additionsを自動で更新してくれるプラグインvagrant-vbguestプラグインなのですが、
自動アップデートされてしまう際に、フォルダの共有が失敗する場合があるっぽかったので無効にしています。

アップデートしたい場合は手動で

$ vagrant vbguest deploy

と実行すればできると思います。

【参考】dotless-de/vagrant-vbguest
https://github.com/dotless-de/vagrant-vbguest

VirtualBoxの設定

VirtualBox周りの設定です。

vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]

okisanjp.hatenablog.jp
上記サイトを参考に、わたしの環境でネットワークが遅かったので指定しています。

vb.gui = false

これをtrueにすると仮想ディスプレイが一緒に起動しますが、いらないのでfalseを指定。

vb.memory = 1024
vb.cpus = 2

こちらはメモリとCPUのコア数設定です。

まとめ

  • デプロイサーバー、Webサーバー、DBサーバーの3台をローカルに準備
  • Vagrantfileで複数台の仮想環境を指定できる
  • 個別にサーバーを起動することも可能
  • BoxファイルはChef社のbentoプロジェクトのBoxファイルが安心っぽい
  • IPアドレスはかぶらないように設定する
  • vagrant-vbguestの自動アップデートは無効にした
  • VirtualBoxのネットワークが遅いときの設定をいれた
  • 仮想ディスプレイはオフ

次は、デプロイサーバーにAnsibleをインストールして自分自身をプロビジョニングしてみたいと思います。

本当はたぶんデプロイサーバーに向けてAnsibleをホストOSから実行すればよいのですが、
Windows環境で(面倒なので)ローカルからAnsibleを実行するのではなく、
デプロイサーバー(兼プロビジョニングサーバー)という風に位置づけてAnsibleのインストールをしたいと思います。


次の記事はこちら
【Laravel Practice02】デプロイサーバーにAnsibleをインストール - 終電23時15分って早くね?

TOEICで600点をとるか挫折してあきらめるまで #1 初受験

f:id:blue_goheimochi:20160314014355j:plain
photo by zwenzini

2016年3月13日、TOEIC初受験をきめてきた。

今年の目標と抱負の中の1つに「TOEICで600点」を掲げました。
会社の同僚とも話をして「まず申し込もうぜ」ってなって1月7日には申し込みが完了。

その時点では、1回目で600点なんかぺろんとクリアして、
「ぼくが3ヶ月でTOEIC600点を取った方法」とかエントリを書くところまで想像してたんですが、
どうやら思い通りに行かないことが分かった(笑)ので自分への戒めの意味と泥臭く600点取るまでどんなことしたかとかが残せればいいなぁと思ってログを残しときます。

TOEIC初受験の感想

実は今までTOEICを受けたことがなかったんですが、みなさんそんなもんなのだろうか。
会社からTOEICのスコアとか必要とされなかったし、昇進とか転職とかそういうのの条件にもなかったので見て見ぬふりをしてました。
過去問すら受けずに試験を受けに行ったわけですがそんな中で感想を記しておく。

自信をもって答えられたものがほとんどなかった

リスニングセクションに関してもリーディングセクションに関しても100%これだ!って思って回答できたものがなかった。
もちろん「これはほぼ確定だな」って思ってマークしたものはあったんですが、なんて言ってるのか聞き取れなかったり、単語が分からなくて問題が理解できなかったりでいろいろアカン気がした。

時間が足りない

これはいろんなサイトとかでも見てたり人から聞いたりしてましたが時間が最後足りなかったです。
残り2つの問題で10回答分くらいが追いつかなかったので適当にマークしてしまいました・・・
そもそも問題文の読解に時間が掛かってしまうってのが問題ではありますが、試験の大まかな内容(どんな問題が出るか?)って言うのはいろいろ調べたら分かるし、試験料をムダにしたくないんであれば絶対に過去問解くとかTOEIC攻略的な本読んだほうがよいと思った。

どんな問題が出るかをほとんど知らなかった

まぁ各パートの冒頭でどういう風な問題かって言うのは書いてあったと思うので、知らなくても何とかはなると思うんですがね。
知ってるのと知っていないのでは、TOEICで点を取るためには必要ですなぁという感じでした。
次はこういうパターンの問題だとかある程度心構えがあったほうがいいと思うし、この問題は設問のほうを読んでから問題文を読んで・・・的なことが有効な部分もあったと思うので、次はちゃんとTOEIC対策自体もしようと思った。

ちなみに、2016年5月29日の回からちょっとだけ出題形式が変わるみたい。
square.toeic.or.jp


問題持って帰れると思ってた

と初受験の感想はこんなところ。
で思ったのは、がんばればもうちょっと解けるようになるかも・・・っという風には思いました。
まぁ大体TOEICみたいな試験を受けたり、勉強会に行った帰りだったりとかって「やるぞっー!」ってパズーみたいな気持ちになってるので、ちゃんとその気持ちを維持できるようにしたいです。できたためしがない気がするけど・・・。

でもね、ちょっとだけ勉強はしたの・・・

ホントちょっとだけ!w
いろいろと気合を入れてテキスト買ったりだとかして、1月初旬の私は完全にパズーでした。
で、最初はちょっとだけやってたんですが、だんだん、だんだんとやらなくなり。。。
「とりあえず受けるだけでもえらいでしょ自分!」って開き直った結果がボロボロなのはしょうがない。

で買ったものとかやったこととかを一応載せてみることにする。

DUO 3.0/DUO 3.0/CD復習用

DUO 3.0

DUO 3.0

DUO 3.0 / CD復習用

DUO 3.0 / CD復習用

いろいろなサイトでもイイヨイイヨと紹介されているDUO 3.0。
実際、たくさんの単語を少ない文章に詰め込んで覚えられるのは効率いい気がする。
1月の中旬くらいから初めて最初はがんばってたんだけど、結局2月の初めくらいには止まってしまっていた。
Section4まで・・・。
電車の中ではその日までにやったセクションまでのところの音声を聞いて・・・とかをやってました。

中学・高校で習った英語の基本を5時間でやり直す本

中学・高校で習った英語の基本を5時間でやり直す本 (PHP文庫)

中学・高校で習った英語の基本を5時間でやり直す本 (PHP文庫)

これは更なる昔に英語の学習に目覚めかけたときに買った本(もちろん挫折)だったんですが、引っ張りだしてきて読み直しました。
が、これも1時間目のところまででストップ。。
やればいいだけなのに・・・なんでやらないんだ自分・・・。

mikan

スマホのアプリ。

株式会社mikan | 圧倒的に一番速く覚えられる英単語アプリmikan

TOEICとかTOEFLとか大学受験とかカテゴリを選んでそれにあった単語の学習が出来るアプリ。
これが一番続いた。
んですが、続いたとは言ってもTOEICの2500単語のうち1400単語までしか進まなかった・・・し、やってるうちにアプリが勝手に「苦手な単語」を分類してくれるんですがその数940単語でおいおいって感じです。笑

と、この3ヶ月でがんばったのは(がんばってないけど)これだけです(苦笑)

まとめ

まだ結果も出ないうちだけど、感想とがんばらなかったことを書きました。
自分に対するがんばるがんばる詐欺をやめるための自戒もこめて。。

次は6月か7月にまた受験しようとは思いますが、日々の学習記録とか今回の結果とかも届いたらまたエントリ書きたいと思います。

とりあえず、上であげたテキストとかをちゃんとやる!ってことをがんばります。
そんなもんクソだ捨てちまってこっちをやれ!!とかあったら教えてください。
タイトルにもありますが挫折してあきらめることの内容がんばりたいです・・!