<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Zoltan Polgar</title>
    <description>The latest articles on DEV Community by Zoltan Polgar (@pozo).</description>
    <link>https://dev.to/pozo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F47810%2F2842cca7-140b-4b71-aa5a-d7f298b18a41.jpeg</url>
      <title>DEV Community: Zoltan Polgar</title>
      <link>https://dev.to/pozo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pozo"/>
    <language>en</language>
    <item>
      <title>Continuous Development with Java and Kubernetes</title>
      <dc:creator>Zoltan Polgar</dc:creator>
      <pubDate>Fri, 01 Mar 2019 12:26:04 +0000</pubDate>
      <link>https://dev.to/pozo/continuous-development-with-java-and-kubernetes-3d08</link>
      <guid>https://dev.to/pozo/continuous-development-with-java-and-kubernetes-3d08</guid>
      <description>&lt;p&gt;If you are developing multiple applications in the same time for Kubernetes, you will realise that running and debugging these during the daily work is very sophisticated and time consuming, since we have to repeat the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building the application&lt;/li&gt;
&lt;li&gt;Building the docker image&lt;/li&gt;
&lt;li&gt;Pushing the container image to a docker registry&lt;/li&gt;
&lt;li&gt;Creating/Refreshing the Kubernetes' objects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's enough to have a database and an MQ connection in addition, and you are in a serious trouble. I'm not saying that It's impossible to test everything together, but I'm absolutely sure that if you need to do the steps above by hand, it will break your productive flow.&lt;/p&gt;

&lt;p&gt;Fortunately Google &lt;a href="https://cloud.google.com/blog/products/application-development/jib-1-0-0-is-ga-building-java-docker-images-has-never-been-easier" rel="noopener noreferrer"&gt;recently announced Jib 1.0.0&lt;/a&gt; which combined with &lt;a href="https://github.com/GoogleContainerTools/skaffold" rel="noopener noreferrer"&gt;Skaffold&lt;/a&gt; able to solve this problem. In this article I'm going to show you a workflow with these tools alongside Spring Boot and &lt;a href="https://helm.sh/" rel="noopener noreferrer"&gt;Helm&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Spring Boot application
&lt;/h3&gt;

&lt;p&gt;First we need to have a basic Spring Boot application. I suggest to use &lt;a href="https://start.spring.io/" rel="noopener noreferrer"&gt;Spring Initiallizr&lt;/a&gt; which can help you bootstrap a Spring Boot application in a few seconds. In this article I'm using Spring Boot 2.1.3 with gradle, however you will find the maven related files &lt;a href="https://github.com/Pozo/continuous-java-kubernetes" rel="noopener noreferrer"&gt;in the repository&lt;/a&gt; too.&lt;/p&gt;

&lt;p&gt;Just download the generated project and let's create a &lt;code&gt;RestController&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/echo/{text}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt; &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nd"&gt;@PathVariable&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HELLO"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During the article I want to demonstrate Jib's customizability, so let's change the default port number to &lt;code&gt;55000&lt;/code&gt;. Create an &lt;code&gt;application.properties&lt;/code&gt; and put this line into the file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;server.port&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;55000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open your favorite shell and run &lt;code&gt;./gradlew bootRun&lt;/code&gt;. If both &lt;code&gt;http://localhost:55000&lt;/code&gt; and &lt;code&gt;http://localhost:55000/echo/test&lt;/code&gt; seems to work, let's continue with the containerisation phase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Jib for docker image creation
&lt;/h3&gt;

