Technote

by sizuhiko

Google Cloud Builder を使って PHP7.2 のアプリケーションを GAE に継続的デプロイする

この記事は、PHPカンファレンス関西2018に参加してGAEに継続的デプロイする方法について発表してきましたの中で紹介しているGoogle Cloud Builderを利用してGAEのPHP SEへ自動デプロイするサンプルコードを最新に更新した解説記事です。

何が変わったのか?

PHPカンファレンス関西2018時点では以下のようになっていました。

  • GAEのPHPは5.5
  • Google Cloud Container Builder を利用

今日では以下のようになっています。

  • GAEのPHPで7.2が利用可能に
  • Cloud Container Builder は Cloud Build という名前に変更

gcloud コマンド利用上での変更

Dockerのバージョンがあがったことで gcloud コマンドから docker コマンドを実行するときに認証設定が必要になりました。 READMEにも反映していますが、以下のコマンドを実行しておく必要があります。

$ gcloud auth configure-docker

gcloud コマンドをアップデートしてみましたが、「PUSH TO DEPLOY のトリガーをセットする」については、まだできませんでした。 projects.builds/create APIは実装されているようなので、CLIから実行できるようになるのを心待ちにしています。

composer イメージの更新

PHP7.2を利用できるようになったので、 composer/composer:php5 のDockerイメージを composer/composer:alpine に変更しました。 composer/composer でも良かったのですが、 alpine ベースの方が軽量だし、いいですよね。

app.yaml の更新

基本的にここがメインなのですが、以下のような変更点があります。

  • runtime を php72 に変更
  • handlersapplication_readable は常に true
  • skip_files でデプロイしないファイルの指定は .gcloudignore ファイルへ移行する
  • / アクセスされたときの script 指定は auto に(ただし index.phppublic/index.php の場合のみで、他はパスを指定)

こういった変更は、Compatibility issues between PHP 5.5 and PHP 7.2にまとめられています。 ※ skip_files については書いていないので、実際にマイグレーションして確認は必要です(これは5.5から7.2の変更というよりは gcloud コマンドのバージョンアップに伴うものだから書いていないのかもしれないです)。

デプロイしてみよう

あとは、用意したコマンドを順番に実行してデプロイ環境を整備してから、 git push するだけで、PHP7.2のアプリケーションがデプロイできます。 githubのリポジトリが Cloud Source Repositories にミラーされるところなどは変わっていませんでした。

さいごに

この内容は プレPHPカンファレンス北海道 で発表する予定だったのですが、地震の影響でイベントが中止となったため、このブログにまとめました。

どこかで機会があれば、GAEとPHP7.2について発表してみたいなと思います。

web-i2cエレメントをより使いやすくしました。

先日のMaker Faire Tokyo 2018 に CHIRIMENコミュニティで参加しましたweb-i2c-element はどうなの? に記述した改良ポイントを使ったchirimen-pianoをアップしました。

変更したポイント:

変更の概要は以下のとおりです。

  • no-web-i2c スロットを指定すると、非対応メッセージを表示できるようになった
  • WebI2cSensorElement を使って、センサー毎の共通実装をなくし、より簡単にセンサーのカスタムエレメントが実装できるようになった
  • Polymer使ってなくても、タグだけを使ってセンサーの値が取得できるようなサンプルに変更した

では、それぞれの変更を詳しく見ていきましょう。

非対応メッセージの表示

chirimen-pianoのリポジトリにあるindex.htmlファイルを見てましょう。

<web-i2c>
  <grove-touch slave-address="0x5a"></grove-touch>
  <grove-gesture slave-address="0x73"></grove-gesture>
  <div slot="no-web-i2c">
    このデバイスはCHIRIMENではありませんが、ピアノ演奏はお楽しみいただけます。
  </div>
</web-i2c>

web-i2c タグの内側に no-web-i2c というslot名のタグを記述することで、 もしCHIRIMEN以外のデバイス(例えばPCなど)から、このページを表示するとメッセージを表示することができるようになります。 試しに、PCからchirimen-pianoのデモページにアクセスしてみてください。

