Deploy Laravel 9 to App Engine with Google Cloud Build and Secret Manager
After a couple of days, I just finished integrating Laravel 9 with App Engine Google Cloud Build, and Secret Manager. Now, I wanna share this with you. So, you don’t need to face the same issue as me.
There are 2 types of App Engine environments e.g. flex and standard. Read how to choose with this link.
In this article, we are gonna use the App Engine standard.
Common Problem
The solution is already included in the step section.
- Failed composer install or cache issue
Make sure the composer scrill is correct. - Storage directory issue
file_put_contents(/storage/framework/view/************.php): failed to open stream: No such file or directory
and many similar issues, Make sure theenv
setup is correct. - Extension issue (not installed)
Make sure the extension is included incomposer.json
App Engine Environment
Both environments support the Laravel framework but there’s a limitation in the PHP version that is supported.
Flex
The Maximum PHP version supported is 7.3, which means the maximum Laravel version supported is 8.
Standard
The Maximum PHP versions supported are 8.1 and 8.2 (preview version), so you can use Laravel 9 here.
The previous time, After I got many errors in the standard environment, I tried running Laravel 9 / PHP 8.1 in the Flex environment and it failed because of the PHP version restriction.
Let’s Start!
Assume you have already installed the Laravel Framework. We will skip the installation process
Step 1: Configure The Project
1. Update your composer.json about Script
...
"scripts": {
...
"post-autoload-dump": [
"mkdir -p ./bootstrap/cache/",
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi"
],
...
"post-install-cmd": [
"chmod -R 755 bootstrap/cache",
"php artisan config:clear",
"php artisan cache:clear",
"php artisan route:clear"
],
}
...
Changes:
- Add mkdir -p ./bootstrap/cache/
in post-autoload-dump
- Add post-install-cmd
2. Update your composer.json about Extension
In this case, I need some extension so we need to add the extension in the require
and config.platform
...
require: {
"php": "8.1.*",
"ext-PDO": "*",
"ext-bz2": "*",
"ext-json": "*",
"ext-zip": "*",
"ext-sodium": "*",
},
...
config: {
...
"platform": {
"php": "8.1",
"ext-sodium": "8.1"
}
}
...
3. Update your bootstrap/app.php
Because the App Engine standard only supports the reading process and the path that is only allowed to create is /tmp
, so we will change the storage path based on the value from the environment.
When this step is skipped or the env value is not passed, it will throw the error likefile_put_contents(/storage/framework/view/************.php): failed to open stream: No such file or directory
Based on these changes, we need this variable in the environment :
APP_STORAGE=/tmp
VIEW_COMPILED_PATH=/tmp
...
$app->useStoragePath(env('APP_STORAGE', base_path() . '/storage'));
/*
|--------------------------------------------------------------------------
| Return The Application
|--------------------------------------------------------------------------
|
| This script returns the application instance. The instance is given to
| the calling script so we can separate the building of the instances
| from the actual running of the application and sending responses.
|
*/
return $app;
4. Create app.yaml
runtime: php81
service: dev
handlers:
- url: /(.*\.(gif|png|jpg|css|js|svg|woff2|ttf))$
static_files: public/\1
upload: public/.*\.(gif|png|jpg|css|js|svg|woff2|ttf)$
- url: /.*
secure: always
redirect_http_response_code: 301
script: auto
env_variables:
APP_NAME: App
APP_ENV: development
APP_STORAGE: /tmp
VIEW_COMPILED_PATH: /tmp
SESSION_DRIVER: cookie
APP_DEBUG: true
The variable that is exist in the app.yaml should be the static variable, for the dynamic variable, we are gonna use the secret manager to provide the environment variable, We will add the dynamic variable in the cloudbuild.yaml
.
the
env_variables
should always in the end of the file because we will append the variable with the append function.
runtime: PHP version that you used
service: a name of your application
5. Create cloudbuild.yaml
At this point, we will use cloud build — subtituion variables
to fill the env_variables
in app.yaml
. We will change this with the secret manager
later.
$_APP_KEY is a substitution variable from the cloud build setting.
steps:
- name: gcr.io/google.com/cloudsdktool/cloud-sdk
args:
- "-c"
- |
echo $'\n APP_KEY: '$_APP_KEY >> app.yaml
gcloud config set app/cloud_build_timeout 3600 && gcloud app deploy app.yaml -q --promote -v=$BUILD_ID --project=$PROJECT_ID --no-cache
entrypoint: bash
Step 2: Configure The Cloud Build
Enable the CloudBuild to connect to other service
Create the CloudBuild trigger with the substitution variable
Fill the name and connect the trigger to your GitHub Repository.
Define the cloudbuild.yaml
, I will rename it to cloudbuild-substitution-variable.yaml
, let the service account empty, and click the save button.
Step 3: Use a Variable from Secret Manager
1. Create the secret in Secret Manager1. Create the secret in Secret Manager
Create a secret for DEV_APP_KEY
.
Copy the resource ID
2. Empty the substitution variable in the CloudBuild Trigger
2. Update cloudbuild.yaml to connect the secret manager
steps:
- name: gcr.io/google.com/cloudsdktool/cloud-sdk
args:
- "-c"
- |
echo $'\n APP_KEY: '$$APP_KEY >> app.yaml
gcloud config set app/cloud_build_timeout 3600 && gcloud app deploy app.yaml -q --promote -v=$BUILD_ID --project=$PROJECT_ID --no-cache
entrypoint: bash
secretEnv: ["APP_KEY"]
availableSecrets:
secretManager:
- versionName: projects/$PROJECT_NUMBER/secrets/DEV_APP_KEY/versions/latest
env: "APP_KEY"
Those steps will deploy your Laravel to App Engine.
STEP 4: App Engine Result
Thank you for reading this article! 🎉
Reach me: https://www.linkedin.com/in/didikmulyadi/
Repository: https://github.com/didikmulyadi/laravel-appengine-cloudbuild