GAEのスタンダード環境にLaravel5.7をデプロイする

f:id:takuyafujita:20190407064943j:plain

はじめに

GAEのスタンダード環境にLaravel5.7をデプロイしたので、その手順を書いています。基本的に公式ドキュメントを参考に実施しましたがLaravel5.7だと同じように設定できない箇所がありましたので、一部公式と手順が異なります。

公式ドキュメント

cloud.google.com

Laravelプロジェクト作成

Homestead:7.20.0
php:7.2
Laravel Framework:5.7.28

LaravelのプロジェクトはHomesteadを使用して作成しています。また、スタンダード環境で動作させるためにphp7.2を指定しています。同じようにHomesteadでプロジェクトを作成する場合は下記の記事を参考にしてください。php7.2を指定する方法も書いてあります。

takuyafujita.hatenablog.com

GAEデプロイ用のapp.yamlを作成

以下の内容でapp.yamlを作成します。app.yamlはLaravelプロジェクトの直下に格納します。

runtime: php72

env_variables:
  ## Put production environment variables here.
  APP_KEY: YOUR_APP_KEY
  APP_STORAGE: /tmp
  VIEW_COMPILED_PATH: /tmp

APP_KEYを設定

app.yamlのYOUR_APP_KEYを、次のコマンドで生成したアプリケーションキーに置き換えます。

php artisan key:generate --show

LinuxmacOSを使用している場合は、次のコマンドで自動的にapp.yamlが更新できます。

sed -i '' "s#YOUR_APP_KEY#$(php artisan key:generate --show --no-ansi)#" app.yaml

APP_STORAGEを設定

キャッシュを書き込むためのパスをapp.yamlのAPP_STORAGEに設定した「/tmp」に変更します。

bootstrap > app.php を変更

return文の前に以下の内容を追記します。

# [START] Add the following block to `bootstrap/app.php`
/*
|--------------------------------------------------------------------------
| Set Storage Path
|--------------------------------------------------------------------------
|
| This script allows you to override the default storage location used by
| the  application.  You may set the APP_STORAGE environment variable
| in your .env file,  if not set the default location will be used
|
*/
$app->useStoragePath(env('APP_STORAGE', base_path() . '/storage'));
# [END]

config > view.php を変更

Compiled View Pathを以下の様に変更します。

/*
|--------------------------------------------------------------------------
| Compiled View Path
|--------------------------------------------------------------------------
|
| This option determines where all the compiled Blade templates will be
| stored for your application. Typically, this is within the storage
| directory. However, as usual, you are free to change this value.
|
*/

// 削除
// 'compiled' => env(
//     'VIEW_COMPILED_PATH',
//     realpath(storage_path('framework/views'))
// ),

// 追加
'compiled' => storage_path(),

laravel-dump-serverを削除

現状、GAEでlaravel-dump-serverを使用すると下記のエラーになります。

Class 'BeyondCode\DumpServer\DumpServerServiceProvider' not found

Laravel5.7.6以降を使用する場合、composer.jsonからbeyondcode/laravel-dump-serverを削除することで回避できます。未確認ですが、laravel-dump-serverはLaravel5.7.6以降で追加されていますので、5.7.5以下のバージョンを使用しているのであれば対応不要かもしれません。

削除前

    "require-dev": {
        "beyondcode/laravel-dump-server": "^1.0",
        "filp/whoops": "^2.0",
        "fzaninotto/faker": "^1.4",
        "mockery/mockery": "^1.0",
        "nunomaduro/collision": "^2.0",
        "phpunit/phpunit": "^7.5"
    },

削除後

    "require-dev": {
        "filp/whoops": "^2.0",
        "fzaninotto/faker": "^1.4",
        "mockery/mockery": "^1.0",
        "nunomaduro/collision": "^2.0",
        "phpunit/phpunit": "^7.5"
    },

削除後はcomposerの更新を忘れずに!

composer update

