I've written about the Serverless Framework before, and how it plays very nicely with AWS. With Google Cloud, I've found things are a bit trickier, and there's less documentation, probably because it's relatively new. But fear not! Here's a complete step by step to set up a GitHub workflow to deploy to Google Cloud using the Serverless Framework. The process shouldn't be too different if you are using another CI provider.
If you haven't, set up a starter project:
serverless create --template google-nodejs
First, you'll need Google Cloud system credentials. The Serverless framework has a complete guide on how to set up a service account with the right roles.
By now you should have downloaded a JSON file with your credentials, and added its path in your serverless.yml
. But this path can be different if you deploy from your machine, or a fellow developer deploys from theirs, or if it's deployed via CI, right? So we want this to be an environment variable. Your complete serverless.yml
file should look something like this:
service: my-project
provider:
name: google
stage: dev
runtime: nodejs8
region: europe-west1
project: my-project
credentials: ${env:CREDENTIALS_PATH}
plugins:
- serverless-google-cloudfunctions
package:
exclude:
- node_modules/**
- .gitignore
- .git/**
functions:
first:
handler: http
events:
- http: path
Now, from your machine you can easily deploy passing the correct path:
CREDENTIALS_PATH=~/path/to/your/keyfile.json serverless deploy
Now we are ready to create our deploy workflow! We'll be using the official Serverless action. In the example workflow, they show how to pass secrets as environment variables, but as we've seen with Google Cloud we need to pass a whole JSON file. And we know it's not a good idea to commit sensitive information, so we'll need to commit an encrypted version of it, and add a script to decrypt it on deploy time. That might sound complicated but don't worry, we'll do it! 💪The GitHub Actions documentation includes a guide on how to do that, but we'll go step by step here too.
First, encrypt the file (with Mac I installed GPG Tools)
$ gpg --symmetric --cipher-algo AES256 keyfile.json
You'll need to enter a passphrase. Make sure to keep it somewhere safe as we'll need it to decrypt the file. Commit the encrypted keyfile.json.gpg
file to your repository.
Create a shell script to decrypt the password. We need to use the $GITHUB_WORKSPACE
path instead of $HOME
(as the documentation example) because the Serverless action runs in a docker container and is not able to access any directory, just the workspace.
#!/bin/sh
# Decrypt the file
mkdir $GITHUB_WORKSPACE/secrets
# --batch to prevent interactive command --yes to assume "yes" for questions
gpg --quiet --batch --yes --decrypt --passphrase="$SECRET_PASSPHRASE" \
--output $GITHUB_WORKSPACE/secrets/keyfile.json keyfile.json.gpg
Save this file in .github/scripts/decrypt_secret.sh
, make sure it is executable by running chmod +x decrypt_secret.sh
, and commit it.
In your GitHub repository settings, add a new SECRET_PASSPHRASE
secret with the passphrase you used when encrypting the file.
Now we are ready to decrypt the keyfile in our workflow, and pass its path to the Serverless action as an environment variable (inside the container the $GITHUB_WORKSPACE
path is accessible via /github/workspace/
). Here's the complete workflow file:
name: Deploy
on:
push:
branches:
- master
jobs:
deploy:
name: deploy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: npm install
run: npm install
- name: Decrypt secret
run: ./.github/scripts/decrypt_secret.sh
env:
SECRET_PASSPHRASE: ${{ secrets.SECRET_PASSPHRASE }}
- name: serverless deploy
uses: serverless/github-action@master
with:
args: deploy
env:
SERVERLESS_ACCESS_KEY: ${{ secrets.SERVERLESS_ACCESS_KEY }}
CREDENTIALS_PATH: /github/workspace/secrets/keyfile.json
Finally, your project is set up for continuous deployment! You can find the whole code in this repository.
Of course, you should also have workflows to run tests or lint your code. At Codegram we love GitHub Actions, and we have a repo with useful workflows. Make sure to take a look!
Cover photo by Daniel Mayovskiy