Symfony5+PostgreSQL+Firebase AuthなアプリをGitHub ActionsでHerokuにデプロイするまで
意外と躓いたのでブログに残しておきます。
Procfile
を作成
1. 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/
app.json
を作成
2. 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の秘密鍵"
}
}
}
composer.json
に compile
カスタムコマンドを追加
3. - デプロイ時に
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