この問題は下記のissuesが参考になりました。英語だと読むのに苦労しますが情報が多いので助かります!

github.com

GAEにデプロイする

gcloud config set project sample

gcloud app deploy

gcloud app browse

GAEにデプロイした事が無い方は以下の記事に詳細を書いていますので参考にしてください。

takuyafujita.hatenablog.com

デプロイできたか確認

ブラウザが立ち上がり、Laravelがデプロイできました!

f:id:takuyafujita:20190407163027j:plain

まとめ

最初はLaravel5.8で試していたのですが、GAEにデプロイすると様々なエラーが出て時間だけが過ぎてしまっていました。ググってみると5.7でデプロイされている方がいたので5.7で試すとあっさりデプロイできました。何だったんだ今までの苦労は・・・。これも経験ですね。苦労した分、Laravelの画面が表示された時は嬉しかったです。

【Homestead】Laravelの開発環境作成とPHPのバージョンを変更する方法

GAEのスタンダード環境にLaravelをデプロイしようと思いプロジェクトを作成しましたが、調べてみるとPHP7.2で作成する必要がありました。

cloud.google.com

Laravelの開発環境はHomesteadを使用しており、現時点(2019/03/29)で最新バージョンを使用するとPHP7.3がデフォルトになります。HomesteadではPHPのバージョンを指定することができますので、今回はLaravelの開発環境であるHomesteadのインストール方法とHomesteadでPHPのバージョンを変更する方法を記載します。

なお、作業環境は windows 10 です。

Laravelの開発環境(Homestead)を作成

Homesteadを使うには、Git、VirtualBoxVagrantが必要になります。使い方はネットで検索すると多数出てきますので割愛しますが、参考までに私はこの記事を参考にしてインストールしました。Laravelのチュートリアルもあります!

www.hypertextcandy.com

Homesteadのbox追加

vagrant box add laravel/homestead

※ネットワークの環境にもよりますが時間がかかります。

途中、どの仮想環境を使用するか聞いてきます。私は'3'のvirtualboxを指定しました。

1) hyperv
2) parallels
3) virtualbox
4) vmware_desktop

Homesteadのインストール

git clone https://github.com/laravel/homestead.git Homestead
cd Homestead
git checkout v8.2.0
./init.bat

PHP7.2を使用する設定

インストールしたHomesteadの最新バージョンではPHPのデフォルトが7.3になりますが、ymlの設定でPHPのバージョンを変更することができます。(7.1、7.2、7.3の何れか)

今回は7.2に変更してみます。

Homestead.yml の設定変更

Homesteadフォルダ内にある「Homestead.yml」の sites: に php: "7.2" を追記します。
ついでに to: の設定もこの次に行うlaravelプロジェクトの作成に合わせて、下記のように変更しておきます。

sites:
    - map: homestead.test
      to: /home/vagrant/code/sample/public
      php: "7.2"

仮想環境を起動する

vagrant up

仮想環境に接続する

vagrant ssh

laravelのプロジェクト作成

codeフォルダを作成し、その配下にlaravelプロジェクト(sample)を作成します。

mkdir code
cd code/
composer create-project laravel/laravel sample

index.php ファイルを作成

PHPのバージョンはphpinfoを表示して確認します。phpinfoを表示する index.php を作成し、以下に格納します。

/home/vagrant/code/sample/public

index.php の内容は以下の通りです。

<?php
echo phpinfo();
?>

Hostsファイルの設定

Hostsファイル(C:\Windows\System32\drivers\etc\hosts)に以下の内容を追加します。

192.168.10.10  homestead.test

PHPのバージョン確認

chromeで以下に接続し、PHPのバージョンが7.2になっていれば変更完了です。

http://homestead.test/

f:id:takuyafujita:20190329234006j:plain

まとめ