WebI2cSensorElementを利用したカスタムエレメントの記述

最初のバージョンでは、 PolymerElement を使っていたため共通的な実装が多くなっていたのですが、 いくつかのセンサー実装をしてみて共通化できそうな箇所もわかってきたので、I2C用の親クラスを作ることにしました。

WebI2cSensorElement を使ったセンサーのクラスとして、GROVEタッチとGROVEジェスチャーのカスタムエレメントを作りました。

例としてchirimen-pianoのリポジトリにあるgrove-touch.jsファイルを見てましょう。

class GroveTouch extends WebI2cSensorElement {
  async init() {
    this._autoRead = true;
    await this._i2cSlave.write8(0x2b,0x01);
    await this._i2cSlave.write8(0x2c,0x01);
    await this._i2cSlave.write8(0x2d,0x01);
    await this._i2cSlave.write8(0x2e,0x01);
    await this._i2cSlave.write8(0x2f,0x01);
    await this._i2cSlave.write8(0x30,0x01);
    await this._i2cSlave.write8(0x31,0xff);
    await this._i2cSlave.write8(0x32,0x02);
    for(var i=0;i<12*2;i+=2){
      // console.log(i);
      var address = 0x41+i;
      // console.log(address);
      await this._i2cSlave.write8(address,0x0f);
      await this._i2cSlave.write8(address+1,0x0a);
    }
    await this._i2cSlave.write8(0x5d,0x04);
    await this._i2cSlave.write8(0x5e,0x0c);
  }

  async read() {
    const value = await this._i2cSlave.read16(0x00);
    // console.log(value);
    var array = [];
    for(var cnt = 0; cnt < 12; cnt ++){
      array.push(((value & (1 << cnt)) != 0)?true:false);
    }
    if (!this.value || (JSON.stringify(array) != JSON.stringify(this.value))) {
      this._setValue(array);
    }
  }
}

window.customElements.define('grove-touch', GroveTouch);

まず WebI2cSensorElement を継承したクラスを定義します。 このクラスには2つのオーバライド可能なメソッドがあります。

  • init
  • read

どちらも async メソッドにすることで I2Cスレーブデバイスからの応答を待ち合わせる(await)ことができるようになっています。

WebI2cSensorElement は、 init 呼び出し時にメンバー変数として _i2cSlave が利用可能になっています。 これはWeb I2Cのスレーブオブジェクトで、どんなメソッドが使えるかはWeb I2C API Specification4.6 Reading the value4.8 Writing a value を参照ください。 サンプルコードの slaveDevice_i2cSlave と同じものになります。

init を実装する

init ではI2Cデバイスの初期化コードを記述します。 とくに戻り値は必要ありません。

もしセンサーが読み取り可能なら、 this._autoRead = true; のように設定してください。 これを設定すると、インターバル間隔(デフォルトは100ミリ秒)ごとに read メソッドを呼び出してくれます。

read を実装する

init で _autoReadtrue に設定した場合、インターバル間隔ごとに呼び出されます。 センサーの値を読み取って、値が変わった場合は this._setValue(value) を呼び出してください。 エレメントの value プロパティに値が保持されると同時に、 value-changed イベントが発行されます。

普通のHTMLからセンサーを取り扱う

ふたたびchirimen-pianoのリポジトリにあるindex.htmlファイルを見てましょう。

<script>
  document.querySelector('grove-touch').addEventListener('value-changed', e => {
    document.querySelector('chirimen-piano-app').touchChanged(e.detail.value);
  });
  document.querySelector('grove-gesture').addEventListener('value-changed', e => {
    document.querySelector('chirimen-piano-app').gestureChanged(e.detail.value);
  });
</script>

センサー値の変更を受け取るには、センサーエレメントに対して value-changed イベントのリスナーを設定します。 値はイベントオブジェクトの detail.value に入っていて、センサーによってセットされる値(型も含め)が違います。

たとえば grouve-touch エレメントは、タッチセンサーの数分のBoolean配列がセットされ、 grove-gesture エレメントは、発生したジェスチャー名がセットされます。

