<p>I have a very simple <code>Spring Boot</code> Helloworld application that displays <code>Hello World!</code> message using a <code>REST</code> <code>API</code>.</p>
<p>I would like to deploy that application on my <code>Ubuntu</code> node which has <code>MicroK8s</code> installed.</p>
<p><strong>Steps Followed:</strong></p>
<ol>
<li>git clone <em>project_repo_url_here</em></li>
<li>Build image using <em>./mvnw k8s:build</em></li>
<li>Apply resources using <em>./mvnw k8s:resource</em></li>
<li>Deploy application using <em>./mvnw k8s:deploy</em></li>
</ol>
<p>I am able to build that image using <code>./mvnw k8s:build</code> command and can also see the image using <code>docker images</code> command but not able to deploy it on <code>MicroK8s</code> cluster using <code>./mvnw k8s:resource</code> and <code>./mvnw k8s:deploy</code> commands</p>
<p><strong>pom.xml</strong></p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
    &lt;parent&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
        &lt;version&gt;2.3.3.RELEASE&lt;/version&gt;
        &lt;relativePath /&gt; &lt;!-- lookup parent from repository --&gt;
    &lt;/parent&gt;
    &lt;groupId&gt;com.example&lt;/groupId&gt;
    &lt;artifactId&gt;helloworld&lt;/artifactId&gt;
    &lt;version&gt;0.0.2-SNAPSHOT&lt;/version&gt;
    &lt;name&gt;helloworld&lt;/name&gt;
    &lt;description&gt;Demo project for Spring Boot&lt;/description&gt;

    &lt;properties&gt;
        &lt;java.version&gt;11&lt;/java.version&gt;
        &lt;spring-boot.build-image.imageName&gt;chandeln/${project.artifactId}:${project.version}&lt;/spring-boot.build-image.imageName&gt;
        &lt;jkube.generator.name&gt;${spring-boot.build-image.imageName}&lt;/jkube.generator.name&gt;
        &lt;docker.skip.tag&gt;true&lt;/docker.skip.tag&gt;
        &lt;jkube.enricher.jkube-service.type&gt;NodePort&lt;/jkube.enricher.jkube-service.type&gt;
    &lt;/properties&gt;

    &lt;dependencies&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-starter-actuator&lt;/artifactId&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-devtools&lt;/artifactId&gt;
            &lt;scope&gt;runtime&lt;/scope&gt;
            &lt;optional&gt;true&lt;/optional&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
            &lt;scope&gt;test&lt;/scope&gt;
            &lt;exclusions&gt;
                &lt;exclusion&gt;
                    &lt;groupId&gt;org.junit.vintage&lt;/groupId&gt;
                    &lt;artifactId&gt;junit-vintage-engine&lt;/artifactId&gt;
                &lt;/exclusion&gt;
            &lt;/exclusions&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;

    &lt;build&gt;
        &lt;plugins&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
                &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
            &lt;/plugin&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.eclipse.jkube&lt;/groupId&gt;
                &lt;artifactId&gt;kubernetes-maven-plugin&lt;/artifactId&gt;
                &lt;version&gt;1.0.2&lt;/version&gt;
            &lt;/plugin&gt;
        &lt;/plugins&gt;
    &lt;/build&gt;

&lt;/project&gt;
</code></pre>
<p><strong>HelloworldController.java</strong></p>
<pre><code>@RestController
public class HelloworldController {

    @GetMapping(&quot;/&quot;)
    public String hello() {
        return &quot;Hello World!&quot;;
    }

}
</code></pre>
<p>On my <code>Ubuntu</code> machine I have <code>MicroK8s</code> installed.</p>
<p><strong>microk8s status --wait-ready</strong></p>
<pre><code>microk8s is running
high-availability: no
  datastore master nodes: &lt;my-ubuntu-machine-public-ip&gt;:19001
  datastore standby nodes: none