最初はコマンド(php -v)でバージョン確認をしており、何故か7.3としか表示されず悩んでいましたがphpinfoで確認したら正しく変更されていました!これも経験ですね。ちなみにsampleプロジェクトをGAEのスタンダード環境にデプロイしてみましたが、色々とエラーになりました。次はGAEでLaravelを動かすのが目標です。

【GCP】GAEにPHPのプロジェクトをデプロイする

はじめに

この記事はGAEにWEBアプリのプロジェクトをデプロイする方法を書いていますが、結果的に「HelloWorld」を表示するだけの「index.php」のみデプロイすることになりました。なので、同じことをやっているGAEのチュートリアルの方が断然分かりやすいです。

それでも読みたいという方はどうぞ読んでください。

Google Cloud Platform 登録

GAE(Google App Engine)を使うにはGCPGoogle Cloud Platform)に登録する必要があります。

以前、GCPの無料トライアル登録手順を書きましたのでこちらを参考にしてください。

takuyafujita.hatenablog.com

プロジェクト作成

GCPのコンソール画面からプロジェクトを作成します。

Google App Engine 設定

GCPのコンソール画面から App Engine を選択します。言語は「PHP」、リージョンは「asia-northeast1」で設定しました。

Google Cloud SDK インストール

GAEにデプロイする為にSDKが必要です。開発環境がwindowsなので、下記サイトからインストーラーをダウンロードしてインストールしました。次に行うSDKの初期化についても書いてあります。

cloud.google.com

Google Cloud SDK 初期化

下記コマンドでSDKの初期化を行います。

gcloud init

PHPプロジェクト作成

本当はHomesteadで作成したLaravelのプロジェクトをデプロイする予定でしたが、デプロイ後にエラーが出たので今回は「HelloWorld」を表示するだけのシンプルな「index.php」を作成しました。

app.yaml 作成

GAEにデプロイする為にプロジェクトの設定を記載した「app.yaml」が必要です。今回は公式ドキュメントに記載されている内容そのままで作成しました。「app.yaml」はプロジェクトのルートディレクトリに配置します。

cloud.google.com

デプロイ

デプロイしたいプロジェクト配下で下記コマンドを実行します。

gcloud app deploy

デプロイしたプロジェクトをブラウザで表示

下記コマンドでブラウザが開き、「HelloWorld」が表示されればデプロイ成功です。

gcloud app browse

まとめ

GAEへのデプロイ方法は簡単ですが、GAEの設定(スタンダードとかフレキシブルって何が違うの?)や「app.yaml」の設定内容を理解するのに時間がかかりました。
また、Laravelのデプロイでエラーになった原因は、PHPのバージョンが原因かもしれません。GAEでサポートしていない7.3を使用していた。
「app.yaml」の設定もちゃんと理解できていないので勉強しつつ再度チャレンジしてみます。

Vue.jsのインストール

Node.jsとnpmのバージョン

node -v
v10.8.0
npm -v
4.0.5

VueCLIのインストール

npm install -g @vue/cli

プロジェクトの作成

vue create sample

サンプルの実行

cd sample
npm run serve

サンプルを表示

http://localhost:8080/

f:id:takuyafujita:20190207220757j:plain

【GCP】無料トライアル登録手順

Google Map のAPIを使用して地図を表示していますが、特定の環境下で「Googleマップが正しく読み込まれませんでした」となります。

ググってみると請求先アカウントが登録されていない場合に表示される(ことがある?)とありましたので早速登録してみます。

今回はGCPの無料トライアル登録で請求先アカウントも登録する手順を紹介します。

Google Cloud Platform の無料トライアル登録手順

右上の有効化ボタンをクリック

f:id:takuyafujita:20190116232312p:plain

国を選択、利用規約に同意して実行

f:id:takuyafujita:20190116232358p:plain

アカウントの種類、名前と住所を入力

f:id:takuyafujita:20190116232410p:plain

メインの連絡先、クレジットカード情報を入力して無料トライアルを開始

f:id:takuyafujita:20190116232424p:plain

完了

f:id:takuyafujita:20190116232434p:plain