&lt;p&gt;Jib is &lt;a href="https://cloudplatform.googleblog.com/2018/07/introducing-jib-build-java-docker-images-better.html" rel="noopener noreferrer"&gt;implemented in Java&lt;/a&gt; and runs as part of your Maven or Gradle build. You do not need to maintain a Dockerfile, run a Docker daemon. You just need to open your &lt;code&gt;build.gradle&lt;/code&gt; file, append the plugins section with &lt;code&gt;id 'com.google.cloud.tools.jib' version '1.0.0'&lt;/code&gt; and add the following piece of code to the end&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;jib&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'com.github.pozo/spring-boot-jib'&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;container&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'55000'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should be noted that the configuration above is not mandatory. However, without these lines Jib would produce an image named &lt;code&gt;spring-boot-jib:0.0.1-SNAPSHOT&lt;/code&gt; where the first part is the value of the &lt;code&gt;rootProject.name&lt;/code&gt; from &lt;code&gt;settings.gradle&lt;/code&gt; and the second one is provided by the &lt;code&gt;version&lt;/code&gt; variable from &lt;code&gt;build.gradle&lt;/code&gt;. In order to build a more advanced image, I suggest to look over the &lt;a href="https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin#extended-usage" rel="noopener noreferrer"&gt;available options&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The above configuration’ equal would look like &lt;a href="https://github.com/GoogleContainerTools/jib/blob/master/docs/faq.md#what-would-a-dockerfile-for-a-jib-built-image-look-like" rel="noopener noreferrer"&gt;this&lt;/a&gt; with Dockerfile&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; gcr.io/distroless/java:latest&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; dependencyJars /app/libs&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; snapshotDependencyJars /app/libs&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; resources /app/resources&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; classFiles /app/classes&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src/main/jib /&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["java", jib.container.jvmFlags, "-cp", "/app/resources:/app/classes:/app/libs/*", jib.container.mainClass]&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; [jib.container.args]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jib uses &lt;a href="https://github.com/GoogleContainerTools/distroless" rel="noopener noreferrer"&gt;distroless&lt;/a&gt; java as the default base image, which seems to use &lt;a href="https://github.com/GoogleContainerTools/distroless/pull/295" rel="noopener noreferrer"&gt;container related JVM flags by default&lt;/a&gt;. The multiple copy statements are used to break the app into layers, allowing for faster rebuilds after small changes. &lt;/p&gt;

&lt;p&gt;If you want to specify a different base image, just add a &lt;a href="https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin#extended-usage" rel="noopener noreferrer"&gt;&lt;code&gt;from&lt;/code&gt;&lt;/a&gt; section&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;jib&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'java:8-jre-alpine'&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'com.github.pozo/spring-boot-jib'&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;container&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'55000'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we want to build the container image we have two options. Using &lt;a href="https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin#build-your-image" rel="noopener noreferrer"&gt;&lt;code&gt;jib&lt;/code&gt;&lt;/a&gt; task which pushes a container image for your application to a container registry, or &lt;a href="https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin#build-to-docker-daemon" rel="noopener noreferrer"&gt;&lt;code&gt;jibDockerBuild&lt;/code&gt;&lt;/a&gt; which uses the docker command line tool and requires that you have docker available on your PATH or you can set the executable location via the &lt;a href="https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin#extended-usage" rel="noopener noreferrer"&gt;&lt;code&gt;dockerClient&lt;/code&gt;&lt;/a&gt; object.&lt;/p&gt;

&lt;p&gt;Open a terminal and execute&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./gradlew jibDockerBuild
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm going to explain why we need to use this task instead of&lt;code&gt;jib&lt;/code&gt; in the next paragraph.&lt;/p&gt;

&lt;p&gt;Check the output of &lt;code&gt;docker images&lt;/code&gt; command. If you wonder why your image created by ~49 years ago, It's &lt;a href="https://github.com/GoogleContainerTools/jib/blob/master/docs/faq.md#why-is-my-image-created-48-years-ago" rel="noopener noreferrer"&gt;for reproducibility purposes&lt;/a&gt;, Jib sets the creation time of the container images to 0. In order to use the current time just add &lt;code&gt;useCurrentTimestamp = true&lt;/code&gt; inside of the &lt;code&gt;jib.container&lt;/code&gt;. For more advanced questions check out the &lt;a href="https://github.com/GoogleContainerTools/jib/blob/master/docs/faq.md" rel="noopener noreferrer"&gt;Jib's FAQ&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After the build phase we can run our image with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:55000 com.github.pozo/spring-boot-jib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If both &lt;code&gt;http://localhost:8080&lt;/code&gt; and &lt;code&gt;http://localhost:8080/echo/test&lt;/code&gt; seems to work, we can continue with our Kubernetes objects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running the application image inside of Kubernetes
&lt;/h3&gt;

