home.


Tagged: tomcat


Docker tutorial: Expose a service (tomcat)

Once you’ve got docker (I’m on 0.6.4) running, you can start a service and expose it to the outside world.

We’ll do this for tomcat7.

First get an container, the basic 120MB ubuntu container for starters

docker pull ubuntu

Then open bin/bash in that container, passing -t allows a psedo tty and -i keeps stdin open even if not attached. You need them to interact with bash.

docker run -t -i ubuntu /bin/bash

You’re now in command prompt of your container. Let’s use this time to install some stuff.

echo "deb http://dk.archive.ubuntu.com/ubuntu/ precise-security main universe" >> /etc/apt/sources.list
apt-get install python-software-properties 
add-apt-repository ppa:webupd8team/java
apt-get update
apt-get install oracle-java7-installer tomcat7 vim
vim /etc/default/tomcat7
# now ensure JAVA_HOME=/usr/lib/jvm/java-7-oracle
service tomcat7 start

Now ensure you get the tomcat7’s index.html page by running “wget localhost:8080” in the container. If you can get it, all is well.

You can exit the container by pressing CTRL-D.

If you run “docker ps -a” you’ll get all the processes, even stopped ones, which your container now is.

docker ps -a
ID                  IMAGE               COMMAND                CREATED             STATUS              PORTS
9cfedc79aefb        ubuntu:12.04        /bin/bash              About an hour ago   Exit 127                                
...

You can now commit all the changes to that container. You need to do this everytime you want to update your container for later use.

docker commit 9cfedc79aefb ITS_NAME

You should now see this new image when you run docker images

docker images
REPOSITORY          TAG                 ID                  CREATED             SIZE
ITS_NAME            latest              9cfedc79aefb        About an hour ago   550.7 MB (virtual 693.8 MB)

You can start this container up again by running ‘docker run -t -i ITS_NAME /bin/bash’.

Notice that only the filesystem changes persist, not the running processes. So your tomcat7 service is no longer running.

You can get around this by detaching from a running container–although when your container stops so do your services.

Exit the container again. Now we’ll run it again, but this time we’ll forward port 8080 on the container, and we’ll start tomcat7.

docker run -i -t -p 8080 ITS_NAME /bin/bash
service tomcat7 start

Now instead of exiting the container, detach from it back to your terminal by typing:

ctrl-p then ctrl-q 

(If you’re using gnu screen, remember it’s ctrl-a a ctrl-p, then ctrl-q)

Now run docker ps you can see the forwarding in action.

docker ps
ID                  IMAGE               COMMAND             CREATED             STATUS              PORTS
9b762583b0d0        ITS_NAME:latest     /bin/bash           2 minutes ago       Up 2 minutes        49173->8080 

Note it says we need connect to port 49173 to connect to the 8080 in the container. First we need ip address of docker however.

‘ifconfig’ should show you something like

docker0   Link encap:Ethernet  HWaddr blar:blar:blar
          inet addr:172.17.42.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: blar:blar:blar/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:86662 errors:0 dropped:0 overruns:0 frame:0
          TX packets:135316 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:4610283 (4.3 MiB)  TX bytes:190087628 (181.2 MiB)

So you see you need to look at 172.17.42.1, in this machine’s case, to connect to docker. And as such you can access your container’s tomcat instance via

http://172.17.42.1:49173

If you want to reattach to your container to run more services, for example, use ‘docker attach’ with your container’s id.

docker ps
# look at the container id
docker attach <the container id>
# now run more command in bash if you wish

You should next look at dockerfiles to automate all this.

unix docker tomcat

JSP: Setup JSTL and EL in Tomcat 7

If you want to use JSTL (and you do) instead of scriptlets you first have to include it in your war file or your tomcat lib file.

I imported it into my project using Gradle. You should see the jar file in the created WAR file once you’re using it.

Now you can use things like:

    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 
    <c:forEach var="p" items="${applicationScope['products'].values().iterator()}">

       ${p.name} | ${p.getPrice()} || <a href="Cart?add=true&id=${p.getId()}">add</a>
       <br />

    </c:forEach>

Note you don’t need the scriptlet %@ page import.. directives anymore. You do need thee taglib directive to point to the jstl core library.

