Time: 1 hour 30 minutes
Difficulty: Intermediate
Price: 5 Credits
Quest: Build a Website on Google Cloud
Last updated: May 23, 2023
You have just started a new role at FancyStore, Inc.
Your task is to take the company's existing monolithic e-commerce website and break it into a series of logically separated microservices. The existing monolith code is sitting in a GitHub repo, and you will be expected to containerize this app and then refactor it.
You are expected to have the skills and knowledge for these tasks, so don't expect step-by-step guides.
You have been asked to take the lead on this, after the last team suffered from monolith-related burnout and left for greener pastures (literally, they are running a lavender farm now). You will be tasked with pulling down the source code, building a container from it (one of the farmers left you a Dockerfile), and then pushing it out to GKE.
You should first build, deploy, and test the Monolith, just to make sure that the source code is sound. After that, you should break out the constituent services into their own microservice deployments.
Some FancyStore, Inc. standards you should follow:
- Create your cluster in
us-central1
. - Naming is normally team-resource, e.g. an instance could be named fancystore-orderservice1.
- Allocate cost effective resource sizes. Projects are monitored and excessive resource use will result in the containing project's termination.
- Use the
n1-standard-1
machine type unless directed otherwise.
As soon as you sit down at your desk and open your new laptop, you receive the following request to complete these tasks. Good luck!
Export the following variables in the Cloud Shell:
export MONOLITH_IDENTIFIER=
export CLUSTER_NAME=
export ORDERS_IDENTIFIER=
export PRODUCTS_IDENTIFIER=
export FRONTEND_IDENTIFIER=
from the labs variables, you can copy the value of each variable and paste it in the cloud shell
Note: Don't forget to replace the value of each variable with the value of the labs variable
Note: Don't forget to enable the API's
gcloud services enable cloudbuild.googleapis.com
gcloud services enable container.googleapis.com
First things first, you'll need to clone your team's git repo.
git clone https://github.com/googlecodelabs/monolith-to-microservices.git
There's a setup.sh
script in the root directory of the project that you'll need to run to get your monolith container built up.
cd ~/monolith-to-microservices
./setup.sh
After running the setup.sh script, ensure your Cloud Shell is running its latest version of nodeJS.
nvm install --lts
There's a Dockerfile located in the ~/monotlith-to-microservices/monolith
folder which you can use to build the application container. Before building the Docker container, you can preview the monolith application on port 8080.
Note: You can skip previewing the application if you want to, but it's a good idea to make sure it's working before you containerize it.
cd ~/monolith-to-microservices/monolith
npm start
CTRL+C
to stop the application.
You will have to run Cloud Build (in that monolith folder) to build it, then push it up to GCR. Name your artifact as follows:
- GCR Repo: gcr.io/${GOOGLE_CLOUD_PROJECT}
- Image name:
MONOLITH_IDENTIFIER
- Image version: 1.0.0
gcloud services enable cloudbuild.googleapis.com
gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${MONOLITH_IDENTIFIER}:1.0.0 .
Create your cluster as follows:
- Cluster name:
CLUSTER_NAME
- Region: us-central1-a
- Node count: 3
gcloud config set compute/zone us-central1-a
gcloud services enable container.googleapis.com
gcloud container clusters create $CLUSTER_NAME --num-nodes 3
gcloud container clusters get-credentials $CLUSTER_NAME
Create and expose your deployment as follows:
- Cluster name:
CLUSTER_NAME
- Container name:
MONOLITH_IDENTIFIER
- Container version: 1.0.0
- Application port: 8080
- Externally accessible port: 80
kubectl create deployment $MONOLITH_IDENTIFIER --image=gcr.io/${GOOGLE_CLOUD_PROJECT}/${MONOLITH_IDENTIFIER}:1.0.0
kubectl expose deployment $MONOLITH_IDENTIFIER --type=LoadBalancer --port 80 --target-port 8080
Make note of the IP address that is assigned in the expose deployment operation. Use this command to get the IP address:
kubectl get service
You should now be able to visit this IP address from your browser and see the following:
Below is the set of services which need to be containerized. Navigate to the source roots mentioned below, and upload the artifacts which are created to the Google Container Registry with the metadata indicated. Name your artifact as follows:
Orders Microservice
- Service root folder:
~/monolith-to-microservices/microservices/src/orders
- GCR Repo: gcr.io/${GOOGLE_CLOUD_PROJECT}
- Image name:
ORDERS_IDENTIFIER
- Image version: 1.0.0
cd ~/monolith-to-microservices/microservices/src/orders
gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${ORDERS_IDENTIFIER}:1.0.0 .
Products Microservice
- Service root folder:
~/monolith-to-microservices/microservices/src/products
- GCR Repo: gcr.io/${GOOGLE_CLOUD_PROJECT}
- Image name:
PRODUCTS_IDENTIFIER
- Image version: 1.0.0
cd ~/monolith-to-microservices/microservices/src/products
gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${PRODUCTS_IDENTIFIER}:1.0.0 .
Deploy these new containers following the same process that you followed for the MONOLITH_IDENTIFIER
monolith. Note that these services will be listening on different ports, so make note of the port mappings in the table below. Create and expose your deployments as follows:
Orders Microservice
- Cluster name:
CLUSTER_NAME
- Container name:
ORDERS_IDENTIFIER
- Container version: 1.0.0
- Application port: 8081
- Externally accessible port: 80
kubectl create deployment $ORDERS_IDENTIFIER --image=gcr.io/${GOOGLE_CLOUD_PROJECT}/${ORDERS_IDENTIFIER}:1.0.0
kubectl expose deployment $ORDERS_IDENTIFIER --type=LoadBalancer --port 80 --target-port 8081
Products Microservice
- Cluster name:
CLUSTER_NAME
- Container name:
PRODUCTS_IDENTIFIER
- Container version: 1.0.0
- Application port: 8082
- Externally accessible port: 80
kubectl create deployment $PRODUCTS_IDENTIFIER --image=gcr.io/${GOOGLE_CLOUD_PROJECT}/${PRODUCTS_IDENTIFIER}:1.0.0
kubectl expose deployment $PRODUCTS_IDENTIFIER --type=LoadBalancer --port 80 --target-port 8082
Get the external IP addresses for the Orders and Products microservices:
kubectl get svc -w
CTRL+C
to stop the command.
Now you can verify that the deployments were successful and that the services have been exposed by going to the following URLs in your browser:
http://ORDERS_EXTERNAL_IP/api/orders
http://PRODUCTS_EXTERNAL_IP/api/products
Write down the IP addresses for the Orders and Products microservices. You will need them in the next task.
Note: You can use the lab method or use my method. Choose one that suits you.
- My method (Using sed (stream editor) and using one-line command)
export ORDERS_SERVICE_IP=$(kubectl get services -o jsonpath="{.items[1].status.loadBalancer.ingress[0].ip}")
export PRODUCTS_SERVICE_IP=$(kubectl get services -o jsonpath="{.items[2].status.loadBalancer.ingress[0].ip}")
cd ~/monolith-to-microservices/react-app
sed -i "s/localhost:8081/$ORDERS_SERVICE_IP/g" .env
sed -i "s/localhost:8082/$PRODUCTS_SERVICE_IP/g" .env
npm run build
- The lab method (Using nano text editor)
Use the nano
editor to replace the local URL with the IP address of the new Products microservices.
cd ~/monolith-to-microservices/react-app
nano .env
When the editor opens, your file should look like this.
REACT_APP_ORDERS_URL=http://localhost:8081/api/orders
REACT_APP_PRODUCTS_URL=http://localhost:8082/api/products
Replace the REACT_APP_ORDERS_URL
and REACT_APP_PRODUCTS_URL
to the new format while replacing with your Orders and Product microservice IP addresses so it matches below.
REACT_APP_ORDERS_URL=http://<ORDERS_IP_ADDRESS>/api/orders
REACT_APP_PRODUCTS_URL=http://<PRODUCTS_IP_ADDRESS>/api/products
Press CTRL+O, press ENTER, then CTRL+X to save the file in the nano
editor. Now rebuild the frontend app before containerizing it.
npm run build
The final step is to containerize and deploy the Frontend. Use Cloud Build to package up the contents of the Frontend service and push it up to the Google Container Registry.
- Service root folder:
~/monolith-to-microservices/microservices/src/frontend
- GCR Repo: gcr.io/${GOOGLE_CLOUD_PROJECT}
- Image name:
FRONTEND_IDENTIFIER
- Image version: 1.0.0
cd ~/monolith-to-microservices/microservices/src/frontend
gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${FRONTEND_IDENTIFIER}:1.0.0 .
Deploy this container following the same process that you followed for the Orders and Products microservices. Create and expose your deployment as follows:
- Cluster name:
CLUSTER_NAME
- Container name:
FRONTEND_IDENTIFIER
- Container version: 1.0.0
- Application port: 8080
- Externally accessible port: 80
kubectl create deployment $FRONTEND_IDENTIFIER --image=gcr.io/${GOOGLE_CLOUD_PROJECT}/${FRONTEND_IDENTIFIER}:1.0.0
kubectl expose deployment $FRONTEND_IDENTIFIER --type=LoadBalancer --port 80 --target-port 8080
kubectl get svc -w
CTRL+C
to stop the command.
Wait until you see the external IP address and check the progress.