&lt;p&gt;If you are not familiar with Kubernetes I recommend to start with the &lt;a href="https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First of all we need an up and running Kubernetes cluster. Fortunately we have several options nowadays. For instance we can use &lt;a href="https://kubernetes.io/docs/setup/minikube/" rel="noopener noreferrer"&gt;Minikube&lt;/a&gt; which runs a &lt;a href="https://kubernetes.io/docs/setup/minikube/" rel="noopener noreferrer"&gt;single-node Kubernetes cluster&lt;/a&gt; inside a VM on your laptop.&lt;/p&gt;

&lt;p&gt;An another option is &lt;a href="https://blog.docker.com/2018/07/kubernetes-is-now-available-in-docker-desktop-stable-channel/" rel="noopener noreferrer"&gt;Docker for Desktop Kubernetes&lt;/a&gt;. It runs a &lt;a href="https://docs.docker.com/v17.09/docker-for-mac/kubernetes/" rel="noopener noreferrer"&gt;single-node cluster&lt;/a&gt; locally &lt;strong&gt;within&lt;/strong&gt; your Docker instance. I believe this one is the most comfortable way to hack around with Kubernetes, so I suggest to use this one. &lt;/p&gt;

&lt;p&gt;We also need &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/" rel="noopener noreferrer"&gt;kubectl&lt;/a&gt; which is a command line interface for &lt;a href="https://kubernetes.io/docs/reference/kubectl/overview/" rel="noopener noreferrer"&gt;running commands&lt;/a&gt; against Kubernetes clusters.&lt;/p&gt;

&lt;p&gt;If you decided to use Minikube then start the cluster with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command &lt;a href="https://kubernetes.io/docs/setup/minikube/#starting-a-cluster" rel="noopener noreferrer"&gt;creates and configures&lt;/a&gt; a Virtual Machine that runs a single-node cluster. This command also configures your kubectl installation to communicate with this cluster. You also need to run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eval $(minikube docker-env)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command &lt;code&gt;minikube docker-env&lt;/code&gt; returns a set of Bash environment variable exports to configure your local environment to re-use the Docker daemon inside the Minikube instance. &lt;a href="https://stackoverflow.com/a/52310892" rel="noopener noreferrer"&gt;(source)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This means you &lt;a href="https://github.com/kubernetes/minikube/blob/0c616a6b42b28a1aab8397f5a9061f8ebbd9f3d9/README.md#reusing-the-docker-daemon" rel="noopener noreferrer"&gt;don't have to build on your host machine&lt;/a&gt; and push the image into a docker registry, you can just build inside the same docker daemon as Minikube. So after&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gradlew jibDockerBuild
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Minikube will be able to reach out the image &lt;code&gt;com.github.pozo/spring-boot-jib&lt;/code&gt;. Don't forget to run &lt;code&gt;eval $(minikube docker-env)&lt;/code&gt; every time when you prompt a new terminal.&lt;/p&gt;

&lt;p&gt;To enable the Kubernetes cluster in case of Docker for Desktop just follow the &lt;a href="https://docs.docker.com/docker-for-mac/#kubernetes" rel="noopener noreferrer"&gt;platform specific instructions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To run our image in the cluster we need to define a &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/" rel="noopener noreferrer"&gt;Deployment&lt;/a&gt; first. Deployment represent a set of multiple, identical &lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/pod/" rel="noopener noreferrer"&gt;Pods&lt;/a&gt; with no unique identities. A Deployment runs multiple replicas of your application and automatically replaces any instances that fail or become unresponsive. In addition we need an externally exposed &lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/" rel="noopener noreferrer"&gt;Service&lt;/a&gt; whereby we can reach our application from outside of the cluster. Here is a diagram about what we want to achieve&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl38r6xr5zv4iiu6p3au5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl38r6xr5zv4iiu6p3au5.png" alt="A Kubernetes Service and Deployment" width="548" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's Create a &lt;code&gt;kubernetes&lt;/code&gt; directory under the project's root and create a file &lt;code&gt;spring-boot-jib.yaml&lt;/code&gt; with the following content under the freshly created directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;spring-deployment&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;spring-boot-jib&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;spring-boot-jib&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;spring-boot-jib-pod&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;com.github.pozo/spring-boot-jib&lt;/span&gt;
          &lt;span class="na"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IfNotPresent&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
              &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;55000&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;spring-boot-jib-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;55000&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;spring-boot-jib&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few important things to mention here. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Deployment's &lt;code&gt;spec.selector.matchLabels.app&lt;/code&gt; value must be the same as the &lt;code&gt;spec.template.metadata.labels.app&lt;/code&gt; value&lt;/li&gt;
