How to have the pod created run an application (command and args) and at the same time have a deployment and service referring to it?

4/26/2020

Context:
Tech: Java, Docker Toolbox, Minikube.
I have a java web application (already packaged as web-tool.jar) that I want to run while having all the benefits of kubernetes.
In order to instruct kubernetes to take the image locally I use an image tag:

docker build -t despot/web-tool:1.0 .

and then make it available for minikube by:

docker save despot/web-tool:1.0 | (eval $(minikube docker-env) && docker load)

The docker file is:

FROM openjdk:11-jre
ADD target/web-tool-1.0-SNAPSHOT.jar app.jar
EXPOSE 1111
EXPOSE 2222

1. How can I have the pod created, run the java application and at the same time have a deployment and service referring to it?

1.1. Can I have a deployment created that will propagate a command and arguments when creating the pod? (best for me as I ensure creating a deployment and a service prior to creating the pod)
1.2. If 1.1. not feasible, can I kubectl apply some pod configuration with a command and args to the already created deployment/pod/service? (worse solution as additional manual steps)
1.3. If 1.2. not feasible, is it possible to create a deployment/service and attach it to an already running pod (that was started with "kubectl run ... java -jar app.jar reg")?

What I tried is:
a) Have a deployment created (that automatically starts a pod) and exposed (service created):

kubectl create deployment reggo --image=despot/web-tool:1.0

With this, a pod is created with a CrashLoopBackoff state as it doesn't have a foreground process running yet.

b) Tried the following in the hope of the deployment accepting a command and args that will propagate to the pod creation (1.1.):

kubectl create deployment reggo --image=despot/web-tool:1.0 -- java -jar app.jar reg

The same outcome of the pod, as the deployment doesn't accept command and args.

c) Tried applying a pod configuration with a command and args after the deployment created the pod, so I ran the command from a), found the id (reggo-858ccdcddd-mswzs) of the pod with (kubectl get pods) and then I executed:

kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: reggo-858ccdcddd-mswzs
spec:
  containers:
  - name: reggo-858ccdcddd-mswzs
    command: ["java"]
    args: ["-jar", "app.jar", "reg"]
EOF

but I got:

Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply The Pod
"reggo-858ccdcddd-mswzs" is invalid:
* spec.containers[0].image: Required value
* spec.containers: Forbidden: pod updates may not add or remove containers

that lets me think that I can't execute the command by applying the command/args configuration.

Solution (using Arghya answer):

kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reggo
spec:
  selector:
    matchLabels:
      app: reggo-label
  template:
    metadata:
      labels:
        app: reggo-label
    spec:
     containers:
     - name: reggo
       image: "despot/web-tool:1.0"
       command: ["java"]
       args: ["-jar", "app.jar", "reg"]
       ports:
       - containerPort: 1111
EOF

and executing:

kubectl expose deployment reggo  --type=NodePort --port=1111
-- despot
docker
docker-toolbox
java
kubernetes
minikube

2 Answers

4/26/2020

You could have the java -jar command as ENTRYPOINT in the docker file itself which tells Docker to run the java application.

FROM openjdk:11-jre
ADD target/web-tool-1.0-SNAPSHOT.jar app.jar
EXPOSE 1111
EXPOSE 2222
ENTRYPOINT ["java", "-jar", "app.jar", "reg"]

Alternatively the same can be achieved via command and args section in a kubernetes yaml

containers:
- name: myapp
  image: myregistry.azurecr.io/myapp:0.1.7
  command: ["java"]
  args: ["-jar", "app.jar", "reg"]

Now coming to the point of Forbidden: pod updates may not add or remove containers error the reason its happening is because you are trying to modify an existing pod object's containers section which is not allowed. Instead of doing that you can get the entire deployment yaml and open it up in an editor and edit it to add the command section and then delete the existing deployment and finally apply the modified deployment yaml to the cluster.

  1. kubectl get deploy reggo -o yaml --export > deployment.yaml
  2. Delete the existing deployment via kubectl delete deploy reggo
  3. Edit deployment.yaml to add right command
  4. Apply the yaml to the cluster kubectl apply -f deployment.yaml
-- Arghya Sadhu
Source: StackOverflow

4/27/2020

As already mentioned, recommended approach is to add ENTRYPOINT in your Dockerfile with the command that you are willing to use.

However if you want to create a deployment using kubectl command you can run

kubectl run $DEPLOYMENT_NAME --image=despot/web-tool:1.0 --command -- java -jar app.jar reg

Additionally if you want to expose the deployment using same command you can pass:

--expose=true argument which will create a service of type ClusterIP and

--port=$PORT_NUMBER to choose port on which it will exposed.

to change port type to NodePort you have to run:

kubectl run $DEPLOYMENT_NAME --image=despot/web-tool:1.0 --expose=true --service-overrides='{ "spec": { "type": "NodePort" } }' --port=$PORT_NUMBER --command -- java -jar app.jar reg
-- KFC_
Source: StackOverflow