Run a script after starting tomcat at k8s pod startup

1/20/2020

I'm trying to run a pod-bootstrapping script (which basically runs a java program) after tomcat is started in the pod. My pod runs a single tomcat-based container. Here is the snippet that I'm working and re-working on:

     - image: myreg/mydir/myimg:local
       name: tomcat-adminapp
       command: ["/bin/sh"]
       args: ["-c", "$CATALINA_HOME/bin/startup.sh && /scripts/runUpg.sh"]

runUpg.sh script:

#!/bin/sh
ls -l $CATALINA_HOME/webapps/app/WEB-INF/lib/
chmod 755 $CATALINA_HOME/webapps/app/WEB-INF/lib/*
java -classpath "$CATALINA_HOME/webapps/app/WEB-INF/lib/*" com.myclass.Upg <args> 
tail -f /dev/nul

It is starting tomcat but my script execution fails. When I exec into the pod, I see the war is exploded, CATALINA_HOME is set and tomcat process is running. But I see following script errors in kubectl logs:

ls: cannot access '/userhome/tomcat/webapps/app/WEB-INF/lib/': No such file or directory chmod: cannot access '/userhome/tomcat/webapps/app/WEB-INF/lib/*': No such file or directory Error: Could not find or load main class com.myclass.Upg Caused by: java.lang.ClassNotFoundException: com.myclass.Upg

From the error I'm guessing the shell script might not be waiting for tomcat to finish its startup. I'm not sure why..

When I manually run the script from inside the pod, it runs fine.

Any pointers here are appreciated..

Update: I confirmed it is indeed the timing issue. When I use $CATALINA_HOME/bin/startup.sh && sleep 60 && /scripts/runUpg.sh, the script seems to run fine. But I think this is hack-ish and not the right way to achieve a call to a class within the webapp.

-- A.R.K.S
kubernetes
tomcat

2 Answers

1/20/2020

Consider postStart hook to execute a script after the container is started.

sample reference

apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
spec:
  containers:
  - name: lifecycle-demo-container
    image: nginx
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
-- P Ekambaram
Source: StackOverflow

1/20/2020

Some things look "suspicious" to me:

  1. /userhome/tomcate/webapps/app/WEB-INF/lib - shouldn't it be /user/home? (its just a side note, I'll assume you've defined it correctly)

  2. Real issue. I don't remember how exactly the tomcat scripts are defined but event without kubernetes you can try to run the tomcat startup script and immediately run something like ls on the lib folder. The chances that the folder indeed won't exist and here is why (in my understanding, again):

Tomcat (as a standalone process) was written in a way that it will run "always" but in some points of time you could place "WARs" into webapps folder and it will extract the WAR and start the appliaction. Then you could later, again, place another war and so forth. In other words, Lifecycle of Tomcat as a process is not bound to the lifecycle of the application

The startup process of the tomcat itself is supposed to read the configurations, create HTTP connector to listen on port 8080 or something and thats it, after this point the script is done, the tomcat is started.

In terms of solution:

Don't rely on tomcat to create a classpath of your process for you, its just wrong. Instead you can:

  1. Wrap your process into WAR so that the tomcat will manage it as well, again it can server many WARs not just one
  2. Create a sidecar container with your application, so that 2 containers will run in the pod side-by-side. This is a kubernetes way of doing things and probably its the best solution. In any case the com.myclass.Upg process should be self-contained (meaning contain its own dependencies).
-- Mark Bramnik
Source: StackOverflow