takaya030の備忘録

PHP、Laravel、Docker などの話がメインです

Lumen の Welcome Page を作る

nginx + php-fpm で Lumen を動かす記事の続編です。

Lumen 5.2 で Welcome Page が無くなっていた

最新版の Lumen をインストールして実行してみたらバージョン番号のテキストが表示されました。あの白い画面の Welcome Page が無いとチョット寂しいので Lumen 5.2 で作ってみました。
f:id:takaya030:20160505005324p:plain

ソースコード

app/Http/Controllers/WelcomeController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class WelcomeController extends Controller
{
    public function index( Request $request )
    {
	$client_ip = $request->ip();
	$server = $request->server();		// $_SERVER

        return view('welcome', ['server' => $server, 'client_ip' => $client_ip]);
    }
}

app/Http/routes.php

<?php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It is a breeze. Simply tell Lumen the URIs it should respond to
| and give it the Closure to call when that URI is requested.
|
*/

$app->get('/', [
	'uses' => 'WelcomeController@index',
]);

resources/views/welcome.blade.php

<!DOCTYPE html>
<html>
<head>
	<title>Lumen</title>

	<link href='//fonts.googleapis.com/css?family=Lato:100' rel='stylesheet' type='text/css'>

	<style>
		body {
			margin: 0;
			padding: 0;
			width: 100%;
			height: 100%;
			color: #B0BEC5;
			display: table;
			font-weight: 100;
			font-family: 'Lato';
		}

		.container {
			text-align: center;
			display: table-cell;
			vertical-align: middle;
		}

		.content {
			text-align: center;
			display: inline-block;
		}

		.title {
			font-size: 96px;
			margin-bottom: 40px;
		}

		.quote {
			font-size: 24px;
		}

		.info {
			font-size: 48px;
		}
	</style>
</head>
<body>
	<div class="container">
		<div class="content">
			<div class="title">Lumen.</div>
			<div class="info">Hostname: {{ gethostname() }}</div>
			<div class="info">Server IP: {{ $server['SERVER_ADDR'] }}</div>
			<div class="info">Client IP: {{ $client_ip }}</div>
@if ( array_key_exists('X-Forwarded-For', $server) )
			<div class="info">X-Forwarded-For: {{ $server['X-Forwarded-For'] }}</div>
@elseif ( array_key_exists('HTTP_X_FORWARDED_FOR', $server) )
			<div class="info">HTTP_X_FORWARDED_FOR: {{ $server['HTTP_X_FORWARDED_FOR'] }}</div>
@elseif ( array_key_exists('REMOTE_ADDR', $server) )
			<div class="info">REMOTE_ADDR: {{ $server['REMOTE_ADDR'] }}</div>
@endif
		</div>
	</div>
</body>
</html>

動作確認のための Docker 関連ファイル

ディレクトリ構成

lumen
│  docker-compose.yml
│  
├─nginx
│    Dockerfile
│    server.conf
│
└─php7
      Dockerfile
      k8s_lumen/

lumen/php7/k8s_lumen は下記コマンドでインストールされた Lumen の実行環境に上記ソースコードを適用したものになります。

$ composer create-project --prefer-dist laravel/lumen k8s_lumen

lumen/docker-compose.yml

nginx: 
  build: ./nginx
  ports: 
    - "80:80"
  links: 
    - php7

php7: 
  build: ./php7

lumen/nginx/Dockerfile

FROM nginx:latest
MAINTAINER takaya030

ADD server.conf /etc/nginx/conf.d/server.conf

lumen/nginx/server.conf

server {
    listen 80 default;
    server_name _;
    root /webapp/public;
    index index.php index.html index.htm;
    charset utf-8;

    access_log off;
    error_log off;

    rewrite ^(.+)/$ $1;

    location / {
        # try_files $uri $uri/ /index.php$is_args$args;
        try_files $uri /index.php?$query_string;
    }

    location ~ ^/index.php$ {
        fastcgi_pass lumen_php7_1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include       fastcgi_params;
    }
}

lumen/php7/Dockerfile

FROM php:7-fpm
MAINTAINER takaya030

RUN apt-get update \
  && apt-get install -y libfreetype6-dev libjpeg62-turbo-dev libpng12-dev libmcrypt-dev \
  && docker-php-ext-install pdo_mysql mysqli mbstring gd iconv mcrypt

RUN mkdir /webapp
COPY k8s_lumen /webapp

イメージのリビルド

$ cd lumen
$ docker-compose build

コンテナの起動

$ cd lumen
$ docker-compose up -d

動作確認

web ブラウザで http://192.168.99.100/ にアクセスして下の画像のように表示されるか確認。
f:id:takaya030:20160627001224p:plain

参考サイト

takaya030.hatenablog.com

