Learning Path: Transform a monolith into a GKE app - Deploy the app to a GKE cluster Stay organized with collections Save and categorize content based on your preferences.
This is the fifth and final tutorial in a learning path that teaches you how tomodularize and containerize a monolithic app.
The learning path consists of the following tutorials:
- Overview
- Understand the monolith
- Modularize the monolith
- Prepare the modular app for containerization
- Containerize the modular app
- Deploy the app to a GKE cluster (this tutorial)
In the previous tutorial,Containerize the modular app, youprepared the modular Cymbal Books app for deployment. You containerized theapp's modules, tested the resulting containers, and pushed the container imagestoArtifact Registry.
In this tutorial, you deploy the containerized app to a Google Kubernetes Engine cluster.This step completes the transformation of the Cymbal Books app into a modularand scalable system that runs on a Kubernetes cluster.
Costs
Following the steps in this tutorial incurs charges on your Google Cloudaccount. Costs begin when you enable GKE and deploy the CymbalBooks sample app. These costs include per-cluster charges forGKE, as outlined on thePricing page, and charges for runningCompute Engine VMs.
To avoid unnecessary charges, ensure that you disable GKE ordelete the project once you have completed this tutorial.
Before you begin
Before you begin this tutorial, make sure that you completed the earliertutorials in the series. For an overview of the whole series, and links toparticular tutorials, seeLearning Path: Transform a monolith into a GKE app - Overview.
In particular, you need to have performed the steps in the previous tutorial,Containerize the modular app.
Set up the GKE cluster
Before you can deploy the modular Cymbal Books app, you must first create aGKE cluster. This cluster provides the infrastructure in whichyour app's containers will run.
In this tutorial, you use thegcloud CLI to create thecluster. Alternatively, you can use theGoogle Cloud console, which provides agraphical user interface (GUI) for creating and managing Google Cloudresources such as GKE clusters.
Create and verify a GKE cluster
A GKE cluster provides the computing resources that are needed torun your containers in Kubernetes. Follow these steps to create a cluster byusing thegcloud CLI.
Go to theGoogle Cloud console.
In the console, click theActivate Cloud Shell button:

