Running SpringBoot app on Docker

Example

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.demo</groupId>
	<artifactId>hellospring</artifactId>
	<version>1</version>
	<name>HelloSpring</name>
	<description>HelloSpring</description>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.7.9</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<properties>
		<java.version>1.8</java.version>
		<maven.compiler.source>${java.version}</maven.compiler.source>
		<maven.compiler.target>${java.version}</maven.compiler.target>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<start-class>com.hellospring.App</start-class>
	</properties>
	<build>
		<pluginManagement>
			<plugins>
				<plugin>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-maven-plugin</artifactId>
				</plugin>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-dependency-plugin</artifactId>
					<executions>
						<execution>
							<goals>
								<goal>sources</goal>
								<goal>resolve</goal>
							</goals>
							<configuration>
								<classifier>javadoc</classifier>
							</configuration>
						</execution>
					</executions>
				</plugin>
				<plugin>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-maven-plugin</artifactId>
					<configuration>
						<mainClass>com.hellospring.App</mainClass>
						<layout>JAR</layout>
					</configuration>
					<executions>
						<execution>
							<goals>
								<goal>repackage</goal>
							</goals>
						</execution>
					</executions>
				</plugin>
			</plugins>
		</pluginManagement>
		<finalName>hello-spring</finalName>
	</build>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
</project>

Main class

package com.hellospring;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class App {
	public static void main(String[] args) {
		SpringApplication.run(App.class, args);
	}
}

Controller Class

package com.hellospring;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController()
@RequestMapping("/hello")
public class AppController {
	@GetMapping
	public String helloGradle() {
		System.out.println("Hello !");
		return "Hello !";
	}
}

Dockerfile

