This sample shows you how to deploy Laravel on Cloud Run, connecting to a Cloud SQL database, and using Secret Manager for credential management.
The deployed example will be a simple CRUD application listing products, and a customised Laravel welcome page showing the deployment information.
In this tutorial, you will:
- Create and connect a Cloud SQL database.
- Create and use Secret Manager secret values.
- Deploy a Laravel app to Cloud Run.
- Host static files on Cloud Storage.
- Use Cloud Build to automate deployment.
- Use Cloud Run Jobs to apply database migrations.
This tutorial uses the following billable components of Google Cloud:
- Cloud SQL
- Cloud Storage
- Cloud Run
- Cloud Build
- Artifact Registry
- Secret Manager
- Create a Google Cloud project
- Ensure Billing is enabled.
- Install and initialize the Google Cloud CLI
- You can run the gcloud CLI in the Google Cloud console without installing the Google Cloud CLI. To run the gcloud CLI in the Google Cloud console, use Cloud Shell.
- Enable the required APIs
gcloud services enable \ run.googleapis.com \ sql-component.googleapis.com \ sqladmin.googleapis.com \ compute.googleapis.com \ cloudbuild.googleapis.com \ secretmanager.googleapis.com \ artifactregistry.googleapis.com
- Ensure sufficient permissions are available to the account used for this tutorial
- Note: In cases where the Owner permissions role cannot be used, the following minimum roles are required to complete the tutorial: Cloud SQL Admin, Storage Admin, Cloud Run Admin, and Secret Manager Admin.
-
Clone a copy of the code into your local machine;
git clone https://github.com/GoogleCloudPlatform/php-docs-samples.git cd php-docs-samples/run/laravel/
You will need PHP on your local system in order to run php artisan
commands later.
-
Check you have PHP 8.1 or higher installed (or install it):
php --version
-
Check you have
composer
installed (or install it):composer --version
-
Install the PHP dependencies:
composer install
You will need Node on your local system in order to generate static assets later.
-
Check you have node and npm installed (or install them):
node --version npm --version
-
Install the Node dependencies:
npm install
There are many variables in this tutorial. Set these early to help with copying code snippets:
export PROJECT_ID=$(gcloud config get-value project)
export PROJECTNUM=$(gcloud projects describe ${PROJECT_ID} --format='value(projectNumber)')
export REGION=us-central1
export INSTANCE_NAME=myinstance
export DATABASE_NAME=mydatabase
export DATABASE_USERNAME=myuser
export DATABASE_PASSWORD=$(cat /dev/urandom | LC_ALL=C tr -dc '[:alpha:]'| fold -w 30 | head -n1)
export ASSET_BUCKET=${PROJECT_ID}-static
-
Create a MySQL instance:
gcloud sql instances create ${INSTANCE_NAME} \ --project ${PROJECT_ID} \ --database-version MYSQL_8_0 \ --tier db-f1-micro \ --region ${REGION}
Note: if this operation takes longer than 10 minutes to complete, run the suggested
gcloud beta sql operations wait
command to track ongoing progress. -
Create a database in that MySQL instance:
gcloud sql databases create ${DATABASE_NAME} \ --instance ${INSTANCE_NAME}
-
Create a user for the database:
gcloud sql users create ${DATABASE_USERNAME} \ --instance ${INSTANCE_NAME} \ --password ${DATABASE_PASSWORD}
-
Create a Cloud Storage bucket:
gsutil mb gs://${ASSET_BUCKET}
-
Create an Artifact Registry:
gcloud artifacts repositories create containers \ --repository-format=docker \ --location=${REGION}
-
Determine the registry name for future operations:
export REGISTRY_NAME=${REGION}-docker.pkg.dev/${PROJECT_ID}/containers
-
Copy the
.env.example
file into.env
cp .env.example .env
-
Update the values in
.env
with your values.⚠️ Replace${}
with your values, don't use the literals. Get these values with e.g.echo ${DATABASE_NAME}
- DB_CONNECTION:
mysql
- DB_SOCKET:
/cloudsql/${PROJECT_ID}:${REGION}:${INSTANCE_NAME}
- DB_DATABASE:
${DATABASE_NAME}
- DB_USERNAME:
${DATABASE_USERNAME}
- DB_PASSWORD:
${DATABASE_PASSWORD}
- ASSET_BUCKET:
${ASSET_BUCKET}
Note:
ASSET_URL
is generated fromASSET_BUCKET
and doesn't need to be hardcoded. - DB_CONNECTION:
-
Update the
APP_KEY
by generating a new key:php artisan key:generate
-
Confirm the
APP_KEY
value in.env
has been updated.
-
Create a secret with the value of your
.env
file:gcloud secrets create laravel_settings --data-file .env
-
Allow Cloud Run access to the secret:
gcloud secrets add-iam-policy-binding laravel_settings \ --member serviceAccount:${PROJECTNUM}[email protected] \ --role roles/secretmanager.secretAccessor
-
Using Cloud Build and Google Cloud Buildpacks, create the container image:
gcloud builds submit \ --pack image=${REGISTRY_NAME}/laravel
With Cloud Run Jobs, you can use the same container from your service to perform administration tasks, such as database migrations.
The configuration is similar to the deployment to Cloud Run, requiring the database and secret values.
-
Create a Cloud Run job to apply database migrations:
gcloud run jobs create migrate \ --image=${REGISTRY_NAME}/laravel \ --region=${REGION} \ --set-cloudsql-instances ${PROJECT_ID}:${REGION}:${INSTANCE_NAME} \ --set-secrets /config/.env=laravel_settings:latest \ --command launcher \ --args "php artisan migrate"
-
Execute the job:
gcloud run jobs execute migrate --region ${REGION} --wait
-
Confirm the application of database migrations by clicking the "See logs for this execution" link.
- You should see "INFO Running migrations." with multiple items labelled "DONE".
- You should also see "Container called exit(0).", where
0
is the exit code for success.
Using the custom npm
command, you can use vite
to compile and gsutil
to copy the assets from your application to Cloud Storage.
-
Upload static assets:
npm run update-static
This command uses the
update-static
script inpackage.json
. -
Confirm the output of this operation
- You should see vite returning "N modules transformed", and gsutil returning "Operation completed over N objects"
-
Deploy the service from the previously created image, specifying the database connection and secret configuration:
gcloud run deploy laravel \ --image ${REGISTRY_NAME}/laravel \ --region $REGION \ --set-cloudsql-instances ${PROJECT_ID}:${REGION}:${INSTANCE_NAME} \ --set-secrets /config/.env=laravel_settings:latest \ --allow-unauthenticated
-
Go to the Service URL to view the website.
-
Confirm the information in the lower right of the Laravel welcome screen.
- You should see a variation of "Laravel v9... (PHP v8...)" (the exact version of Laravel and PHP may change)
- You should see the a variation of "Service: laravel. Revision laravel-00001-vid." (the revision name ends in three random characters, which will differ for every deployment)
- You should see "Project: (your project). Region (your region)."
-
Click on the "demo products" link, and create some entries.
- You should be able to see a styled page, confirming static assets are being served. You should be able to write entries to the database, and read them back again, confirming database connectivity.
While the initial provisioning and deployment steps were complex, making updates is a simpler process.
To make changes: build the container (to capture any new application changes), then update the service to use this new container image:
```bash
gcloud builds submit \
--pack image=${REGISTRY_NAME}/laravel
```
To apply application code changes, update the Cloud Run service with this new container:
```bash
gcloud run services update laravel \
--image ${REGISTRY_NAME}/laravel \
--region ${REGION}
```
Note: you do not have to re-assert the database or secret settings on future deployments, unless you want to change these values.
To apply database migrations, run the Cloud Run job using the newly built container:
```bash
gcloud run jobs execute migrate --region ${REGION}
```
Note: To generate new migrations to apply, you will need to run `php artisan make:migration` in a local development environment.
To update static assets, run the custom npm command from earlier:
```bash
npm run update-static
```
This tutorial opts to use Cloud Run Jobs to process database applications in an environment where connections to Cloud SQL can be done in a safe and secure manner.
This operation could be done on the user's local machine, which would require the installation and use of Cloud SQL Auth Proxy. Using Cloud Run Jobs removes that complexity.
This tutorial opts to use the user's local machine for compiling and uploading static assets. While this could be done in Cloud Run Jobs, this would require building a container with both PHP and NodeJS runtimes. Because NodeJS isn't required for running the service, this isn't required to be in the container.
bootstrap/app.php
includes code to load the mounted secrets, if the folder has been mounted. This relates to the --set-secrets
command used earlier. (Look for the cloudrun_laravel_secret_manager_mount
tag.)
routes/web.php
includes code to retrieve the service and revision information from Cloud Run environment variable, and from the\ Cloud Run metadata service (Look for the cloudrun_laravel_get_metadata
tag.)