Lumen の Controller の namespace について

Lumen 5.2 でコントローラのルートの namespace が App\Http\Controllers に変更されていたのでメモ

Lumen 5.1 で動いていたコードが 5.2 でエラーになった件

app/Http/routes.php

<?php

$app->get('/', [
	'uses' => 'App\Http\Controllers\WelcomeController@index',
]);

上のコードを Lumen の最新版(5.2)で実行したとき発生したエラー

[2016-06-25 04:01:55] lumen.ERROR: ReflectionException: Class App\Http\Controllers\App\Http\Controllers\WelcomeController does not exist in /webapp/vendor/illuminate/container/Container.php:734

Lumen 5.1 では Controller のルートは namespace 無しだったが、5.2 では 'App\Http\Controllers' になったらしい。
以下のように変更したら無事動きました。

<?php

$app->get('/', [
	'uses' => 'WelcomeController@index',
]);

ちなみに Controller のデフォルト namespace は bootstrap/app.php で定義されている。
Lumen 5.1 の bootstrap/app.php 84行目

<?php

/*
|--------------------------------------------------------------------------
| Load The Application Routes
|--------------------------------------------------------------------------
|
| Next we will include the routes file so that they can all be added to
| the application. This will provide all of the URLs the application
| can respond to, as well as the controllers that may handle them.
|
*/

require __DIR__.'/../app/Http/routes.php';

Lumen 5.2 の bootstrap/app.php 85行目

<?php

/*
|--------------------------------------------------------------------------
| Load The Application Routes
|--------------------------------------------------------------------------
|
| Next we will include the routes file so that they can all be added to
| the application. This will provide all of the URLs the application
| can respond to, as well as the controllers that may handle them.
|
*/

$app->group(['namespace' => 'App\Http\Controllers'], function ($app) {
    require __DIR__.'/../app/Http/routes.php';
});

検証した Lumen のバージョン

Lumen 5.1

$ php artisan --version
Laravel Framework version Lumen (5.1.6) (Laravel Components 5.1.*)

Lumen 5.2

$ php artisan --version
Laravel Framework version Lumen (5.2.7) (Laravel Components 5.2.*)

Kubernetes で nginx + php-fpm を動かす

Google Container Engine (GKE) で Kubernetes を使って nginx + php-fpm を動かしたときの手順メモ

Docker イメージの作成

今回は 1 個の pod 内で nginx と php-fpm の 2 つのコンテナを起動させます。そのための Docker イメージを作成します。

nginx の Dockerfile

FROM nginx:latest
MAINTAINER takaya030

ADD server.conf /etc/nginx/conf.d/server.conf

server.conf

同じ pod のコンテナは同一ホストで起動するので php-fpm を localhost:9000 で参照する設定にしています。

server {
    listen 80 default;
    server_name _;
    root /var/www/html;
    index index.php index.html index.htm;
    charset utf-8;

    access_log off;
    error_log off;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ ^/index.php$ {
        fastcgi_pass localhost:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include       fastcgi_params;
    }
}

nginx イメージのビルド

$ docker build -t gcr.io/my_project_id/k8sphp_nginx .

php-fpm の Dockerfile

FROM php:7-fpm
MAINTAINER takaya030

RUN apt-get update \
  && apt-get install -y libfreetype6-dev libjpeg62-turbo-dev libpng12-dev libmcrypt-dev \
  && docker-php-ext-install pdo_mysql mysqli mbstring gd iconv mcrypt

COPY index.php /var/www/html/

index.php

<?php
	phpinfo();

php-fpm イメージのビルド

$ docker build -t gcr.io/my_project_id/k8sphp_php7 .

イメージを Container Registry へ push

$ gcloud docker push gcr.io/my_project_id/k8sphp_nginx
$ gcloud docker push gcr.io/my_project_id/k8sphp_php7

pod の作成

pod-k8sphp.yaml

apiVersion: v1
kind: Pod
metadata:
  name: k8sphp
  labels:
    app: webphp
spec:
  containers:
    - name: nginx
      image: gcr.io/my-project-id/k8sphp_nginx
      ports:
        - containerPort: 80
    - name: php-fpm
      image: gcr.io/my-project-id/k8sphp_php7
      ports:
        - containerPort: 9000

pod の作成

$ kubectl create -f pod-k8sphp.yaml
pod "k8sphp" created

pod の作成確認

$ kubectl get pods
NAME      READY     STATUS    RESTARTS   AGE
k8sphp    2/2       Running   0          34s

service の作成

service-k8sphp.yaml

apiVersion: v1
kind: Service
metadata:
  name: phptest
spec:
  ports:
    -
      port: 80
      targetPort: 80
  selector:
    app: webphp
  type: LoadBalancer

service の作成