FROM maven AS build
MAINTAINER suraj kutteri <gill.tyson332@gmail.com>
WORKDIR /opt/build
COPY . .
#RUN mvn -B package --file pom.xml
RUN mvn -B package --file pom.xml spring-boot:repackage
FROM openjdk
#RUN groupadd --gid 1200 tyson332 && adduser --disabled-password --home /app --gecos "" --uid 1200 --gid 1200 tyson332
RUN groupadd --gid 1200 tyson332 && adduser --home /app --uid 1200 --gid 1200 tyson332
WORKDIR /app
COPY --from=build /opt/build/target/*.jar app.jar
COPY start.sh start.sh
RUN chmod +x start.sh
# RUN chown -R atomuser:atomuser /app
#ENTRYPOINT ["/app/start.sh"]
CMD ["java","-jar","app.jar"]

Create an Image of Docker

docker build -t spring_build_test:1 .

Run the Docker Image

#First Find the Id of docker image using below command
docker images
#Run the docker image by using below command
docker run <image_id>
docker run 86b3f95d7c91

Basics of k8 Deployment

  • You describe a desired state in deployment
  • Traditionally deployment a usually done by shell scripts which execute line by line from top to bottom
  • In k8 deployment, you don’t write that but instead, we describe how the deployment will be with the help of a YAML file (desired state) and k8 takes care of the reset
  • The deployment controller is the component that takes the deployment file and relays the information to POD and replica set about the deployment
  • Control loop components are the objects which which compare the actual state and the desired state and scales the application according to the need mentioned in the deployment yaml file

Benefits :

  • You can scale the application with n number of pods on demand

Deployment.yaml for a Image which is already present on the local system (Docker Desktop)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-boot-test
spec:
  replicas: 2
  selector:
    matchLabels:
      app: spring-boot-test
  template:
    metadata:
      labels:
        app: spring-boot-test
    spec:
      containers:
      - name: spring-boot-test
        image: spring_build_test:1
        ports:
        - containerPort: 9090

Running the deployment.yaml using kubectl

kubectl apply -f k8\deployment.yaml

Checking the deployment status

kubectl get deploy

Check the deployment description (Step1 – Debugging)

kubectl describe deployment spring-boot-test

Check the pods description (Step2 – Debugging)

kubectl get pods
kubectl describe pod spring-boot-test-7c9d4947dd-4lz9n

Check the logs of pods (Step3 – Debugging)

kubectl get pods
kubectl logs spring-boot-test-7c9d4947dd-4lz9n | tail -20

Summary :

  • How to Start a deployment
    • kubectl apply -f k8\deployment.yaml
  • How to delete a deployment
    • kubectl delete deploy spring-boot-test
  • How to check the status of deployment
    • kubectl get deploy
  • Details for debugging
    • Check Deployment
      • kubectl get deployments
      • kubectl describe deployments <deployment_name>
    • Check Pods
      • kubectl get pods
      • kubectl describe pods <pod_name>
    • Check Logs of pods
      • kubectl logs <pod_name>

Basics of k8 & kubectl

  • Utility to configure and operate Kubernetes
  • kubectl can point to multiple clusters

How kubectl connects to a cluster

  • Kubectl connects to cluster using config file
  • Location of config file (in order of precendence)
    • Config file is located under location “C:\Users\Tyson\.kube\config”
    • kubectl config –kubeconfig=”C:\folder\file”
    • KUBECONIFG — Environment variable sets the path
  • Config file has three parts
    • clusters (and https endpoint)
      • Cluster has information about the server details
      • certificate-authority-data for that Cluster
    • users
      • User has list of users who can connect to any cluster
    • contexts
      • Context Combines User and Clusters, letting us know which user can connect to which cluster

Commands

  • kubectl config current-context
    • To find the current context
  • kubectl config get-contexts
    • List all the context
  • kubectl config use-context <context-name>

Kubectl get commands

  • kubectl get pods
  • kubectl get deployments
  • kubectl get services
  • kubectl get configmaps
  • kubectl get secrets
  • kubectl get ingress

Namespace

  • Normally resources are scoped to a namespace
  • Namespaces are like project groups or a resource group
  • Allows resources to be separated from one another
  • By default all the commands run against be default namespace
  • You can query to a specific name space by passing an argument -n <namespace>

Command

  • kubectl get namespaces
    • List all the namespaces
  • kubectl create namespace <new-namespace-name>
    • To create a new namespace
  • kubectl get pods -n <namespace-name>
    • List all the pods in a namespace

Describe Command (Troubleshooting command)

  • kubectl describe <resource> <name>

Example :

  • Lets take an example of a system namespace that bydefault comes with K8
  • And then describe it to see its details

Command

  • kubectl get namespace
  • kubectl get pods -n kube-system
  • kubectl describe pod coredns-565d847f94-fpvkp -n kube-system

Important labels to look for

  • Event section usually shows an error description if the pod is in a crashback look

Reference :

ulimit (user limit)

ulimit is admin access required Linux shell command which is used to see, set, or limit the resource usage of the current user. It is used to return the number of open file descriptors for each process. It is also used to set restrictions on the resources used by a process.

Syntax:

To check the ulimit value use the following command:

ulimit -n (open files)
ulimit -a
ulimit values

Working with ulimit commands:

1. To display maximum users process or for showing maximum user process limit for the logged-in user.

ulimit -u
showing maximum users per process

2. For showing the maximum file size a user can have.

ulimit -f
For showing the maximum file size a user can have

3. For showing maximum memory size for the current user.

ulimit -m
For showing maximum memory size for the current user.

4. For showing maximum memory size limit.

ulimit -v
For showing maximum memory size limit.

What are Soft limits and Hard limits in Linux? 

The soft limits are the limits which are allocated for actual processing of application or users while the Hard limits are nothing but an upper bound to the values of soft limits. Hence,  

(soft limits <= hard limit)

Working with Hard and Soft limit values:

1. For displaying the Hard limit. Hard limits are a restriction to the maximum value of soft limits

ulimit -Hn
For displaying the Hard limit

2. For displaying Soft Limit. The soft limits are the limits that are there for processing.

ulimit -Sn
Displaying soft limit values

3. To change Soft Limit values:

sysctl -w fs.file-max=<value>

Note: Replace <value> with the value you want to set for the soft limit and also remember size can not exceed the Hard Limit!

4. Displaying current Values for opened files

cat /proc/sys/fs/file-max
Displaying current Values for opened files

Kubernetes deployment

  • User perform Kubernetes deployment directly
    • Deployment performs replication
    • POD creation
    • Container creation
  • Kubernetes deployment can be done by
    • Command (Internally a yaml file is created when command fired)
    • Yaml file

Create and Edit deployment

Syntax to Create Deployment

kubectl create deployment <deployment-name> --image=<image_name>

Example :

kubectl create deployment nginx-depl --image=nginx

Syntax to edit Deployment

kubectl edit deployment <deployment-name>

Example :

kubectl edit deployment nginx-depl

Now you can check if the old pod is terminated and new pod is recreated

Debug a deployment

  • logs
  • describe
  • bash terminal

Example of mongo db

logs
describe
Visit the container

Delete Deployment

Nginx Deployment on k8 with Service

Deployment File – nginx-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-deployment
  labels:
    app: orderlabel
spec:
  replicas: 3
  selector:
    matchLabels:
      app: orderlabel
  template:
    metadata:
      labels:
        app: orderlabel
    spec:
      containers:
      - name: orderapi
        image: nginx:1.14.2
        ports:
        - containerPort: 80

Servcie File – service.yaml

apiVersion: v1
kind: Service
metadata:
  name: order-service
spec:
  selector:
    app: orderlabel
  type: LoadBalancer
  ports:
    - protocol: TCP
      port: 8083
      targetPort: 80

How to execute these files on k8 ?

kubectl get all #display all status
cd /to/the/yaml/files/directory/
kubectl apply -f nginx-deployment.yaml
kubectl apply -f service.yaml
kubectl get all
kubectl get pods
kubectl get service

How to check if it is working ? – http://localhost:8083/

hit the URL – http://localhost:8083/

How to stop the deployment ?

kubectl scale --replicas=0 deployment.apps/order-deployment
kubectl get all #check if no pods exist
kubectl delete deploy order-deployment
kubectl delete service order-service

Kubernetes namespace Information

  • Namespaces are a way to organize clusters into virtual sub-clusters
  • They can be helpful when different teams or projects share a Kubernetes cluster
  • Any number of namespaces are supported within a cluster, each logically separated from others but with the ability to communicate with each other. 
  • Namespaces cannot be nested within each other.

  • Any resource that exists within Kubernetes exists either in the default namespace or a namespace that is created by the cluster operator
  • Only nodes and persistent storage volumes exist outside of the namespace; these low-level resources are always visible to every namespace in the cluster.

What is the “default” namespace in Kubernetes?

Kubernetes comes with three namespaces out-of-the-box. They are:

  1. default: As its name implies, this is the namespace that is referenced by default for every Kubernetes command, and where every Kubernetes resource is located by default. Until new namespaces are created, the entire cluster resides in ‘default’.
  2. kube-system: Used for Kubernetes components and should be avoided.
  3. kube-public: Used for public resources. Not recommended for use by users.

Namespace can be used on

  • deployment
  • pods
  • service
  • configmap
  • secrets

  • List of namespace
kubectl get namespace
  • Create namespace