こんにちはじゅんです。会社で試験的に作成したLaravelアプリケーションをHerokuにデプロイする機会があり、いくらかハマりポイントなどがあったのでメモがてら残そうと思います。どんなLaravel アプリなのかなど、ある程度具体的な要件の定義から書くので、
「さっさとデプロイの説明しろや!」という人は目次から 「Herokuへのデプロイ作業を開始」 をクリックして飛んでください。
会社でRestfulなWebAPIとそのコンテンツを提供するサービスを開発しようという動きがあり、Laravelやvue、webAPIは少しわかる私に試験的な開発をまかされLaravelで作りました。
最近、巷で有名な 「Headless CMS」と似たような動きをします。 細かい要件は書くことはできないですが、 LaravelでAPIサーバー兼コンテンツ管理画面を作成して置きます。 お客さんはアプリケーションにログインしてコンテンツの編集などを行えます。そしてフロントエンドは別のサーバーに配置するか、既存のアプリを使用します。
Ajaxなどを通して認証付きAPIをLaravelが置いてあるサーバーに投げれば、 データ(掲載コンテンツの内容)をJSON・XMLで手に入れることができます。 欲しい情報は適宜、非同期でAPIで呼び出して取得するという形式を取っています。モダンなやり方ですね。
APIサーバーを構築するフレームワークは他にもありますが以下のような理由により、Laravelを選びました。
決められたお客さんのコンテンツ(サーバー)からのAPIアクセスを許可する。 お試しユーザー、プレミアムユーザーと言ったユーザーロールごとに使用できるAPIの制限が簡単。 と言ったことも可能です。「やっぱりLaravelはフルスタックフレームワークだけあるな」と思えるほどの物です。とにかく上記のようなLaravel アプリを今回はHerokuにデプロイします。
作成したLaravelアプリについての説明・構築は今回の記事ではしません。Herokuへのデプロイがメインになります。
今回のプロジェクト自体がまだ試験的であることも理由の一つですが、単にVPSとかで構築するのが面倒だったからです。 各種ミドルウェア やソフトが最新版の物であっても、マニュアルがあってもセキュリティや権限の設定とかを考えて構築すると日が暮れます。
Herokuの理念が
とあるようにインフラの構築や管理は面倒です。そのため予めインフラがすぐに作られ、しかしある程度カスタマイズが可能なサービスを利用すると開発者としてはアプリ(今回でいうLaravelアプリ)の開発に注力できます。
またVPSでも可能だと思いますが、GitHubとかと連携して本番環境・開発環境を構築できるのも魅力の一つです。まだ試験的な段階なので、AWSやVPSほどの自由度は今回のアプリではいらないかな?と思いHerokuにしました。
下図のような感じです。バージョン管理などはGitHubを用いています。適宜、リモートリポジトリにpushしたらその変更が自動でHerokuのアプリ(個々のサーバーみたいなものだと思ってください。)に反映されます。
プルリクエストを送ると、 そのリクエストに応じたアプリが自動的に構築されるように設定もできます。 Stagingで最終確認をしてOKであれば公開環境にデプロイさせます。
そのため今回の記事では以下のような流れで構築してます。
当たり前ですがHerokuでのアカウントを作成します。これがないと何も始まりません。 https://jp.heroku.com/にアクセスして「新規登録」に進みます。
名前やアドレスなど適宜入力します。アカウントを作成する段階では日本語でも大丈夫です。選択するプランですがとりあえず無料の物にしておきましょう。
https://jp.heroku.com/pricing にてプランの内容や価格を知ることができます。完全フリーの場合はSSL(httpsにするやつ)の設定が行えない、最低限のスペックしかないなど本当に試験的にサーバー上にアップする程度に使用します。
商用で運用する場合は有料のStandardなどにアップグレードしましょう。ここでは開発サーバーをフリー版、本番環境をhobbyにしておきます。
今回デプロイするLaravelのソース達を入れる、Herokuアプリを作成します。 Herokuアプリというのは簡単にいうとサーバーそのものだと思ってください。 Herokuアプリに、使用するソフトやドキュメントルートの設定、環境変数の設定、連携するGithubのレポジトリなどの設定を行うことで、Laravelが正常に動いてアプリケーションサーバー(サービスを提供するサーバー)として機能するようになります。
ここでは実務の開発体制をとるのでpipelineを構築します。
pipe linesというのは「開発、レビュー、ステージング、本番」など複数の段階に分けてアプリを動かすことができるHerokuアプリのグループのことをいいます。 もう少し簡単にいうと、
修正した物開発中のものをテストする「開発サーバー」、お客さんが触り実際にサービスが提供される「本番サーバー」を同時に構築して管理しやすくしたアプリ達です。今回は開発用・確認用、本番の2つの構成にします。
アカウントを作ると個人のダッシュボード画面に移動します。そこの「New」をクリックし、[Create New pipeline」を選択します。
pipelineを作成すると、pipelineの名前と連携するリポジトリを選ぶことができます。ここではまだ連携しないので、名前だけ入力して「create pipeline」で作成。すると二つのアプリを加えることができるpipelineが作成されました。
そしてたらアプリの構築をしていきます。二つ作るのは少し面倒ですが仕方ないです。では 開発の方(staging) から作成していきます。「Add app」をクリックすると、既存のアプリを追加するか、新しく作るかを聞いてきます。ここでは「create new app」を選択。すると右側にアプリの基本情報を入力する欄が出てきます。
そしたらアプリの名前とリージョンを選択して「create app」します。フリープランの場合はアメリカかヨーロッパリージョンしか選べませんが、特に問題ないです。(その地域に隕石が落るとかしてサーバーが物理的にやられない限り)
アプリ名を英語で入力して「create」をクリックして作成されます。名前はとりあえず「staging-app-laravel」としておきます。
開発用アプリの設定が可能になったのでダッシュボードから、アプリ名をクリックして移動します。すると下のようなアプリに関する設定ができる画面に移ります。設定画面でできることは後で使用するheroku CLIでも行うことができます。今回はGUIの方をつかっていきます。
まずは 一番最初にbuild packというものを設定 します。build packではnode.js,PHPなどを選択します。まあ使うサーバーサイドの言語を選ぶ物だと思ってください。上記の画面から「Settings」を選択します。
「Buildpacks」という項目があるので「Add builpack」でパックを追加します。
LaravelなのでPHPは必須です。そしてnode modulesもあるのでnode.jsも入れます。ここでサーバーサイドの言語を複数追加すれば各言語でアプリを動かすことができます。
まずは Laravelアプリケーションのソースをこのアプリにぶち込む必要があります。 herokuではGithubとの連携がオススメされているので、今回はその方法で行きます。上記画面から「Deploy」をクリックして移動します。
deployment method でGithubを選びます。すると連携するリポジトリ名を入力する欄が出現します。もし初めてherokuを触ってgithubと連携していない場合は「githubと連携する?」みたいな物が表示されたはずなので、言われる通りに連携します。
githubのアカウントを持っていてログイン状態が保持されていれば、githubの連携許可画面が表示されます。それで簡単に連携ができます。
連携が完了すると下のようにデプロイに関する設定が出てきます。githubを用いる場合は2通りのデプロイがあります。
毎回herokuにログインするのも面倒なので「Enable Automatic Deploys」を選択して自動デプロイができるようにしておきます。
リポジトリにソースをプッシュすると以下のようにbuildしているのがダッシュボードで見ることができます。(たまに更新ボタンを押さないと表示されない時がある。)
しかしまだDBとの連携や環境変数の設定が済んでいないので、アプリをみたところで500エラーしか表示されません。次はDBの設定に移ります。
herokuではProcfile
を用いてドキュメントルート やwebサーバー&phpの設定ができますが、DBに関してはアドオンを利用する必要があります。herokuではpostgreSQLの使用を進めていますが、私が作成したLaravelアプリはmysql仕様で作っていたので 今回はmysqlをDBとして使用します。(まあpostgreSQLに変更もできましたけど…)
ちなみに、「heroku mysql DB」と検索すると **「ClearDB」というmysqlベースのDBアドオンを入れるように書かれた記事が多いですが、私はそこでハマった物がありました。**以下に記述しておきます。
ClearDBを用いててデータベースへマイグレーションをおこなった際に。こんなエラーが発生。
php artisan migrate
...
...
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table `users` add unique `users_email_unique`(`email`))
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes
ローカルでは起きなかった謎のエラー。「上限は767bytesだけど、1071bytesのキーが設定されている」と怒っている。とりあえずmigrationが中途半端にUserテーブルだけ作って止まってしまったので、migrationをリフレッシュする。
php artisan migrate:fresh
このエラーを調べたところどうやら使用した「ClearDB」のmysqlが5.5と古い上に、Laravelで設定していたmysqlで用いる文字コードとの関係で起きていた。以下のQiita記事が非常に参考になった。
対処は2つ。
今回の場合はmysqlのバージョンを上げる方にした。しかしこちらのStackOver Flow にもあるようにClear DBで用いられているmysqlのバージョンを上げるのは無理らしい。。
代わりに「JawsDB」というのを使うとmysqlのバージョンが5.7のものが入ってくれる。
herokuでのmysql導入を調べると「ClearDBを入れろ」という記事が多く、言われたままにやったら起きたのでハマりポイントでした。
アドオンはherokuの追加機能のような物です。「Resources」を選ぶと「Add-ons」という項目がありそこでアドオンを導入できます。jawsDBと入力するとすぐに出てきます。 「jawsDB MySQL」を選択して追加。
データ容量などに応じたプランを選ぶことができます。ここではFreeでおk。「Provision」をクリックしてアプリに追加します。
このjawsDBはherokuのアプリ内(というかサーバー)に組み込まれている訳ではないので、ホストやポートなどを指定する必要があります。jawsDBを導入するとそのherokuアプリを結びついたデータベースが作成されます。
その情報はアドオンのページで、jawsDBの箇所がリンクになっているのでそこをクリックします。
するとDBへの接続情報が書かれた画面が表示されます。ここに接続先ホスト、ユーザー名、パスワードなどが書いてあるので控えておきます。
自前のmysqlコマンドやクラアントから普通にアクセスすることができます。では次にこれらの情報を元に環境変数を設定します。後少しでアプリがデプロイされます!頑張ってください!
DBの接続情報を手に入れたのでLaravel内で使用される環境変数を定義していきます。Laravelのファイル群に「.env」というのがあったと思います。そのファイルは環境変数を定義しており、DBのパスワード、APIキーなど重要な値や環境によって変化する値が格納されています。
基本的には.envはgitでは管理せず、githubにはプッシュされないように除外してあります。ローカルとherokuではDBの接続情報も違うので異なる環境変数を設定する必要がります。
そのために 「Settings」の「config bars」にて環境変数を設定できます。Laravelの.envを開いて必要な項目をコピーして適宜適切な値を入れておきましょう。
環境変数の設定を終えればLaravelのマイグレーションが使えるようになります。heroku CLIを用いてアプリをBashで操作します。ローカルにheroku CLIをダウンロードします。
macならターミナルを開いてログインをします。
~ % heroku login
heroku: Press any key to open up the browser to login or q to exit:[Enter]
Opening browser to https://cli-auth.heroku.com/auth/cli/browser/********
Logging in... done
Logged in as your@email.com
ブラウザがいったん開いてログインが完了です。そしたらアプリをbashで操作します。以下のコマンドを唱えます。
~ % heroku run bash -a staging-app-laravel
Running bash on ⬢ staging-app-laravel... done
「-a」でアプリ名を指定できます。バッシュの時はアプリ名を指定しないと怒られます。 すると表示が少し変わりバッシュ操作が可能になります。
ホームディレクトリ 内にLaravelのソース達が配置されているのが確認できます。このLaravelアプリのルートで php artisan
を唱えることができます。それ以外のディレクトリなどで行うと「そんなコマンド知らんよ」と怒られます。ではマイグレーション。
~ $ php artisan migrate
**************************************
* Application In Production! *
**************************************
Do you really wish to run this command? (yes/no) [no]:
> yes
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (0.06 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (0.05 seconds)
Migrating: 2016_06_01_000001_create_oauth_auth_codes_table
Migrated: 2016_06_01_000001_create_oauth_auth_codes_table (0.09 seconds)
Migrating: 2016_06_01_000002_create_oauth_access_tokens_table
Migrated: 2016_06_01_000002_create_oauth_access_tokens_table (0.09 seconds)
Migrating: 2016_06_01_000003_create_oauth_refresh_tokens_table
Migrated: 2016_06_01_000003_create_oauth_refresh_tokens_table (0.06 seconds)
Migrating: 2016_06_01_000004_create_oauth_clients_table
Migrated: 2016_06_01_000004_create_oauth_clients_table (0.05 seconds)
Migrating: 2016_06_01_000005_create_oauth_personal_access_clients_table
Migrated: 2016_06_01_000005_create_oauth_personal_access_clients_table (0.02 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (0.03 seconds)
...#自分で設定した他のテーブルも無事マイグレーションされた。
これでDBに必要なテーブルが設定されました。ユーザーテーブルに私たちが管理するための管理ユーザーを作成するシーダーを予め作成したおいたのでそれも実行。
~ $ php artisan db:seed
これでDBにもテーブルが挿入されたのでアプリが動くようになりました。
ブラウザのHerokuの画面に戻り、pipe lineの一覧を開きます。 開発アプリの「Open app」をクリックすると構築したLaravelアプリの画面が表示されました。
「500 Internal ServerError」などが表示されている場合は以下の4つを確かめましょう。
アプリのビルドが成功している場合はサーバー自体は構築できています。Laravelアプリや環境変数などに問題ある可能性が高いので確認してみましょう。
ここまでもかなりボリューミーですが、今回は2つアプリを入れたので2つ目も設定します。ですがやることは開発の方でやったように
ぐらいです。そして私の運用ではgithubと本番のアプリは連携させず、stagingのアプリを本番に移行するので少し手間が省けます。stagingのものを本番に移行する場合はpipelineの画面で「promote to production」を選択すればすぐに反映されます。
最後に本番サーバーのSSL化です。無料プランのは自動でSSLは付与されません。証明書があれば付与することができますが無料のdynoはスペックが最低限な上、証明書取得でもお金がかかるので大人しくhobbyプラン以上の有料版にアップグレードしましょう。
本番アプリをhobbyプランに上げるとACM(自動証明書管理)が有効になり、証明書が発行できて有効になってます。SSL化はこれだけです。込み入った証明書や独自ドメイン の付与の際には少し設定が必要です。
とりあえず本番環境までのデプロイが完了しました。Laravel Passport を用いて認証付きAPIを投げられるのでそのチェックをしてみます。とその前にlaravel passportの設定上必要なものがあるのでアプリ内にbashで入って以下を実行。
~ $ php artisan passport:install
Laravel Passport を用いて認証付きAPIを投げられるのでそのチェックをしてみます。シーダーで作成した管理ユーザーでログインします。Laravel Passport ではユーザーごとのアクセストークンが発行できるので、それを作成。(トークン取得画面のUIなどは適宜作成してください。Laravel側でも用意されています。)
アクセストークンを発行して手元にメモしておきます。「Talend API Tester」というChrome拡張機能を使ってこのHerokuアプリ宛にAPIを投げてみます。
アプリのドメイン名が表示されているのでコピー。外部からのAPIアクセスの際にはAPIキーをリクエストヘッダーに仕込んで送ると受け取る設定になっています。まずはAPIキーなして投げると、
おっ!401 Unauthorized が戻ってきました。 とりあえず指定のAPIルーティングは存在して、リクエストが受け取れています。つまりAPIサーバーとして機能していることがわかります。 ではヘッダに先ほどのキーを仕込んで、また諸所の設定値も入れて再度投げると、
200 OK が返りました。プレビューを見るとJSONでのデータが戻ってきているので成功です。これでHerokuにLaravelで開発したAPIサーバー及び管理アプリを構築することができました。このサーバーに認証キー付きAPIを投げることでデータを取得できます。
以上がherokuにlaravel で作成したAPIサービスを構築する手順でした。めちゃくちゃ長い記事になりましたが、VPSならもっと長くなっています笑。githubやSSL化そして他の管理を気にせず簡単にデプロイできるのでherokuが人気なのもわかります。Xserverとかは異なってスケーラブルでnodeとかpythonとかも入れられ、githubで管理できるのは大きいです。