Minikube springboot receive request and doesn't respond correctly - spring-boot

I'm beginning with kubernetes and docker and facing an issue.
Deployed a springboot app on minikube after converting it to docker image (using minikube's docker)... the app is online and receiving request so well as you can see in the below screenshots, but doesn't reply as expected.
For example, when i deploy the app normally (on my computer like usually) everything works well i can go on all html pages etc, but once deployed inside minikube it doesn't reply correctly. (all working part is the receiving of favicon of spring)
YAMLs used to deploy the app:
apiVersion: apps/v1
kind: Deployment
metadata:
name: esse-deployment-1
labels:
app: esse
spec:
replicas: 1
selector:
matchLabels:
app: esse-1
template:
metadata:
labels:
app: esse-1
spec:
containers:
- image: mysql:5.7
name: esse-datasource
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: esse_password
- image: esse_application
name: esse-app-1
imagePullPolicy: Never
ports:
- containerPort: 8080
volumes:
- name: esse-1-mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-persistent-storage-claim
---
apiVersion: v1
kind: Service
metadata:
name: esse-service-1
spec:
selector:
app: esse-1
ports:
- protocol: TCP
port: 8080
type: NodePort
----
kind: PersistentVolume
apiVersion: v1
metadata:
name: mysql-persistent-storage
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/home/docker/data"
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: mysql-persistent-storage-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Mi
Docker file to contruct image:
FROM openjdk:8
ADD ESSE_Application.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

I can see you have .yml files to define the deployment and the service, but I can see no "Ingress". A .yml file of kind: Route is needed in order to tell kubernetes that there should be an external url pointing to your service; a minimal Ingress resource example:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /testpath
backend:
serviceName: test
servicePort: 80
**Please don't take this code literally, I'm just trying to draft some example code here and may not match perfectly your naming/data :)

Finally solved the problem.
Everything was working fine because i was launching the app from Eclipse IDE, and when packaging a .jar file, the jps files included inside the /webapp/WEB-INF/jsps folder were not included inside the .jar file and even including them throw the <resources> tag in the pom.xml file didn't solve the problem since the jar packaging isn't suitable for jsp file.
I fixed the problem by adding <packaging>war</packaging> inside the pom.xml file to change the packaging method as the .jsp files feel confortable within a .war file.
Thanks to #Marc for the help.

Related

How to read spring boot configuration file in Kubernetes deployment

Im new in Kubernetes and having a hard time making to read application.properties in the deployment. I have attached our ConfigMap as a mounted volume under the /config path.
This is my deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: 34343434.dkr.ecr.asia-2.amazonaws.com/myapp:latest
ports:
- containerPort: 80
volumeMounts:
- name: application-properties
mountPath: /config
volumes:
- name: application-properties
configMap:
name: application-properties
I have created configmap using kubectl command from a file that is located in my local computer.
kubectl create configmap application-properties -–from-file=/users/me/application.properties
Now the issue is the application.property file which i am setting it using the kubectl configmap is not getting picked up. Can you help me on this?
Based on the discussion, the issue was the configmap, instead of the property file, it was rendered as a string in the configmap.
kubectl get configmap application-properties -o yaml
>shows the contents but with all in oneline format. separated by \n
Converting it to YAML application.yml did the trick.

Kubernetes deployment object throws the 405 errors