A Cloud Shell session opens inside a frame lower on the console.
Set your default project in the Google Cloud CLI:
gcloudconfigsetprojectPROJECT_IDReplace
PROJECT_IDwith the project ID of the projectthat you created or selected in theselect or create a Google Cloud projectsection of the previous tutorial. A project ID is a unique string thatdifferentiates your project from all other projects in Google Cloud. Tolocate the project ID, go to theproject selector.On that page, you can see the project IDs for each of your Google Cloudprojects.Create a GKE cluster:
gcloudcontainerclusterscreateCLUSTER_NAME\--location=CONTROL_PLANE_LOCATION\--num-nodes=2Replace the following:
CLUSTER_NAME: a name for your cluster, such ascymbal-cluster.CONTROL_PLANE_LOCATION: the Compute Enginelocation of the control plane of yourcluster. Provide a region for regional clusters, or a zone for zonal clusters, such asus-central1oreurope-west1-b.
Retrieve the cluster's credentials so that the
kubectlCLI can connect tothe cluster:gcloudcontainerclustersget-credentialsCLUSTER_NAME\--location=CONTROL_PLANE_LOCATIONThis command updates your Kubernetes config file, which is stored by defaultin
~/.kube/config. This config file contains the credentials thatkubectlrequires to interact with your GKE cluster.Verify that
kubectlis connected to the cluster by listing the clusternodes:kubectlgetnodesIf the setup is successful, this command lists the nodes in yourGKE cluster. Because you created the cluster with
--num-nodes=2, you should see information about two nodes, similar to thefollowing:NAME STATUS ROLES AGE VERSIONgke-nov18-default-pool-6a8f9caf-bryg Ready <none> 30s v1.30.8-gke.1128000gke-nov18-default-pool-6a8f9caf-ut0i Ready <none> 30s v1.30.8-gke.1128000In this example, both nodes are in the
Readystate. This state means thatthe GKE cluster is ready to host your containerizedworkloads!
Deploy the app
Now that you've created a GKE cluster, you can deploy the CymbalBooks app to it. To deploy an app to a cluster, you apply the Kubernetesmanifest to the cluster.
Apply the Kubernetes manifest
In Cloud Shell, deploy the app to the GKE cluster by runningthe following commands:
Navigate to the root directory of the containerized application:
cdkubernetes-engine-samples/quickstarts/monolith-to-microservices/containerized/Apply the Kubernetes manifest:
kubectlapply-fkubernetes_manifest.yaml
The previous command instructs Kubernetes to create the resources specified inthekubernetes-manifest.yaml file. These resources include Services, aDeployment, and Pods.
You first encountered Services in theChange the modular code section in thePrepare the modular app for containerization tutorial.In that tutorial, you updated the app's code to use Service names instead oflocalhost. That update enables Kubernetes to route requests between modulesand ensures that the modules can communicate with each other within a cluster.Now, when you apply the manifest, Kubernetes creates the Services inside thecluster.
ADeployment is a Kubernetes API object that lets you run multiple replicas of Pods that are distributed among the nodes in a cluster.. The next section explains what Pods are.
What is a Kubernetes Pod?
In the previous tutorial, you created a container image for each module of theCymbal Books app. For example, you created container images based on thehome_app andbook_details_app modules.
When you use thekubectl apply command to deploy the Kubernetes manifest,Kubernetes pulls your container images from Artifact Registry into the cluster. In thecluster, the container images become containers, and the containers run insidePods.
A Pod is an isolated environment in which containers run, and it performs thefollowing tasks:
- Allocates CPU and memory: a Pod provides the resources that containersneed to operate.
- Provides networking: each Pod has its own IP address. This enables thePod to communicate with other Pods.
Pods run onnodes, which are the machines that provide computing power forthe cluster. Kubernetes automatically assigns Pods to nodes and distributes thePods across the cluster's nodes to reduce the risk of overloading any singlenode. This distribution helps the cluster use its computing and memory resourcesefficiently.
Verify the Deployment
After you apply the Kubernetes manifest with thekubectl apply command, verifythat the app was deployed successfully to the cluster. To verify theDeployment, check that the Pods and Services are running correctly.
Check the Pods
To view the Pods in your cluster, run the following command:
kubectlgetpodsThis command lists the Pods and their current status. Look for theSTATUScolumn to confirm that all Pods are marked asRunning, which indicates thatthey are successfully running and ready to serve requests. The expected outputlooks like the following:
NAME READY STATUS RESTARTS AGEhome-app-67d59c6b6d-abcde 1/1 Running 0 30sbook-details-app-6d8bcbc58f-xyz 1/1 Running 0 30sbook-reviews-app-75db4c4d7f-def 1/1 Running 0 30simages-app-7f8c75c79c-ghi 1/1 Running 0 30sA Pod's status initially appears asPending while it's being created and itscontainers are in the process of starting. If a Pod remainsPending for anextended period, the cluster might lack sufficient resources for that Pod toenter a healthyRunning state. If a Pod has a status ofCrashLoopBackOff,there might be a problem with the container. Troubleshooting steps are providedlater in the tutorial.
Check the Services
Services enable communication between Pods and allow external clients (forexample, users, automated scripts, or monitoring tools) to access the app. Toview the Services in your cluster, run the following command:
kubectlgetservicesOutput from this command looks like the following:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEhome-app-service LoadBalancer 10.12.3.4 35.185.1.2 80:30837/TCP 30sdetails-service ClusterIP 10.12.3.5 <none> 80/TCP 30sreviews-service ClusterIP 10.12.3.6 <none> 80/TCP 30simages-service LoadBalancer 10.12.3.7 34.125.6.3 80:32014/TCP 30sKey fields to observe in the output are the following:
TYPE: this field indicates how the Service is exposed.Services of typeLoadBalancerprovide external access to the app.EXTERNAL-IP: for a Service of typeLoadBalancer, theEXTERNAL-IPfield shows the public IP address that users can enter intotheir web browser to access the app. For a Service of typeClusterIP, thisfield is empty becauseClusterIPServices are only accessiblewithin the cluster.
Test the deployment
After you deploy the Cymbal Books app to the GKE cluster, verifythat the app is accessible and that the containers can communicate with eachother.
Access the app
Confirm that the app is accessible by following these steps:
Retrieve the external IP address for the
home-app-service:kubectlgetservicesLook for the
**EXTERNAL-IP**column in the output, and note the IP addressthat's associated withhome-app-service.Open a web browser and enter the following URL:
http://EXTERNAL-IPReplace
EXTERNAL-IPwith the IP address that you foundin the previous step.Verify that the homepage of the Cymbal Books app loads correctly.
Verify inter-service communication
The containers in the Cymbal Books app rely on Services to exchange information.Ensure that the containers can communicate effectively by following these steps:
Retrieve the external IP address for the
home-app-serviceas describedearlier.Use the app's interface to test interactions between containers. To do that,confirm that the following features work by clicking all available links inthe app's interface:
- Check book cover images: confirm that the book cover images loadcorrectly on both the homepage and the book details page. If they do,
home_appandbook_details_appcontainers are successfullycommunicating with theimages_appcontainer. - View book details: navigate to a book details page from the homepage. If you see a book's details, the
home_appcontainer is correctlycommunicating with thebook_details_app. - View book reviews: click a book review link to verify that the
home_appcontainer can communicate with thebook_reviews_appcontainer.
- Check book cover images: confirm that the book cover images loadcorrectly on both the homepage and the book details page. If they do,
Your app is now running on a GKE cluster!
Congratulations! You've seen how to transform a monolithic app into a modular,containerized system that runs on a live GKE cluster. Along theway, you learned how to divide tightly coupled code into independent modules,build and push container images to a repository, define Kubernetes manifests,and deploy your app from the registry to GKE. That's a majoraccomplishment, and it reflects the real-world steps teams take to modernizeapplications for the cloud!
Troubleshooting
If the app doesn't respond or containers fail to communicate, use the followingtroubleshooting steps to diagnose and resolve common issues.
Check the status of your Pods
Start by listing all Pods in your cluster to determine if they are running asexpected:
kubectlgetpodsReview the output to confirm that each Pod is in theRunning state. If any Podisn't running, note its name for further inspection.
Inspect Pod logs
If a Pod isn't handling requests properly, check its logs to look for any errormessages:
kubectllogsPOD_NAMEReplacePOD_NAME with the name of the Pod you want toinspect. This command is useful for identifying startup issues or runtimeerrors.
Describe a Pod for detailed information
If a Pod remains in a non-Running state for longer than five minutes—forexample, it's in aPending,ContainerCreating, orCrashLoopBackOffstate—you can see detailed information about the Pod's status and eventsby using the following command:
kubectldescribepodPOD_NAMEReplacePOD_NAME with the name of the Pod that you wantdetailed information about.
TheEvents section in the output might indicate that resource constraints orissues with image pulls are preventing the Pod from starting properly.
Verify Service configuration
Ensure that your Services are set up correctly, especially the Service thatexposes the home module with an external IP address. List the Services with thefollowing command:
kubectlgetservicesIf you notice that the Service for the home module has anEXTERNAL-IP addressthat's listed asPending, run the following command:
kubectldescribeserviceSERVICE_NAMEReplaceSERVICE_NAME with the name of the home moduleService.
This command provides more details about the Service configuration and helps youidentify delays in assigning the external IP address or other configurationissues.
Check cluster events
You can examine cluster events to determine if a problem is affecting multiplecomponents of your cluster:
kubectlgeteventsThis command can determine if broader resource or network issues are affectingyour deployment.
Clean up resources
Running a GKE cluster incurs costs. After you complete thistutorial, clean up your resources to avoid additional charges. Follow thesesteps to remove the cluster and, optionally, the entire project.
Delete the GKE cluster
To delete the GKE cluster, use the following command:
gcloudcontainerclustersdeleteCLUSTER_NAME--location=CONTROL_PLANE_LOCATIONReplace the following:
CLUSTER_NAME: the name of the cluster you created, suchascymbal-cluster.CONTROL_PLANE_LOCATION: the Compute Enginelocation of the control plane of yourcluster. Provide a region for regional clusters, or a zone for zonal clusters.
When prompted, confirm the deletion.
Verify that the cluster is deleted
To ensure that the cluster was deleted, run the following command:
gcloudcontainerclusterslistThe cluster should no longer appear in the output. If it does, wait a fewmoments and try again.
(Optional) Delete the Google Cloud project
If you created a Google Cloud project specifically for this tutorial and you nolonger need it, you can delete the entire Google Cloud project. Deleting theproject removes all resources and stops billing for the project:
- In the Google Cloud console, open theManage Resources page.
- Select the project you want to delete.
- ClickDelete Project and follow the prompts to confirm.
Summary of the series
Congratulations! By completing this learning path, you've learned thefundamentals of converting a monolithic app into a modular, containerized appthat runs on a Kubernetes cluster. The following steps summarize the process:
- Explored the structure of the Cymbal Books monolithic app.
- Set up a local Python environment to run the monolith and tested itsendpoints.
- Gained an understanding of the app's codebase to prepare it formodularization.
- Learned how to split monolithic code into separate modules. Each modulehandles a distinct feature, such as displaying book details or reviews.
- Saw how these modules are implemented as independent Flask apps runningon different ports.
- Tested the modularized app.
Prepare the modular code for containerization
- Learned that you had to update URLs in
home.pyto use Service namesinstead oflocalhost. - Learned how the Kubernetes manifest defines Services that enable theapp's modules, which already communicate with each other, to find eachother within the context of a Kubernetes cluster.
- Learned that you had to update URLs in
- Set up a Google Cloud project and cloned the app from GitHub intoCloud Shell.
- Built container images for each module using Docker and testedcontainers locally.
- Pushed the container images to Artifact Registry to prepare the app fordeployment to a cluster.
- Updated the Kubernetes manifest to refer to the container image paths inArtifact Registry.
Deploy the app to a GKE cluster (the tutorial you're in now):
- Created a GKE cluster.
- Deployed the container images from Artifact Registry to the GKEcluster.
- Tested the final version of the app, which is now scalable and runs in aKubernetes environment!
What's next
For further practical training about how to create clusters, see our series,Learning Path: Scalable applications.
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2026-02-18 UTC.