Search code examples
phplaravelgoogle-cloud-build

Run php artisan commands from Cloud Build


I'm using Cloud Build to deploy my app on Cloud Run. I'd like to set php artisan commands in my cloudbuild.yaml to run migrations, init passport library... But I got this error on my Laravel init step:

Starting Step #3 - "Laravel Init"
Step #3 - "Laravel Init": Already have image (with digest): gcr.io/cloud-builders/gcloud
Step #3 - "Laravel Init": bash: php: command not found
Step #3 - "Laravel Init": bash: line 1: php: command not found
Step #3 - "Laravel Init": bash: line 2: php: command not found
Step #3 - "Laravel Init": bash: line 3: php: command not found
Step #3 - "Laravel Init": bash: line 4: php: command not found
Finished Step #3 - "Laravel Init"
ERROR
ERROR: build step 3 "gcr.io/cloud-builders/gcloud" failed: step exited with non-zero status: 127

And here is my cloudbuild.yaml

steps:
  # Build the container image
  - name: 'gcr.io/cloud-builders/docker'
    args:
    ...
    id: Build

  # Push the container image to Artifacts Registry
  - name: 'gcr.io/cloud-builders/docker'
    ...
    id: Push

  # Deploy container image to Cloud Run
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    id: Deploy
    entrypoint: gcloud
    ...

 # Laravel Init
  - name: 'gcr.io/cloud-builders/gcloud'
    id: Laravel Init
    entrypoint: "bash"
    args:
      - "-c"
      - |
          php artisan migrate --force
          php artisan db:seed --force
          php artisan db:seed --class=Database\\Seeders\\UsersTableSeeder --force
          php artisan passport:install

images:
  - 'europe-west3-docker.pkg.dev/$PROJECT_ID/.....'
tags:
  - latest

How can I do to execute my php artisan commands ?


Solution

  • I found a solution. I used the helper exec-wrapper. With this helper I can use my laravel container env and connect to Cloud SQL with the embedded cloud sql proxy. So I just have to pass my latest current image previously built in the first step in cloudbuild.yaml. I set the database socket connection and then I pass the migration.sh file where I can run all my php artisan commands.

    I'm using mysql so you have to adjust port and connection name if you are using another Database.

    cloudbuild.yaml:

    steps:
      # Build the container image
      - name: 'gcr.io/cloud-builders/docker'
        args:
        ...
        id: Build
    
      # Push the container image to Artifacts Registry
      - name: 'gcr.io/cloud-builders/docker'
        ...
        id: Push
    
      # Deploy container image to Cloud Run
      - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
        id: Deploy
        entrypoint: gcloud
        ...
    
     # Laravel Init
      - name: 'gcr.io/google-appengine/exec-wrapper'
        id: Laravel Init
        args: [
          '-i', '<YOUR_IMAGE_URL>',
          '-e', 'DB_CONNECTION=mysql',
          '-e', 'DB_SOCKET=/cloudsql/<YOUR_CLOUD_SQL_INSTANCE>',
          '-e', 'DB_PORT=3306',
          '-e', 'DB_DATABASE=<YOUR_DATABASE_NAME>',
          '-e', 'DB_USERNAME=<YOUR_DB_USER>',
          '-e', 'DB_PASSWORD=<YOUR_DB_PASS>',
          '-s', '<YOUR_CLOUD_SQL_INSTANCE>',
          '--', '/app/scripts/migration.sh'
        ]
    images:
      - 'europe-west3-docker.pkg.dev/$PROJECT_ID/.....'
    

    Care about /app folder in /app/scripts/migration.sh. /app is my WORKDIR that I set in my Dockerfile

    migration.sh look like this:

    #!/bin/bash
    
    php artisan migrate --force
    php artisan db:seed --force
    #... add more commands
    

    Don't forget to Add the permission Client Cloud SQL to the Cloud Build service in the IAM section else Cloud Build cannot connect to your Cloud SQL instance.

    And care about if your image has an entrypoint file. You have to use exec $@ to execute the -- command from app engine exec wrapper. If you don't use it the commands will be ignored.

    Edit

    Now with Laravel 9 we can easily lock the database during the migration with the --isolated argument php artisan migrate --isolated.

    So we can remove gcr.io/google-appengine/exec-wrapper step and add the php artisan migrate --isolated command into the laravel image (Dockerfile).