Sunday, August 16, 2020

Using GCP Source Repository, Cloud Build to configure automatic deployment of docker container on Google Cloud Run

Introduction 

In this article I will walk through the steps required to setup continuous integration environment and create build pipeline and automate deployment of a sample Angular App on Google Cloud Run. I will be using GCP stack end-end. Cloud Source Repositories for Git repository for version control, Cloud Build for creating docker containers which will be stored on Container Registry and then deploying the image on Cloud Run - serverless runtime environment. Finally, I will outline steps for configuring automated integration/deployment that will trigger builds and deployment of new version of application for any merge. 

Key Concepts and Services

Cloud Source Repositories - Fully managed free git repository from Google Cloud to storing and version control of source code. Tightly integrated with Cloud Build for triggering build for continuous integration. 

Docker - software that is most popularly used to build containers. Docker would combining the application code and set of instructions called DockerFile and produce a container that contains code all the required dependencies (listed as part of instructions in the docker file) to run the code. 

Containers - a self contained environment that can be run on many platforms 

Cloud Build - provide service similar to Docker and integrated with Cloud Source Repositories and can be triggered to produce container images and provides Continuous development and Continuous deployment. Cloud build can be configured to push the images to container registry and deployed to Cloud Run

Container Registry - Google Cloud Repository that can be used for hosting container images produced by Cloud Build

Cloud Run is fully managed serverless compute platform to deploy and running containerized application. Managed Serverless environment allows you to focus on your application and not worry about the underlying infrastructure or setting up and managing runtime environments. 

Steps

  1. Build a sample angular application
  2. Create Git Repository
  3. Containerize the application
  4. Build Container Image
  5. Verify Image in Container Registry
  6. Deploy Image to Cloud Run
  7. Configure continuous integration / deployment (CI/CD)

Pre-requisites

  1. GCP account
  2. GCloud sdk installed on development machine
  3. Nodejs/Angular CLI (for angular project)
  4. Enable APIs on GCP - Cloud Run API, Container Registry, Cloud build

Build Sample angular application

Create a Simple angular app and test locally. 
ng new my-app
cd my-app ng serve --open

Create Git Repository


Log on to GCP console and Create a project

 
From hamburger menu on left go to Source Repositories. Create a new project my-app and click Add repository button (on top right) and select Create New Repository option.

Provide name, say my-app select project id and click Create

There are multiple options to upload your code:

Option 1 - Using Google Cloud SDK 



Initialize GCloud


gcloud init && git config --global credential.https://source.developers.google.com.helper gcloud.sh

Make sure to select the correct account and project created above

Add Cloud Repository as repository


git remote add google https://source.developers.google.com/p/cloud-run-blog/r/my-app

Push code from local git repository

git push --all google

Refresh browser - you should see your code



Option 2 - using SSH Authentication


Note: instructions below are for mac

Create and register key 
cd ~/.ssh && ssh-keygen

Copy the file in memory
cat ~/.ssh/id_rsa.pub | pbcopy

Register SSH key on Google Cloud

Click on options on top right and click Manage SSH Keys


Clone this repository to a local Git repository:

git clone ssh://mbhasin@gmail.com@source.developers.google.com:2022/p/cloud-run-blog/r/my-app

Push the code
cd my-app2
git push -u origin master

Configure web server

Containerize your application

Before we define the Docker file we need to do one more step. By default, angular app runs on port 4200. To expose the web app we will use nginx server. Create a folder nginx under root and create file default.conf under it and add following contents.

server {
listen 80;
sendfile on;
default_type application/octet-stream;
gzip on;
gzip_http_version 1.1;
gzip_disable "MSIE [1-6]\.";
gzip_min_length 1100;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
gzip_comp_level 9;
root /usr/share/nginx/html;
location / {
try_files $uri $uri/ /index.html =404;
}
}

Create a DockerFile under application root and populate with following:

