Deploy Laravel 9 to App Engine with Google Cloud Build and Secret Manager

Didik Mulyadi
5 min readApr 6, 2023

--

https://www.cloudways.com/blog/wp-content/uploads/Laravel-9.jpg

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.

  1. Failed composer install or cache issue
    Make sure the composer scrill is correct.
  2. 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 the env setup is correct.
  3. Extension issue (not installed)
    Make sure the extension is included in composer.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 like
file_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

Enable other service

Create the CloudBuild trigger with the substitution variable

Create trigger

Fill the name and connect the trigger to your GitHub Repository.

Trigger Form Creation

Define the cloudbuild.yaml , I will rename it to cloudbuild-substitution-variable.yaml , let the service account empty, and click the save button.

Define the cloudbuild and substituion variable
CloudBuild Trigger Result

Step 3: Use a Variable from Secret Manager

1. Create the secret in Secret Manager1. Create the secret in Secret Manager

Create Secret

Create a secret for DEV_APP_KEY .

Secret Creation Form

Copy the resource ID

Secret Detail

2. Empty the substitution variable in the CloudBuild Trigger

CloudBuild Trigger Edit Form

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

Learn More

--

--