$ kubectl create -f service-k8sphp.yaml
service "phptest" created

service の作成確認

$ kubectl get services
NAME         CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
kubernetes   10.3.240.1    <none>        443/TCP   45m
phptest      10.3.242.13                 80/TCP    25s

動作確認

service を作成してから 1 分程経過するとグローバルIP (EXTERNAL-IP) が割り当てられるので、 http://EXTERNAL-IP にブラウザでアクセスして以下のように表示されれば成功です。
f:id:takaya030:20160618004808p:plain

後始末

service、pod の削除

$ kubectl delete -f service-k8sphp.yaml
service "phptest" deleted

$ kubectl delete -f pod-k8sphp.yaml
pod "k8sphp" deleted

Google Container Engine (GKE) に kubectl で Docker コンテナを起動する

GKE に作成したクラスタに kubectl を使って Docker コンテナを単体起動したときの手順メモ

Docker イメージを Container Registry へ push

今回は nginx の Docker Hub 公式イメージをそのまま使います。

$ docker pull nginx
$ docker tag nginx gcr.io/my_project_id/nginx
$ gcloud docker push gcr.io/my_project_id/nginx

my_project_id にハイフンが含まれている場合、アンダースコアに置き換えて下さい。
push されたイメージは GKE のコンソールで確認できます。
f:id:takaya030:20160604215241p:plain

コンテナクラスタの作成

GKE のコンソールからコンテナクラスタを作成します。
f:id:takaya030:20160604215333p:plain
今回はこのような内容で作成しました。Cluster size がノード数になります。
f:id:takaya030:20160604215344p:plain
作成ボタンを押してから数分後にクラスタが作成されます。
f:id:takaya030:20160604215409p:plain

Container Registry のイメージを使ってコンテナを起動

$ kubectl run hello-nginx --image=gcr.io/my-project-id/nginx:laest --port=80

コンテナのエクスポート

外部からアクセス可能にするため下記コマンドを実行

$ kubectl expose deployment hello-nginx --type="LoadBalancer"

数分待つとコンテナにグローバル IP が割り当てられます。

コンテナのグローバル IP の確認

$ kubectl get service hello-nginx
NAME          CLUSTER-IP     EXTERNAL-IP      PORT(S)   AGE
hello-nginx   10.3.243.148   130.211.xxx.xx   80/TCP    7m

EXTERNAL-IP がコンテナのグローバル IP になります。

動作確認

web ブラウザで http://EXTERNAL-IP を開いて以下の通りに表示されば成功です。
f:id:takaya030:20160604215454p:plain

コンテナの停止

$ kubectl delete service hello-nginx

コンテナクラスタをそのまま放置すると課金されるので、コンソールで削除します。

トラブルシューティング

kubectl run のとき "The connection to the server localhost:8080 was refused" のエラーになる

gcloud の config にクラスタの情報が登録されていないのが原因です。
以下の操作で登録します。

$ gcloud config set project my-project-id
$ gcloud config set compute/zone us-central1-b
$ gcloud config set container/cluster cluster-1
$ gcloud container clusters get-credentials cluster-1
Fetching cluster endpoint and auth data.
kubeconfig entry generated for cluster-1.
$ gcloud config list
Your active configuration is: [default]

[compute]
region = us-central1
zone = us-central1-b
[container]
cluster = cluster-1
...

kubectl version で Server Version が表示されていれば、サーバーと通信できています。

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"2", GitVersion:"v1.2.4", GitCommit:"3eed1e3be6848b877ff80a93da3785d9034d0a4f", GitTreeState:"clean"}
Server Version: version.Info{Major:"1", Minor:"2", GitVersion:"v1.2.4", GitCommit:"3eed1e3be6848b877ff80a93da3785d9034d0a4f", GitTreeState:"clean"}

Docker コンテナに Google Cloud SDK (gcloud) と Kubernetes (kubectl) をインストール

WindowsGoogle Cloud SDK では Kubernetes (kubectl) が動かないため、Docker コンテナ にインストールしたときの手順メモ

Dockerfile

gcloud を動作させるために Python 2.7 が必要なため、Docker Hub の公式イメージを流用して作成

# gcloud shell
#

FROM python:2.7
MAINTAINER takaya030

RUN apt-get update && apt-get install -y openssh-server sudo
RUN mkdir /var/run/sshd
RUN echo 'root:root' | chpasswd
RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# SSH login fix. Otherwise user is kicked off after login
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd

ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile

# create login user
RUN useradd -d /home/gcp -m -s /bin/bash gcp
RUN echo gcp:****gcp | chpasswd
RUN echo 'gcp ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]

イメージのビルド

$ docker build -t takaya030/gcloud .

コンテナの起動

