sakutarou’s blog

とりあえずWeb系技術をゆるく書いていく

Vagrant + Hyper-Vでboxを作成する

自分の開発環境はVagrant + Hyper-Vを使っているのですが、 今回ノートPCを新しく購入したこともあって、ゼロからVagrantを起動しようとしたら自分が利用していたboxの公開が終了してました。。。

Vagrant + Hyper-Vは選択肢少ないんですよね。。。

なので今回はbox作成をメモ代わりに残しておこうと思います。
Windows + Hyper-Vなこともあって色々躓きました。。。

ここに記載する内容は必要最低限にしてあります。

CentOS7のイメージ(iso)からOSを起動する

以下のURLからCentOSのイメージをダウンロードして、CentOSを立ち上げます。
自分は Minimal ISOCentOS7 64bit を利用しました。

Download CentOS

hypervkvpdのインストール

hypervkvpd をインストールしておかないと Waiting for the machine to report its IP address... と出たところでタイムアウトします。

yum install hypervkvpd
systemctl enable hypervkvpd

vagrantユーザーの作成 + 鍵ファイルの設置

passwd # rootのパスワードはvagrantに設定
useradd -g wheel vagrant
passwd vagrant # vagrantのパスワードはvagrantに設定
mkdir /home/vagrant/.ssh
chmod 700 /home/vagrant/.ssh

cd /home/vagrant/.ssh
curl -k -L -o authorized_keys 'https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub'
chmod 600 /home/vagrant/.ssh/authorized_keys
chown -R vagrant:wheel /home/vagrant/.ssh

その他設定

systemctl stop firewalld
systemctl disable firewalld

vi /etc/selinux/config
- SELINUX=enforcing
+ SELINUX=disabled

vi /etc/sysctl.d/disable_ipv6.conf

+ net.ipv6.conf.all.disable_ipv6 = 1
+ net.ipv6.conf.default.disable_ipv6 = 1

vi /etc/sysconfig/network-scripts/ifcfg-eth0
- UUID=XXXXXXXXXXX

sudoの設定

visudo

# コメントアウトを外す
%wheel  ALL=(ALL)       NOPASSWD: ALL

キャッシュの削除

完成するbox自体のサイズを小さくするために、キャッシュを削除しておきます。

yum clean all
rm ~/.bash_history
history -c

OSの終了

shutdown -h now

作成したOSをエクスポートする

Hyper-V マネージャーを開いて、仮想マシンをエクスポートします。

f:id:sakutarou:20170213000715p:plain

boxの作成(その1)

エクスポートしたフォルダを開くと以下のようになってるはずです。

  • Snapshots
  • Virtual Hard Disks
  • Virtual Machines

上記のうち、 Snapshots は不要なので削除します。

boxの作成(その2)

エクスポートしたフォルダに metadata.json を作成する。
最低限以下のような内容になります。

{
    "name": "sakutarou/centos7",
    "provider": "hyperv"
}

作成後、以下になります。

  • Virtual Hard Disks
  • Virtual Machines
  • metadata.json

boxの作成(その3)

Virtual Hard Disks , Virtual Machines , metadata.json の3つ選択した状態で、zip圧縮します。
※この時、上階層のフォルダを選択してzip圧縮するではなく、3つを選択して圧縮してください。

zipファイルが完成後、拡張子を .box に変更してください。

これでbox完成です。

boxとして利用する

以下のコマンドを実行すれば、作成したboxファイルを利用することが出来ます。

vagrant box add --name "sakutarou/centos7" "centos7.box"

もしくは、atlasにアップするなどして利用してください。

その他

これ使ったら、もっと簡単に作成できるかも?
何も試してないけど

github.com

などなど

CentOS7でPowerShellを実行する

さて、別にPowerShellを日頃からばりばり使っているわけではありません。
コマンドじゃないとめんどくさいときに、やっとPowerShell出てきてやっと使うレベルです。
あとは、Vagrant立ち上げるとき。。。

なぜ、CentOS7でPoserShellなのかというと、ついにWindowsから「コマンドプロンプト」が消えるらしいです。

そもそも、自分は開発OS自体はWindowsなので、使えた方がいろいろと効率がいいはずです。きっと。。。たぶん。。。
とりあえずトライ!

http://business.newsln.jp/news/201612072350480000.html

インストール

yum install https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.13/powershell-6.0.0_alpha.13-1.el7.centos.x86_64.rpm

実行

powershell で実行できます。

powershell

PowerShell
Copyright (C) 2016 Microsoft Corporation. All rights reserved.

PS /root>

とりあえずコマンドレットの数を計測してみる

必要かは別として、Windows10 と CentOS7 を比較すると2500くらいは差がありますね。。。

# CentOS 7
Get-Command | measure | select count

Count
-----
  349
# Windows10
Get-Command | measure | select count

Count
-----
 2725

参考

github.com

CakePHP3のMiddleware導入

この記事は 「Fusic Advent Calendar 2016の6日目」になります

使ってますか?Middleware

これですね。CakePHP3.3から導入されている機能ですね。
http://book.cakephp.org/3.0/ja/controllers/middleware.html

Middlewareって何?

アクセスに対するリクエスト、レスポンスに対して処理を挟むことができます。 処理を挟むといわれると、Controllerには initialize とかありますけどもっと前に処理を挟むことが可能になります。なります。

また、 PSR-7 に互換しているため、 Packagist などで公開されている PSR-7 互換のライブラリを利用することが可能となります。

例えば、 Laravelで利用されているMiddlewareをCakePHPで利用するということも可能になります。(Laravelに依存していなければ)

どのタイミングで動くの?

初期だと以下の順番で動作します。

  1. ErrorHandlerMiddleware(リクエスト処理)
  2. AssetMiddleware(リクエスト処理)
  3. RoutingMiddleware(リクエスト処理)
  4. CakePHP
  5. RoutingMiddleware(レスポンス処理)
  6. AssetMiddleware(レスポンス処理)
  7. ErrorHandlerMiddleware(レスポンス処理)

この図のようにMiddlewareを複数重ねていくイメージで動作します。

Untitled (3).png

どんなところで使えるの?

認証やリクエストオブジェクトやレスポンスオブジェクトの加工、IPアドレス制限などアプリケーションが起動する前の処理などは適した処理だと言えると思います。 レスポンス側だと、ログ出力や実行時間の計測などがいいのでしょうか。

上記の図でもそうですが、 initializeはアプリケーションが起動した後になります。 認証などは起動前の処理でいいものはいろいろとあると思われます。

Middlewareサンプル

1メソッドの中で、リクエスト処理、レスポンス処理を行います。 癖はありますね。

<?php

// src/Middleware/TrackingCookieMiddleware.php の中で
namespace App\Middleware;

class TrackingCookieMiddleware
{
    public function __invoke($request, $response, $next)
    {
        // ここでリクエスト処理

        $response = $next($request, $response);

        // ここでレスポンス処理

        return $response;
    }
}

Middlewareの使い方

Middlewareの起動などの設定は src/Application.php に記述します。 必要なMiddlewareを追記してきます。

注意点としては、作成したMiddlewareの __invoke にrequest, responseオブジェクトが渡ってきますが、 それぞれ、 Zend\Diactoros\ServerRequest, Zend\Diactoros\Response になっており、 Cake\Network\Request, Cake\Network\Response とは違うことに注意が必要です。

webroot/index.php$server->run() の引数に利用したいオブジェクトを渡すと、Cake\Network\Request, Cake\Network\Response など使いたいオブジェクトに切り替えることが可能です。

メンテナンス画面表示用プラグイン作ってみた

Middlewareの勉強がてら、 Maintenanceプラグインを作ってみました。 簡単にメンテナンス画面に切り替えるためのプラグインになります。

https://github.com/fusic/maintenance/

CakePHP3のRouteクラス3種

CakePHP3でRouteクラスを利用してるのでしょうか? Router::scope などはよく使うのですが、 DashedRouteInflectedRouteRedirectRoute は頻繁には利用せず毎回調べてるので備忘録程度に残しておきます。

ようはどういうURLでアクセスするかというやつですね。

DashedRoute

特に気にしていない場合は、DashedRouteを利用していると思います。

  • アクセスするURL => /my-controller/my-action
  • クラス => MyController::myAction

InflectedRoute

CakePHP2までと同じようなURLでアクセスしたい場合はこちらですね

  • アクセスするURL => /my_controller/my_action
  • クラス => MyController::myAction

RedirectRoute

これは少し毛色の違うRouteです。
特定のURLにアクセスされたら、別ページにRedirectしたい場合があると思います。
RedirectRouteを使えばRouteだけでRedirect可能です。

  • アクセスするURL => /my-controller/my-action
  • アクセスしたいURL => http://example.com

使い方

routes.php に記述するだけです。

$routes->connect('/', ['redirect' => 'http://example.com'], ['routeClass' => 'RedirectRoute']);

その他

全体をInflectedRouteにしたい

デフォルトのRouteを指定する

Router::defaultRouteClass(InflectedRoute::class);

Vagrantで使用するプロバイダを指定する

タイトル通りですが、「Vagrantで使用するプロバイダを指定する」方法の備忘録です。

Vagrantを使用してる人は「VirtualBox」を使ってる人が多いと思うので、ほとんど使うことはないでしょうか?

自分はWindows上で「Vagrant + Hyper-V」を使っているので、毎度毎度 vagrant up --provider=hyperv と入力するのがめんどくさいのです。

設定内容

環境変数VAGRANT_DEFAULT_PROVIDER を設定するだけです。
設定する値は使いたいプロバイダです。自分の場合だと hyperv ですね。

簡単!

laravel/envoyでデプロイしてみる

PHPで作られているシステムをデプロイをするために、Envoyを使ってみました。
CapistranoやRocketeerとかと似たような立ち位置のものですね。

ただこれらよりはずっとシンプルです。
簡単な機能しかないですが、シンプルなものであれば全然問題ないと思う。

Envoyはこれ↓ github.com

これって、Laravelでしか使えないの?

Laravelってついてるけど、Laravelに限らずどこで使えます。
自分はCakePHP3と組み合わせて使ってます。