&lt;li&gt;Service's &lt;code&gt;spec.selector.app&lt;/code&gt; value must be the same as the Deployment's &lt;code&gt;spec.selector.matchLabels.app&lt;/code&gt; value. So the service can find our Pod, and hand over every request to it.&lt;/li&gt;
&lt;li&gt;The Service's &lt;code&gt;spec.ports.port&lt;/code&gt; value should be what we want to expose to the outside world, in our case &lt;code&gt;8080&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The Service's &lt;code&gt;spec.ports.targetPort&lt;/code&gt; must be the same as the Deployment's &lt;code&gt;spec.template.spec.containers.ports.containerPort&lt;/code&gt; so the Service will redirect everything to the container's port number &lt;code&gt;55000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Finally the Pod's &lt;code&gt;spec.containers.imagePullPolicy&lt;/code&gt; &lt;strong&gt;must be &lt;code&gt;IfNotPresent&lt;/code&gt; or &lt;code&gt;Never&lt;/code&gt;&lt;/strong&gt;. The default value &lt;code&gt;Always&lt;/code&gt; would produce an error, since there is no such &lt;code&gt;com.github.pozo&lt;/code&gt;repository exist. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As we previously used &lt;code&gt;jibDockerBuild&lt;/code&gt; we have our image locally, and because of Docker for Desktop's cluster uses our host's docker instance, it will able reach the image by default. In case of Minikube, due to &lt;code&gt;eval $(minikube docker-env)&lt;/code&gt; the image built by Minikube's docker daemon, and it will able reach the image too.&lt;/p&gt;

&lt;p&gt;Open a terminal and run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; kubernetes/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#create" rel="noopener noreferrer"&gt;create&lt;/a&gt; command iterates over the &lt;code&gt;kubernetes&lt;/code&gt; directory and creates Kubernetes resources from it's content.&lt;/p&gt;

&lt;p&gt;Open a browser and try to reach &lt;code&gt;http://localhost:8080&lt;/code&gt; and &lt;code&gt;http://localhost:8080/echo/test&lt;/code&gt; again. In case of a Minikube execute &lt;code&gt;minikube service list&lt;/code&gt; to find out the deployed service address. If we are getting status code &lt;code&gt;200&lt;/code&gt; then we did a great job, and we have a running application in our cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Put everything together with Skaffold
&lt;/h3&gt;

&lt;p&gt;We almost crossed the finish line! Currently we have a containerised application and we can deploy it anytime into the cluster &lt;em&gt;by hand&lt;/em&gt;. At this point we must repeat the building and deploying steps after every changes. &lt;/p&gt;

