Intro to container-optimised Google Cloud VM instance

Recently I was deciding what to use to implement an API for one of my personal projects on a Google Cloud Platform. Kubernetes - too heavy for a simple need of a lightweight Node logic. Cloud Run - sounds almost perfect, however I required an instance to be always connected to a socket connection, and Cloud Run by its nature is known to have a cold start "feature". Alright, what about a good old VM instance? Yes, but I'd prefer to have a containerised approach... speaking of which here is what I found while creating a VM instance:

Deploy a container image into VM instance.

After reading more about how does it work: Google is provisioning an instance with an optimised for container OS. Sounds cool!

For my project I was using Cloud Build connected to GitHub repository via hooks, and here is a snapshot of  cloudbuild.yaml file:

   steps:
    - name: gcr.io/cloud-builders/docker
      args:
          - build
          - '--no-cache'
          - '-t'
          - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:latest'
          - .
          - '-f'
          - Dockerfile
      id: Build
    - name: gcr.io/cloud-builders/docker
      args:
          - push
          - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:latest'
      id: Push
    - name: gcr.io/cloud-builders/gcloud
      args:
        - '-c'
        - >-
            gcloud compute instances update-container my-amazing-api --container-image us.gcr.io/api/my-amazing-api/my-amazing-api:latest --zone us-central1-a
      entrypoint: bash
images:
    - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:latest'
options:
    substitutionOption: ALLOW_LOOSE
substitutions:
    _SERVICE_NAME: my-amazing-api
    _DEPLOY_REGION: us-central1
    _GCR_HOSTNAME: us.gcr.io
tags:
    - my-amazing-api 

Let's go one by one what does this configuration does...

Firstly, we initiate a build stage where Docker file within the project is used to build an image:

steps:
    - name: gcr.io/cloud-builders/docker
      args:
          - build
          - '--no-cache'
          - '-t'
          - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:latest'
          - .
          - '-f'
          - Dockerfile
      id: Build

After our image is built, it is a time to push it to a Google Cloud Repository with relevant tag, hostname, project id and repository name:

    - name: gcr.io/cloud-builders/docker
      args:
          - push
          - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:latest'
      id: Push

Alright, now here comes the question: Do we expect that our container-optimised VM will listen for every new version of container being deployed and update itself? Not really... That's why we need this last part which is responsible for update of compute instance container:

- name: gcr.io/cloud-builders/gcloud
  args:
    - '-c'
    - >-
        gcloud compute instances update-container my-amazing-api --container-image us.gcr.io/api/my-amazing-api/my-amazing-api:latest --zone us-central1-a
  entrypoint: bash

And in the end we simply declare the values assigned to variable used in configuration file:

images:
    - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:latest'
options:
    substitutionOption: ALLOW_LOOSE
substitutions:
    _SERVICE_NAME: my-amazing-api
    _DEPLOY_REGION: us-central1
    _GCR_HOSTNAME: us.gcr.io
tags:
    - my-amazing-api

At this stage every time we push to a master branch (or whatever your Cloud Build configuration is) a new container is built, pushed and updated within your container-optimised Google Cloud VM instance.