Symfony5+PostgreSQL+Firebase AuthなアプリをGitHub ActionsでHerokuにデプロイするまで
意外と躓いたのでブログに残しておきます。
1. Procfile を作成
PHP 向けの Web サーバーおよびランタイム設定のカスタマイズ | Heroku Dev Center
#nginx
あたりを参考に heroku/nginx/default.conf を以下の内容で作成して、
location / {
# try to serve file directly, fallback to rewrite
try_files $uri @rewriteapp;
}
location @rewriteapp {
# rewrite all to index.php
rewrite ^(.*)$ /index.php/$1 last;
}
以下の内容で Procfile を作成します。
web: vendor/bin/heroku-php-nginx -C heroku/nginx/default.conf public/
2. app.json を作成
Heroku側の環境設定はWeb UIなどで行うとしても、インフラの情報をコードベースに残す意味で app.json を作っておきます。
{
"buildpacks": [
{
"url": "heroku/nodejs"
},
{
"url": "heroku/php"
}
],
"addons": [
{
"plan": "heroku-postgresql:hobby-dev",
"options": {
"version": "13"
}
}
],
"env": {
"APP_ENV": "dev",
"APP_SECRET": {
"generator": "secret"
},
"DATABASE_URL": "",
"FIREBASE_CREDENTIALS": {
"description": "Firebaseの秘密鍵"
}
}
}
3. composer.json に compile カスタムコマンドを追加
- デプロイ時に
bin/console doctrine:migrations:migrateを実行する - デプロイ時に
--no-devなしでcomposer installする -
--no-devでcomposer installされたときは@auto-scriptsを実行しない(require-devのクラスたちがClassNotFoundErrorになってしまって@auto-scriptsの実行が失敗してしまうので)
という3つのことを達成すべく、composer.json を修正します。
詳しくは
過去にこちらの記事で解説していますので、先に目を通してみていただけるとよいかもしれません✋
{
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
},
"auto-commands": [
"npm install"
],
"post-install-cmd": [
"if [ $COMPOSER_DEV_MODE -ne 0 ]; then composer auto-scripts; fi",
"@auto-commands"
],
"post-update-cmd": [
"if [ $COMPOSER_DEV_MODE -ne 0 ]; then composer auto-scripts; fi",
"@auto-commands"
],
"db-migrate": "bin/console doctrine:migrations:migrate --no-interaction --no-debug --allow-no-migration",
"compile": [
"composer install --prefer-dist --optimize-autoloader --no-interaction",
"@db-migrate"
]
}
}
こんな感じです。
ちなみに、最初は
"db-migrate": "bin/console doctrine:migrations:migrate --no-interaction --no-debug --allow-no-migration",
ではなく
"db-migrate": [
"bin/console doctrine:database:create --if-not-exists",
"bin/console doctrine:migrations:migrate --no-interaction --no-debug --allow-no-migration"
],
と書いていたんですが、Heroku Postgres だと bin/console doctrine:database:create --if-not-exists を叩いた時点で User does not have CONNECT privilege というエラーになりました。
webpack-encore を導入している場合は、npm install 後に npm run build が実行されるよう package.json も修正しておきましょう。
{
"scripts": {
"dev-server": "encore dev-server",
"dev": "encore dev",
"watch": "encore dev --watch",
"build": "encore production --progress",
+ "postinstall": "npm run build"
}
}
4. Firebaseの秘密鍵を環境変数からファイルに出力するように
kreait/firebase-bundle を使っている場合、Firebaseの秘密鍵はファイルから読み込むことしかできません。
kreait/firebase-php には 秘密鍵のJSON文字列を渡せるAPIがある のですが、
kreait/firebase-bundleではそこは隠蔽されてファイル読み込みしかできなくなっています。
Herokuでは ファイルシステムが永続的ではない ので、環境変数に秘密鍵をセットしておいて、デプロイ時にその内容をファイルに出力するようにする必要があります。
そこで、composer.json の auto-commands カスタムコマンドに以下のような2行を追記してみましたが、これだと上手く行きませんでした。
{
"scripts": {
"auto-commands": [
"npm install",
+ "if [ ! -f firebase-credentials-dev.json ]; then echo $FIREBASE_CREDENTIALS > firebase-credentials-dev.json; fi",
+ "if [ ! -f firebase-credentials-prod.json ]; then echo $FIREBASE_CREDENTIALS > firebase-credentials-prod.json; fi"
]
}
}
原因はよく分かっていませんが、Heroku環境上 && Composerカスタムコマンド経由の場合のみ、echo $FIREBASE_CREDENTIALS が \n を改行文字として出力してしまい、正しい秘密鍵の内容ではなく \n という文字列が改行文字に置換された内容がファイルに書き込まれて、Symfonyのコンテナのコンパイルが失敗してしまいました。
echo -Eオプションで行けるかと思ったけどHeroku環境のechoコマンドには-Eオプションありませんでした。
なので、echo コマンドの代わりに php -r を使って以下のように対処したところ期待どおりに動作しました。
{
"scripts": {
"auto-commands": [
"npm install",
- "if [ ! -f firebase-credentials-dev.json ]; then echo $FIREBASE_CREDENTIALS > firebase-credentials-dev.json; fi",
- "if [ ! -f firebase-credentials-prod.json ]; then echo $FIREBASE_CREDENTIALS > firebase-credentials-prod.json; fi"
+ "if [ ! -f firebase-credentials-dev.json ]; then php -r \"echo getenv('FIREBASE_CREDENTIALS');\" > firebase-credentials-dev.json; fi",
+ "if [ ! -f firebase-credentials-prod.json ]; then php -r \"echo getenv('FIREBASE_CREDENTIALS');\" > firebase-credentials-prod.json; fi"
]
}
}
5. GitHub ActionsからHerokuにデプロイできるように
ここまでで、コードベースはHerokuにデプロイ可能な状態になりました。
最後に、GitHub Actionsでテストが成功したときのみHerokuへデプロイするようワークフローを書きます。
name: CI
on: push
jobs:
test:
# 略
deploy:
if: ${{ github.ref == 'refs/heads/main' }} # mainブランチへのpushでのみ実行
needs: test # testをパスした場合のみ実行
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: akhileshns/heroku-deploy@v3.12.12
with:
heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
heroku_app_name: YOUR_HEROKU_APP_NAME
heroku_email: ${{ secrets.HEROKU_EMAIL }}
参考:
Deploy to Heroku アクションを使えばGitHub Actionsから簡単にHerokuにデプロイできます。
HerokuのAPIキーとHerokuアカウントのメールアドレスが必要なので、
https://dashboard.heroku.com/account/applications
の Create Authorization でAPIキーを作成して、

https://github.com/{owner}/{repo}/settings/secrets/actions
の New repository secret で HEROKU_API_KEY として登録します。同様に HEROKU_EMAIL としてメールアドレスも登録します。

これで、mainブランチが更新されてテストがパスしたら自動でHerokuにデプロイされるようになりました👍
Discussion