Tomcat : Mise en place d'un serveur Tomcat

From Deimos.fr / Bloc Notes Informatique
Jump to: navigation, search
Tomcat

Software version 5.5/6/7
Operating System Debian 6
Website Tomcat Website
Last Update 17/06/2013
Others

1 Introduction

Apache Tomcat est un conteneur de servlet J2EE. Issu du projet Jakarta, Tomcat est désormais un projet principal de la fondation Apache. Tomcat implémente les spécifications des servlets et des JSP de Sun Microsystems. Il inclut des outils pour la configuration et la gestion, mais peut également être configuré en éditant des fichiers de configuration XML. Comme Tomcat inclut un serveur HTTP interne, il est aussi considéré comme un serveur HTTP. Tomcat est également considéré comme un serveur d'applications.

2 Installation

Comme d'h'abitude, sous Debian, c'est over simple :

Command aptitude
aptitude install tomcat5.5

Si vous avez un message du genre :

Des erreurs ont été rencontrées pendant l'exécution :
 tomcat5.5
E: Sub-process /usr/bin/dpkg returned an error code (1)
Échec de l'installation d'un paquet. Tentative de réparation : 
Paramétrage de tomcat5.5 (5.5.20-2) ...
Starting Tomcat servlet engine: tomcat5.5invoke-rc.d: initscript tomcat5.5, action "start" failed.
dpkg : erreur de traitement de tomcat5.5 (--configure) :
 le sous-processus post-installation script a retourné une erreur de sortie d'état 1
Des erreurs ont été rencontrées pendant l'exécution :
 tomcat5.5
Appuyez sur Entrée pour continuer.

Alors il va falloir analyser les logs :

Command tail
> tail /var/lib/tomcat5.5/logs/catalina_`date +%Y-%m-%d`.log 
The java-gcj-compat-dev environment currently doesn't support a security manager. Please check the TOMCAT5_SECURITY variable in /etc/default/tomcat5.5.
Using CATALINA_BASE:   /var/lib/tomcat5.5
Using CATALINA_HOME:   /usr/share/tomcat5.5
Using CATALINA_TMPDIR: /var/lib/tomcat5.5/temp
Using JRE_HOME:       /usr/lib/jvm/java-gcj
The java-gcj-compat-dev environment currently doesn't support a security manager. Please check the TOMCAT5_SECURITY variable in /etc/default/tomcat5.5.

Là, je pense que c'est suffisament clair. Nous allons éditer le fichier /etc/default/tomcat5.5 pour remplacer :

Configuration File /etc/default/tomcat5.5
TOMCAT5_SECURITY=yes

par

Configuration File /etc/default/tomcat5.5
TOMCAT5_SECURITY=no