さいごに

このようにHTMLからセンサーの値をコントロールできたり、センサーのエレメントを簡単に実装できるようになりました。 今後は、それぞれのエレメントやベースクラスを npm install で取得できるようにしたいと思っています。

また、以前作った WebGpioElementPolymer3 で書き換えていきたいなと思っています。

WebComponents と CHIRIMEN の融合は、私がそれぞれのコミュニティに参加して得られたもののアウトプットです。 もしこれらの活動に興味がありましたら、Polymer Japan CHIRIMEN Open Hardware Polymer.co-edo などの活動に参加ください。

Polymer.co-edo meetup #17 を開催しました

今年8回目となる Polymer.co-edo ミートアップ を開催しました。

今回の議題は

Polymer3 を使って、カスタムエレメントを作ってみよう!

ということで、またまたcodelabsにある、Polymer1系のエレメント作成では定番の Build your first Polymer element ですが、 これをPolymer3用に移植しました!(ついでに日本語化もしたよ!)

codelabsのはじめかた

はじめての Polymer 3 エレメントの作り方を順番に読み進めるだけで大丈夫です。 イベント中でも特にはまりどころはありませんでした。 (スクショが微妙に違うという指摘を受けましたが、これはPolymer1のベースが間違っているという…)

Polymer1や2は触ったことがあるけど、3はまだ、という人にはオススメの教材になっていると思います。

GDG DevFest の codelab にも採用されました

GDG DevFest Tokyo 2018 CodelabsのWEBカテゴリにもリンクされました。 WEBは#20 Your First Progressive Web Appと、はじめての Polymer 3 エレメントの作り方でした。 WEB自体、トライしてくれる人は少なかったのですが、当日は何名かの方にPolymerを試してもらえて良かったです(Polymer Japanステッカーを差し上げました!)。

次回は

9月にも開催を予定していたのですが、日程が調整できず、10月に予定どおり開催できる見込みです。 Doorkeeperのコミュニティページに今年の予定も書いてあるので参考にしてください。

前回も書きましたが、そろそろ、edoエレメントの開発をしないとなー、なんて思っています…

Maker Faire Tokyo 2018 に CHIRIMENコミュニティで参加しました

MFTokyo(昨年まではMFTと省略していましたが、今年からこのように変更となりました)のデモ準備として、 先日 CHIRIMEN Raspi setupという記事を書きましたが、これはその結果報告です。

デモ準備

実際にソースを書いて、動かしてみると 開封したばかりのGroveタッチセンサーが4つのうち1つだけ反応しません 。 ハブ側の裏にあるハンダ部分を触って通電させるとタッチ状態になるので、静電側が異常だということを認識し、 処理不良だから書い直せば大丈夫…と思い、前日の金曜日に秋葉原へ向かいしました。

実は8/3は半透明なブギーボード BB-11 の発売日で、翌日にMFTokyoへ持って行くなら量販店で買うしかない!と思いアキヨドにも行くつもりだったのです。 参考:13.8インチで半透明、ブギーボード新モデルが8月3日発売

何を作ったか

chirimen-piano という、ピアノアプリを作りました。

このアプリの特徴は以下のとおりです。

  • Polymer3で作られていて、以下のCustomElementsの実装評価を兼ねていた
    • web-i2c タグ
    • grove-gesture タグ
    • grove-touch タグ
  • CHIRIMENでなくても動作するWebアプリである
  • 4鍵(タッチセンサーの4つが対応)しかないが、左右に手を振ることでジェスチャーセンサーが反応し、音階が移動する。CHIRIMENでない場合は左右ボタンで移動

ちなみに昨年は Echigo という B2G OS ベースのボードで web-gpio エレメントを検証するために polymerchirimen というサンプルを作っていました。 これは人感センサーに反応すると、LEDが点灯するというものでした。

先日購入したものに追加して、以下の部品が必要になります。

完成画像は以下のとおりです。

苦労したこと

