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
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.
kubectl get deploy reggo -o yaml --export > deployment.yaml
kubectl delete deploy reggo
kubectl apply -f deployment.yaml
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