以上です!

Truffleを使ってERC20の独自トークンを発行する

こんにちは。休みの日はDapps開発をしている 藤田拓弥 です。

今回はERC20の独自トークン作成からローカル環境にデプロイまでを行います。
Truffle(Ethereumのスマートコントラクト開発フレームワーク)を使うので、何それ?という方は下記の記事を参考にして環境構築をお願いします。

takuyafujita.hatenablog.com

それでは早速作っていきましょう。

Truffleでプロジェクトを作成する

今回は自分の名前(takuya)でトークンを発行しますので「takuya_token」という名前のディレクトリを作成します。

mkdir takuya_token

作成したディレクトリに移動します。

cd takuya_token

Truffleを初期化してプロジェクトに必要なファイル一式を作成します。

truffle init

OpenZepplinをインストールする

続いて独自トークンとなるコントラクトを作成しますが、その前にOpenZepplinをインストールします。
OpenZepplinはEthereum上で安全なコントラクトを実装するためのフレームワークです。
その中にERC20も含まれており、トークンに必要な機能が一通り揃っています。

まずは「package.json」を作成します。

npm init -f

続いてOpenZeppelinをインストールします。

npm install zeppelin-solidity

インストールすると以下の警告が出ました。

This package has been renamed to openzeppelin-solidity. Please update your dependency, or you will no longer receive updates.

OpenZeppelinのバージョンが上がり、パッケージ名が変わっているようです。

新:openzeppelin-solidity
旧:zeppelin-solidity

今回は旧の方を使用します。

コントラクトを実装する

プロジェクト(takuya_token)配下の「contracts」ファルダ内に、「TakuyaToken.sol」という名前でファイルを新規作成します。

「TakuyaToken.sol」の内容は下記の通りです。


マイグレーションファイルを作成する

デプロイを行うので、マイグレーションファイルを作成します。

プロジェクト(takuya_token)配下の「migrations」ファルダ内に、「2_deploy_takuya_token.js」という名前でファイルを新規作成します。

「2_deploy_takuya_token.js」の内容は下記の通りです。


テストコードを作成する

プロジェクト(takuya_token)配下の「test」ファルダ内に、「TestTakuyaToken.js」という名前でファイルを新規作成します。

「TestTakuyaToken.js」の内容は下記の通りです。


テストを実施する

今回はローカル環境を使用するので、以下のコマンドでEthereumブロックチェーンエミュレータを起動します。

truffle develop

truffle consoleに入りますので、そのままテストを実行します。

truffle(develop)> test

テスト結果が表示されます。想定通りの結果になればデプロイに進みます。

Compiling .\contracts\Migrations.sol...
Compiling .\contracts\TakuyaToken.sol...
Compiling zeppelin-solidity/contracts/token/ERC20/StandardToken.sol...
Compiling zeppelin-solidity\contracts\math\SafeMath.sol...
Compiling zeppelin-solidity\contracts\token\ERC20\BasicToken.sol...
Compiling zeppelin-solidity\contracts\token\ERC20\ERC20.sol...
Compiling zeppelin-solidity\contracts\token\ERC20\ERC20Basic.sol...

  Contract: TakuyaToken
    √ should put 1000 TAKUYA in the first account

  1 passing (65ms)

デプロイする

以下のコマンドでローカル環境にデプロイを行います。

truffle(develop)> migrate

デプロイされた内容を確認する

以下のコマンドでデプロイしたTakuyaTokenのオブジェクトを変数(TakuyaToken)に格納します。

truffle(develop)> TakuyaToken = TakuyaToken.at(TakuyaToken.address)

コントラクトを作成する際に設定した情報を確認します。

トークンの名称

truffle(develop)> TakuyaToken.name()
'TAKUYA'

トークンの単位

truffle(develop)> TakuyaToken.symbol()
'TAKUYA'

トークンの総発行量