CHIRIMENでなくても動作するWebアプリ を目指して作り始めたら、Raspberry Pi版のpolyfillにいくつか問題があることがわかって、それを修正しながら進めたのでギリギリまで時間がかかりました。 こちら、まだchirimen-pianoにしか入っていませんが、近いうちに公式版へPRを送る予定です。

あとはセンサーの初期不良は、まぁあるものと思っていた方が良いですね。 最近あんまりハズレを引かなかったので忘れていました。

web-i2c-element はどうなの?

現時点はまだデモプログラム内での評価用ですが、今回思ったよりもうまく動作しそうなので、こちらもちゃんとエレメントとして分割したいです。 いくつか改善したいポイントがあります。

no-web-i2c 対応

まず CHIRIMEN 以外で動作させていたとき、 noscript タグみたいにして書けるようにする予定です。

現在は web-i2c.js にベタ打ちになっていますが

<div class="message">
  このデバイスはCHIRIMENではありませんが、ピアノ演奏はお楽しみいただけます。
</div>

これを利用側から指定できるようにしたいと思います。

<web-i2c>
  <div slot="no-web-i2c">
    このデバイスはCHIRIMENではありませんが、ピアノ演奏はお楽しみいただけます。
  </div>
</web-i2c>

WebI2cSensorElement 対応

センサーのタグは PolymerElement を継承して作るようにしていますが、これを WebI2cSensorElement のように親クラスを作って、センサータグ実装を楽にしたいと思っています。

現在のgrove-touchエレメントのソースコード を、以下のように書けるようにしたいと思っています。

class GroveTouch extends WebI2cSensorElement {
  async init(i2cSlave) {
    await i2cSlave.write8(0x2b,0x01);
    await i2cSlave.write8(0x2c,0x01);
    await i2cSlave.write8(0x2d,0x01);
    await i2cSlave.write8(0x2e,0x01);
    await i2cSlave.write8(0x2f,0x01);
    await i2cSlave.write8(0x30,0x01);
    await i2cSlave.write8(0x31,0xff);
    await i2cSlave.write8(0x32,0x02);
    for(var i=0;i<12*2;i+=2){
      var address = 0x41+i;
      await i2cSlave.write8(address,0x0f);
      await i2cSlave.write8(address+1,0x0a);
    }
    await i2cSlave.write8(0x5d,0x04);
    await i2cSlave.write8(0x5e,0x0c);
  }

  read(i2cSlave) {
    i2cSlave.read16(0x00).then((v)=>{
      var array = [];
      for(var cnt = 0;cnt < 12;cnt ++){
        array.push(((v & (1 << cnt)) != 0)?true:false);
      }
      if (!this.value || (JSON.stringify(array) != JSON.stringify(this.value))) {
        this.set('value', array);
      }
    })
  }

  defaultInterval() {
    return 1000;
  }
}
window.customElements.define('grove-touch', GroveTouch);

共通化のポイントは以下のような感じです。

  • 値のプロパティを value で共通化
  • エレメントのプロパティをWebI2cSensorElementで定義
  • ポートのオープンや、web-i2cエレメントとやりとりしてポートを設定するところなどをWebI2cSensorElementで定義
  • 値読み込みのインターバル制御をWebI2cSensorElementに移譲

2つのI2Cセンサータグを作ってみて、このぐらいは共通化しても大丈夫そうだし、便利そうだなと思っています。

on-change 対応

現時点はアプリもPolymerで書いているので、値の変更はデータバインディングでできているのですが、最終的にはタグから change イベントを飛ばすようにする予定です。

つまり利用者はPolymerを使わなくても、以下のようなHTMLコードを追加するだけで利用可能になることを想定しています。

