Skip to content

Instantly share code, notes, and snippets.

@williamli
Last active August 21, 2019 20:06
Show Gist options
  • Save williamli/922d3aa50a18b9e32038f93a21336634 to your computer and use it in GitHub Desktop.
Save williamli/922d3aa50a18b9e32038f93a21336634 to your computer and use it in GitHub Desktop.
GitHub Actions with GCloud credentials passed around as artifacts vs Bitbucket Pipeline and Google Cloud Build. https://twitter.com/_wli/status/1164038895614353408?s=20
options:
docker: true
pipelines:
branches:
master:
- step:
image: google/cloud-sdk:latest
name: Deploy to Production
deployment: production
caches:
- docker
script:
# SETUP
- export GCLOUD_PROJECT=bbi-core
- export GCLOUD_ZONE=asia-east1-a
- export GCLOUD_CLUSTER=kluster-01-asia-east1-a
- export IMAGE_NAME=gcr.io/$GCLOUD_PROJECT/$BITBUCKET_REPO_SLUG
- export ENVIRONMENT=production
- echo $GCLOUD_API_KEYFILE | base64 -d > ~/.gcloud-api-key.json
- gcloud auth activate-service-account --key-file ~/.gcloud-api-key.json
- gcloud config set project $GCLOUD_PROJECT
- gcloud config set compute/zone $GCLOUD_ZONE
- gcloud container clusters get-credentials $GCLOUD_CLUSTER
- gcloud auth configure-docker --quiet
# PULL SUBMODULES
- git submodule update --init
# BUILD IMAGE
- docker build . -t $IMAGE_NAME -t $IMAGE_NAME:$BITBUCKET_COMMIT -t $IMAGE_NAME:$ENVIRONMENT
# PUBLISH IMAGE
- docker push $IMAGE_NAME
# CREATE and FLUSH / UPDATE CONFIGS
- set +e
- kubectl create configmap $BITBUCKET_REPO_SLUG-$ENVIRONMENT --from-env-file=.env-$ENVIRONMENT
- kubectl create configmap $BITBUCKET_REPO_SLUG-$ENVIRONMENT --from-env-file=.env-$ENVIRONMENT --dry-run -o yaml | kubectl replace -f -
- set -e
# DEPLOYMENT
- kubectl apply -f deployment-$ENVIRONMENT.yml
- kubectl set image deployment $BITBUCKET_REPO_SLUG-$ENVIRONMENT wordpress=$IMAGE_NAME:$BITBUCKET_COMMIT
# EXPOSE
- kubectl apply -f loadbalancer-$ENVIRONMENT.yml
steps:
# Decrypt the file containing the key
- name: 'gcr.io/cloud-builders/gcloud'
args:
- kms
- decrypt
- --ciphertext-file=.cloudbuild/github/id_rsa.enc
- --plaintext-file=/root/.ssh/id_rsa
- --location=global
- --keyring=cloudbuild-keyring
- --key=github-key
volumes:
- name: 'ssh'
path: /root/.ssh
# Set up git with key and domain.
- name: 'gcr.io/cloud-builders/git'
entrypoint: 'bash'
args:
- '-c'
- |
chmod 600 /root/.ssh/id_rsa
cat <<EOF >/root/.ssh/config
Hostname github.com
IdentityFile /root/.ssh/id_rsa
EOF
mv .cloudbuild/github/known_hosts /root/.ssh/known_hosts
volumes:
- name: 'ssh'
path: /root/.ssh
# Pull from git
- name: gcr.io/cloud-builders/git
dir: $REPO_NAME
entrypoint: 'bash'
args:
- '-c'
- |
git clone git@github.com:bbiHQ/$REPO_NAME .
git reset --hard $SHORT_SHA
git submodule update --init --recursive
echo
echo
echo "====================================="
echo
ls -la
du -hs .
echo
echo "====================================="
echo
echo
volumes:
- name: 'ssh'
path: /root/.ssh
# Try to pull previous Docker image as cache
- name: 'gcr.io/cloud-builders/docker'
dir: $REPO_NAME
entrypoint: 'bash'
args:
- '-c'
- |
pull gcr.io/$PROJECT_ID/$REPO_NAME:${_ENVIRONMENT} || exit 0
# Docker build and push
- name: 'gcr.io/cloud-builders/docker'
dir: $REPO_NAME
args: ['build', '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME', '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:$SHORT_SHA', '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:${_ENVIRONMENT}', '--cache-from', 'gcr.io/$PROJECT_ID/$REPO_NAME:${_ENVIRONMENT}', '.']
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'gcr.io/$PROJECT_ID/$REPO_NAME']
# Setup Kubernetes credentials
- name: 'gcr.io/cloud-builders/kubectl'
dir: $REPO_NAME
entrypoint: 'gcloud'
args:
- container
- clusters
- get-credentials
- --zone
- ${_COMPUTE_ZONE}
- ${_CLUSTER}
# Create / flush configs
- name: 'gcr.io/cloud-builders/kubectl'
dir: $REPO_NAME
entrypoint: 'bash'
args:
- '-c'
- |
kubectl create configmap $REPO_NAME-${_ENVIRONMENT} --from-env-file=.env-${_ENVIRONMENT} || exit 0
env:
- 'CLOUDSDK_COMPUTE_ZONE=${_COMPUTE_ZONE}'
- 'CLOUDSDK_CONTAINER_CLUSTER=${_CLUSTER}'
- name: 'gcr.io/cloud-builders/kubectl'
dir: $REPO_NAME
entrypoint: 'bash'
args:
- '-c'
- |
kubectl create configmap $REPO_NAME-${_ENVIRONMENT} --from-env-file=.env-${_ENVIRONMENT} --dry-run -o yaml | kubectl replace -f - || exit 0
env:
- 'CLOUDSDK_COMPUTE_ZONE=${_COMPUTE_ZONE}'
- 'CLOUDSDK_CONTAINER_CLUSTER=${_CLUSTER}'
# Deploy to Kubernetes
- name: 'gcr.io/cloud-builders/kubectl'
dir: $REPO_NAME
args:
- apply
- '-f'
- deployment-${_ENVIRONMENT}.yml
env:
- 'CLOUDSDK_COMPUTE_ZONE=${_COMPUTE_ZONE}'
- 'CLOUDSDK_CONTAINER_CLUSTER=${_CLUSTER}'
- name: 'gcr.io/cloud-builders/kubectl'
dir: $REPO_NAME
args:
- set
- image
- deployment
- $REPO_NAME-${_ENVIRONMENT}
- wordpress=gcr.io/$PROJECT_ID/$REPO_NAME:$SHORT_SHA
env:
- 'CLOUDSDK_COMPUTE_ZONE=${_COMPUTE_ZONE}'
- 'CLOUDSDK_CONTAINER_CLUSTER=${_CLUSTER}'
# Expose deployment via loadbalancer service
- name: 'gcr.io/cloud-builders/kubectl'
dir: $REPO_NAME
args:
- apply
- '-f'
- loadbalancer-${_ENVIRONMENT}.yml
env:
- 'CLOUDSDK_COMPUTE_ZONE=${_COMPUTE_ZONE}'
- 'CLOUDSDK_CONTAINER_CLUSTER=${_CLUSTER}'
images: ['gcr.io/$PROJECT_ID/$REPO_NAME:$SHORT_SHA']
# artifacts:
# objects:
# location: 'gs://cloudbuild.bbi.codes/$REPO_NAME/$BRANCH_NAME/$SHORT_SHA/artifacts'
# paths: ['$REPO_NAME']
substitutions:
_COMPUTE_ZONE: asia-east1-a
_CLUSTER: kluster-01-asia-east1-a
options:
substitution_option: 'ALLOW_LOOSE'
steps:
# Debug - checks files checkedout from Github
# - name: 'gcr.io/cloud-builders/gcloud'
# entrypoint: 'bash'
# args:
# - '-c'
# - |
# ls -la
# ls -la wp-content
- name: 'gcr.io/cloud-builders/gcloud'
entrypoint: 'bash'
args:
- '-c'
- |
echo
echo
echo "Deploying and building branch $BRANCH_NAME @ $REPO_NAME ($SHORT_SHA)..."
echo
echo
case $BRANCH_NAME in
master)
gcloud builds submit --gcs-log-dir=gs://cloudbuild.bbi.codes/$REPO_NAME/$BRANCH_NAME/$SHORT_SHA/logs --gcs-source-staging-dir=gs://cloudbuild.bbi.codes/$REPO_NAME/$BRANCH_NAME/$SHORT_SHA/sources --config=cloudbuild-deploy.yml --substitutions=_ENVIRONMENT="production",REPO_NAME="$REPO_NAME",SHORT_SHA="$SHORT_SHA",BRANCH_NAME="$BRANCH_NAME"
;;
*)
echo
echo
echo "branch $BRANCH_NAME ignored."
echo
echo
;;
esac
logsBucket: 'gs://cloudbuild.bbi.codes/$REPO_NAME/$BRANCH_NAME/$SHORT_SHA'
# options:
# substitution_option: 'ALLOW_LOOSE'
name: Build and Deploy
on:
push:
branches:
- master
jobs:
GitHub:
name: GitHub Context
runs-on: ubuntu-18.04
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
gCloudSDKInit:
name: Google Cloud SDK initisation
runs-on: ubuntu-18.04
steps:
- name: Auth for Google Cloud
uses: actions/gcloud/auth@master
env:
GCLOUD_AUTH: ${{ secrets.GCLOUD_AUTH }}
- name: Set Credential Helper for Docker
uses: actions/gcloud/cli@master
with:
args: auth configure-docker --quiet
- name: Set default project and zone on Google Cloud SDK
uses: actions/gcloud/cli@master
env:
CLOUDSDK_COMPUTE_ZONE: ${{ secrets.CLOUDSDK_COMPUTE_ZONE }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
entrypoint: sh
args: -l -c "gcloud config set project $CLOUDSDK_PROJECT && gcloud config set compute/zone $CLOUDSDK_COMPUTE_ZONE"
- name: Load GKE kube credentials
uses: actions/gcloud/cli@master
env:
CLOUDSDK_CONTAINER_CLUSTER: ${{ secrets.CLOUDSDK_CONTAINER_CLUSTER }}
CLOUDSDK_COMPUTE_ZONE: ${{ secrets.CLOUDSDK_COMPUTE_ZONE }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
args: container clusters get-credentials $CLOUDSDK_CONTAINER_CLUSTER --zone $CLOUDSDK_COMPUTE_ZONE
--project $CLOUDSDK_PROJECT
- run: sudo tar -czvf gcloudsdk.tar.gz /home/runner/work/_temp/_github_home/.config /home/runner/work/_temp/_github_home/.docker /home/runner/work/_temp/_github_home/.kube
# - run: sudo ls -laR /home/runner/work/_temp/_github_home
- uses: actions/upload-artifact@master
with:
name: gcloudsdk-artifact
path: gcloudsdk.tar.gz
dockerBuild:
name: Building Docker image
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@master
- name: Build Docker image
uses: actions/docker/cli@master
env:
APPLICATION_NAME: ${{ secrets.APPLICATION_NAME }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
args: build -t gcr.io/$CLOUDSDK_PROJECT/$APPLICATION_NAME -t gcr.io/bbi-core/$APPLICATION_NAME:$GITHUB_SHA .
- name: Save Docker image
uses: actions/docker/cli@master
env:
APPLICATION_NAME: ${{ secrets.APPLICATION_NAME }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
entrypoint: sh
args: -l -c "docker save gcr.io/bbi-core/$APPLICATION_NAME:$GITHUB_SHA | gzip > docker-image.tar.gz"
- uses: actions/upload-artifact@master
with:
name: docker-image
path: docker-image.tar.gz
pushToGCR:
name: Push Docker image to GCR
runs-on: ubuntu-18.04
needs: ['gCloudSDKInit', 'dockerBuild']
steps:
- uses: actions/download-artifact@master
with:
name: gcloudsdk-artifact
path: /home/runner/work/_temp/_github_home/
- run: sudo tar -xzvf /home/runner/work/_temp/_github_home/gcloudsdk.tar.gz -C /
# - run: sudo ls -laR /home/runner/work/_temp/_github_home
- uses: actions/download-artifact@master
with:
name: docker-image
path: /home/runner/work/_temp/_github_home/
- run: mv /home/runner/work/_temp/_github_home/docker-image.tar.gz $GITHUB_WORKSPACE
# - run: sudo chmod 777 $GITHUB_WORKSPACE/docker-image.tar.gz
- name: Load Docker image
uses: actions/docker/cli@master
env:
APPLICATION_NAME: ${{ secrets.APPLICATION_NAME }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
args: load < docker-image.tar.gz
- name: Push image to GCR
uses: actions/gcloud/cli@master
env:
APPLICATION_NAME: ${{ secrets.APPLICATION_NAME }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
entrypoint: sh
args: -c "docker push gcr.io/$CLOUDSDK_PROJECT/$APPLICATION_NAME"
deploy2GKEproduction:
name: Deploy Image to GKE (production)
runs-on: ubuntu-18.04
needs: ['pushToGCR', 'gCloudSDKInit']
steps:
- uses: actions/checkout@master
- uses: actions/download-artifact@master
with:
name: gcloudsdk-artifact
path: /home/runner/work/_temp/_github_home/
- run: sudo tar -xzvf /home/runner/work/_temp/_github_home/gcloudsdk.tar.gz -C /
- name: Create and flush / update configs
uses: docker://gcr.io/cloud-builders/kubectl
env:
APPLICATION_NAME: ${{ secrets.APPLICATION_NAME }}
ENVIRONMENT: production
CLOUDSDK_CONTAINER_CLUSTER: ${{ secrets.CLOUDSDK_CONTAINER_CLUSTER }}
CLOUDSDK_COMPUTE_ZONE: ${{ secrets.CLOUDSDK_COMPUTE_ZONE }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
entrypoint: sh
args: -l -c "kubectl create configmap $APPLICATION_NAME-$ENVIRONMENT --from-env-file=.env-$ENVIRONMENT --dry-run -o yaml | kubectl apply -f -"
- name: Deploy to GKE
uses: docker://gcr.io/cloud-builders/kubectl
env:
APPLICATION_NAME: ${{ secrets.APPLICATION_NAME }}
ENVIRONMENT: production
CLOUDSDK_CONTAINER_CLUSTER: ${{ secrets.CLOUDSDK_CONTAINER_CLUSTER }}
CLOUDSDK_COMPUTE_ZONE: ${{ secrets.CLOUDSDK_COMPUTE_ZONE }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
entrypoint: sh
args: -l -c "kubectl apply -f deployment-$ENVIRONMENT.yml
&& kubectl set image deployment $APPLICATION_NAME-$ENVIRONMENT wordpress=gcr.io/$CLOUDSDK_PROJECT/$APPLICATION_NAME:$GITHUB_SHA"
- name: Expose GKE deployment
uses: docker://gcr.io/cloud-builders/kubectl
env:
APPLICATION_NAME: ${{ secrets.APPLICATION_NAME }}
ENVIRONMENT: production
CLOUDSDK_CONTAINER_CLUSTER: ${{ secrets.CLOUDSDK_CONTAINER_CLUSTER }}
CLOUDSDK_COMPUTE_ZONE: ${{ secrets.CLOUDSDK_COMPUTE_ZONE }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
entrypoint: sh
args: -l -c "kubectl apply -f loadbalancer-$ENVIRONMENT.yml"
- name: Verify GKE production deployment
uses: docker://gcr.io/cloud-builders/kubectl
env:
APPLICATION_NAME: ${{ secrets.APPLICATION_NAME }}
ENVIRONMENT: production
CLOUDSDK_CONTAINER_CLUSTER: ${{ secrets.CLOUDSDK_CONTAINER_CLUSTER }}
CLOUDSDK_COMPUTE_ZONE: ${{ secrets.CLOUDSDK_COMPUTE_ZONE }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
entrypoint: sh
args: -l -c "kubectl rollout status deployment/$APPLICATION_NAME-$ENVIRONMENT"
name: Build and Deploy
on:
push:
branches:
- master
jobs:
buildAndDeploy:
name: Build Docker image, push to GCR, deploy to GKE
runs-on: ubuntu-18.04
steps:
- name: Setup Google Cloud
uses: actions/gcloud/auth@master
env:
GCLOUD_AUTH: ${{ secrets.GCLOUD_AUTH }}
- name: Google Cloud initisation
uses: actions/gcloud/cli@master
env:
CLOUDSDK_COMPUTE_ZONE: ${{ secrets.CLOUDSDK_COMPUTE_ZONE }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
entrypoint: sh
args: -l -c "gcloud config set project $CLOUDSDK_PROJECT && gcloud config set compute/zone $CLOUDSDK_COMPUTE_ZONE"
- uses: actions/checkout@master
- name: Build Docker image
uses: actions/docker/cli@master
env:
APPLICATION_NAME: ${{ secrets.APPLICATION_NAME }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
args: build -t gcr.io/$CLOUDSDK_PROJECT/$APPLICATION_NAME -t gcr.io/bbi-core/$APPLICATION_NAME:$GITHUB_SHA .
- name: Set Credential Helper for Docker
uses: actions/gcloud/cli@master
with:
args: auth configure-docker --quiet
- name: Push image to GCR
uses: actions/gcloud/cli@master
env:
APPLICATION_NAME: ${{ secrets.APPLICATION_NAME }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
entrypoint: sh
args: -c "docker push gcr.io/$CLOUDSDK_PROJECT/$APPLICATION_NAME"
- name: Load GKE kube credentials
uses: actions/gcloud/cli@master
env:
CLOUDSDK_CONTAINER_CLUSTER: ${{ secrets.CLOUDSDK_CONTAINER_CLUSTER }}
CLOUDSDK_COMPUTE_ZONE: ${{ secrets.CLOUDSDK_COMPUTE_ZONE }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
args: container clusters get-credentials $CLOUDSDK_CONTAINER_CLUSTER --zone $CLOUDSDK_COMPUTE_ZONE
--project $CLOUDSDK_PROJECT
- name: Create and flush / update configs
uses: docker://gcr.io/cloud-builders/kubectl
env:
APPLICATION_NAME: ${{ secrets.APPLICATION_NAME }}
ENVIRONMENT: production
CLOUDSDK_CONTAINER_CLUSTER: ${{ secrets.CLOUDSDK_CONTAINER_CLUSTER }}
CLOUDSDK_COMPUTE_ZONE: ${{ secrets.CLOUDSDK_COMPUTE_ZONE }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
entrypoint: sh
args: -l -c "kubectl create configmap $APPLICATION_NAME-$ENVIRONMENT --from-env-file=.env-$ENVIRONMENT --dry-run -o yaml | kubectl apply -f -"
- name: Deploy to GKE
uses: docker://gcr.io/cloud-builders/kubectl
env:
APPLICATION_NAME: ${{ secrets.APPLICATION_NAME }}
ENVIRONMENT: production
CLOUDSDK_CONTAINER_CLUSTER: ${{ secrets.CLOUDSDK_CONTAINER_CLUSTER }}
CLOUDSDK_COMPUTE_ZONE: ${{ secrets.CLOUDSDK_COMPUTE_ZONE }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
entrypoint: sh
args: -l -c "kubectl apply -f deployment-$ENVIRONMENT.yml
&& kubectl set image deployment $APPLICATION_NAME-$ENVIRONMENT wordpress=gcr.io/$CLOUDSDK_PROJECT/$APPLICATION_NAME:$GITHUB_SHA"
- name: Expose GKE deployment
uses: docker://gcr.io/cloud-builders/kubectl
env:
APPLICATION_NAME: ${{ secrets.APPLICATION_NAME }}
ENVIRONMENT: production
CLOUDSDK_CONTAINER_CLUSTER: ${{ secrets.CLOUDSDK_CONTAINER_CLUSTER }}
CLOUDSDK_COMPUTE_ZONE: ${{ secrets.CLOUDSDK_COMPUTE_ZONE }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
entrypoint: sh
args: -l -c "kubectl apply -f loadbalancer-$ENVIRONMENT.yml"
- name: Verify GKE production deployment
uses: docker://gcr.io/cloud-builders/kubectl
env:
APPLICATION_NAME: ${{ secrets.APPLICATION_NAME }}
ENVIRONMENT: production
CLOUDSDK_CONTAINER_CLUSTER: ${{ secrets.CLOUDSDK_CONTAINER_CLUSTER }}
CLOUDSDK_COMPUTE_ZONE: ${{ secrets.CLOUDSDK_COMPUTE_ZONE }}
CLOUDSDK_PROJECT: ${{ secrets.CLOUDSDK_PROJECT }}
with:
entrypoint: sh
args: -l -c "kubectl rollout status deployment/$APPLICATION_NAME-$ENVIRONMENT"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment