I will add 300 points as bounty
I have recently started to take a closer look at Docker and how I can use it for faster getting new member of t
The way you would normally deploy anything with Docker is by producing a new image atop of the platform base image. This way you follow Docker dependency bundling philosophy.
In terms of Maven, you can produce a tarball assembly (let's say it's called jars.tar
) and then call ADD jars.tar /app/lib
in Dockerfile. You might also implement a Maven plugin that generates a Dockerfile as well.
This is the most sane approach with Docker today, other approaches, such as building image FROM scratch
are not quite applicable for Java applications.
See also Java JVM on Docker/CoreOS.
For my current deployment process I use glassfish and this trick, which works very nicely.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${plugin.exec.version}</version>
<executions>
<execution>
<id>docker</id>
<phase>package</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>docker</executable>
<arguments>
<argument>cp</argument>
<argument>${project.build.directory}/${project.build.finalName}</argument>
<argument>glassfish:/glassfish4/glassfish/domains/domain1/autodeploy</argument>
</arguments>
</configuration>
</plugin>
Once you run: mvn clean package, the containers kicks-in and starts deployment of the latest war.
I've used Docker with Glassfish extensively, for a long time now and wrote a blog on the subject a while ago here.
Its a great tool for JavaEE development.
For your production image I prefer to bundle everything together, building off the static base image and layering in the new WAR. I like to use the CI server to do the work and have a CI configuration for production branches which will grab a base, layer in the release build, and then publish the artifact. Typically we manually deploy into production but if you really want to get fancy you can even automate that with the CI server deploying into a production environment and using proxy servers to ensure new sessions that come it get the updated version.
In development I like to take the same approach when it comes time to locally running any that rely on the container (eg. Arquillian integration tests) prior to checking in code. That keeps the environment as close to production as possible which I think is important when it comes to testing. That's one big reason I am against approaches like testing with embedded containers but deploying to non-embedded ones. I've seen plenty of cases where a test will pass in the embedded environment and fail in the production/non-embedded one.
During a develop/deploy/hand test cycle, prior to committing code, I think the approach of deploying into a container (which is part of a base image) is more cost effective in terms of speed of that dev. cycle vs. building in your WAR each time. It's also a better approach if your dev environment uses a tool like JRebel or XRebel where you can hot deploy your code and simply refresh your browser to see the changes.
The blog post about setting up JRebel with Docker by Arun Gupta would probably be handy here: http://blog.arungupta.me/configure-jrebel-docker-containers/
With the latest version of Docker, you can achieve that easily with Docker Links, Docker Volume and Docker Compose. More information about these tools from Docker site.
Back to your workflow as you have mentioned: for any typical Java EE application, an application server and a database server are required. Since you do not mention in your post how the database is set up, I would assume that your development environment will have separated database server for each developer.
Taking all these into assumption, I could suggest the following workflow:
docker run -d -it -p 8080:8080 -p 9990:9990 --name baseWildfly jboss/wildfly
The application server is running now, you need to configure it to connect to your database server and also configure the datasource settings and other configuration if neccessary in order to start your Java EE application. For this, you need to log into bash terminal of the Jboss container:
docker exec -i -t baseWildfly /bin/bash/
You are now in the terminal of container. You can configure the application server as you do for any linux environment.
You can test the configuration by manually deploying the WAR file to Wildfly. This can be done easily with the admin console, or maven plugin, or ADD command as you said. I usually do that with admin console, just for testing quickly. When you verify that the configuration works, you can remove the WAR file and create a snapshot of your container:
docker commit --change "add base settings and configurations" baseWildfly yourRepository:tag
You can now push the created image to your private repository and share that with your developer team. They can now pull the image and run the application server to deploy right away.
We don't want to deploy the WAR file for every Maven build using admin console as that is too cumbersome, so next task is to automate it with Docker Volume.
Assuming that you have configured Maven to build the WAR file to "../your_project/deployments/", you can link that to deployment directory of Jboss container as following:
docker run -d -p 8080:8080 -v ../your_project/deployments:/opt/jboss/wildfly/standalone/deployments
Now, every time you rebuild the application with Maven, the application server will scan for changes and redeploy your WAR file.
It is also quite problematic to have separated database server for each developer, as they have to configure it by themselves in the container because they might have different settings (e.g. db's url, username, password, etc...). So, it's good to dockerize that eventually.
Assuming you use Postgres as your db server, you can pull it from postgres official repository. When you have the image ready, you can run the db server:
docker run -d -p 5432:5432 -t --name postgresDB postgres
or run the database server with the linked "data" directory:
docker run -d -p 5432:5432 -v ../your_postgres/data:/var/lib/postgresql -t --name postgresDB postgres
The first command will keep your data in the container, while the latter one will keep your data in the host env.
Now you can link your database container with the Wildfly:
docker run -d -p 8080:8080 --link postgresDB:database -t baseWildfly
Following is the output of linking:
Now you can have the same environment for all members in developer's team and they can start coding with minimal set up.
The same base images can be used for Production environment, so that whenever you want to release new version, you just need to copy the WAR file to "your_deployment" folder of the host.
The good thing of dockerizing application server and db server is that you can cluster it easily in the future to scale it or to apply the High Availability.
I have tried a simular scenario to use docker to run my application. In my situation i wanted to start docker with tomcat running the war. Then at the integration-test phase of maven start the cucumber/phantomjs integration test on the docker. The example implementation is documented at https://github.com/abroer/cucumber-integration-test. You could extend this example to push the docker image to your private repo when the test is successfull. The pushed image can be used in any enviroment from development to production.