<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Kubernetes Archives - Codersee blog- Kotlin on the backend</title>
	<atom:link href="https://blog.codersee.com/tag/kubernetes/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Kotlin &#38; Backend Tutorials - Learn Through Practice.</description>
	<lastBuildDate>Wed, 16 Apr 2025 04:50:30 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://blog.codersee.com/wp-content/uploads/2025/04/cropped-codersee_logo_circle_2-32x32.png</url>
	<title>Kubernetes Archives - Codersee blog- Kotlin on the backend</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Deploy Kotlin Spring Boot App with MySQL on Kubernetes</title>
		<link>https://blog.codersee.com/deploy-kotlin-spring-boot-app-with-mysql-on-kubernetes/</link>
					<comments>https://blog.codersee.com/deploy-kotlin-spring-boot-app-with-mysql-on-kubernetes/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Thu, 22 Oct 2020 07:50:57 +0000</pubDate>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<guid isPermaLink="false">http://codersee.com/?p=1542</guid>

					<description><![CDATA[<p>In this article, we will learn how to deploy the Kotlin Spring Boot application with MySQL on Kubernetes cluster.</p>
<p>The post <a href="https://blog.codersee.com/deploy-kotlin-spring-boot-app-with-mysql-on-kubernetes/">Deploy Kotlin Spring Boot App with MySQL on Kubernetes</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="article-heading-introduction">1. Introduction</h2>
<p><a href="http://codersee.com/spring-boot-on-google-gke-with-cloud-sql-and-kotlin/" target="_blank" rel="noopener noreferrer">Last week</a>, we&#8217;ve learned how to deploy the <strong>Spring Boot</strong> application to <strong>Google Kubernetes Engine</strong> and connect it to the <strong>CloudSQL</strong> instance of <strong>MySQL</strong> database.</p>
<p>This time, I want to show you a more universal approach- deploying the <strong>Kotlin Spring Boot App with MySQL directly on Kubernetes</strong>. This approach requires a little more setup, but thanks to that, we gain more independence- we can easily migrate our environment between Kubernetes managed services providers (or to self-hosted k8s).</p>
<h2 class="article-heading-main">2. Prerequisites</h2>
<p>To follow the tutorial you need the following prerequisites:</p>
<ul>
<li><a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/" target="_blank" rel="noopener noreferrer">kubectl</a> (Kubernetes CLI to manage a cluster)</li>
<li><a href="https://minikube.sigs.k8s.io/docs/start/" target="_blank" rel="noopener noreferrer">minikube</a> (local Kubernetes, making it easy to learn and develop for Kubernetes)</li>
<li><a href="https://docs.docker.com/engine/install/" target="_blank" rel="noopener noreferrer">docker</a> (containerization tool)</li>
</ul>
<h2 class="article-heading-main">3. Create Spring Boot Application</h2>
<p>In this tutorial, I&#8217;d like to begin with developing our <strong>Spring Boot app</strong> first (but it&#8217;s also OK to start with the Kubernetes part).</p>
<h3 class="article-heading-sub">3.1. Imports</h3>
<p>As the first step, let&#8217;s add the following dependencies:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="groovy">    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    runtimeOnly("mysql:mysql-connector-java")
</pre>
<p>Please remember, that you can see the full <a href="https://github.com/codersee-blog/kotlin-spring-boot-mysql-k8s/blob/master/build.gradle.kts" target="_blank" rel="noopener noreferrer">build.gradle configuration here</a>.</p>
<h3 class="article-heading-sub">3.2. Configure Application Properties</h3>
<p>After we&#8217;ve successfully added the import, let&#8217;s head to the <strong>application.yaml</strong> file and configure it as follows:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="yaml">spring:
  datasource:
    url: jdbc:mysql://mysql-svc:3306/${DB_NAME}?useSSL=false
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}
  jpa:
    hibernate:
      ddl-auto: update
    databasePlatform: "org.hibernate.dialect.MySQL5InnoDBDialect"
</pre>
<p>As you might have noticed, we are setting the <em>MySQL connection details</em> here. Please remember, that the host (<em><strong>mysql-svc</strong></em>) has to match the MySQL Kubernetes service name (we will set it up later). The <em><strong>ddl-auto</strong></em> property set to <em><strong>update</strong></em> will automatically export the schema DDL to the database when the SessionFactory is created (to put it simply, it will create the database schema based on our Spring Boot entities).</p>
<h3 class="article-heading-sub">3.2. Create Model</h3>
<p>As the next step, let&#8217;s add two classes to our project. <strong>User</strong> class, which will be the user entity we will persist in our MySQL database:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@Entity
class User(
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0,

    @Column
    val name: String
)
</pre>
<p>As you can see, it is a simple class containing two fields- autogenerated <em>id</em> and a<em> name</em>.</p>
<p>Nextly, let&#8217;s add <strong>UserRequest</strong>, which will be bound to the bodies of the web requests later:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">class UserRequest(
    val name: String
)
</pre>
<h3 class="article-heading-sub">3.4. Create Repository</h3>
<p>After that, we can create the <strong>UserRepository</strong> interface, which will be used to perform the operations on the database:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">interface UserRepository : CrudRepository&lt;User, Long&gt;
</pre>
<h3 class="article-heading-sub">3.4. Create Service</h3>
<p>As the next step, let&#8217;s implement the <strong>UserService</strong> class as follows:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@Service
class UserService(
    private val userRepository: UserRepository
) {

    fun saveUser(request: UserRequest): User =
        userRepository.save(
            User(
                name = request.name
            )
        )

    fun findAllUsers(): MutableIterable&lt;User&gt; =
        userRepository.findAll()
}
</pre>
<p>These two functions will be responsible for creating and getting the list of all users.</p>
<h3 class="article-heading-sub">3.5. Implement Controllers</h3>
<p>Finally, we can set up our controllers responsible for handling the incoming requests. Let&#8217;s start by adding the <strong>ApiStatusController</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@RestController
@RequestMapping("/api/status")
class ApiStatusController {
    @GetMapping
    fun getStatus(): ResponseEntity = ResponseEntity.ok("OK")
}
</pre>
<p>The <strong>GET /api/status</strong> endpoint will be used later to configure our <strong>K8s</strong> Pod&#8217;s readiness and liveness probes.</p>
<p>As the last step, let&#8217;s create the <strong>UserController</strong> class:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@RestController
@RequestMapping("/api/user")
class UserController(
    private val userService: UserService
) {
    @PostMapping
    fun createUser(@RequestBody request: UserRequest): ResponseEntity {
        val user = userService.saveUser(request)

        return ResponseEntity.ok(user)
    }

    @GetMapping
    fun findAllUsers(): ResponseEntity&lt;MutableIterable&gt; {
        val users = userService.findAllUsers()

        return ResponseEntity.ok(users)
    }
}
</pre>
<p>These two functions will be responsible for responding to the <strong>POST</strong> and <strong>GET</strong> requests to the<strong> /api/user</strong> endpoint. As you can see, we are using here the <strong>UserRequest</strong> class, we&#8217;ve implemented earlier as the <em><strong>createUser</strong></em> method parameter.</p>
<h3 class="article-heading-sub">3.6. Build the JAR</h3>
<p>Let&#8217;s build the jar with the Gradle wrapper:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">./gradlew clean build -x test
</pre>
<p>Please notice <strong>&#8220;-x test&#8221;</strong> flag here. Testing goes beyond the main topic of this tutorial, so I&#8217;ve decided to go with this workaround for now.</p>
<h3 class="article-heading-sub">3.7. Create Dockerfile</h3>
<p>Nextly, let&#8217;s create the <strong>Dockerfile</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">FROM openjdk
WORKDIR /work
COPY ./build/libs/k8s-mysql-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/work/app.jar"]
</pre>
<h2 class="article-heading-main">4. Deploy to Kubernetes</h2>
<p>In this part, we are going to prepare the <strong>Kubernetes</strong> environment for our <strong>Spring Boot application</strong>. To keep this article as pragmatic as possible, we won&#8217;t spend too much time on the details here. If you would like to get a better understanding of these topics, please, let me know about it and I will prepare more materials about it.</p>
<h3 class="article-heading-sub">4.1. Create Secrets</h3>
<p>As the first step, let&#8217;s create the <strong>secrets.yaml</strong> file and put the configuration for our secrets here:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="yaml">apiVersion: v1
kind: Secret
data:
  root-password: &lt;BASE64-ENCODED-PASSWORD&gt;
  database-name: &lt;BASE64-ENCODED-DB-NAME&gt;
  user-username: &lt;BASE64-ENCODED-DB-USERNAME&gt;
  user-password: &lt;BASE64-ENCODED-DB-PASSWORD&gt;