&lt;p&gt;Skaffold going to help us to eliminate this handwork. Go to &lt;a href="https://skaffold.dev/docs/getting-started/#installing-skaffold" rel="noopener noreferrer"&gt;their website&lt;/a&gt; and follow the installation instructions. If everything set, create a &lt;code&gt;skaffold.yaml&lt;/code&gt; into the project's root directory with the following content&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;skaffold/v1beta4&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Config&lt;/span&gt;
&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;local&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;com.github.pozo/spring-boot-jib&lt;/span&gt;
      &lt;span class="na"&gt;jibGradle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kubectl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;manifests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kubernetes/*.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is our brand new &lt;a href="https://skaffold.dev/docs/concepts/#configuration-of-the-skaffold-pipeline-skaffold-yaml" rel="noopener noreferrer"&gt;Skaffold pipeline file&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;build.local.push: false&lt;/code&gt; &lt;a href="https://skaffold.dev/docs/how-tos/builders/" rel="noopener noreferrer"&gt;enforces Skaffold&lt;/a&gt; to use &lt;code&gt;jibDockerBuild&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://skaffold.dev/docs/how-tos/builders/#dockerfile-locally-with-docker" rel="noopener noreferrer"&gt;&lt;code&gt;build.artifacts&lt;/code&gt;&lt;/a&gt; is a list of the actual images we're going to be build. &lt;/li&gt;
&lt;li&gt;The &lt;code&gt;build.artifacts.jibGradle&lt;/code&gt; configures Skaffold to use Jib during the image building phase. &lt;/li&gt;
&lt;li&gt;The &lt;a href="https://skaffold.dev/docs/how-tos/deployers/#deploying-with-kubectl" rel="noopener noreferrer"&gt;&lt;code&gt;deploy.kubectl.manifests&lt;/code&gt;&lt;/a&gt; value set the folder name where we already have our kubernetes manifest files. If we skip this the default directory name would be &lt;a href="https://github.com/GoogleContainerTools/skaffold/blob/cff3918df8c165f2c4bb17b07f3ed50222f6a63c/pkg/skaffold/constants/constants.go#L79" rel="noopener noreferrer"&gt;&lt;code&gt;k8s&lt;/code&gt;&lt;/a&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are looking for more advanced pipeline configuration I recommend to check out &lt;a href="https://github.com/GoogleContainerTools/skaffold/blob/b9c979d7b59a15bba9e4a9c7977ece407b21d0c4/integration/examples/annotated-skaffold.yaml" rel="noopener noreferrer"&gt;this well annotated example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Open a terminal and run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;skaffold dev &lt;span class="nt"&gt;--trigger&lt;/span&gt; notify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command runs our pipeline file in development mode, which means every change in our codebase will trigger Skaffold to call Jib to build the image, and kubectl to deploy it. Sounds cool right ?&lt;/p&gt;

&lt;p&gt;Change the return value of &lt;code&gt;TestController&lt;/code&gt;'s &lt;code&gt;hello&lt;/code&gt; method to &lt;code&gt;"GOODBYE"&lt;/code&gt; and see what happens in the terminal. Refresh the browser after a few seconds, and you will see &lt;code&gt;"GOODBYE"&lt;/code&gt; instead of &lt;code&gt;"HELLO"&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using helm
&lt;/h3&gt;

&lt;p&gt;If you are not familiar with helm I suggest to take a look at the &lt;a href="https://docs.helm.sh/using_helm/#quickstart" rel="noopener noreferrer"&gt;official quick starter guide&lt;/a&gt; first.&lt;/p&gt;

&lt;p&gt;I must admit It's absolutely not mandatory to use &lt;a href="https://docs.helm.sh/using_helm/#quickstart" rel="noopener noreferrer"&gt;Helm&lt;/a&gt; for development, and someone suggest you to &lt;a href="https://medium.com/virtuslab/think-twice-before-using-helm-25fbb18bc822" rel="noopener noreferrer"&gt;think twice before using it&lt;/a&gt;, however according to my experience helm making the application deployment easy, standardised and reusable, especially when you have to work with several applications.&lt;/p&gt;

&lt;p&gt;Create a &lt;a href="https://helm.sh/docs/developing_charts/" rel="noopener noreferrer"&gt;helm chart&lt;/a&gt; for our application with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm create spring-boot-jib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The helm's &lt;a href="https://docs.helm.sh/helm/#helm-create" rel="noopener noreferrer"&gt;create command&lt;/a&gt; will generate a directory structure with several files. In order to make it cleaner what do we have in this folder, rename it to &lt;code&gt;helm&lt;/code&gt;. The most important files are in the templates directory and the &lt;code&gt;values.yaml&lt;/code&gt; itself. &lt;/p&gt;

&lt;p&gt;Change the generated &lt;code&gt;service.yaml&lt;/code&gt;'s &lt;code&gt;spec.ports.targetPort&lt;/code&gt; to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;.Values.service.containerPort&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;deployment.yaml&lt;/code&gt;'s &lt;code&gt;spec.template.spec.containers.image&lt;/code&gt; value to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;.Values.image.repository&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;if&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;.Values.image.tag&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}:{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;.Values.image.tag&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;end&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the &lt;code&gt;deployment.yaml&lt;/code&gt;'s &lt;code&gt;spec.template.spec.containers.ports&lt;/code&gt; value to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;- toYaml .Values.container.ports | nindent 12&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything between &lt;code&gt;{{ }}&lt;/code&gt; came from the &lt;code&gt;values.yaml&lt;/code&gt; or &lt;code&gt;_helper.tpl&lt;/code&gt; files. In fact we are using &lt;a href="https://helm.sh/docs/chart_template_guide/" rel="noopener noreferrer"&gt;Go templating&lt;/a&gt;. And change the &lt;code&gt;values.yaml&lt;/code&gt; file like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;replicaCount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;

&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;com.github.pozo/spring-boot-jib&lt;/span&gt;
  &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latest&lt;/span&gt;
  &lt;span class="na"&gt;pullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IfNotPresent&lt;/span&gt;

&lt;span class="na"&gt;nameOverride&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;span class="na"&gt;fullnameOverride&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spring-boot-jib"&lt;/span&gt;

&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
  &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;55000&lt;/span&gt;

&lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
      &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;55000&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we want to use Helm instead of kubectl, we need to adjust the Skaffold pipeline accordingly&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;skaffold/v1beta4&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Config&lt;/span&gt;
&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;local&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;com.github.pozo/spring-boot-jib&lt;/span&gt;
      &lt;span class="na"&gt;jibGradle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;helm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;releases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;spring-boot-jib&lt;/span&gt;
        &lt;span class="na"&gt;chartPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;helm&lt;/span&gt;
        &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;image.repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;com.github.pozo/spring-boot-jib&lt;/span&gt;
        &lt;span class="na"&gt;setValues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;image.tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We must configure the &lt;code&gt;chartPath&lt;/code&gt;, the &lt;code&gt;image.repository&lt;/code&gt;, and we must &lt;a href="https://stackoverflow.com/a/50936738" rel="noopener noreferrer"&gt;set &lt;code&gt;image.tag&lt;/code&gt; value to empty string&lt;/a&gt; for Helm, so Skaffold will be able to manage custom tags on the deployment.&lt;/p&gt;

&lt;p&gt;If everything set, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;skaffold dev &lt;span class="nt"&gt;--trigger&lt;/span&gt; notify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we are using Minikube we don't need to execute &lt;code&gt;eval $(minikube docker-env)&lt;/code&gt; anymore, since Skaffold will take care of it. If you want to see what happens under the hood, just add the &lt;code&gt;-v debug&lt;/code&gt; switch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;skaffold dev &lt;span class="nt"&gt;--trigger&lt;/span&gt; notify &lt;span class="nt"&gt;-v&lt;/span&gt; debug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Live debugging
&lt;/h3&gt;

&lt;p&gt;During the development It's a natural demand to setup a breakpoint and check the application's state while It's running. Locally It's a very easy process but what if we have everything in the cluster ? Actually It's easier as you might think, we need to adjust just a few things.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;5005&lt;/code&gt; to the list of port under the jib configuration in the &lt;code&gt;build.gradle&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add the &lt;code&gt;agentlib&lt;/code&gt; related configuration inside of &lt;code&gt;jvmFlags&lt;/code&gt; property
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;jib&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'com.github.pozo/spring-boot-jib'&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;container&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;useCurrentTimestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="n"&gt;ports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'55000'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'5005'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;jvmFlags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005'&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Extend &lt;code&gt;values.yaml&lt;/code&gt;'s &lt;code&gt;container.ports&lt;/code&gt; with
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;debug&lt;/span&gt;
  &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5005&lt;/span&gt;
  &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create a &lt;a href="https://stackoverflow.com/a/30793101" rel="noopener noreferrer"&gt;remote configuration&lt;/a&gt; for the debugger&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then run the pipeline. Skaffold will automatically forward every listed ports, however be careful, after a change Skaffold might &lt;a href="https://skaffold.dev/docs/how-tos/portforward/" rel="noopener noreferrer"&gt;pick a random port if the requested one isn't available&lt;/a&gt;. Set a breakpoint, and run the previously created Remote configuration, call the corresponding endpoint and voilà.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed reading the article as much as I enjoyed writing it. I'm not a proficient writer, so if you have a comment, remark feel free to share it in the comments section. The source code of this article is available &lt;a href="https://github.com/Pozo/continuous-java-kubernetes" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I want to thank &lt;a href="https://dev.to/@szgergo"&gt;Gergő Szabó&lt;/a&gt; and &lt;a href="https://dev.to/@szada92"&gt;Dániel Szabó&lt;/a&gt; for all the help.&lt;/p&gt;

&lt;p&gt;If you are interested in this topic I suggest to look over these articles as well&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://mrhaki.blogspot.com/2018/09/spring-sweets-dockerize-spring-boot.html" rel="noopener noreferrer"&gt;Dockerize Spring Boot Application With Jib&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/jib-dockerizing" rel="noopener noreferrer"&gt;Dockerizing Java Apps using Jib&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://speakerdeck.com/coollog/skaffold-for-java-continuous-development-for-kubernetes" rel="noopener noreferrer"&gt;Continuous Development for Kubernetes (Slides)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloudplatform.googleblog.com/2018/07/introducing-jib-build-java-docker-images-better.html" rel="noopener noreferrer"&gt;Introducing Jib — build Java Docker images better&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ramitsurana/awesome-kubernetes" rel="noopener noreferrer"&gt;awesome-kubernetes - A curated list for awesome kubernetes sources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://platform9.com/blog/kubernetes-helm-why-it-matters/" rel="noopener noreferrer"&gt;Kubernetes Helm: Why It Matters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.hasura.io/draft-vs-gitkube-vs-helm-vs-ksonnet-vs-metaparticle-vs-skaffold-f5aa9561f948/" rel="noopener noreferrer"&gt;Draft vs Gitkube vs Helm vs Ksonnet vs Metaparticle vs Skaffold&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>java</category>
      <category>jib</category>
      <category>skaffold</category>
    </item>
    <item>
      <title>A small piece of code which is going to inspire you to try out Kotlin</title>
      <dc:creator>Zoltan Polgar</dc:creator>
      <pubDate>Thu, 07 Dec 2017 22:12:24 +0000</pubDate>
      <link>https://dev.to/pozo/a-small-piece-of-code-which-gonna-inspire-you-to-try-outkotlin-2hm</link>
      <guid>https://dev.to/pozo/a-small-piece-of-code-which-gonna-inspire-you-to-try-outkotlin-2hm</guid>
      <description>&lt;p&gt;A few months ago I’ve started to discover Jetbrains’ Kotlin language which gave a good impression to me. I can't express my thoughts better than this comment&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Kotlin isn’t revolutionary but that’s what is nice about it. If you want revolution then there is Scala and all its headaches. If you want a language that basically codifies Effective Java then that’s Kotlin. — &lt;a href="https://www.reddit.com/r/java/comments/6pgz0e/what_are_your_thoughts_as_a_java_developer_on/dkpj7mi/"&gt;meddlepal@reddit&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is a &lt;a href="http://kotlinlang.org/docs/tutorials/"&gt;bunch&lt;/a&gt; of excellent &lt;a href="https://code.tutsplus.com/tutorials/an-introduction-to-kotlin--cms-24051"&gt;tutorial&lt;/a&gt; on the web, and I don’t want to bore you with the basics, I just simply want to show you through an example that besides the highlighted sentence Kotlin is less verbose than Java.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So given a string as key, and a list of integers as value. Add a value to the key's list if its exits, otherwise create the list first, then add the value for it.&lt;/strong&gt;&lt;br&gt;
Java version &lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 Kotlin version &lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;So don't hesitate it absolutely worth a try :)&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>java</category>
    </item>
  </channel>
</rss>
