Cat in the Cloud: Apache Tomcat in Amazon EC2
Part II - Taking control over your Java stack
By Dmitry LESKOV
Last update: 17-Nov-2011
This is the second part of a step-by-step guide for Java Web application developers
wanting to get their feet wet in the Amazon cloud. Here is the
link to Part I, in case you missed it.
As I briefly mentioned in the first part, Amazon Linux repos contain
Java (in fact, a JRE is preinstalled), Tomcat,
and many supplementary libraries such as log4j. So why write this
part of the series at all?
First and foremost, Amazon Linux repositories contain customized builds
of specific versions of the respective software, which may not be what
your application requires.
As of now, these are an OpenJDK build of Java 1.6.0_20
with security patches applied, and some build of Tomcat 6.0.32
(jar files differ from the official Apache download).
Second, these packages are controlled by the package management system
and may therefore get upgraded when you update the system, inadvertently
breaking things.
Whether you want to use the latest and greatest versions of everything
for that shiny new app you are building from scratch,
or you have been given the task of moving into the cloud
a legacy application requiring an older version of Java and/or Tomcat,
or you prefer the official builds because they get the security updates first,
this article is for you.
If those are not enough reasons, here are two more.
-
The filesystem layouts and configuration files of these packages
are substantially tweaked. You'd need to wrap your head
around all those changes.
-
The number of package dependencies is overwhelming. Installing the
tomcat6 package will bring over 60 other packages
onto a fresh Amazon Linux instance, including the entire print stack
from GhostScript to CUPS (Common Unix Printing System) to foomatic
(database of printers and printer drivers).
Are there (m)any web apps that print anything on the server side?
Note that the command
yum deplist package
only shows the immediate dependencies of package.
To find out what would have actually been installed, issue the following command:
echo n | sudo yum install package
Installing Oracle Java
First of all, a fresh Oracle JRE is in fact available in the
amzn-nosrc repository:
yum --enablerepo amzn-nosrc info jre
. . .
Version : 1.6.0_29
. . .
It is the original RPM as released by Oracle.
If you don't mind having your Java installation exposed to the
automatic system update mechanism, you may install it as follows:
sudo yum --enablerepo amzn-nosrc install jre
It will appear under /usr/java/jre1.6.0_29.
This JRE, however, may be upgraded when you update the system.
If this is not acceptable, or if you need the full JDK or some other version
of Oracle Java, read on. Otherwise you may go straight to the section on
manual Tomcat installation.
JDK or JRE?
Most Tomcat installation guides recommend that you install the JDK.
However, the official Apache Tomcat FAQ
states:
"Tomcat 4 requires the full JDK. Tomcat 5.5 onwards will work with a JRE or a JDK."
There is one exception that the FAQ does not mention though:
running Tomcat in debug mode requires the JDK.
If you plan to develop "in the cloud", you may want to install the full JDK
on your development instances.
You also may be under the impression that the JRE does not contain the Hotspot Server VM.
But this is only true for the 32-bit Windows JRE.
(Source: HotSpot VM FAQ)
RPM or Self-Extracting?
Oracle's Java downloads for Linux come in pairs: an RPM and a self-extracting archive.
Again, most other guides suggest that you download the former if your flavor
of Linux supports RPMs.
But if you inspect the RPM pre/post-install scripts, you will
notice that they primarily fiddle with Gnome desktop integration, Java Web Start,
making jars directly executable, and other stuff that is pretty much irrelevant
for running a Tomcat server.
I have only spotted one difference that may be of significance:
the location of the preferences directory (/etc/.java/.systemPrefs/
if you install from RPM, or .systemPrefs/ under the root directory
of an extracted SFX, e.g. jre1.6.0_29/.systemPrefs/.)
To sum it up, for production instances I recommend that you download
and install the self-extracting JRE and configure Tomcat to use it.
You need not remove the preinstalled OpenJDK if you wish to use it for
running, for example, the command-line EC2 API tools.
Download and Install
-
To download the latest update release of a maintained major Java version, go to the
Oracle Java SE download page,
scroll down to the desired version and click the Download button.
To download a prior version of Java, go to the
Oracle Java Archive
instead and locate the specific version you need.
-
Select Accept License Agreement (technically, you are supposed to read it first. ;) )
-
Download the self-extracting Linux x86 JRE binary, e.g.
jre‑6u29‑linux‑i586.bin.
-
Upload the downloaded binary to your instance (refer to the
SSH inset
in the previous article for instructions on uploading files via SSH).
-
Log in to your instance via SSH, make the uploaded file executable and run it:
chmod u+x jre-6u29-linux-i586.bin
./jre-6u29-linux-i586.bin
-
The archive will self-extract into a subdirectory of the current directory,
in this case
./jre1.6.0_29.
Upon successful extraction, move that directory to a common location
and lock it down by setting file ownership and permissions:
sudo mv ./jre1.6.0_29 /opt
sudo chown -R root:root /opt/jre1.6.0_29
sudo chmod -R go-w /opt/jre1.6.0_29
Replacing the OpenJDK Java Gracefully
Amazon Linux relies on the
alternatives system
for managing co-existence of
multiple software packages providing the same functionality.
To register Oracle Java as an alternative, issue the following
command, making sure to replace paths accordingly and use priority
(“16029” below)
matching the version you are registering.
sudo alternatives \
--install /usr/bin/java java /opt/jre1.6.0_29/bin/java 16029 \
--slave /usr/lib/jvm/jre jre /opt/jre1.6.0_29
(alternatives --display java will display many more slave links,
but of them, only jre is essential for running Tomcat.)
If you register a version newer than 1.6.0, it will override
the preinstalled OpenJDK JRE automatically:
java -version
java version "1.6.0_29"
Java(TM) SE Runtime Environment (build 1.6.0_29-b11)
Java HotSpot(TM) Client VM (build 20.4-b02, mixed mode, sharing)
Otherwise, you need to issue the following command:
sudo alternatives --set java java-path
where
java-path is the path you have specified
in
alternatives ‑‑install, e.g.
/opt/j2re1.4.2_30/bin/java.
-
If you have followed
the first article of this series,
Tomcat installed from the Amazon Linux repo
may still be running on your instance. Make sure to stop it and
disable automatic startup:
sudo service tomcat6 stop
sudo chkconfig tomcat6 off
chkconfig --list
Expected output:
. . .
tomcat6 0:off 1:off 2:off 3:off 4:off 5:off 6:off
. . .
-
Go to the official Apache Tomcat Web site,
and copy the URL of the desired binary distribution. Then fetch it to your instance and unpack
to the /opt directory:
wget -c http://mirror/path/apache-tomcat-version.tar.gz
sudo tar xvfz apache-tomcat-version.tar.gz -C /opt
This will extract Tomcat into the /opt/apache-tomcat-version/ directory.
You may wish to create a version-agnostic symbolic link to it.
(This will enable you to quickly switch between multiple Tomcat installations if needed):
sudo ln -s /opt/apache-tomcat-version /opt/tomcat
-
If you have installed Oracle Java, but have not
made it the default alternative,
JAVA_HOME still points to the location of the preinstalled
OpenJDK JRE.
To point the Tomcat startup script to the desired Java runtime,
create a file setenv.sh in the Tomcat bin/
directory with the following contents:
#!/bin/sh
export JAVA_HOME=Java-runtime-location
For instance:
sudoedit /opt/tomcat/setenv.sh
#!/bin/sh
export JAVA_HOME=/opt/jre1.6.0_29
-
It is a good idea to create a dedicated user account to run Tomcat.
If you have previously installed the
tomcat6 package from
the Amazon Linux repo, you already have a system group tomcat
and a system user tomcat.
(They are not removed even if you uninstall the package.)
Otherwise, you may create them as follows:
sudo /usr/sbin/groupadd -g 91 -r tomcat
sudo /usr/sbin/useradd -c "Apache Tomcat" -u 91 -g tomcat -s /sbin/nologin -r -d /opt/tomcat tomcat
It makes sense to maintain the same user and group IDs across all EC2 instances
so as to care less about file ownership. The "official" tomcat6
package uses 91 as user and group ID, so you may be more or less
sure that installation of other packages won't adversely interfere with this selection.
If you omit the respective options, smallest values greater than any existing
IDs will be selected.
-
Set file ownership and permissions. Recommendations in Tomcat documentation,
books, and on the Internet vary.
I prefer using group permissions, as there may be a need to grant
other applications access.
-
All Tomcat files and directories shall belong to the superuser,
and only the superuser shall have write access to the core
files residing in
bin/ and lib/.
-
On a development/test EC2 instance you may want to leave auto-deployment
enabled and the Manager web app installed.
The members of the
tomcat group shall then be allowed to write
to the following directories: conf/, logs/,
temp/, webapps/, and work/.
cd /opt/tomcat
sudo chown -R root:tomcat *
sudo chmod -R go-w bin lib
sudo chmod -R g+rw conf logs temp webapps work
Files under conf/ are only owner-accessible by default, hence
the explicit setting of group read permissions in the last command.
On a production instance, it makes sense to restrict file permissions.
This will be discussed in the respective section of the next article.
-
Create a minimalistic start/stop script:
sudoedit /etc/init.d/tomcat
#!/bin/sh
# Baseline Apache Tomcat start/stop script
#
# chkconfig: 345 80 20
# description: Apache Tomcat
case $1 in
start)
/bin/su -s /bin/sh -l tomcat -c /opt/tomcat/bin/startup.sh
;;
stop)
/bin/su -s /bin/sh -l tomcat -c /opt/tomcat/bin/shutdown.sh
;;
restart)
/bin/su -s /bin/sh -l tomcat -c /opt/tomcat/bin/shutdown.sh
/bin/su -s /bin/sh -l tomcat -c /opt/tomcat/bin/startup.sh
;;
esac
exit 0
Group and world should not have write permissions to it, but just to be safe:
sudo chmod go-w /etc/init.d/tomcat
- Try to start the Tomcat service:
sudo service tomcat start
Using CATALINA_BASE: /opt/tomcat
Using CATALINA_HOME: /opt/tomcat
Using CATALINA_TMPDIR: /opt/tomcat/temp
Using JRE_HOME: /opt/jre1.6.0_29
Using CLASSPATH: /opt/tomcat/bin/bootstrap.jar:/opt/tomcat/bin/tomcat-juli.jar
-
Now try connecting your browser to port 8080 on your instance. You should
see the default Tomcat home page.
If you cannot connect:
-
Check that Tomcat has indeed started and is listening on port 8080:
sudo fuser -v -n tcp 8080
Expected output:
USER PID ACCESS COMMAND
8080/tcp: tomcat pid F.... java
-
Check that your instance's security group permits inbound connections to port 8080.
-
To have Tomcat start automatically on instance boot, issue the following command:
sudo /sbin/chkconfig --add tomcat
If you receive a message "service tomcat does not support chkconfig",
check that the following comments are present near the top of your Tomcat
service script /etc/init.d/tomcat:
# chkconfig: 345 80 20
# description: Apache Tomcat
Verify that Tomcat has been added to the list of managed services:
chkconfig --list
. . .
tomcat 0:off 1:off 2:off 3:on 4:on 5:on 6:off
. . .
Summary
You have learned how to manually install any version of Oracle Java and
Apache Tomcat to an Amazon EC2 instance running Amazon Linux.
However, the baseline configuration described above needs some tweaking
before you roll it into production.
In the follow-up article, we'll discuss advanced configuration topics
and the protection of your Web applications.