metadata:
  name: mysql-secret
</pre>
<p>In simple words, <strong>secrets</strong> let us store and manage sensitive information in a secure manner.<br />
Please also notice that all of the values should be encoded as<strong> base 64</strong>. You can do that for instance <a href="https://www.base64encode.org/" target="_blank" rel="noopener noreferrer">on this website.</a></p>
<h3 class="article-heading-sub">4.2. Create Persistent Volume</h3>
<p>As the next step, let&#8217;s create the <strong>deployment-mysql.yaml</strong> file:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="yaml">apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
  labels:
    type: local
spec:
  storageClassName: standard
  capacity:
    storage: 250Mi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"
  persistentVolumeReclaimPolicy: Retain
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
  labels:
    app: spring-boot-mysql
spec:
  storageClassName: standard
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 250Mi
</pre>
<p>A <strong>PersistentVolume (PV)</strong> is a piece of the storage in the cluster, while the <strong>PersistentVolumeClaim (PVC)</strong> is the request for storage.</p>
<h3 class="article-heading-sub">4.3. Create MySQL Deployment</h3>
<p><strong>Deployments</strong> allow us to provide updates for our <strong>Pods</strong> and <strong>ReplicaSets</strong> in a declarative manner. To configure the MySQL database let&#8217;s add the following config to our <strong>deployment-mysql.yaml</strong> file:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="yaml">---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-deployment
  labels:
    app: spring-boot-mysql