<html lang="en">
  <head>
    <script src="node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
    <script src="node_modules/@chirimen/polyfill/polyfill.js"></script>
    <script type="module" src="node_modules/@chirimen/web-i2c/web-i2c.js"></script>
    <script type="module" src="node_modules/@chirimen/grove-touch/grove-touch.js"></script>
    <script type="module" src="node_modules/@chirimen/grove-gesture/grove-gesture.js"></script>
  </head>
  <body>
    何かしらのアプリ


    <web-i2c>
      <div slot="no-web-i2c">
        このデバイスはCHIRIMENではありませんが、xxxxx。
      </div>
      <grove-touch slave-address="0x5a"></grove-touch>
      <grove-gesture slave-address="0x73"></grove-gesture>
    </web-i2c>

    <script>
      window.addEventListener('WebComponentsReady', e => {
        document.querySelector('grove-touch').addEventListener('change', e => {
          // 値が変わったときの処理
        });
      });
    </script>
  </body>
</html>

さいごに

WebComponentsを作るためのPolymerについては、 PolymerJapan コミュニティで活動しています。 毎月の集まりを Polymer.co-edoでも開催しているので、参加を待っています。

またCHIRIMENで、ブラウザからセンサーを動かしたいというような活動に興味があれば、コミュニティに参加ください。

どちらもユーザー主導で活動していますので、みなさまの参加をお待ちしております。

PHPカンファレンス関西2018に参加してGAEに継続的デプロイする方法について発表してきました

2018/7/14 に行われたPHPカンファレンス関西2018に参加してきました。

今年も参加

昨年と同じくGRAND FRONT OSAKAで開催されました。

夜はスピーカーとスタッフの前夜祭から、コミュニティ前夜祭と合流しての2次会へと流れ、タクシーでホテルに戻りました。その後、3次会、4次会があったとかないとか…(これ毎年のコピペですwww)

PHPカンファレンス関西2018

PHPカンファレンス関西は3トラック+スポンサーブースです。朝一番の講演に参加者が多いのも特徴ですね。 今年はあまりセッションは聞かずに参加者と話したり、アンカンファレンスでPHPの非同期処理について話を聞いていたりしました。

私の発表はGAEへの継続的デプロイだったのですが、なんとタイムテーブルを見ると、私の前に

  • Amazonの中の人が PHPアプリケーションのコンテナ化入門 というタイトルで CI/CD の話をするらしい
  • Herokuの中の人が HerokuでPHPアプリ開発速度を倍にする というタイトルで 継続的デリバリー機能 の話をするらしい

ということでネタ丸かぶり?とか、私だけ中の人じゃないよ!とか心配になったので、この2つのセッションはしっかり前の席で聞きました。

GAEにPHPアプリを継続的デプロイする方法について発表しました

昨年に引き続きPHPネタですが、主にはDockerとGoogle Cloud Container Builderの話でした。

GAEを使っていて当然コードがPUSHされたらデプロイしたくなるのですが、何が良いのかよくわからない時期があって、調べて試した結果を発表するに至りました。 調べた過程で、まぁどんなツールを使っていても gcloud コマンドさえ動けば、あとはGAEと接続するための認証情報をそのCI/CDツールに最適な方法で管理するだけで、どんなものでも良いということがわかりました。 ただ、Cloud Container Builder使うとプライベートな空間を使えるわりには結構安いし、良いのではないかと思ったわけです。

デプロイのデモもギリギリ間に合って、ほっとしました。リポジトリの README に詳しい説明が書いてあるので、そちらを見ながらコードを動かしてみてください。

PHPカンファレンス関西2018デモプログラム

今回の発表をするのに30分でできる(当社比) Google Cloud Container Builderを利用した AppEngine SE環境への自動デプロイという記事が大変参考になったのですが、 GCPのコンソール(画面)から操作するのは、環境の再現性がなくて嫌だなーと思ったので、 gcloud コマンドを駆使して自動構築できるようにしました。 これは今回、かなり頑張ったところです。そしてデモ環境を何度も壊して作り直すことができたので、リハーサルも捗りました。

大阪を堪能

最終日は恒例の ねぎ焼き やまもと へ。 今年はPHPerを4人(昨年は3人)引き連れ、梅田エスト店にやってきました。 そのあと有志で明石焼き/たこ焼きを食べに行って、聖地タイガースショップで買い物をして帰京しました。

さいごに

また来年も参加/発表したいので、1年の努力を惜しまずに…