Envoyインストール

composer require "laravel/envoy=~1.0"

Envoyファイルの作成

# 127.0.0.1がデプロイ先になります。
php vendor/bin/envoy init 127.0.0.1

上記コマンドを実行すると Envoy.blade.php が作成されます。
こんなやつ

// Envoy.blade.php
@servers(['web' => '127.0.0.1'])

@task('deploy')
    cd /var/www/html
    git pull origin master
@endtask

taskからendtaskの間がデプロイ先で実行するスクリプトになります。

複数サーバーにデプロイするような場合は、 @servers(['web1' => '127.0.0.1', 'web2' => '127.0.0.1']) のように単純に複数並べます。

実行してみる

deploy が実行するタスク名になります。
以下を実行すると、リモートサーバーにログインして、 /var/www/html に移動して、 git pull をする というものになります。簡単!

php vendor/bin/envoy run deploy

story

storyは、複数のタスクをまとめて実行することができる機能です。
storyに、実行したいタスク名を羅列するだけです。

@servers(['web' => '192.168.1.1'])

@story('deploy')
    git
    composer
@endstory

@task('git')
    git pull origin master
@endtask

@task('composer')
    composer install
@endtask

setup

デプロイ処理をするときに必ず初期化したいような処理を書いておくのが、 setup です。
setupは PHPで記述します

タスクでPHPの変数を使いたい場合は、{{}} で変数を囲みます。

@setup
    $date = date('Y/m/d');
@endsetup

@task('deploy'])
    echo {{$date}}
@endtask

特定のサーバーに限定してタスクを実行したい

特定のサーバーに限定する場合は、タスクのパラメーターとして、 on にサーバー名を追加します。

@servers(['web1' => '192.168.1.1', 'web2' => '192.168.1.2'])

@task('deploy', ['on' => ['web1']])
    cd site
    git pull origin master
@endtask

並列処理

基本的に処理は、1サーバーごとに実行されます。
たた、同時に実行して問題がない場合は並列でデプロイしたほうがいいかもしれません。

並列処理も簡単で、並列に処理したいタスクのパラメーターとして、 parallel をtrueに設定するだけです

@servers(['web1' => '192.168.1.1', 'web2' => '192.168.1.2'])

@task('deploy', ['parallel' => true])
    cd site
    git pull origin master
@endtask

ifやforを使いたい

使いどころがいまいち思いついてないですが、ループや分岐も使えます。
マニュアルにも載ってないので、必要ないかも?

@servers(['web1' => '192.168.1.1'])

@setup
    $list = ['one', 'two', 'three'];
@endsetup

@task('deploy')
    @foreach ($list as $user)
        @if ($user == 'aaa')
            echo {{$user}}
        @endif
    @endforeach
@endtask

終了処理

これもマニュアルに載ってない。。。
タスクごと、デプロイ自体の終了処理も書くことが可能です。

// タスクごとの終了処理
@after
    echo "タスク完了";
@endafter

// デプロイ自体の終了処理
@finished
    echo "デプロイ終了";
@endfinished

Slack通知

デプロイとは関係ないですが、Slack、Hipchatへの通知機能を持ってます。
setupやafter、finishedで使うといい感じかも

@servers(['web1' => '192.168.1.1'])

@finished
    @slack('Incoming WebHooks URL', '通知先チャンネル', 'デプロイ終わったよー')
@endfinished

DockerでAmazonLinuxを動かす

AmazonLinuxがdocker上で簡単に動かせるようになったので試してみました。

環境

  • ホストOS・・・CentOS 7
  • Docker・・・1.12.3

CentOS 6上のDocker 1.7で試したら、 image amazonlinux:latest not found と出て実行できませんでした。

AWS cliのインストール

AWS cliをすでにインストールしている場合はスキップ

インストール

yum install python-pip
pip install pip --upgrade
pip install awscli

AWS cliの設定

aws configure

# 以下は環境に合わせて
AWS Access Key ID [None]: Access Key
AWS Secret Access Key [None]: Secret Key
Default region name [None]: ap-northeast-1
Default output format [None]: json

Amazon Linuxイメージ取得

aws ecr get-login --region ap-northeast-1 --registry-ids 137112412989

# ecr get-loginを実行すると以下のようなコマンドが出力されるので、そのまま実行する
docker login -u AWS -p {パスワード} -e none https://137112412989.dkr.ecr.ap-northeast-1.amazonaws.com

# Docker Imageを取得
docker pull 137112412989.dkr.ecr.ap-northeast-1.amazonaws.com/amazonlinux:latest

Amazon Linuxの起動

ここまで来たら、通常通りコンテナを起動するだけです。

docker run -it 137112412989.dkr.ecr.ap-northeast-1.amazonaws.com/amazonlinux:latest /bin/bash

AmazonLinux起動してみるとわかるのですが、本当に何も入ってないです。

image名の変更

特に必要ないですがimage名を変更したほうが楽かも

docker tag {イメージID} amazonlinux
docker rmi 137112412989.dkr.ecr.ap-northeast-1.amazonaws.com/amazonlinux

参考

Amazon Linux Container Image - Amazon ECR