spec:
  selector:
    matchLabels:
      app: spring-boot-mysql
      tier: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: spring-boot-mysql
        tier: mysql
    spec:
      containers:
        - image: mysql:5.7
          name: mysql
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: root-password
            - name: MYSQL_DATABASE
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: database-name
            - name: MYSQL_USER
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: user-username
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: user-password
          ports:
            - containerPort: 3306
              name: mysql
          volumeMounts:
            - name: mysql-persistent-storage
              mountPath: /var/lib/mysql
      volumes:
        - name: mysql-persistent-storage
          persistentVolumeClaim:
            claimName: mysql-pvc
</pre>
<p>As you can see above, we are passing our 4 secrets to the MySQL container as the environment variables- these values will be used for our connection.</p>
<h3 class="article-heading-sub">4.4. Create MySQL Service</h3>
<p>Finally, we need to expose the database for our <strong>Spring Boot application</strong>. Let&#8217;s do that by creating the <strong>service-mysql.yaml</strong> file and putting the following confirugation:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="yaml">apiVersion: v1
kind: Service
metadata:
  name: mysql-svc
  labels:
    app: spring-boot-mysql
spec:
  ports:
    - port: 3306
  selector:
    app: spring-boot-mysql
    tier: mysql
  clusterIP: None
</pre>
<p>Please notice, that the <em><strong>name</strong></em> property of the metadata has to match the value from the <strong>application.yaml</strong> file of the<strong> Spring Boot</strong> project.</p>
<h3 class="article-heading-sub">4.5. Create Spring Boot Deployment</h3>
<p>After the <strong>MySQL</strong> part is correctly set up, we can configure the resources for our application. Let&#8217;s start by creating the <strong>deployment-spring.yaml</strong> file:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="yaml">apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-boot-deployment
  labels:
    app: spring-boot-mysql