I try to make Kubernetes test cluster with Minikube on Windows 10. I use my Spring Boot image which contains Tomcat middleware and Thymeleaf. First I make Pod manifest:
apiVersion: v1
kind: Pod
metadata:
name: app-boot
labels:
deploy: boot-app
spec:
containers:
- name: boot-app
image: app:latest # This image is generated by local docker machine and it works successfully. It contains tomcat and thymeleaf
imagePullPolicy: Never
ports:
- containerPort: 8080
args: ["-t", "-i"]
---
apiVersion: v1
kind: Service
metadata:
name: app-boot-svc
spec:
selector:
deploy: boot-app
ports:
- port: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: boot.aaa.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-boot-svc
port:
number: 8080
The above Kubernetes manifest works successfully without errors. Then I change the Pod object to Deployment like below,
apiVersion: apps/v1
kind: Deployment
metadata:
name: boot-deploy
spec:
replicas: 2
selector:
matchLabels:
deploy: boot-app
template:
metadata:
labels:
deploy: boot-app
spec:
containers:
- name: boot-app
image: app:latest
imagePullPolicy: Never
ports:
- containerPort: 8080
args: ["-t", "-i"]
But the ingress hostname throws the errors,
[nio-8080-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]
The Spring Boot codes which bring out this issue has only http get method only.
#GetMapping("/list")
public void list(#ModelAttribute("pageVO") PageVO vo, Model model) {
....
....
However when I use my Spring Boot Pod objects, the ingress hosts throws no errors. In the case of using Deployment objects, the web browser throws the following errors.
There was an unexpected error (type=Method Not Allowed, status=405)
Is there another option which configure the default web method of Kubernetes pod, service or ingress? If there is, I want to know how to set the default web method of ingress host.
Update
I set the replicas number of Deployment object to 1, Then no errors are thrown from Minikube. And below codes are the Service codes.
apiVersion: v1
kind: Service
metadata:
name: app-boot-svc
spec:
selector:
deploy: boot-app
ports:
- port: 8080
I am afraid my service object codes would contain some errors. Any idea?

Kubernetes spring application in docker connect external service

I'm new in kubernetes and docker world :)
I try to deploy our application in docker in kubernetes, but i can't connect to external mysql database..
my steps:
1, Install kubernetes with kubeadm in our new server.
2, Create a docker image from our application with mvn spring-boot:build-image
3, I create a deployment and service yaml to use image.
Deployment YAML:
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
labels:
app: demo-app
name: demo-app
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: demo-app
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app: demo-app
spec:
containers:
- image: demo/demo-app:0.1.05-SNAPSHOT
imagePullPolicy: IfNotPresent
name: demo-app-service
env:
- name: SPRING_DATASOURCE_URL
value: jdbc:mysql://mysqldatabase/DBDEV?serverTimezone=Europe/Budapest&useLegacyDatetimeCode=false
ports:
- containerPort: 4000
volumeMounts:
- name: uploads
mountPath: /uploads
- name: ssl-dir
mountPath: /ssl
volumes:
- name: ssl-dir
hostPath:
path: /var/www/dev.hu/backend/ssl
- name: uploads
hostPath:
path: /var/www/dev.hu/backend/uploads
restartPolicy: Always
Service YAML:
apiVersion: v1
kind: Service
metadata:
labels:
app: demo-app
name: demo-app
namespace: default
spec:
ports:
- port: 4000
name: spring
protocol: TCP
targetPort: 4000
selector:
app: demo-app
sessionAffinity: None
type: LoadBalancer
4, Create an endpoints and Service YAML, to communicate to outside:
kind: Endpoints
apiVersion: v1
metadata:
name: mysqldatabase
subsets:
- addresses:
- ip: 10.10.0.42
ports:
- port: 3306
---
kind: Service
apiVersion: v1
metadata:
name: mysqldatabase
spec:
type: ClusterIP
ports:
- port: 3306
targetPort: 3306
But it's not working, when i going to see logs i see spring cant connect to database.
Caused by: java.net.UnknownHostException: mysqldatabase
at java.net.InetAddress.getAllByName0(InetAddress.java:1281)
at java.net.InetAddress.getAllByName(InetAddress.java:1193)
at java.net.InetAddress.getAllByName(InetAddress.java:1127)
at com.mysql.cj.protocol.StandardSocketFactory.connect(StandardSocketFactory.java:132)
at com.mysql.cj.protocol.a.NativeSocketConnection.connect(NativeSocketConnection.java:63)
thanks for any helps
hold on. you don't create endpoints yourself. endpoints are registered by kubernetes when a service has matching pods. right now, you have deployed your application and exposed it via a service.
if you want to connect to your mysql database via service it needs to be deployed and kubernetes as well. if it is not hosted on kubernetes you will need a hostname or the ip address of the database and adapt your SPRING_DATASOURCE_URL accordingly!

Start sprinboot in minkube with custom context url as environnement variable

I have a springboot app which I want to deploy on Kubernetes (I'm using minikube) with a custom context path taken from the environment variables.
I've compiled an app.war file. exported an environment variable in Linux as follow:
export SERVER_SERVLET_CONTEXT_PATH=/app
And then started my app on my machine as follow:
java -jar app.war --server.servlet.context-path=$(printenv CONTEXT_PATH)
and it works as expected, I can access my app throw browser using the url localhost:8080/app/
I want to achieve the same thing on minikube so I prepared those config files:
Dockerfile:
FROM openjdk:8
ADD app.war app.war
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.war", "--server.servlet.context-path=$(printenv CONTEXT_PATH)"]
deployment config file:
apiVersion: apps/v1
kind: Deployment
metadata:
name: esse-deployment-1
labels:
app: esse-1
spec:
replicas: 1
selector:
matchLabels:
app: esse-1
template:
metadata:
labels:
app: esse-1
spec:
containers:
- image: mysql:5.7
name: esse-datasource
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: root
- image: esse-application
name: esse-app
imagePullPolicy: Never
ports:
- containerPort: 8080
env:
- name: server.servlet.context-path
value: /esse-1
volumes:
- name: esse-1-mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-persistent-storage-claim
---
apiVersion: v1
kind: Service
metadata:
name: esse-service-1
labels:
app: esse-1
spec:
selector:
app: esse-1
ports:
- protocol: TCP
port: 8080
targetPort: 8080
type: NodePort
However, the java container inside the pod fails to start and here's the exception is thrown by spring:
Initialization of bean failed; nested exception is
java.lang.IllegalArgumentException: ContextPath must start with '/'
and not end with '/'
Make use of configmaps.
The configmap will holds application.properties of your springboot application.
---
apiVersion: v1
kind: ConfigMap
metadata:
name: esse-config
data:
application-dev.properties: |
spring.application.name=my-esse-service
server.port=8080
server.servlet.context-path=/esse-1
NOTE: server.servlet.context-path=/esse-1 will override context-path of your springboot application.
Now refer this configmap in your deployment yaml.
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: esse-deployment-1
labels:
app: esse-1
spec:
replicas: 1
selector:
matchLabels:
app: esse-1
template:
metadata:
labels:
app: esse-1
spec:
containers:
- image: mysql:5.7
name: esse-datasource
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: root
- image: esse-application
name: esse-app
imagePullPolicy: Never
command: [ "java", "-jar", "app.war", "--spring.config.additional-location=/config/application-dev.properties" ]
ports:
- containerPort: 8080
volumeMounts:
- name: esse-application-config
mountPath: "/config"
readOnly: true
volumes:
- name: esse-application-config
configMap:
name: esse-config
items:
- key: application-dev.properties
path: application-dev.properties
- name: esse-1-mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-persistent-storage-claim
NOTE: Here we are mounting configmap inside your springboot application container at /config folder. Also --spring.config.additional-location=/config/application-dev.properties is pointing to the application.properties config file.
In future if you want to add any new config or update the value of existing config that just make the change in configmap and kubectl apply it. Then to reflect those new config changes, just scale down and scale up the deployment.
Hope this helps.
Finally, I found a solution.
I configured my application to startup with a value for the context path taken from the environment variables by adding this line inside my application.properties:
server.servlet.context-path=${ESSE_APPLICATION_CONTEXT}
And the rest remains as it was, means I'm giving the value of the variable ESSE_APPLICATION_CONTEXT throw the config
env:
- name: ESSE_APPLICATION_CONTEXT
value: /esse-1
And then starting the application without the --server.servlet.context-path parameeter, which means like that:
java -jar app.war
NOTE: as pointed by #mchawre's answer, it's also possible to make use of ConfigMap as documented in Kubernetes docs.
Looks like what you want is SERVER_SERVLET_CONTEXT_PATH variable defined in your container spec:
apiVersion: apps/v1
kind: Deployment
metadata:
name: esse-deployment-1
labels:
app: esse-1
spec:
replicas: 1
selector:
matchLabels:
app: esse-1
template:
metadata:
labels:
app: esse-1
spec:
containers:
- image: mysql:5.7
name: esse-datasource
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: root
- image: esse-application
name: esse-app
imagePullPolicy: Never
ports:
- containerPort: 8080
env:
- name: SERVER_SERVLET_CONTEXT_PATH <== HERE
value: /esse-1
volumes:
- name: esse-1-mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-persistent-storage-claim
Note that in your Pod spec you are using /esse-1 while on your local setup you have /app

ReadWriteMany storage on Google Kubernetes Engine for StatefulSets

I used NFS for to mount a ReadWriteMany storage on a deployment on Google Kubernetes Engine as described in the following link-
https://medium.com/platformer-blog/nfs-persistent-volumes-with-kubernetes-a-case-study-ce1ed6e2c266
However my particular use case(elasticsearch production cluster- for snapshots) requires mounting the ReadWriteMany volume on a stateful set.
On using the NFS volume created previously for stateful sets, the volumes are not provisioned for the different replicas of the stateful set.
Is there any way to overcome this or any other approach I can use?
The guide makes a small mistake depending on how you follow it. The [ClusterIP] defined in the persistent volume should be "nfs-server.default..." instead of "nfs-service.default...". "nfs-server" is what is used in the service definition.
Below is a very minimal setup I used for a statefulset. I deployed the first 3 files from the tutorial to create the PV & PVC, then used the below yaml in place of the busybox bonus yaml the author included. This deployed successfully. Let me know if you have troubles.
apiVersion: v1
kind: Service
metadata:
name: stateful-service
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: thestate
---
apiVersion: apps/v1
metadata:
name: thestate
labels:
app: thestate
kind: StatefulSet
spec:
serviceName: stateful-service
replicas: 3
selector:
matchLabels:
app: thestate
template:
metadata:
labels:
app: thestate
spec:
containers:
- name: nginx
image: nginx:1.8
volumeMounts:
- name: my-pvc-nfs
mountPath: /mnt
ports:
- containerPort: 80
name: web
volumes:
- name: my-pvc-nfs
persistentVolumeClaim:
claimName: nfs

Resources