addons:
  enabled:
    dashboard            # The Kubernetes dashboard
    dns                  # CoreDNS
    ha-cluster           # Configure high availability on the current node
    ingress              # Ingress controller for external access
    metrics-server       # K8s Metrics Server for API access to service metrics
  disabled:
    ambassador           # Ambassador API Gateway and Ingress
    cilium               # SDN, fast with full network policy
    fluentd              # Elasticsearch-Fluentd-Kibana logging and monitoring
    gpu                  # Automatic enablement of Nvidia CUDA
    helm                 # Helm 2 - the package manager for Kubernetes
    helm3                # Helm 3 - Kubernetes package manager
    host-access          # Allow Pods connecting to Host services smoothly
    istio                # Core Istio service mesh services
    jaeger               # Kubernetes Jaeger operator with its simple config
    knative              # The Knative framework on Kubernetes.
    kubeflow             # Kubeflow for easy ML deployments
    linkerd              # Linkerd is a service mesh for Kubernetes and other frameworks
    metallb              # Loadbalancer for your Kubernetes cluster
    multus               # Multus CNI enables attaching multiple network interfaces to pods
    prometheus           # Prometheus operator for monitoring and logging
    rbac                 # Role-Based Access Control for authorisation
    registry             # Private image registry exposed on localhost:32000
    storage              # Storage class; allocates storage from host directory
</code></pre>
<p><strong>kubectl cluster-info</strong></p>
<pre><code>Kubernetes master is running at https://127.0.0.1:16443
Metrics-server is running at https://127.0.0.1:16443/api/v1/namespaces/kube-system/services/https:metrics-server:/proxy
CoreDNS is running at https://127.0.0.1:16443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
</code></pre>
<p><strong>kubectl get all</strong></p>
<pre><code>NAME                            READY   STATUS    RESTARTS   AGE
pod/microbot-5f5499d479-t2cdz   1/1     Running   1          31d
pod/microbot-5f5499d479-r6d57   1/1     Running   3          31d
pod/microbot-5f5499d479-7zztm   1/1     Running   3          31d
pod/nginx-6799fc88d8-9sf5j      1/1     Running   5          31d

NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/kubernetes         ClusterIP   10.152.183.1     &lt;none&gt;        443/TCP        31d
service/microbot-service   NodePort    10.152.183.184   &lt;none&gt;        81:31587/TCP   31d

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/microbot   3/3     3            3           31d
deployment.apps/nginx      1/1     1            1           31d

NAME                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/microbot-5f5499d479   3         3         3       31d
replicaset.apps/nginx-6799fc88d8      1         1         1       31d
</code></pre>
<p><strong>./mvnw k8s:build</strong></p>
<p>Docker image built successfully. See below.</p>
<p><strong>docker images</strong></p>
<pre><code>REPOSITORY                            TAG                     IMAGE ID            CREATED             SIZE
chandeln/helloworld                   0.0.2-SNAPSHOT          dc061ea2b469        17 minutes ago      509MB
chandeln/helloworld                   latest                  dc061ea2b469        17 minutes ago      509MB
</code></pre>
<p><strong>./mvnw k8s:resource</strong></p>
<pre><code>[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------&lt; com.example:helloworld &gt;-----------------------
[INFO] Building helloworld 0.0.2-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- kubernetes-maven-plugin:1.0.2:resource (default-cli) @ helloworld ---
[WARNING] Error reading service account token from: [/var/run/secrets/kubernetes.io/serviceaccount/token]. Ignoring.
[WARNING] k8s: Cannot access cluster for detecting mode: Unknown host kubernetes.default.svc: Name or service not known
[WARNING] Error reading service account token from: [/var/run/secrets/kubernetes.io/serviceaccount/token]. Ignoring.
[INFO] k8s: Running generator spring-boot
[INFO] k8s: spring-boot: Using Docker image quay.io/jkube/jkube-java-binary-s2i:0.0.8 as base / builder
[INFO] k8s: Using resource templates from /home/admin/apps/helloworld/src/main/jkube
[INFO] k8s: jkube-controller: Adding a default Deployment
[INFO] k8s: jkube-service: Adding a default service 'helloworld' with ports [8080]
[INFO] k8s: jkube-healthcheck-spring-boot: Adding readiness probe on port 8080, path='/actuator/health', scheme='HTTP', with initial delay 10 seconds
[INFO] k8s: jkube-healthcheck-spring-boot: Adding liveness probe on port 8080, path='/actuator/health', scheme='HTTP', with initial delay 180 seconds
[INFO] k8s: jkube-revision-history: Adding revision history limit to 2
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  10.701 s
[INFO] Finished at: 2020-12-24T03:01:08Z
[INFO] ------------------------------------------------------------------------
</code></pre>
<p><strong>./mvnw k8s:deploy</strong></p>
<pre><code> .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.3.RELEASE)