spec:
  replicas: 2
  selector:
    matchLabels:
      app: spring-boot-mysql
  template:
    metadata:
      labels:
        app: spring-boot-mysql
    spec:
      containers:
        - image: spring-boot:0.0.1
          name: spring-boot-container
          imagePullPolicy: Never 
          ports:
            - containerPort: 8080
          readinessProbe:
            httpGet:
              port: 8080
              path: /api/status
            initialDelaySeconds: 10
            failureThreshold: 5
          livenessProbe:
            httpGet:
              port: 8080
              path: /api/status
            initialDelaySeconds: 10
            failureThreshold: 5
          env:
            - name: DB_NAME
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: database-name
            - name: DB_USERNAME
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: user-username
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: user-password
</pre>
<p>Please notice one important thing here- in the next steps, I will show you how to use the <strong>local Spring Boot Docker image</strong> of our application. That&#8217;s why we&#8217;ve set the <em><strong>imagePullPolicy</strong></em> property to <em><strong>Never</strong></em>.</p>
<h3 class="article-heading-sub">4.6. Create Spring Boot Service</h3>
<p>The last thing, we need to configure for our backend is a <strong>Service</strong>. Let&#8217;s create then the <strong>service-spring.yaml</strong> file:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="yaml">apiVersion: v1
kind: Service
metadata:
  name: spring-boot-svc
spec:
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
      name: http
  selector:
    app: spring-boot-mysql
  type: LoadBalancer
</pre>
<h3 class="article-heading-sub">4.7. Apply and Verify Resources</h3>
<p>Finally, we can deploy our configurations to the <strong>Kubernetes</strong> cluster. As the first step, let&#8217;s start a <strong>local</strong> <strong>Kubernetes</strong> <strong>cluster</strong> with <em><strong>minikube</strong></em>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">minikube start --vm-driver=virtualbox
</pre>
<p>As I&#8217;ve mentioned in step<strong> 4.5</strong>, in this tutorial, we will use the local docker image without pushing to any remote image repository.</p>
<p>To do that, let&#8217;s <strong>reuse the Docker daemon from Minikube</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">eval $(minikube docker-env)
</pre>
<p>Please keep in mind, that this is a <strong>Unix</strong> command. If you are using Windows OS, please check out <a href="https://stackoverflow.com/questions/1195494/equivalent-to-unix-eval-in-windows" target="_blank" rel="noopener noreferrer">this StackOverflow topic</a>.</p>
<p>Nextly, let&#8217;s build our docker image:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">docker build -t spring-boot:0.0.1 .
</pre>
<p>Please remember, that the tag has to match the value from our<strong> Spring Boot deployment</strong>.</p>
<p>As the last step, let&#8217;s apply our configurations:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">kubectl apply -f k8s/secrets.yaml
kubectl apply -f k8s/deployment-mysql.yaml 
kubectl apply -f k8s/service-mysql.yaml
kubectl apply -f k8s/deployment-spring.yaml
kubectl apply -f k8s/service-spring.yaml
</pre>
<p>To verify if everything is ready, we can use the following commands:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">kubectl get svc
kubectl get deployments
kubectl get pods
kubectl get secrets
</pre>
<h2 class="article-heading-main">5. Verify the Application</h2>
<p>To verify, if the application is working correctly, we will have to get the IP address of the running cluster and the port of the Spring Boot Service.</p>
<p>We can obtain the IP address in two ways: either by minikube or using kubectl command:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">minikube ip
//result
192.168.39.87


kubectl cluster-info
//result
Kubernetes master is running at https://192.168.39.87:8443
</pre>
<p>To get the port of the application, let&#8217;s invoke the following command:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">kubectl get svc spring-boot-svc 