$ docker run -d -it -p 2222:22 --hostname gcsh --name gcp_gcsh_1 takaya030/gcloud

コンテナへログイン

$ ssh -p 2222 gcp@192.168.99.100

※パスワードは '****gcp'

Google Cloud SDK のインストール

$ curl https://sdk.cloud.google.com | bash

今回は /home/gcp/google-cloud-sdk/ にインストールした。
インストール後、直ちにコマンドのパスを有効にしたい場合は以下のコマンドを入力

$ source .bashrc

GCP のユーザー情報の設定

$ gcloud init

kubectl のインストール

$ gcloud components update kubectl
$ which kubectl
/home/gcp/google-cloud-sdk/bin/kubectl

Docker で nginx + php-fpm を動かす

Docker で nginx + php-fpm を動かすまでの作業手順メモ

検証環境

Docker Toolbox 1.10.3 と同じ構成です。

  • VirtualBox 5.0.16
  • docker 1.10.3
  • docker-machine 0.6.0
  • dokcer-compose 1.6.2

docker-compose.yml の作成

Docker ホストマシン (CoreOS) に /home/docker/phpfpm ディレクトリを作り、そこに下記の内容でファイルを配置します。

phpfpm
│  docker-compose.yml
│  
├─nginx
│    Dockerfile
│    server.conf
│
└─php7
      Dockerfile
      index.html

docker-compose.yml

nginx: 
  build: ./nginx
  ports: 
    - "80:80"
  links: 
    - php7

php7: 
  build: ./php7

nginx/Dockerfile

FROM nginx:latest
MAINTAINER takaya030

ADD server.conf /etc/nginx/conf.d/server.conf

nginx/server.conf

server {
    listen 80 default;
    server_name _;
    root /var/www/html;
    index index.php index.html index.htm;
    charset utf-8;

    access_log off;
    error_log off;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        fastcgi_pass phpfpm_php7_1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include       fastcgi_params;
    }
}

php7/Dockerfile

FROM php:7-fpm
MAINTAINER takaya030

COPY index.php /var/www/html/

php7/index.php

<?php
	phpinfo();

コンテナの起動

docker@dev:~$ cd /home/docker/phpfpm/
docker@dev:~/phpfpm$ docker-compose up -d

動作確認

web ブラウザで http://192.168.99.100/ にアクセスして下の画像のように表示されるか確認。

コンテナの停止

docker@dev:~$ cd /home/docker/phpfpm/
docker@dev:~/phpfpm$ docker-compose stop

Docker で構築した nginx + php-fpm で Lumen を動かす

WindowsVirtualBox の Docker 環境上で構築した nginx + php-fpm で Lumen を動かしたときの作業メモ

Docker のホスト OS に Windows のフォルダをマウントする

下記の記事の手順でホスト OS (CoreOS) の /workspace に Windows のフォルダをマウントする。

Lumen のインストール

マウントした /workspace に移動して下記のコマンドで Lumen をインストールする。

$ composer create-project --prefer-dist laravel/lumen lumen

各種設定ファイル

こちらの記事で作成した Dockerfile や conf ファイルを下記の通りに変更します。
docker-compose.yml

nginx: 
  build: ./nginx
  ports: 
    - "80:80"
  links: 
    - php7

php7: 
  build: ./php7
  volumes: 
    - /workspace/lumen:/webapp

nginx/Dockerfile

FROM nginx:latest
MAINTAINER takaya030

ADD server.conf /etc/nginx/conf.d/server.conf

nginx/server.conf

server {
    listen 80 default;
    server_name _;
    root /webapp/public;
    index index.php index.html index.htm;
    charset utf-8;

    access_log off;
    error_log off;

    rewrite ^(.+)/$ $1;

    location / {
        # try_files $uri $uri/ /index.php$is_args$args;
        try_files $uri /index.php?$query_string;
    }

    location ~ ^/index.php$ {
        fastcgi_pass phpfpm_php7_1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include       fastcgi_params;
    }
}

php7/Dockerfile

FROM php:7-fpm
MAINTAINER takaya030

RUN apt-get update \
  && apt-get install -y libfreetype6-dev libjpeg62-turbo-dev libpng12-dev libmcrypt-dev \
  && docker-php-ext-install pdo_mysql mysqli mbstring gd iconv mcrypt

COPY index.php /var/www/html/

php7/index.php

<?php
	phpinfo();

イメージのリビルド

docker@dev:~$ cd /home/docker/phpfpm/
docker@dev:~/phpfpm$ docker-compose build

コンテナの起動

docker@dev:~$ cd /home/docker/phpfpm/
docker@dev:~/phpfpm$ docker-compose up -d

動作確認

web ブラウザで http://192.168.99.100/ にアクセスして下の画像のように表示されるか確認。