Mais ceci comporte évidemment quelques risques (ne me demandez pas lesquels, j'avoue que je n'en sais rien et n'ai pas eu le temps de me pencher sur le problème). Il ne reste plus qu'à relancer l'install :

Command aptitude
apt-get install tomcat5.5

Et pour ceux qui souhaitent installer les outils d'admin :

Command aptitude
apt-get install tomcat5.5-admin

3 Configuration

Tomcat est assez complexe dans sa configuration. C'est pourquoi de bonnes explications ne sont pas toujours de trop[1].

3.1 Modifier les variables d'environnement de Tomcat

Vous avez peut être besoin de toucher au Xmx ou Xms de Tomcat, éditez le fichier /etc/default/tomcat5.5 :

Configuration File /etc/default/tomcat5.5
# Run Tomcat as this user ID. Not setting this or leaving it blank will use the
# default of tomcat55.
TOMCAT5_USER=tomcat55
 
# The home directory of the Java development kit (JDK). You need at least
# JDK version 1.4. If JAVA_HOME is not set, some common directories for 
# the Sun JDK, various J2SE 1.4 versions, and the free runtimes
# java-gcj-compat-dev and kaffe are tried.
JAVA_HOME=/usr/lib/jvm/java-6-sun
 
# Directory for per-instance configuration files and webapps. It contain the
# directories conf, logs, webapps, work and temp. See RUNNING.txt for details.
# Default: /var/lib/tomcat5.5
#CATALINA_BASE=/var/lib/tomcat5.5
 
# Arguments to pass to the Java virtual machine (JVM).
JAVA_OPTS="-Djava.awt.headless=true -Xms512m -Xmx512m"
 
# Java compiler to use for translating JavaServer Pages (JSPs). You can use all
# compilers that are accepted by Ant's build.compiler property.
#JSP_COMPILER=jikes
 
# Use the Java security manager? (yes/no, default: yes)
# WARNING: Do not disable the security manager unless you understand
# the consequences!
# NOTE: java-gcj-compat-dev currently doesn't support a security
# manager. 
TOMCAT5_SECURITY=no

Par soucis de sécurité, décommentez comme plus haut la ligne TOMCAT5_USER.

3.2 Rediriger les logs

Pour rediriger les logs de Tomcat, je vous invite à suivre cette documentation.

3.3 Donner accès aux interfaces d'administration

Pour avoir accès à l'interface de manager et d'admin, il va falloir éditer le fichier de configuration des utilisateurs :

Configuration File /etc/tomcat5.5/tomcat-users.xml
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
<role rolename="manager"/>
<role rolename="tomcat"/>
<role rolename="admin"/>
<role rolename="role1"/>
<user username="tomcat" password="tomcat" roles="tomcat,manager,admin"/>
<user username="both" password="tomcat" roles="tomcat,role1"/>
<user username="role1" password="tomcat" roles="role1"/>
</tomcat-users>

Adaptez en fonction des logins et mot de passe que vous souhaitez.

Vous pouvez ensuite accéder via les liens suivants (en adaptant selon vos besoins) :

3.4 Changer la version de java

Pour changer la version de java par défaut (la 6 ici) :

Command update-java-alternatives
update-java-alternatives -s java-6-sun

Vérifiez à bien avoir cette ligne dans le fichier de default tomcat :

Configuration File /etc/default/tomcat5.5
...
JAVA_HOME=/usr/lib/jvm/java-6-sun
...

3.5 mod_jk

Il est parfois intéressant de pouvoir rediriger un Apache vers un Tomcat afin de simplifier l'URL pour l'utilisateur finale et permettre au Tomcat de ne pas gérer les connexions. Il est également possible d'utiliser mod_proxy (qui est d'ailleurs de plus en plus utilisé au détriment de mod_jk).

Installez Apache et mod_jk :

Command aptitude
aptitude install apache2 libapache2-mod-jk

Editez ensuite le fichier workers.properties :

Configuration File /etc/libapache2-mod-jk/workers.properties
workers.tomcat_home=/usr/share/tomcat6
workers.java_home=/usr/lib/jvm/default-java
ps=/
worker.list=ajp13_worker,jk-status,jk-manager,examples
worker.ajp13_worker.port=8009
worker.ajp13_worker.host=localhost
worker.ajp13_worker.type=ajp13
worker.examples.port=8009
worker.examples.host=localhost
worker.examples.type=ajp13
worker.jk-status.read_only=True
worker.jk-status.type=status
worker.jk-manager.type=status
#worker.ajp13_worker.lbfactor=1
#worker.loadbalancer.type=lb
#worker.loadbalancer.balance_workers=ajp13_worker

Ici j'ai donc ajouter ajp13 avec les informations du connecteur. Nous allons maintenant dé-commenter celui ci dans la configuration de Tomcat :

Configuration File /etc/tomcat6/server.xml
[...]
    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
[...]

Vous pouvez redémarrer Tomcat pour que cette configuration soit prise en compte. Maintenant, nous allons nous attaquer à Apache :

Command
a2enmod mod_jk
touch /etc/apache2/mods-available/jk.conf
cd /etc/apache2/mods-enabled/
ln -s /etc/apache2/mods-available/jk.conf .

Puis nous allons éditez ce fichier de configuration pour lui indiquer le fichier workers.properties :

Configuration File
<ifmodule mod_jk.c>
    JkWorkersFile   /etc/libapache2-mod-jk/workers.properties
    JkShmFile       /var/log/apache2/mod_jk.shm
    JkLogFile       /var/log/apache2/mod_jk.log
    JkLogLevel      info
</ifmodule>

Et pour finir nous allons modifier le VirtualHost pour lui indiquer que nous voulons utiliser mod_jk :

