I\'m using GlassFish to serve up a Java EE web app. Things are working fine on my local dev machine. I have
What follows is something that works for me - but I have a feeling I'm missing something. Any edits/comments would be most welcome.
There are various hooks in the EB/Docker deployment that allow execution of post-deployement hooks to be run in a glassfish instance, within a docker container, within a EB instance. I used post-deployment hooks to set up a connection pool. Here's what the final install looks like, just for reference:
| | | \_WAR_/ | | |
| | \_Glassfish_/ | |
| \____Docker____/ |
\____EC2 Instance____/
The overall desired outcome is that, after the app is deployed, inside the Docker instance, the asadmin commands are run to create a JDBC connection pool, and to make that connection pool into a jdbc resource. On my local machine, the commands would be
asadmin create-jdbc-connection-pool
--datasourceclassname org.postgresql.ds.PGConnectionPoolDataSource
--restype javax.sql.ConnectionPoolDataSource
--property user=USERNAME:password=PASSWORD:serverName=DBHOST:portNumber=5432:databaseName=DBNAME
poolName
asadmin create-jdbc-resource --connectionpoolid poolName jdbc/dev
Where 'jdbc/dev' is the name that the java code needs to know to get a connection in the usual manner i.e.
InitialContext ctx = new InitialContext();
ds = (DataSource)ctx.lookup("jdbc/dev");
We want the commands to run inside the docker instance, because the docker instance has access to the environment variables that you declare in the AWS admin console, so I can pass configuration information without having it in my build scripts.
To achieve this outcome, we require that a file is created in the EC2 instance during installation, in my case called /opt/elasticbeanstalk/hooks/appdeploy/post/99_configure_jdbc.sh. This file will be executed post-deployment, as root, in the EC2 instance. I'll refer to it as the ec2-post-deploy-hook.
We're going to create that file using a .ebextensions/.config file, as documented here
My .config file has the following contents:
files:
"/opt/elasticbeanstalk/hooks/appdeploy/post/99_configure_jdbc.sh":
mode: "000755"
owner: root
group: root
content: |
#!/bin/bash
date > /tmp/post 2>&1
dockerid=`docker ps | grep latest | cut -d" " -f1`
echo $dockerid >> /tmp/post 2>&1
docker ps >> /tmp/post 2>&1
docker exec $dockerid /var/app/WEB-INF/classes/setup_pool.sh >> tmp/post 2>&1
Everything after the content: | ends up in the ec2-post-deploy-hook.
I learned this idea from http://junkheap.net/blog/2013/05/20/elastic-beanstalk-post-deployment-scripts.
Only the last line and the 4th last line are needed, but the other lines are useful for debugging. Output ends up in /tmp/post on the EC2 instance.
The one trick in that file is that we can always get the ID of the docker container by
sudo docker ps | grep latest | cut -d" " -f1
because after deployment there will only be one Docker container running, and it will have "latest" in its name.
The last line of the ec2-post-deploy-hook uses docker to run, inside the docker instance, those commands that I originally wanted run - that is, the asadmin commands. I deploy a file called setup_pool.sh inside my .war file, so it ends up in a known location during deployment. My setup_pool.sh looks like this (and I call it a docker-post-deploy-hook):
dbuser=$PARAM1
dbpass=$PARAM2
dbhost=$PARAM3
dbname=$PARAM4
date > /tmp/setup_connections
echo '*********' >> /tmp/setup_connections
asadmin create-jdbc-connection-pool --datasourceclassname org.postgresql.ds.PGConnectionPoolDataSource --restype javax.sql.ConnectionPoolDataSource --property user=${dbuser}:password=${dbpass}:serverName=${dbhost}:portNumber=5432:databaseName=${dbname} ei-connection-pool >> /tmp/setup_connections 2>&1
echo '*********' >> /tmp/setup_connections
asadmin create-jdbc-resource --connectionpoolid ei-connection-pool jdbc/dev >> /tmp/setup_connections 2>&1
echo '*********' >> /tmp/setup_connections
This file is run within in docker instance. The two asadmin commands are the meat, but again, there's some debugging into /tmp/setup_connections within the docker instance
Passwords, etc, are obtained from the AWS environment.
The only thing I cannot do at this point is have the AWS environment variables available on first deployment. I have no idea why, but I only seem to be able to set them after the instance is up and running. This means that I have to deploy twice, a dummy deploy, followed by an edit of the environment, followed by a real deploy.
So, summing up,
And it all works. It's kind of ugly to behold, but, you know, so am I.
After struggling with this myself for sometime, I think I have finally found an acceptable workaround (atleast for me) as follows :-
Create DockerFile and package it directly inside the WAR (at the highest level, not in any folder). DockerFile -
# Use the AWS Elastic Beanstalk Glassfish image
FROM amazon/aws-eb-glassfish:4.1-jdk8-onbuild-3.5.1
# Exposes port 8080
EXPOSE 8080 4848 8181
# Install Datasource dependencies
RUN curl -L -o /tmp/connectorj.zip https://server/path/connectorj.zip && \
unzip /tmp/connectorj.zip -d /tmp && \
cp /tmp/connectorj/mysql-connector-java-5.1.36-bin.jar /usr/local/glassfish4/glassfish/domains/domain1/lib/ && \
mv /var/app/WEB-INF/classes/domain.xml /usr/local/glassfish4/glassfish/domains/domain1/config/
Now when this WAR is deployed (I am using 'eb deploy'). This DockerFile is executed.
In the simple example above - first mysql jdbc driver is downloaded and setup into glassfish's lib directory. Next I have packaged domain.xml (all the resources, etc already setup) inside the WAR itself, gets moved to glassfish's domain config folder to be loaded when glassfish will start.