Application deployment is one of the important dimensions, including all of the steps, processes of installing, configuring, and enabling a specific application or set of applications. However, I didn’t figure out well what is continuous integration.
For learning it, I started to deploy a Laravel8 application to Google Cloud Run, develop and deploy highly scalable containerized applications on a fully managed serverless platform. But pieces of information about it scattered out on WEB, and I was desperate to understand it, wasting time.
So I will share with you as easily as possible the way of deployment to Google Cloud Run and Google Cloud SQL via GitHub Actions. Let’s get started!
Directory architecture
The next figure shows us the directory architecture of the git repository.
. ├── .github/ │ └── workflows │ └── deploy.yml # yml file to run scripts in Github Actions ├── env/ ├── docker/ │ ├── 000-default.conf │ ├── Dockerfile │ └── php.ini ├── sh/ # useful shell files ├── src/ # the directory installed Laravel application └── docker-compose.yml
1. Build and run the Laravel application on Docker compose
1-1. Clone a repository from GitHub
In this time, we will proceed as the next repository. Under the directory you like, let’s clone it initially and move there.
$ git clone git@github.com:uuta/cloud-run-laravel8.git $ cd cloud-run-laravel8
Build and run the Laravel application on Docker compose to make sure of working out well.
$ cp env/.env.example env/.env.local $ docker-compose up -d --build ... ... ... Creating cloud-run-laravel8_db_1 ... done Creating cloud-run-laravel8_app_1 ... done Time: 0h:00m:24s
The APP_KEY in src/.env would be empty, so create it in a docker container.
$ docker-compose exec app bash $ php artisan route:clear && \ php artisan cache:clear && \ php artisan config:clear && \ php artisan view:clear && \ php artisan key:generate
A Laravel app key would be generated.
# before APP_KEY= # after APP_KEY=base64:<key>
Alright, we'll see the default page of Laravel to access http://localhost:8080/ after the installation.
How about migration? If you execute the migration command after entering the app container, maybe you can see a message such as the next.
$ docker-compose exec app bash $ php artisan migrate Nothing to migrate.
The reason why migration has already finished is to be executed while building a docker image based on Dockerfile. Let’s take a look at Dockerfile.local
for a while.
FROM composer:latest as build WORKDIR /app COPY . /app FROM php:8.0-apache COPY docker/php.ini /usr/local/etc/php/ RUN apt update RUN apt install -y git RUN apt install -y vim RUN apt install -y zip unzip RUN docker-php-ext-install bcmath pdo_mysql # composer install RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer EXPOSE 8080 COPY --from=build /app /var/www COPY docker/000-default.conf /etc/apache2/sites-available/000-default.conf RUN chmod 777 -R /var/www WORKDIR / RUN echo "Listen 8080" >> /etc/apache2/ports.conf RUN chown -R www-data:www-data /var/www RUN a2enmod rewrite # Make the file executable, or use "chmod 777" instead of "chmod +x" RUN chmod +x /var/www/sh/laravel/laravel.local.sh # This will run the shell file at the time when container is up-and-running successfully (and NOT at the BUILD time) ENTRYPOINT ["/var/www/sh/laravel/laravel.local.sh"]
At the end of this file, there are codes to execute a shell command.
RUN chmod +x /var/www/sh/laravel/laravel.local.sh ... ENTRYPOINT ["/var/www/sh/laravel/laravel.local.sh"]
So let’s take a look at sh/laravel/laravel.local.sh
file. composer install
and migrate
commands are executed here.
#!/bin/bash # initialize laravel cd /var/www/src composer install --optimize-autoloader php artisan config:cache php artisan route:cache php artisan view:cache # Run Laravel migration php artisan migrate # Run Apache in "foreground" mode (the default mode that runs in Docker) apache2-foreground
The reason why I dare to make this file is to migrate to Google Cloud SQL in the production environment. According to the next page, the Google Cloud SQL connection is not available during the build phase. Thus, I had to put these commands out for execution after building successfully. In the local environment, this application attempts to connect with the local database instead of Google Cloud SQL.
1-2. More detail of Dockerfile
Let’s see Dockerfile.local
again. I can’t explain everything, but I’ll try to add descriptions briefly. To build an image on Google Cloud Run, shell scripts expose port of 8080.
EXPOSE 8080 ... RUN echo "Listen 8080" >> /etc/apache2/ports.conf
This command copies 000-default.conf
to configure the Apache WEB server.
COPY docker/000-default.conf /etc/apache2/sites-available/000-default.conf
2. Deploy Laravel application to Google Cloud Run
Now let's deploy the Laravel application from the local side. First, let docker containers be down.
$ docker-compose down
2-1. Set up GCP with console
Execute the following commands with checking project name in GCP.
$ gcloud auth login $ PROJECT_NAME=(<Project name in GCP>) PROJECT_ID=$(gcloud projects list --format 'value(projectId)' --filter name=$PROJECT_NAME) export PROJECT_ID gcloud config set project $PROJECT_ID gcloud services enable \ containerregistry.googleapis.com \ cloudresourcemanager.googleapis.com \ iam.googleapis.com
2-2. Create an authorized service account
Create a service account and give it Owner privileges. Download the key, save it as laravel8_google_cloud_run_key.json, set it as an environment variable, and authorize it as a service account. The following command makes it possible.
$ gcloud iam service-accounts create deployer \ --display-name "deployer" gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member serviceAccount:deployer@${PROJECT_ID}.iam.gserviceaccount.com \ --role roles/owner export GOOGLE_APPLICATION_CREDENTIALS=credentials/laravel8_google_cloud_run_key.json gcloud iam service-accounts keys create $GOOGLE_APPLICATION_CREDENTIALS \ --iam-account deployer@${PROJECT_ID}.iam.gserviceaccount.com gcloud auth activate-service-account --key-file=$GOOGLE_APPLICATION_CREDENTIALS
In the above example command, laravel8_google_cloud_run_key.json
is stored in the credentials directory.
export GOOGLE_APPLICATION_CREDENTIALS=~/credentials/laravel8_google_cloud_run_key.json
2-3. Build docker image
Build docker image instead of docker-compose
command.
$ export SERVICE_NAME=docker-laravel8-run docker build -f docker/Dockerfile.prod -t asia.gcr.io/${PROJECT_ID}/${SERVICE_NAME} .
Run a docker container to work out correctly on the local environment.
$ docker run --init -d -e PORT=8080 -p 8080:8080 asia.gcr.io/${PROJECT_ID}/${SERVICE_NAME}
Make sure the local page works correctly.
2-4. Push the docker image to Container Registry
$ gcloud auth configure-docker docker push asia.gcr.io/${PROJECT_ID}/${SERVICE_NAME}
You’ll make sure to register a repository named docker-laravel8.
2-5. Enable Cloud SQL Admin API
To connect Google Cloud Run and Google Cloud SQL, try to enable Cloud SQL Admin API.
3. Google Cloud SQL
Create a Google Cloud SQL instance temporarily for test. I’ll create an instance like the following example in this sample, but you can modify configuration for your environment. This process might take a long time.
$ DATABASE_NAME=(docker-laravel8-run) gcloud sql instances create $DATABASE_NAME \ --database-version=MYSQL_8_0 \ --region=us-central1 \ --storage-size=100 \ --storage-type=HDD \ --tier=db-f1-micro \ --root-password=homestead
- How to securely connect to Cloud SQL from Cloud Run? - Stack Overflow
- How do I connect to Cloud SQL from a Laravel project running on Cloud Run? - Stack Overflow
It would be better to create a database named laravel.
$ gcloud sql databases create laravel \ --instance=$DATABASE_NAME
3-1. Deploy to Google Cloud Run
Let’s try to deploy to Google Cloud Run. Replace <Connection name>
to the Connection name in Google Cloud SQL and execute the following command.
$ SQL_CONNECTION_NAME=(<Connection name>) gcloud run deploy ${SERVICE_NAME} \ --image asia.gcr.io/"${PROJECT_ID}"/"${SERVICE_NAME}" \ --region asia-east1 \ --platform=managed \ --add-cloudsql-instances ${SQL_CONNECTION_NAME} \ --allow-unauthenticated
A URL will be generated after deploying. Make sure to be shown the page for Laravel8 correctly.
4. Deploy from GitHub Actions
4-1. Brief description
Now we’ve deployed the Laravel application successfully from the Local environment. Then, let’s consider deploying from GitHub Actions. I’m assumed that GitHub Actions runs commands to deploy when commits are pushed to the master or main branch. In this example, the deploy command is defined in .github/workflows/deploy.yml
file. And the trigger for deployment is set when pushing to master
.
name: cloud-run-laravel8-deploy on: push: branches: - master
Let’s see some more. This remote repository has no .env file to configure the Laravel application by the .gitignore
file. So we should put .env
file only when deploying. Then, by encoding an environment variable decoded as base64 of the .env
file on the local, it’s available to deploy.
- name: Decode .env file run: | echo ${{ secrets.TEST_ENV_FILE }} | base64 --decode > src/.env
There are six environment variables in .github/workflows/deploy.yml
file.
- secrets.TEST_GCP_EMAIL: deploy email
- secrets.TEST_GCP_CREDENTIALS: the content of
credentials/laravel8_google_cloud_run_key.json
in your local environment - secrets.TEST_ENV_FILE:
env/.env.prod
- secrets.TEST_GCP_PROJECT: project id
- secrets.TEST_GCP_APPLICATION: service name
- secrets.TEST_SQL_CONNECTION_NAME: SQL connection name
4-2. Change remote repository
Then, change the remote branch to test-cloud-run
. The name can be anything you like.
$ git config remote.origin.url git@github.com:uuta/cloud-run-laravel8.git $ git remote set-url origin git@github.com:uuta/test-cloud-run.git $ git config remote.origin.url
4-3. Enter the environment variables
Enter the environment variables on GitHub like this.
TEST_GCP_EMAIL can be obtained from the Google Cloud Run UI.
Modifying TEST_ENV_FILE is somewhat tricky. First of all, copy the .env.example file as .env.prod.
$ cp env/.env.local env/.env.prod
Modify the .env.prod file as follows, and don't forget to add DB_SOCKET.
APP_NAME=Laravel APP_ENV=production APP_KEY=<your app key> APP_DEBUG=false APP_URL=<your app url> LOG_CHANNEL=stack LOG_DEPRECATIONS_CHANNEL=null LOG_LEVEL=debug DB_CONNECTION=mysql DB_HOST=localhost DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=root DB_PASSWORD=homestead DB_SOCKET=/cloudsql/<connection name to Google Cloud SQL>
By the following command, values in the env
file will transfer to string encoded Base64. So you can copy and paste it as the value of TEST_ENV_FILE.
$ cat env/.env.prod | base64 | pbcopy
4-4. Git push, and then deploy automatically
$ git push
After pushing the master repository, it will automatically start deploying in your remote repository. Please check if it succeeds.
You made it!
Top comments (0)