Note we’re using the JSP EL, expression language, syntax to call method and attribute (p.name is the same as p.getName()). EL comes with Tomcat 7 - no additional libraries are required.

As with scriplets there are implicit objects in EL, applicationScope, in this example. ’applicationScope[‘products’] is the same as applicationScope.getAttribute(‘products’).

jsp jstl jstl-foreach tomcat jsp-el

Tomcat 7: Apache HTTPd 2.2 integration with virtual-hosts

First install and enable the mod_jk module for Apache

    apt-get install libapache2-mod-jk
    a2enmod jk

Then create a workers file. A worker is a process that will connect you to a tomcat instance. We’re creating the workers.properties file at /etc/apache2/workers.properties.

    worker.list=worker1
    worker.worker1.type=ajp13
    worker.worker1.host=localhost
    worker.worker1.port=8009

We’re giving it a name (will be used later), saying we’re using the ajp13 connector to connect to tomcat 6 and above instances, saying it’s on localhost and saying we’re listening on port 8009 (we’ll set tomcat listening on this port in a little while.)

Now in your apache.conf file, add:

    JkWorkersFile /etc/apache2/workers.properties
    JkShmFile /var/log/apache2/mod_jk.shm
    JkLogFile /var/log/apache2/mod_jk.log
    JkLogLevel info
    JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "

Here we point to our workers file, setup some file locations to be next to each other and set some logging information.

Finally edit the /etc/tomcat7/server.xml to accept these ajp13 connections. Uncommend this line:

    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

The only thing left is to setup your virual host file. Here’s an example of a virtual host file you should have in /etc/apache2/sites-available/blar

    <VirtualHost *:80>
      ...

      JkMount / worker1
      JkMount /* worker1

      RewriteEngine on
      RewriteRule ^/(.*)$ /YOUR_DEPLOYMENT_NAME/$1 [L,PT]

      ...
    </VirtualHost>

Note we’re pointing all the files that hit the root of our virual host to our worker via the JkMount command.

Generally, our tomcat servlets or jsp pages are prefixes with the name of the deployment file. Hello.war would be prefixed with Hello/. To get around this the RewriteRule gets around this by rewriting anything going to the root by transparently adding the deployment name.

tomcat apache apache-mod_rewrite

Tomcat 7: Heap dump on Out Of Memory errors.

In your /usr/share/tomcat7/bin/catalina.sh file, add this to JAVA_OPTS file. For example:

    JAVA_OPTS='-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dir'

Your JAVA_OPTS could most likely contain other options. But these will make a core dump when tomcat runs out of memory. And dump it to that location (make sure that is writable by your application / server).

If you, for example, create a servlet with this code it will cause a heap dump:

ArrayList<String> a = new ArrayList<String>();
while(true) {
    a.add("asdfasdjf;lasdkjfl;SJF;LAJFDL;ASJDFL;ASJDFL;AJSDFL;JSLFJSDL;FJS;LFJA;LSDKJ;ksdjflsjdf;lasjdlfkj");
}

Run it and you will see this in catalina.out:

    java.lang.OutOfMemoryError: Java heap space
    Dumping heap to /path/to/dir/java_pid32394.hprof ...
    Heap dump file created [334354454 bytes in 2.124 secs]
    Exception in thread "http-bio-8080-exec-250" java.lang.OutOfMemoryError: Java heap space
       at java.util.Arrays.copyOf(Arrays.java:2760)
       at java.util.Arrays.copyOf(Arrays.java:2734)

You can then take that hprof file and run it in a memory analyser, like Eclipse MAT or jhat.

If the dump is particularly large, you’ll have to ensure the program parsing it has enough memory. In the case of jhat, you pass it a parameter to do so:

    jhat -J-mx1000m /path/to/java_pid32394.hprof
java tomcat java-memory

Tomcat 7: Debugging in Eclipse

In your catalina.sh file (if you’re using unix), you must place this at the top:

    export JAVA_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n"

Note the line may contain other options, but the above must be there nonetheless.

Now stop and start tomcat.

Then go into Debug Configurations in Eclipse and add a new Remove Java Application. Enter the following details:

    host: localhost
    post: 8000

You can now start this debug configuration. Your application will stop and eclipse will move to a breakpoint added in eclipse should you hit on.

tomcat tomcat-debug

Page 1 of 3
Next