1

I have an application-level context.xml with three different databases connections, and my application successfully connects and works fine against those databases. The war file is added to a Tomcat Docker image, and the container runs great.

But, what I really need is the ability to bring up my WAR file with different context.xml files in different environments (Development, QA, and Production). Each environment has its own set of three database connections (i.e. unique URLs/usernames/passwords but the same resource names).

Is there a mechanism in Tomcat where I can pass an environment variable into the Tomcat container at startup, and specify which context file to use? e.g. if I had META-INF/context_dev.xml, META-INF/context_qa.xml, and META-INF/context_prod.xml.

Or, is there some other different kind of mechanism I should be using to have one Docker image that works with three different sets of database resources?

Thanks, John

John Fisher
  • 137
  • 3
  • 15
  • You can mount the environment-specific config file on top of the one included in the container image. That way you can use the same image with different configuration files without rebuilding the image when configs change. – Burak Serdar Jul 27 '20 at 19:23
  • Thank you for responding but I'd like to keep all the configuration information within the docker image, so the context files don't need to be maintained elsewhere. This will be especially true when we eventually move to Kubernetes, and the server it runs on can vary. – John Fisher Jul 27 '20 at 19:27
  • With Kubernetes, you are expected to use configmaps for this purpose. You can effectively maintain multi-environment configurations using configmap and kustomize. When you store configurations in an image, a configuration change requires an image build and deployment, which can be avoided using configmaps. – Burak Serdar Jul 27 '20 at 19:42
  • I guess the emphasis is on the word "eventually" :-) We need an intermediate solution that just works with Docker. – John Fisher Jul 27 '20 at 19:51
  • There's no out-of-the-box configuration to establish JNDI data sources from a Kubernetes server. This is actually something I've been interested in looking into. If this is something you'd like to discuss further, please join the Tomcat users' mailing list and bring the topic up for discussion. – Christopher Schultz Jul 31 '20 at 19:56

2 Answers2

0

In containers and docker as well as kubernetes, ENV variables are the way to go to pass configuration to your container.

You set your tomcat so it also take them into account and use the ENV name in the file.

For tomcat (independtly of having containers or not) an explanation on how to pass env variables is shown there: Tomcat 8 - context.xml use Environment Variable in Datasource

How to pass env variable to your container: How do I pass environment variables to Docker containers?

Then you can pass your env variable in command line with RAW docker or use an .env file. Changing the command like with different values for the ENV variable or just a different .env file to use will do the trick.

Nicolas Bousquet
  • 3,990
  • 1
  • 16
  • 18
  • Thanks Nicolas. Unfortunately, my ability to use environment variables is clouded by my use of a password vault (https://weinan.io/2017/03/04/how-to-use-tomcat-vault.html) to encrypt and store the database passwords. This tool uses a variable solution inside the context.xml, that I'm guessing will conflict with your suggestion. – John Fisher Jul 27 '20 at 20:48
  • Then, you use docker secrets (enablind docker swarm on your docker if it isn't the case already) to push you various volf file to the container. Basically dockers secrets work a bit like volumes but are encrypted and safe to store sensitive data. More explanation are available there: https://docs.docker.com/engine/swarm/secrets/ – Nicolas Bousquet Jul 27 '20 at 20:58
0

I made a solution that will work for me with minimal changes, taking as inspiration the suggestions I received above. Basically, I put ALL the resources for ALL the environments in context.xml, then I named them like such:

<Resource
   name="${PRODENV}/mydb1"
   XXXXXXX
/>

<Resource
   name="${PRODENV}/mydb2"
   XXXXXXX
/>

<Resource
   name="${QAENV}/mydb1"
   XXXXXXX
/>

<Resource
   name="${QAENV}/mydb2"
   XXXXXXX
/>

Then, when I start the container, I just add -DPRODENV=jdbc or -DQAENV=jdbc to the JAVA_OPTS environment variable. Only the two that I want get loaded, as appropriate. The rest are just never referenced.

John Fisher
  • 137
  • 3
  • 15
  • This is a reasonable technical solution to the problem, but it may contain some security problems. Is it okay with you to disclose QA or prod's database credentials to dev/test environments? – Christopher Schultz Jul 31 '20 at 20:00