2020-12-24 03:18:13.492  INFO 1828768 --- [           main] c.e.h.HelloworldApplicationTests         : Starting HelloworldApplicationTests on tools-server.kanaaritech.com with PID 1828768 (started by admin in /home/admin/apps/helloworld)
2020-12-24 03:18:13.494  INFO 1828768 --- [           main] c.e.h.HelloworldApplicationTests         : The following profiles are active: tools
2020-12-24 03:18:24.499  INFO 1828768 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-12-24 03:18:27.959  INFO 1828768 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 2 endpoint(s) beneath base path '/actuator'
2020-12-24 03:18:28.684  INFO 1828768 --- [           main] c.e.h.HelloworldApplicationTests         : Started HelloworldApplicationTests in 15.912 seconds (JVM running for 18.923)
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 20.012 s - in com.example.helloworld.HelloworldApplicationTests
2020-12-24 03:18:31.927  INFO 1828768 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ helloworld ---
[INFO] Building jar: /home/admin/apps/helloworld/target/helloworld-0.0.2-SNAPSHOT.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:2.3.3.RELEASE:repackage (repackage) @ helloworld ---
[INFO] Replacing main artifact with repackaged archive
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ helloworld ---
[INFO] Installing /home/admin/apps/helloworld/target/helloworld-0.0.2-SNAPSHOT.jar to /home/admin/.m2/repository/com/example/helloworld/0.0.2-SNAPSHOT/helloworld-0.0.2-SNAPSHOT.jar
[INFO] Installing /home/admin/apps/helloworld/pom.xml to /home/admin/.m2/repository/com/example/helloworld/0.0.2-SNAPSHOT/helloworld-0.0.2-SNAPSHOT.pom
[INFO]
[INFO] &lt;&lt;&lt; kubernetes-maven-plugin:1.0.2:deploy (default-cli) &lt; install @ helloworld &lt;&lt;&lt;
[INFO]
[INFO]
[INFO] --- kubernetes-maven-plugin:1.0.2:deploy (default-cli) @ helloworld ---
[WARNING] Error reading service account token from: [/var/run/secrets/kubernetes.io/serviceaccount/token]. Ignoring.
[WARNING] k8s: Cannot access cluster for detecting mode: Unknown host kubernetes.default.svc: Name or service not known
[WARNING] Error reading service account token from: [/var/run/secrets/kubernetes.io/serviceaccount/token]. Ignoring.
[WARNING] Error reading service account token from: [/var/run/secrets/kubernetes.io/serviceaccount/token]. Ignoring.
[WARNING] k8s: Cannot access cluster for detecting mode: Unknown host kubernetes.default.svc
[WARNING] Error reading service account token from: [/var/run/secrets/kubernetes.io/serviceaccount/token]. Ignoring.
[WARNING] Error reading service account token from: [/var/run/secrets/kubernetes.io/serviceaccount/token]. Ignoring.
[ERROR] k8s: Could not connect to kubernetes cluster!
[ERROR] k8s: Connection error: %s: java.net.UnknownHostException: kubernetes.default.svc
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  38.670 s
[INFO] Finished at: 2020-12-24T03:18:42Z
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.eclipse.jkube:kubernetes-maven-plugin:1.0.2:deploy (default-cli) on project helloworld: Execution default-cli of goal org.eclipse.jkube:kubernetes-maven-plugin:1.0.2:deploy failed: Could not connect to kubernetes cluster. Have you started a cluster via `mvn jkube:cluster-start` or connected to a remote cluster via `kubectl`? Error: java.net.UnknownHostException: kubernetes.default.svc: An error has occurred. Unknown host kubernetes.default.svc -&gt; [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException
</code></pre>
<p>Information about Eclipse JKube (successor of Jib plugin) plugin can be found here.</p>
<p><a href="https://www.eclipse.org/jkube/docs/kubernetes-maven-plugin" rel="nofollow noreferrer">https://www.eclipse.org/jkube/docs/kubernetes-maven-plugin</a></p>

<p><strong>MicroK8s</strong> has his own packaged version of <code>kubectl</code> that by default it's accessed through <strong>MicroK8s</strong> including its <strong>configuration</strong>.</p>
<p><code>microk8s kubectl</code></p>
<p>In order that <strong>JKube</strong> knows about your <strong>MicroK8s</strong> cluster you will need to export the configuration <code>microk8s config</code> and put it on your kubeconfig file <code>~/.kube/config</code></p>
<pre><code>cd $HOME
mkdir .kube
cd .kube
microk8s config &gt; config
</code></pre>
<p>Reference: <a href="https://microk8s.io/docs/working-with-kubectl" rel="nofollow noreferrer">https://microk8s.io/docs/working-with-kubectl</a></p>