truffle(develop)> TakuyaToken.totalSupply()
BigNumber { s: 1, e: 21, c: [ 10000000 ] }

独自トークンを送金する

1つ目のアカウントはトークンの発行者なので作成した全てのトークンが入っていることを確認します。

truffle(develop)> TakuyaToken.balanceOf(web3.eth.accounts[0])
BigNumber { s: 1, e: 21, c: [ 10000000 ] }

2つ目のアカウントはトークンの残高が0であることを確認します。

truffle(develop)> TakuyaToken.balanceOf(web3.eth.accounts[1])
BigNumber { s: 1, e: 0, c: [ 0 ] }

1つ目のアカウントから2つ目のアカウントに 100 TAKUYA を送金します。

truffle(develop)> TakuyaToken.transfer(web3.eth.accounts[1], 100)

2つ目のアカウントの残高が100であることを確認します。

truffle(develop)> TakuyaToken.balanceOf(web3.eth.accounts[1])
BigNumber { s: 1, e: 2, c: [ 100 ] }

これで独自トークンを発行し、送金できることが確認できました!

本当はRopstenにデプロイしたかったのですがエラーが出て解決に時間がかかりそうだったので断念しました。

次はRopstenへのデプロイに挑戦しようかな。

【CryptoZombiesを触ってみた】Lesson6で学んだこと

【CryptoZombiesとは】

Solidityでスマートコントラクトの構築を学習できるサイトです。日本語で丁寧に説明してくれるので、プログラミング未経験の人でも学習できます。

cryptozombies.io

【はじめに】

Solidityは未経験ですが、JavaScriptは触ったことがあります。そんな人が自分用の学習メモとして書いています。

【学んだこと】

Web3.js

イーサリアムのノードにアクセスできるJavaScriptライブラリです。フロントエンド(Webページ)からスマートコントラクトの関数を呼び出す場合に使用します。

まずは、Web3.jsをダウンロードして、htmlのheadタグ内にscriptタグを追加します。

<script language="javascript" type="text/javascript" src="web3.min.js"></script>

Web3プロバイダとMetamask

続いて、Web3プロバイダの設定(どのノードを使用すれば良いか教えてくれる)が必要になります。また、ブロックチェーンに書き込みを行う場合は秘密鍵を使って署名するので、秘密鍵の安全な管理も必要になります。これら全てを自前で実装することも可能ですが、今はMetamaskを使用するのがデファクトスタンダードになっています。MetamaskがインストールされていればMetamaskで使用しているWeb3プロバイダをそのまま使用することができ、イーサリアムのアカウントと秘密鍵も安全に管理してくれます。
Metamaskのインストール方法や使い方は他の方々がブログで紹介しているので、そちらを参考にしてください。

window.addEventListener('load', function() {
  // MetamaskがJavaScriptのグローバルオブジェクト web3 にWeb3プロバイダを設定するので
  // web3が設定されているかを確認すればMetamaskのインストール状況を判断できます。
  if (typeof web3 !== 'undefined') {
    // Web3が設定されていればMetamaskで使用しているWeb3プロバイダを設定
    web3js = new Web3(web3.currentProvider);
  } else {
    // web3が設定されていなければMetamaskをインストールするメッセージを表示
  }
  // 処理開始
  startApp()
})

コントラクトアドレスとABI

Web3.jsを使用してスマートコントラクトにアクセスするには
・スマートコントラクトをデプロイする際に付与されるコントラクトアドレス
・スマートコントラクトをコンパイルする際に作成されるABI(Application Binary Interface)
 ※ABIは関数の定義(関数名や引数など)がJSON形式で記載されています。
が必要になります。

var myContract;
function startApp() {
  // デプロイする際に付与されたコントラクトアドレス
  var myContractAddress = "YOUR_CONTRACT_ADDRESS";
  // コンパイルする際に作成されたABI
  var myContractABI = "YOUR_CONTRACT_ABI";
  // コントラクトアドレスとABIを使用してコントラクトを初期化
  myContract = new web3js.eth.Contract(myContractABI, myContractAddress);
}