Configuration File /etc/apache2/sites-enabled/000-default
<VirtualHost *:80>
	ServerAdmin webmaster@localhost
 
	DocumentRoot /var/www
 
	JkMountCopy	On	JkMount		/docs/* ajp13_worker	JkUnMount	/docs/*.gif ajp13_worker         JkMount         /examples/* examples         #JkMount         /jk-status/* jk-status        <Location /jk-status/>            JkMount jk-status            Order deny,allow            Deny from all            Allow from 127.0.0.1        </Location>         #JkMount           /jk-manager/* jk-manager        <Location /jk-manager/>            JkMount jk-manager            Order deny,allow            Deny from all            Allow from 127.0.0.1        </Location> 
	<Directory />
		Options FollowSymLinks
		AllowOverride None
	</Directory>
	<Directory /var/www/>
		Options Indexes FollowSymLinks MultiViews
		AllowOverride None
		Order allow,deny
		allow from all
	</Directory>
 
	ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
	<Directory "/usr/lib/cgi-bin">
		AllowOverride None
		Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
		Order allow,deny
		Allow from all
	</Directory>
 
	ErrorLog ${APACHE_LOG_DIR}/error.log
 
	# Possible values include: debug, info, notice, warn, error, crit,
	# alert, emerg.
	LogLevel warn
 
	CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Maintenant vous pouvez accéder à :

Vous avez également accès au status en lecture seule et au manager. J'ai laissé des lignes commentées au cas ou vous ne souhaiteriez pas utiliser les Locations d'Apache.

4 Configuration avancée

4.1 Load Balancing

Il est indispensable de bien maitriser le mod_jk avant de continuer. Le load balancing permet de faire de la distribution de charge en Round Robin sur plusieurs serveurs Tomcat.

Tomcat loadbalancing.png

Pour faire ceci, il vous faut donc 2 serveurs Tomcat. Sur chacun d'entre eux, éditez le fichier server.xml et ajoutez la directive jvmRoute :

Configuration File /etc/tomcat6/server.xml
<Engine name="Catalina" defaultHost="localhost" jvmRoute="worker1">

J'ai donc mis worker1 sur mon serveur 1 et worker2 sur mon serveur 2. Ensuite éditez ce fichier pour configurer les workers et le load balancer :

Configuration File /etc/libapache2-mod-jk/workers.properties
workers.tomcat_home=/usr/share/tomcat6
workers.java_home=/usr/lib/jvm/default-java
ps=/
 
# Worker list
worker.list=loadbalancer,jk-status,jk-manager
 
# Tomcat Status & Manager
worker.jk-status.read_only=True
worker.jk-status.type=status
worker.jk-manager.type=status
 
# Worker 1
worker.worker1.port=8009
worker.worker1.host=server1
worker.worker1.type=ajp13
worker.worker1.lbfactor=1
 
# Worker 2
worker.worker2.port=18009
worker.worker2.host=server2
worker.worker2.type=ajp13
worker.worker2.lbfactor=1
 
# Load Balancer
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=worker1, worker2
worker.loadbalancer.sticky_session=True

Il ne nous reste plus qu'à configurer Apache pour lui dire d'aller taper sur le bon Worker qui est en fait le load balancer :

Configuration File /etc/apache2/sites-enabled/000-default
<VirtualHost *:80>
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www
        JkMountCopy    On
        JkMount         /demo/* loadbalancer

Redémarrez Apache et Tomcat.

Téléchargez ce fichier, décompressez le et ajoutez le à vos 2 instances Tomcat. Maintenant la page de démo est accessible en mode load balancé sur http://server-apache/demo/jsp/test.jsp. Vous obtiendrez quelque chose comme ceci :

date du jour: Tue Nov 06 13:46:19 CET 2012
param message: null
session ID: C706F51B9ACAB96A10CCDACCADEA9026
node: /var/lib/tomcat6
objet List en session: 

Essayez de couper un Tomcat, vous verrez qu'il basculera sur l'autre :-).

Nous allons utiliser l'interface du manager pour voir l'état de vos serveurs : http://server-apache/jk-manager/ :

Tomcat jk-manager.png

Vous voyez ici que les tomcat sont activés et fonctionnels. Dans le cas ou l'un d'eux viendrait à tomber, il sera en erreur 'ERR'. Il faudra alors cliquer sur l'hyperlink 'R' pour reseter son état. Le load balancer acceptera de nouveau d'envoyer des requêtes dessus. Vous avez également un autre menu qui vous permet de sortir proprement un noeud Tomcat en cliquant sur 'Edit this attribute for all members: Activation' :

Tomcat member activation.png

Mettez à jour ensuite les états en cliquant sur le bouton 'Update balancer'.

4.2 Clustering

Pour faire du clustering[2], vous allez normalement avoir besoin du Load Balancing. Avec le clustering, vous allez pouvoir partager les sessions de vos applicatifs à travers Tomcat. L'avantage est que si vous perdez une machines, les sessions seront présentes sur les autres machines et l'utilisateur n'aura rien vu. Il faut bien entendu que les applications en questions soient développées pour gérer ce genre de mécanismes.

Pour pouvoir tester la réplications de sessions, ajoutez cette petite application qui vous permettra de tester les sessions, téléchargez ce fichier.

Pour mettre en place du cluster, éditez le fichier suivant et rajoutez cette ligne juste avant la fin :

Configuration File /etc/tomcat6/web.xml
[...]
   <distributable /></web-app>

Ensuite nous allons éditer la partie serveur et rajouter un bloc cluster dans la partie Engine :

Configuration File /etc/tomcat6/server.xml
[...]
    <!-- You should set jvmRoute to support load-balancing via AJP ie :
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
    -->
    <Engine name="Catalina1" defaultHost="localhost" jvmRoute="worker2"> 
      <!--For clustering, please take a look at documentation at:
          /docs/cluster-howto.html  (simple how to)
          /docs/config/cluster.html (reference documentation) -->
      <!--
      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
      -->
        <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8">
 
            <Manager className="org.apache.catalina.ha.session.DeltaManager"                  expireSessionsOnShutdown="false"
                  notifyListenersOnReplication="true"/>
 
            <Channel className="org.apache.catalina.tribes.group.GroupChannel">
 
                <Membership className="org.apache.catalina.tribes.membership.McastService"
                        address="228.0.0.4"
                        port="45564"
                        frequency="1000"
                        dropTime="30000" />
 
                <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                      address="auto"
                      port="4000"
                      autoBind="100"
                      selectorTimeout="5000"
                      maxThreads="6" />
 
                <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
                    <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender" timeout="60000"/>
                </Sender>
 
                <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
                <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
            </Channel>
 
         <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
                filter=".*\.gif;.*\.js;.*\.jpg;.*\.htm;.*\.html;.*\.txt;" />
 
         <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
                   tempDir="D:/cluster/temp/war-temp/"
                   deployDir="D:/cluster/temp/war-deploy/"
                   watchDir="D:/cluster/temp/war-listen/"
                   watchEnabled="false" />
 
         <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
   </Cluster>
[...]

Au niveau du nom de l'engine, mettez des noms différents suivant les nœuds du cluster. Je ne détaillerais pas ici toutes les options mais vous laisse regarder les ressources de cette page ou bien le site officiel. Sachez juste que cette configuration permet de mettre plusieurs nœuds et réplique les sessions sur tous les noeuds (DeltaManager). Il est possible de faire simple un simple backup en changeant la className du manager.

Redémarrez ensuite vos serveurs Tomcat, ils se synchroniseront entre eux via multicast. Pour tester, utilisez votre load balancer pour ouvrir cette URL : http://tomcat-lb/clustertest/jsp/myjsp.jsp. Et ensuite ? Et bien c'est simple, vous allez voir quelque chose comme ceci :

date du jour: Sat Nov 17 21:33:58 CET 2012
param message: null
session ID: E7FFB32D3EDEF512C118ACDCC7FB4255.worker2
node: /var/www/tomcat7
objet List en session: 

Faites un SIGKILL (kill -9) sur l'instance worker2. Le load balancer fera son taf de basculer toutes les connexions sur un autre worker et le numéro de session (session ID) sera identique. Il n'aura pas changé même en ayant basculé de serveur :-).

4.3 Créer un context

Quel est l'utilité de créer un contexte ? Et bien par exemple, pour se connecter à une base MySQL via le connecteur JDBC. Pour faire un contexte sur une base de donnée :

Configuration File /etc/tomcat6/Catalina/localhost/mon_appli.xml
<Context path="/mon_appli" docBase="mon_appli">
    <Resource name="jdbc/test" auth="Container" type="javax.sql.DataSource" username="user" password="password" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/database" maxActive="8" maxIdle="4"/>
</Context>

5 Monitoring

Nous allons voir 2 solution pour monitorer votre Tomcat. Une via l'URL et une autre par ouverture d'un port.

5.1 JMXproxy

Pour cette solution, il suffit de donner le droit à un utilisateur de requêter via les URL en JMX :

Configuration File
[...]
  <role rolename="manager-jmx"/>
  <user username="tomcat" password="tomcat" roles="tomcat,admin,manager,manager-jmx"/>
[...]

Maintenant, l'utilisateur tomcat peut requêter comme ceci : http://tomcat:18080/manager/jmxproxy/?qry=*:*

Ce qui va me donner une tonne de lignes :

OK - Number of results: 170

Name: Catalina:j2eeType=Servlet,name=HelloWorldExample,WebModule=//localhost/demo,J2EEApplication=none,J2EEServer=none
modelerType: org.apache.catalina.mbeans.ContainerMBean
minTime: 9223372036854775807
countAllocated: 0
eventProvider: false
statisticsProvider: false
objectName: Catalina:j2eeType=Servlet,name=HelloWorldExample,WebModule=//localhost/demo,J2EEApplication=none,J2EEServer=none
processingTime: 0
errorCount: 0
maxTime: 0
available: 0
asyncSupported: false
backgroundProcessorDelay: -1
loadOnStartup: -1
maxInstances: 20
stateName: STARTED
[...]

Vous pouvez affiner la requête au niveau de l'URL pour éviter d'avoir des pages et des pages d'informations.

5.2 JMX

Pour cette solution, nous allons dire à Tomcat d'écouter sur un port en particulier pour pouvoir le requêter par JMX :

Configuration File /etc/default/tomcat6
[...]
JAVA_OPTS="-Djava.awt.headless=true -Xmx128m -XX:+UseConcMarkSweepGC"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.port=9003"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.password.file=/etc/tomcat6/jmxremote.password"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.access.file=/etc/tomcat6/jmxremote.access"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.ssl=false
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.authenticate=false
JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname="x.x.x.x"
[...]

Si vous avez un firewall entre vos équipements, il faudra peut être que vous avez a ajouter cette configuration :

Configuration File /etc/tomcat6/server.xml
<Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="10001" rmiServerPortPlatform="10002" />

Nous mettons un fichier avec la liste des utilisateurs et leurs mots de passe :

Configuration File /etc/tomcat6/jmxremote.password
[user] [password]

Et un autre pour les autorisation :

Configuration File /etc/tomcat6/jmxremote.access
[user] readwrite
[user] readonly

Et enfin nous mettons les bons droits :

Command
chmod 600 /etc/tomcat6/jmxremote.access
chmod 600 /etc/tomcat6/jmxremote.password
chown tomcat6:tomcat6 /etc/tomcat6/jmxremote.access
chown tomcat6:tomcat6 /etc/tomcat6/jmxremote.password

Redémarrez ensuite Tomcat pour que les changements prennent effets. Vous pouvez maintenant vous connecter via VisualVM par exemple pour monitorer ou profiler votre Tomcat.

Visual vm.png

6 FAQ

6.1 Problème de stop sur un vserver

Tomcat peut poser des problèmes sur un stop dans un vserver. Etant donné que je n'ai pas trouvé la solution, je met le service en dernier au boot et à l'arrêt pour éviter qu'il bloque la fermeture des autres services :

Command update-rc.d
update-rc.d -f tomcat5.5 remove
update-rc.d tomcat5.5 defaults 99

7 Ressources

How To Set Up Apache Tomcat (mod jk) SSO (CAS mod auth cas)

  1. ^ http://www.datadisk.co.uk/html_docs/java_app/tomcat6/tomcat6_web_config.htm
  2. ^ http://www.datadisk.co.uk/html_docs/java_app/tomcat6/tomcat6_clustering.htm