Google App EngineでPHPからHello World
こんにちは。
開発チームのワイルド担当、まんだいです。
Google App Engine(以下、GAE)は、強力なPaasですが、始めるに当たって知っとかないと進められない事が結構あります。
例えば、app.yamlの書き方だったり、どんな関数が使えるのかだったり、そもそもフレームワークは使えるのかだったり、URLはどうなるのかだったり。
しかも、SDKやgcloudコマンドの開発速度も速く、調べたコマンドでデプロイできなくて、投げ出しそうになったりする事も。
というわけで、現時点(2017/03/22)での、最新のGAE環境を踏まえつつ、Hello World的なプログラムをデプロイしてみて、流れを掴んでみます。
紙面の都合上、最新のgcloudコマンドがインストールされている前提で話を進めていきます。
app.yamlの作成
適当なディレクトリを作成して、app.yamlを作成します。
app.yamlはプログラムの環境設定を行う設定ファイルになります。
app.yamlでは、ひとまず実行環境を入れておきます。
# app.yaml # 必須項目です runtime: php55
実行環境として、PHP5.5を選択しました。
というか、GAEではPHP5.5以外選択肢がないようです。
ソースを書く
今回は、Hello Worldですが、「echo "hello world";」 するだけでは芸がないので、Google SQLを使う簡単なプログラムを作成しようと思います。
form.phpという名前でファイルを作ってみます。
ソースは以下のようなものを用意しました。
<?php if ($_SERVER['REQUEST_METHOD'] === 'POST') { $username = getenv('MYSQL_USER'); $password = getenv('MYSQL_PASSWORD'); $dsn = getenv('MYSQL_DSN'); $subject = isset($_POST['subject']) ? $_POST['subject'] : null; $content = isset($_POST['content']) ? $_POST['content'] : null; if (!empty($dsn) && !empty($username) && !empty($password) && !is_null($subject) && !is_null($content)) { $db = new PDO($dsn, $username, $password); $stmt = $db->prepare('INSERT INTO `forms` (`subject`, `content`, `created_at`) VALUES (?, ?, ?)'); $data = array( $subject, $content, date('Y-m-d H:i:s'), ); if (!$stmt->execute($data)) { $info = array( 'title' => $stmt->errorCode(), 'body' => $stmt->errorInfo(), ); } else { $info = array( 'title' => 'info', 'body' => '登録しました!', ); } } }?> <!doctype html> <html> <head> <title>test form</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body> <div class="container"> <?php if (isset($info)){?> <div class="panel panel-default alert alert-info"> <div class="panel-heading"><?php echo $info['title'] ?></div> <div class="panel-body"><?php echo $info['body'] ?></div> </div> <?php } ?> <form method="POST"> <div class="form-group"> <label for="subject">タイトル</label> <input id="subject" type="text" class="form-control" name="subject"> </div> <div class="form-group"> <label for="content">本文</label> <textarea id="content" class="form-control" name="content" rows="10"></textarea> </div> <button class="btn btn-default">送信</button> </form> </div> </body> </html>
Twitter Bootstrapを使った、簡単な登録フォームのページになります。
こちらのプログラムで使うDBのテーブルは、以下のものを使いました。
CREATE TABLE `forms` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `subject` varchar(255) DEFAULT NULL, `content` text, `created_at` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Google Cloud SQLを使うので、Google Cloud SQLへのログイン情報が必要ですので、root以外のユーザーを使用する場合は、事前に作成しておきます。
ソースコードに直接書いてももちろん動作に問題ないですが、せっかくapp.yamlという設定ファイルもあるので、そちらに記述するようにしてみます。
# app.yaml # 先に作成したapp.yamlに追記する env_variables: MYSQL_DSN: mysql:unix_socket=/cloudsql/[インスタンス接続名];dbname=[利用するDBスキーマ名] MYSQL_USER: [MySQLのログインユーザー] MYSQL_PASSWORD: [MySQLのログインパスワード] # ついでにURLのルーティングも追加しておく handlers: - url: /test script: form.php secure: always
env_variablesの項目は、defineするような感覚で定数を登録する事ができます。
PHP側でこの値を受け取るには、getenv()関数で取得します(実際にdefineされている訳ではありません)。
あと、こっそりとhandlersという項目も追加していますが、これがないと、URLが認識してくれないので、/test というURLを作っておきます。
secureの項目は、HTTPSの利用に関する項目で、以下の選択肢があります。
always
HTTPSのみ利用する(HTTPでアクセスするとリダイレクトされる)
optional
HTTP / HTTPS どちらでもアクセス可能
never
HTTPのみアクセス可能
ローカル環境で動作確認する
ソースを書いて動作確認をGAE上でするのは面倒ですし、運用が始まってからはそれもなかなか難しいので、ローカル環境でテストする方法も提供されています。
gcloud SDKの中に含められている、dev_appserver.pyというpythonスクリプトを実行すると、ローカルサーバーが立ち上がって動作確認する事ができますが、このままではCloud SQLにうまく接続できないようです。
が、後述のcloud_sql_proxyを使えば何も考えずにDBへ接続する事ができます。
dev_appserver.pyは、google cloud SDKに含まれていて、app.yamlが置いてあるディレクトリのパス(相対パスでも可)を引数に指定して実行します。
Windowsの場合、結構深いディレクトリにインストールされてしまうので、google cloud SDKの実行ファイルがあるディレクトリにパスを通してしまうのも一つの手かなと思います。
cloud_sql_proxyを使ってGoogle Cloud SQLにローカル開発環境から接続
ローカル環境からは、本番と同じapp.yamlではCloud SQLに接続できませんが、別途cloud_sql_proxyというツールを使うと、簡単にローカルからでもCloud SQLを使ったアプリケーションのテストを実施できます。
簡単にですが、手順をまとめておきます。
- Using Google Cloud SQLを参考に、cloud_sql_proxyを取得して、ファイル名をリネーム。
- パスが通った場所(例えば、Google Cloud SDKのディレクトリなど)に移動する。
- gcloud auth application-default login を実行
- ブラウザにOAuth認証のページが表示されるので、ログインユーザーを選択して許可する
-
cloud_sql_proxyを実行する。参考URL:https://cloud.google.com/sql/docs/mysql/sql-proxy#flags[Windowsの場合] cloud_sql_proxy.exe -instances=[インスタンス接続名]=tcp:3306
もしかすると複数のユーザーを使い分けるような状況では、少しコマンドも変わってくるかと思います(主にgcloud authコマンドあたり)が、未検証なので何とも言えません。
このツールを使うと、Cloud SQLに接続元のIPアドレスなどを登録する必要もないので、一度設定が終わってしまえばかなり開発は楽になります。
デプロイする
GAEにデプロイするためのgcloudコマンドが用意されているので、app.yamlのあるディレクトリで以下のコマンドを実行します。
gcloud app deploy
既にデプロイされている場合は、確認が入りますが、概ね問題なくデプロイできるかと思います。
また、このタイミングで、app.yamlにルーティングされないhandlersが登録されている場合は、以下のようなWarningが表示されます。
WARNING: The URL path "/hogehoge" is reserved and will not be matched.
この場合は、このままデプロイしてもプログラムを実行するためのURLが設定されないので、調整します。
アクセスログをみる
アクセスログは若干のタイムラグはあるものの、ローカル環境からgcloudコマンドを経由して確認できます。
gcloud app logs tail -s default
上記のように、アクセスされたパスとレスポンスコードが表示されるので、簡単なエラーチェックは可能です。
エラーログをみる
GAEはPaasですので、サーバーにログインしてエラーログを確認するという訳にはいきません。
ですので、デプロイした後で、エラーの発生を確認するには、ダッシュボードだったり、Stackdriver Error Reportingなどを活用してログを確認します。
きれいにパースされたものが表示されるので、見やすいですが、あっちこっちに情報が分かれすぎていて、慣れるまでが大変ですね。
まとめ
いつもの開発とは少しやり方が違うので、戸惑う事も多いですが、1つずつ進めていけば、何とかなるような印象です。
特に、Google Cloud SQLがプロキシを経由してローカルから接続できるあたりは、非常に使いやすいなと思いました。
ちょっとした便利ツールなどをホストしておくにはもってこいのサービスですし、規模が大きくなっても、自動でインスタンスを増やしてくれたり、便利な面も多いので、色んな用途に利用できそうです。
他にも、memcacheが使えたり、Google Cloud Storageにアプリケーション用のディレクトリが作成され、簡単に扱えるように設計されていたりするので、各種データの保管場所にも困らないようになっています。
以上です。