call

Web3.jsを使用してスマートコントラクトのview関数、pure関数を呼び出します。読み取り専用なのでブロックチェーンへのトランザクションは発生しません。

myContract.methods.myMethod(argument1, argument2, argument3).call()

send

Web3.jsを使用してスマートコントラクトのview関数、pure関数以外の関数を呼び出します。ブロックチェーンのデータを更新するのでトランザクションが発生します。当然、ガス(Gas)の支払いや署名が必要になりますが、Metamaskがインストールされていれば全てMetamaskが行ってくれます。

myContract.methods.myMethod(argument1, argument2, argument3).send()

アカウント取得

Web3プロバイダを設定したグローバルオブジェクト web3 からユーザーのアカウントを取得することができます。Metamaskを使用している場合、Metamaskでアクティブになっているユーザーのアカウントを取得します。

var userAccount = web3.eth.accounts[0]

ユーザーのアカウントが変更されているかチェックしたい場合は、setInterval(JavaScriptのループ関数)を使います。

var accountInterval = setInterval(function() {
  // アカウントが変更されているかチェック
  if (web3.eth.accounts[0] !== userAccount) {
    userAccount = web3.eth.accounts[0];
    // 変更後のアカウントで行いたい処理
  }
}, 100);

トランザクションの送信

トランザクションが大量に保留されていたり、設定したガス代が安すぎると数ブロック待つ必要があるため、非同期処理で記述する必要があります。

function createRandomZombie(name) {
  // しばらく時間がかかるので、ユーザーにトランザクションが送信されたことを知らせる
  $("#txStatus").text("Creating new zombie on the blockchain. This may take a while...");
  // トランザクションをコントラクトに送信する
  return cryptoZombies.methods.createRandomZombie(name)
  .send({ from: userAccount })
  // トランザクションがブロックに含まれるとreceiptが発行される
  .on("receipt", function(receipt) {
    // トランザクションがブロックチェーンに取り込まれたことを知らせる
    $("#txStatus").text("Successfully created " + name + "!");
    getZombiesByOwner(userAccount).then(displayZombies);
  })
  .on("error", function(error) {
    // トランザクションが失敗したことをユーザーに知らせる
    $("#txStatus").text(error);
  });
}

Wei

イーサ(イーサリアムの通貨)の最小単位
1 wei = 0.000000000000000001 ether

// payable関数を呼び出す際、etherではなくweiで指定する必要があるので
// toWeiを使用してetherをweiに変換する
cryptoZombies.methods.levelUp(zombieId)
.send({ from: userAccount, value: web3js.utils.toWei("0.001", "ether") })

eventをトリガーにする

Web3.jsではスマートコントラクトのイベントをトリガーにすることができます。

// スマートコントラクト側(Solidity)
// eventを設定
event NewZombie(uint zombieId, string name, uint dna);

// フロントエンド側(javascript)
// eventをトリガーとして処理を行います。
cryptoZombies.events.NewZombie()
.on("data", function(event) {
  let zombie = event.returnValues;
  console.log("A new zombie was born!", zombie.zombieId, zombie.name, zombie.dna);
}).on("error", console.error);

indexedを使用すればイベントのフィルタリングができます。

// スマートコントラクト側(Solidity)
// indexedで引数を設定しておきます
event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);

// フロントエンド側(javascript)
// '_to'が'userAccount'と同じ場合のみ処理が行われます。
cryptoZombies.events.Transfer({ filter: { _to: userAccount } })
.on("data", function(event) {
  let data = event.returnValues;
}).on("error", console.error);

【できたもの】

今回のLessonはフロントエンド(javascript)がメインだったので比較的分かりやすかったです。Metamaskのお面カワイイ!
f:id:takuyafujita:20181014194805j:plain

現在はLesson6で終了ですが、もうすぐseason2が登場しそうなので楽しみです!