Start sprinboot in minkube with custom context url as environnement variable

8/2/2019

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 '/'

-- Mssm
contextpath
environment-variables
kubernetes
minikube
spring-boot

3 Answers

8/3/2019

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

-- Rico
Source: StackOverflow

8/3/2019

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.

-- mchawre
Source: StackOverflow

8/3/2019

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.

-- Mssm
Source: StackOverflow