FROM node as builder
COPY package.json package-lock.json ./
RUN npm ci && mkdir /ng-app && mv ./node_modules ./ng-app
WORKDIR /ng-app
COPY . .
RUN npm run ng build -- --prod --output-path=dist
FROM nginx
COPY nginx/default.conf /etc/nginx/conf.d/
RUN rm -rf /usr/share/nginx/html/*
COPY --from=builder /ng-app/dist /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]

Checkin the code

git add .
git commit -m "containerizing the app"
git push --all google

Build Container Image

From Cloud Source Repositories page select my-app and then click on the button Edit Code (top right)


On the console window below give command to build the image

gcloud builds submit --tag gcr.io/cloud-run-blog/my-app-image

This command will use get docker image and start executing the instructions on the Dockerfile configured and included in the source code earlier

mbhasin@cloudshell:~/cloudshell_open/my-app (cloud-run-blog)$ cloud builds submit --tag gcr.io/cloud-run-blog/my-app-imageCreating temporary tarball archive of 33 file(s) totalling 558.4 KiB before compression.Some files were not included in the source upload.Check the gcloud log [/tmp/tmp.6uBFOBZmOk/logs/2020.08.17/00.02.18.534654.log] to see which files and the contents of thedefault gcloudignore file used (see `$ gcloud topic gcloudignore` to learnmore).Uploading tarball of [.] to [gs://cloud-run-blog_cloudbuild/source/1597622538.788477-eb6c8ebe5ab04462b08e8878b090e231.tgz]Created [https://cloudbuild.googleapis.com/v1/projects/cloud-run-blog/builds/97ddb164-fae6-4057-8d52-b006c13312e0].Logs are available at [https://console.cloud.google.com/cloud-build/builds/97ddb164-fae6-4057-8d52-b006c13312e0?project=268340482308].------------------------------------------------------------------------------------ REMOTE BUILD OUTPUT ------------------------------------------------------------------------------------starting build "97ddb164-fae6-4057-8d52-b006c13312e0"FETCHSOURCEFetching storage object: gs://cloud-run-blog_cloudbuild/source/1597622538.788477-eb6c8ebe5ab04462b08e8878b090e231.tgz#1597622539464344Copying gs://cloud-run-blog_cloudbuild/source/1597622538.788477-eb6c8ebe5ab04462b08e8878b090e231.tgz#1597622539464344.../ [1 files][142.8 KiB/142.8 KiB]Operation completed over 1 objects/142.8 KiB.

After successful completion you should see something like following

DONE---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ID CREATE_TIME DURATION SOURCE IMAGES STATUS97ddb164-fae6-4057-8d52-b006c13312e0 2020-08-17T00:02:19+00:00 3M4S gs://cloud-run-blog_cloudbuild/source/1597622538.788477-eb6c8ebe5ab04462b08e8878b090e231.tgz gcr.io/cloud-run-blog/my-app-image (+1 more) SUCCESSm

Verify image in Container Registry



Deploy Image to Cloud Run

From Console:

Click on three vertical dots on the right end and select the option Deploy to Cloud Run



This will take you to Cloud Run page and launch the wizard to give you opportunity to configure the deployment - select Region, authentication and click Create





This will open the Cloud Run page and start the deployment. After about 1 min you will see the deployment complete. 





Go to Cloud Build. You can create a separate build config file (using YAML or JSON syntax) but in our case we are using Dockerfile created earlier. 

Go to Details tab and click on URL to launch the application in browser



Deploying from cloudshell CLI:

gcloud run deploy --image gcr.io/cloud-run-blog/my-app-image --platform managed


Configure CI/CD

Finally, you can automate deployment such that whenever new code is merged it will trigger cloud build and after successful build the new version of the app will be deployed. 

While on Cloud Run page click on the service name my-app-image and then click Setup Continuous Deployment button on the top right corner (refer last screenshot above)


Select Cloud Source Repository and my-app for the Repository



While on Click on Settings button (gear shaped - top right of the page) and click Next. Provide Build Configuration and select Build Type as Dockerfile



You will see message - Setting up continuous deployment


Verify build trigger

If you go back to Cloud Build page and then Triggers section you will now see a trigger for my-app

Click on the name to see configuration file. It also allows you to define variables whose value can be substituted at build time. For example, project id, build id etc.

Another navigation path to configure triggers from Cloud Source Repository page. Click on link Cloud Build Triggers and it will take you to Cloud Build's Triggers section. 


Then click on Create Trigger button on  and list all the repositories configured in this project



Conclusion 


In this blog we walked though the steps to configure development environment on GCP. From configuring Git repository to setting up automated builds for continuous integration/deployment on serverless managed environment Cloud Run.



No comments:

Understanding JavaScript Prototypal Inheritance for Java developers

Inheritance is a fundamental concept in programming languages. However, it is implemented differently in Object-Oriented Languages such as J...