//Example response
NAME              TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
spring-boot-svc   LoadBalancer   10.107.222.166        8080:30264/TCP   33s
</pre>
<p>As you can see above, the desired port of the application will be <strong>30264</strong>. Please keep in mind, that this value will be different each time we will create the <strong>Service</strong>.</p>
<p>Finally, let&#8217;s create the user using the curl command:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">curl -X POST -H "Content-Type: application/json" \
  --data '{"name":"Piotr"}' \
  192.168.39.87:30264/api/user

//response
{"id":1,"name":"Piotr"}
</pre>
<p>As the last step, let&#8217;s get the list of all users:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">curl 192.168.39.87:30264/api/user

//Response:
[{"id":1,"name":"Piotr"}]
</pre>
<h2 class="article-heading-main">6. Summary</h2>
<p>And that would be all for this article. In this step by step guide, we&#8217;ve learned how to deploy the<strong> Spring Boot and MySQL</strong> application on <strong>Kubernetes</strong>.</p>
<p>I am really aware that this topic is quite complex and requires an understanding of several concepts. The main goal for this tutorial was to walk you through the whole process without diving too much into the details. If you find anything in this article confusing or have any additional questions/suggestions, I will be more than happy if you would let me know about it (you can do that by our <a href="https://www.facebook.com/codersee/" target="_blank" rel="noopener noreferrer"><strong>fan page</strong></a>, <a href="https://www.facebook.com/groups/622361565094117" target="_blank" rel="noopener noreferrer"><strong>group</strong></a>, or a <strong><a href="http://codersee.com/contact/" target="_blank" rel="noopener noreferrer">contact</a> </strong>form).</p>
<p>To see the whole project, please visit <a href="https://github.com/codersee-blog/kotlin-spring-boot-mysql-k8s" target="_blank" rel="noopener noreferrer">this GitHub repository</a>.</p>
<p>The post <a href="https://blog.codersee.com/deploy-kotlin-spring-boot-app-with-mysql-on-kubernetes/">Deploy Kotlin Spring Boot App with MySQL on Kubernetes</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/deploy-kotlin-spring-boot-app-with-mysql-on-kubernetes/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Deploy Spring Boot application to GKE</title>
		<link>https://blog.codersee.com/deploy-spring-boot-application-to-gke/</link>
					<comments>https://blog.codersee.com/deploy-spring-boot-application-to-gke/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Thu, 01 Oct 2020 09:50:26 +0000</pubDate>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[Google Cloud]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<guid isPermaLink="false">http://codersee.com/?p=1097</guid>

					<description><![CDATA[<p>In this tutorial, we'll see how to set up and deploy the sample Spring Boot application to Google Kubernetes Engine (GKE)</p>
<p>The post <a href="https://blog.codersee.com/deploy-spring-boot-application-to-gke/">Deploy Spring Boot application to GKE</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="article-heading-introduction">1. Introduction</h2>
<p>If you&#8217;ve been learning programming for some time you probably heard about <strong><a href="https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/" target="_blank" rel="noopener noreferrer">Kubernetes</a></strong> (also known as <strong>Kube</strong> or <strong>K8s</strong>). In simple words, Kubernetes is a system for automating loads of processes, like deployment, scaling, and management of containerized applications.</p>
<p>There is no doubt that the K8s can improve our productivity and make our application more stable. However, maintaining the whole system might become more difficult and time-consuming. Fortunately, we can find lots of cloud providers offering Kubernetes as a managed service, like:</p>
<ul>
<li>Google Kubernetes Engine <strong><a href="https://cloud.google.com/kubernetes-engine" target="_blank" rel="noopener noreferrer">(GKE)</a></strong>,</li>
<li>Azure Kubernetes Service <strong><a href="https://azure.microsoft.com/en-us/services/kubernetes-service/" target="_blank" rel="noopener noreferrer">(AKS)</a></strong>,</li>
<li>Amazon Elastic Container Service for Kubernetes <strong><a href="https://aws.amazon.com/eks/" target="_blank" rel="noopener noreferrer">(Amazon EKS)</a></strong></li>
</ul>
<p>Choosing a provider-managed solution transfers the responsibility for managing and provisioning the master node to the cloud provider allowing us to focus more on the development itself.</p>
<p>In this tutorial, we&#8217;ll see how to set up and deploy the sample <strong>Spring Boot</strong> application to <strong>Google Kubernetes Engine (GKE).</strong></p>
<h2 class="article-heading-main">2. Prerequisites</h2>
<p>To follow the tutorial you need the following prerequisites:</p>
<ul>
<li>kubectl (Kubernetes CLI to manage a cluster)</li>
<li>gcloud (CLI tool to create and manage Google Cloud resources)</li>
<li>Google Cloud Account (free $ 300 trial)</li>
</ul>
<h2 class="article-heading-main">3. Create TestController Class With Test Endpoint</h2>
<p>Let&#8217;s start with implementing the example <em><strong>TestController</strong></em> with <strong>getHelloMessage</strong> function:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">@RestController
@RequestMapping("/api/hello")
class TestController {

    @GetMapping
    fun getHelloMessage() : ResponseEntity&lt;String&gt; = ResponseEntity.ok("Hello world!")
}
</pre>
<p>This is a very straightforward function responding to <em><strong>GET</strong></em> requests to <strong><em>/api/hello</em></strong> and returning &#8220;Hello world!&#8221; String as the response.</p>
<h2 class="article-heading-main">4. Create Dockerfile</h2>
<p>As the next step, let&#8217;s prepare the <strong>Dockerfile</strong> we will use to build the Docker image later:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="dockerfile">FROM openjdk
VOLUME /tmp
RUN mkdir /work
COPY . /work
WORKDIR /work
RUN /work/gradlew build
RUN mv /work/build/libs/*.jar /work/app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/work/app.jar"]
</pre>
<h2 class="article-heading-main">5. Build Docker Image</h2>
<p>Secondly, let&#8217;s build a Docker image using already prepared <strong>Dockerfile</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">docker build -t spring-boot-example .
</pre>
<p>When the command finishes its execution we will be informed that the image has been built and tagged successfully. We can also type <strong><em>docker images</em></strong> in the terminal to list all top-level images:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">docker images

## command output
REPOSITORY                                          TAG                 IMAGE ID            CREATED              SIZE
spring-boot-example                                 latest              52eaa2a8ef8c        About a minute ago   1.12GB
openjdk                                             latest              0cd6de5fdbee        About a minute ago   511MB
</pre>
<p>As can be seen, the <strong>spring-boot-example</strong> image has been created and the <strong>OpenJDK</strong> image has been pulled as well.</p>
<h2 class="article-heading-main">6. Push Docker Image to Container Registry</h2>
<p>As the next step, we will push the created image to the <strong>Google Container Registry</strong>. Before we will be able to do it, let&#8217;s make sure that we&#8217;ve got the container registry already <a href="https://cloud.google.com/container-registry/docs/pushing-and-pulling#before_you_begin">configured</a> and choose a correct hostname, which specifies the location where we will store the <a href="https://cloud.google.com/container-registry/docs/pushing-and-pulling#pushing_an_image_to_a_registry">image</a>.</p>
<p>Let&#8217;s start with tagging the local image with the registry name with the <strong><em>docker tag</em></strong> command:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">docker tag spring-boot-example gcr.io/[PROJECT-ID]/spring-boot-example:0.0.1
</pre>
<p>Then, let&#8217;s push our image to the container registry:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">docker push gcr.io/[PROJECT-ID]/spring-boot-example:0.0.1
</pre>
<p>Finally, when the command finishes its execution we can validate, whether the image has been uploaded successfully by listing Google Container Registry images:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">gcloud container images list

## command output
NAME
gcr.io/[PROJECT-ID]/spring-boot-example
</pre>
<p>Please notice, that <strong>[PROJECT-ID]</strong> will be different depending on our project&#8217;s id.</p>
<h2 class="article-heading-main">7. Create a Cluster</h2>
<p>Finally, we can create a new Kubernetes cluster within <strong>Google Kubernetes Engine</strong>. In this tutorial, we will use the <a href="https://console.cloud.google.com/kubernetes/" target="_blank" rel="noopener noreferrer">cloud console</a> (we could also do that using <strong>gcloud CLI</strong>). Let&#8217;s navigate to the panel and start by clicking the <em><strong>&#8220;Create cluster&#8221;</strong></em> button. Secondly, let&#8217;s configure cluster basics, like name and location type:</p>
<p><img fetchpriority="high" decoding="async" class="alignnone size-medium wp-image-1148" src="http://blog.codersee.com/wp-content/uploads/2020/09/post_4_2.png" alt="Image contains screenshot from Google Kubernetes Engine console page showing how to configure cluster basics, like name and location type" width="880" height="698" srcset="https://blog.codersee.com/wp-content/uploads/2020/09/post_4_2.png 880w, https://blog.codersee.com/wp-content/uploads/2020/09/post_4_2-300x238.png 300w, https://blog.codersee.com/wp-content/uploads/2020/09/post_4_2-768x609.png 768w" sizes="(max-width: 880px) 100vw, 880px" /></p>
<p>Then, let&#8217;s navigate to the node pools&#8217; <strong>default-pool tab</strong> and set the number of nodes to <strong>1</strong> (this number will be bigger in the real scenarios, but for the educational purposes we do not need more):</p>
<p><img decoding="async" class="alignnone size-medium wp-image-1150" src="http://blog.codersee.com/wp-content/uploads/2020/09/post_4_4.png" alt="Image contains screenshot from Google Kubernetes Engine console page showing how to set the number of nodes" width="952" height="697" /></p>
<p>As the last step, let&#8217;s click the <strong>Nodes tab</strong>, choose our machine type and boot disk size and click the <strong>&#8220;Create&#8221;</strong> button at the bottom of the site:</p>
<p><img decoding="async" class="alignnone size-medium wp-image-1149" src="http://blog.codersee.com/wp-content/uploads/2020/09/post_4_3.png" alt="Image contains screenshot from Google Kubernetes Engine console page showing how to set machine type and boot disk size" width="864" height="809" /></p>
<p>Please notice, that it may take some time before the changes will take place.</p>
<h2 class="article-heading-main">8. Create Kubernetes Deployment and Service</h2>
<p>In order to run our application in the <strong>K8s environment</strong>, we will prepare two configuration files- one for the <a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/" target="_blank" rel="noopener noreferrer">Deployment</a> and one for the <a href="https://kubernetes.io/docs/concepts/services-networking/service/" target="_blank" rel="noopener noreferrer">Service</a>. In a nutshell, a <strong>Deployment</strong> is an object representing an application running on our cluster and a <strong>Service</strong> allows us to expose an application as a network service.</p>
<h3 class="article-heading-sub">8.1. Create Deployment</h3>
<p>Firstly, let&#8217;s create the <em><strong>deployment.yaml</strong></em> file containing the following configuration:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="yaml">apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-boot-example
  labels:
    app: spring-boot-example
spec:
  replicas: 1
  selector:
    matchLabels:
      app: spring-boot-example
  template:
    metadata:
      labels:
        app: spring-boot-example
    spec:
      containers:
        - image: gcr.io/[PROJECT-ID]/spring-boot-example:0.0.1
          name: spring-boot-example-container
          imagePullPolicy: Always
          ports:
            - containerPort: 8080
          readinessProbe:
            httpGet:
              port: 8080
              path: /api/status
            initialDelaySeconds: 5
            failureThreshold: 5
          livenessProbe:
            httpGet:
              port: 8080
              path: /api/status
            initialDelaySeconds: 5
            failureThreshold: 5
</pre>
<p>Please remember to replace <strong>[PROJECT-ID]</strong> with the correct value.</p>
<h3 class="article-heading-sub">8.2. Create Service</h3>
<p>Similarly, let&#8217;s create the <em><strong>service.yaml</strong></em> file containing service&#8217;s configuration:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="yaml">apiVersion: v1
kind: Service
metadata:
  name: spring-boot-example-svc
spec:
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
      name: http
  selector:
    app: spring-boot-example
  type: LoadBalancer
</pre>
<p>And that’s all the configuration that we need to prepare in order to set up our Pods and Service.</p>
<h2 class="article-heading-main">10. Apply Deployment and Service</h2>
<h3 class="article-heading-sub">10.1. Configure Kubectl Context</h3>
<p>As one of the last steps we need to <strong>fetch the credentials</strong> of the running cluster and <strong>configure our kubectl context</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">gcloud container clusters get-credentials [CLUSTER-NAME] --zone [CLUSTER-ZONE] --project [PROJECT-ID]

## command output
Fetching cluster endpoint and auth data.
kubeconfig entry generated for example-cluster.
</pre>
<p>Finally, let&#8217;s apply our configurations using the <a href="https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#apply" target="_blank" rel="noopener noreferrer"><strong><em>apply</em></strong></a> command:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
</pre>
<h2 class="article-heading-main">11. Verification</h2>
<h3 class="article-heading-sub">11.1. Verify K8s Pods and Service</h3>
<p>In order to check, whether the <strong>Pods</strong> have been created successfully let&#8217;s run kubectl <strong><em>get pods</em></strong> command:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">kubectl get pods

## command output
NAME                                   READY   STATUS    RESTARTS   AGE
spring-boot-example-697976c749-klc64   1/1     Running   0          50s
</pre>
<p>As can be seen, all pods are ready and the status is <strong><em>Running</em></strong>, so we can check whether the service has been created and the external IP address has been assigned:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">kubectl get svc

## command output
NAME                      TYPE           CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
kubernetes                ClusterIP      10.0.0.1     &lt;none&gt;        443/TCP        10m
spring-boot-example-svc   LoadBalancer   10.0.4.57    34.69.49.59   80:31509/TCP   2m56s
</pre>
<h3 class="article-heading-sub">11.2. Verify Test Endpoint</h3>
<p>Finally, let&#8217;s check our test endpoint:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">curl 34.69.49.59/api/hello
</pre>
<p>And we see that we <em>Hello world!</em> text is returned as the response, meaning that our application has been deployed successfully and exposed to the world.</p>
<h2 class="article-heading-main">12. Conclusion</h2>
<p>In this article, we&#8217;ve learned how to deploy the <strong>Spring Boot application to Google Kubernetes Engine (GKE)</strong>. We&#8217;ve covered how to containerize our application, build the image, push it to Google Container Registry, and finally deploy it to GKE.</p>
<p>For the source code, please visit our project on <a href="https://github.com/codersee-blog/kotlin-spring-boot-gke" target="_blank" rel="noopener noreferrer"><strong>GitHub</strong></a>.</p>
<p>If you are reading this paragraph, I want to know that I am more than happy that you decided to spend your time learning with Codersee and I hope that this article helped you to learn something new. If you have any ideas or comments that you would like to share with us, please let us know in the comments below, by our Facebook <a href="https://www.facebook.com/codersee/" target="_blank" rel="noopener noreferrer"><strong>page</strong></a> or <a href="https://www.facebook.com/groups/622361565094117" target="_blank" rel="noopener noreferrer"><strong>group</strong></a>, or by using our <strong><a href="http://codersee.com/contact/" target="_blank" rel="noopener noreferrer">contact</a> </strong>form.</p>
<p>The post <a href="https://blog.codersee.com/deploy-spring-boot-application-to-gke/">Deploy Spring Boot application to GKE</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/deploy-spring-boot-application-to-gke/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: blog.codersee.com @ 2026-03-12 07:26:56 by W3 Total Cache
-->