Containerized Payara with a Google Cloud SQL JDBC resource

In this post we'll explore how we can use docker to automatically setup the Payara application server with a jdbc resource that will securely communicate with a Google Cloud SQL instance and then auto deploy a war file. We'll make use of payara's pre and post boot script files to make all of this happen seamlessly.

I'm going to assume that you have a Google Cloud SQL instance already setup in your google cloud console. If you don't you can go sign up for a Google cloud account and get some free credit here.

Once you have your instance setup you'll want to go to the SSL tab and enable secure connections. You'll then need to create a client certificate and download the client cert, client key, and server CA file. We will use all three of these in our docker container.

Once we have our keys we'll need to download payara and the mysql driver jar file. We'll place all of these files together in a single folder so that we can easily reference them in the Dockerfile that we are going to create. You'll also want your web app's war file here as well so that we can setup the auto deployment.

Now that we have all of the 'ingredients' that we need for this docker recipe we will create our Dockerfile and base it off of the openjdk 8 image. Next we'll define some build-args that will allow us to pass sensitive information to the docker build command via the command line when we build this image. We'll do this so we dont need to hard code passwords or jdbc urls into our dockerfile, in addition to that being a little more secure we also get an image that can be reused easily for building and deploying different apps that may talk to different cloud sql instances.

FROM openjdk:8-jdk

LABEL author="Brett Tucker"

LABEL version="1.0"

LABEL description="This image will use the pre boot and post boot payara scripts to add a \
    google cloud sql datasource to a payara server and then automatically deploy a given war file."








The next part of our Dockerfile will create some environment variables. These will just take the values of the build args and put them into environment variables so that we can make use of them once our container is up and running.
For example, the jdbc url to our sql instance will be referenced in the payara resource.xml file using the ${ENV=SOME_VARIABLE} syntax. That way we dont have to hard code the value of the jdbc url into our resource file so we can easily switch what cloud sql instance we talk to based on where and when we build this Dockerfile.







ENV CERT_DIRECTORY /opt/cloud-sql-certs

Once we've declared all of the build arg and environment variables that we need, we'll copy over our payara server zip file, mysql driver jar, and cloud sql ssl files.

ADD /opt/

RUN unzip /opt/ -d /opt

ADD mysql-connector.jar /opt/payara41/glassfish/lib/


ADD client-cert.pem $CERT_DIRECTORY

ADD client-key.pem $CERT_DIRECTORY

ADD server-ca.pem $CERT_DIRECTORY

After we've brought those files into our image we can use keytool to get them ready for use with payara server. We'll create our own keystore to house our credentials and place it in a place that payara server can reach, then we'll add our sql instance's certificate to the payara trust store as a trusted CA.

RUN openssl pkcs12 -export -in ${CERT_DIRECTORY}/client-cert.pem -inkey ${CERT_DIRECTORY}/client-key.pem -out ${CERT_DIRECTORY}/gcloudsql.p12 -name gcloudsql -CAfile ${CERT_DIRECTORY}/server-ca.pem -caname gcloudsqlCA -passout env:CLOUD_SSL_STORE_PASSWORD

RUN keytool -importkeystore -deststorepass ${CLOUD_SSL_STORE_PASSWORD} -destkeypass ${CLOUD_SSL_KEY_PASSWORD_ARG} -destkeystore /opt/payara41/glassfish/domains/payaradomain/config/my-keystore.jks -srckeystore ${CERT_DIRECTORY}/gcloudsql.p12 -srcstoretype PKCS12 -srcstorepass ${CLOUD_SSL_STORE_PASSWORD} -alias gcloudsql

RUN openssl x509 -outform der -in ${CERT_DIRECTORY}/server-ca.pem -out server-ca.der

RUN keytool -import -noprompt -deststorepass changeit -alias gcloudCA -keystore /opt/payara41/glassfish/domains/payaradomain/config/cacerts.jks -file server-ca.der

Now our payara server is able to securely connect to the cloud sql instance. The next section of the Dockerfile will add our jdbc resource.xml file into the docker image and then take advantage of the fact that we can use text files to change our payara server's admin password without any console interaction at boot time. We do this by first creating the changepassword.txt file. This file contains one line for the current empty password that comes by default in our server and then another line to point at the new password we would like to set. You can see that we make use of our environment variable when creating this file.
The last thing we do in this section of the file is create the password.txt file which we will use whenever we are just executing admin commands in our payara admin console. It simply contains a single line with our new password in it.

ADD resource.xml /opt

RUN touch /tmp/changepassword.txt

RUN chmod 600 /tmp/changepassword.txt

RUN echo "AS_ADMIN_PASSWORD=\n" > /tmp/changepassword.txt

RUN echo "AS_ADMIN_NEWPASSWORD=$PAYARA_ADMIN_PASSWORD" >> /tmp/changepassword.txt

RUN touch /tmp/password.txt

RUN chmod 600 /tmp/password.txt


The end of our dockerfile will expose the ports that we need to expose to use payara, add our pre and post boot scripts to the image as well as our startup shell file. The last thing it will do is set our working directory and then use our startup shell file as our entry point.

EXPOSE 4848 8009 8080 8181

ADD preboot-script.txt /opt/

ADD postboot-script.txt /opt/

WORKDIR /opt/payara41/bin


RUN chmod a+x

ADD application.war /opt/


Let's look at the scripts we added to our image since they will perform the last bit of magic that we need in order for our server to be able to connect to our cloud sql instance.

#Change admin user password to something safer than empty string
change-admin-password admin --passwordfile /tmp/changepassword.txt

#Add our google cloud sql resource
add-resources --user admin --passwordfile /tmp/password.txt /opt/resource.xml

#enabled secure admin
enable-secure-admin --interactive=false --user admin --passwordfile /tmp/password.txt

The preboot script is first changing our admin password using our changepassword.txt file. Then it uses our resource.xml and password.txt file to add our cloud sql jdbc resource and finally it enables secure admin so we can log into the admin console of our payara server once the container is running.

#Test that our connection to cloud sql is good
ping-connection-pool --user admin --passwordfile /tmp/password.txt jdbc/cloudsql-pool

#deploy the app
deploy /opt/application.war

The post boot script is going to ping our connection pool just to make sure everything is healthy and then its going to deploy our application.war file automatically.

#!/usr/bin/env bash
/opt/payara41/bin/asadmin --user admin --passwordfile /tmp/changepassword.txt start-domain --verbose --postbootcommandfile /opt/postboot-script.txt --prebootcommandfile /opt/preboot-script.txt payaradomain

The startup shell file is what docker will execute when we run the container. It is simply executing a start domain command and passing along the location of our pre and post boot command files.

That's it! You now have everything you need to spin up a containerized payara instance capable of securely communicating with your cloud sql database and auto deploying your application's war file. I'm including links to github gists for all of the files that I used to create this tutorial at the bottom of the page and if you are looking for more great examples of Dockerfiles and JavaEE related tech then I strongly suggest you look at Adam Bien's dockland repository