Tomcat en production

Cette page a été rédigée il y a fort fort longtemps, et n'a pas tellement été mise à jour.

 

Vous savez, moi je ne crois pas qu'il y ait de bonne ou de mauvaise page. Moi, si je devais résumer mon wiki aujourd'hui avec vous, je dirais que c'est d'abord des rencontres. Des gens qui m'ont tendu la main, peut-être à un moment où je ne pouvais pas, où j'étais seul chez moi. Et c'est assez curieux de se dire que les hasards, les rencontres forgent une destinée... Parce que quand on a le goût de la chose, quand on a le goût de la chose bien faite, le beau geste, parfois on ne trouve pas l'interlocuteur en face je dirais, le miroir qui vous aide à avancer. Alors ça n'est pas mon cas, comme je disais là, puisque moi au contraire, j'ai pu ; et je dis merci au wiki, je lui dis merci, je chante le wiki, je danse le wiki... je ne suis qu'amour ! Et finalement, quand des gens me disent « Mais comment fais-tu pour avoir cette humanité ? », je leur réponds très simplement que c'est ce goût de l'amour, ce goût donc qui m'a poussé aujourd'hui à entreprendre une construction logicielle... mais demain qui sait ? Peut-être simplement à me mettre au service de la communauté, à faire le don, le don de soi.

Petit récapitulatif des opérations à réaliser pour la mise en production d’un serveur Tomcat 5.5 ou 6.0 (mise à jour en cours pour Tomcat 7 et 8).

Installation

Machine virtuelle

Il faut installer un JDK récent. Celui d’Oracle devrait convenir, ou éventuellement OpenJDK.

Tomcat

Même sous Linux, on installe Tomcat depuis l'archive téléchargée sur leur site.
L'installation par paquet rpm, apt-get ou autre amène parfois des surprises.
(cf. link:http://www.developpez.net/forums/f262/java/developpement-web-java/tomcat/[forum developpez.net])

Log4J

<strike>Je préfère largement Log4J au Java Logging API. Je fais donc le remplacement.</strike>

JULI n'est pas terrible, mais il s'est largement amélioré.
Par exemple, depuis Tomcat 8, il sait écrire chaque trace sur une seule ligne, et de façon asynchrone. Je le conserve donc, en simplifiant sa link:#Traces[configuration].

Script de démarrage

<strike>Pour commencer, il peut être pratique de renseigner CATALINA_HOME, pour pouvoir l'utiliser dans la suite du script.</strike>
Tomcat est démarré avec son propre user, et surtout pas _root_.
Comme j'utilise un Apache frontal, je n'ai pas besoin d'écouter sur le port 80.

Profile JVM et Mémoire

La JVM se lance avec les options par défaut, ce qui est rarement la meilleure de solutions.

  • Ajouter l’option -server

  • Ajouter les options -Xms et -Xmx

JAVA_OPTS="$JAVA_OPTS -server -Xms512m -Xmx512m"

Pour faire générer un dump de mémoire en cas de OutOfMemoryError :

JAVA_OPTS="$JAVA_OPTS -XX:-HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$CATALINA_HOME/logs"

Garbage Collector

Il n'y généralement pas d'optimisation a priori du ramasse-miettes.
Son paramétrage se fait après diagnostic d'un problème.
En revanche, l'existence de collections explicites dans le code peut être une source de lenteur, il faut donc les désactiver.
JAVA_OPTS="$JAVA_OPTS -XX:+DisableExplicitGC"

JMX

<strike>En Java 5, on ajoute la propriété permettant de monitorer avec jConsole ou tout autre client JMX, comme MC4J ou jManage.</strike>

<strike>JAVA_OPTS="$JAVA_OPTS "-Dcom.sun.management.jmxremote</strike>
Si le serveur n'a pas de couche graphique, on va permettre l'accès à distance.
Cet accès est sécurisé et nécessite une authentification dont les données sont stockées dans des fichiers properties, avec un fichier qui contient les couples user/password et un fichier qui associe les rôles aux users.
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.rmi.port=1098
                      -Dcom.sun.management.jmxremote.access.file=$CATALINA_HOME/conf/jmx.access
                      -Dcom.sun.management.jmxremote.password.file=$CATALINA_HOME/conf/jmx.password"

<strike>Avec Java 6, l’accès JMX local est automatique ouvert, sans avoir à spécifier de variable supplémentaire. Cependant, en l’absence de la variable -Dcom.sun.management.jmxremote, Tomcat n’enregistrera pas ses propres MBeans ; on ne pourra donc monitorer que les données de la JVM, comme l’utilisation de la mémoire, mais pas les datasources ou connecteurs.</strike>

En conclusion, à partir de Java 5, on ajoute systématiquement la variable -Dcom.sun.management.jmxremote.

La page JMX/Remote donne des explications plus détaillées sur cet accès.

AWT - Display

Si Tomcat est lancé sur un serveur sans display, des erreurs peuvent se produire au démarrage.
Cela est du à l'utilisation de composants AWT, qui, bien que pouvant ne pas être graphiques, essaient de se rattacher à un display.

Pour éviter cette tentative de rattachement, il faut ajouter la variable -Djava.awt.headless :

JAVA_OPTS="$JAVA_OPTS -Djava.awt.headless=true"

Applications fournies

Activer SSL

A partir du moment ou je veux utiliser les applications de gestion, comme le Manager, je passe par du SSL.

Sécurité du Manager

Il faut à la fois créer un user dans tomcat-users.xml et forcer l’utilisation de SSL.

Il vaut mieux stocker la version chiffrée du mot de passe :

> bin/digest.sh -a sha-512 sewatech
sewatech:6f9341ffb9...552c8a0e4
<!-- conf/tomcat-users.xml -->
<role rolename="manager" />
<user username="alexis" password="6f9341ffb9...552c8a0e4" roles="manager-gui" />
<!-- conf/server.xml -->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase" digest="sha-512"/>

Et pour forcer le SSL, on ajouter une user-data-constraint aux contraintes de sécurité existantes dans le fichier WEB-INF/web.xml du manager

 <!-- WEB-INF/web.xml -->
 <security-constraint>
   <web-resource-collection>
     <web-resource-name>HTML Manager interface (for humans)</web-resource-name>
     <url-pattern>/html/*</url-pattern>
   </web-resource-collection>
   <auth-constraint>
      <role-name>manager-gui</role-name>
   </auth-constraint>

   <user-data-constraint>
      <transport-guarantee>CONFIDENTIAL</transport-guarantee>
   </user-data-constraint>

 </security-constraint>

La même portion doit être ajoutée à chaque security-constraint.

Ménage

Je retire les applications inutiles :

  • docs

  • examples

  • host-manager

Pour ROOT, j’en vide le contenu pour le remplacer par une simple page index.html de redirection.

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="REFRESH" content="0;URL=/myapp/">
    <title>Redirecting...</title>
  </head>
  <body>
  </body>
</html>

Applications d’admin

<strike>Je n’installe pas l’application admin, de toute façon elle ne fonctionne plus correctement dans Tomcat 6.</strike>

J’ajoute (et sécurise) les applications suivantes :

  • Jolokia pour accéder aux informations JMX au format JSON

  • Psi Probe, le successeur de Lambda Probe

Applications métier

J’installe les applications métier + DataSource (+ Realm).

Je précompile les JSP (avec <strike>lambda probe</strike> Psi Probe)

Configuration

Ménage

Pour y voir un peu plus clair, je retire tous les commentaires dans le fichier server.xml.

Connector

SSL, mais je l'ai déjà dit.
J'ouvre le connecteur AJP, pour installer Apache en frontal.
Éventuellement, si AJP ne convient pas (par choix des administrateurs réseau), je crée un nouveau connecteur sur le 8082.

Chaque connecteur utilise son propre pool de thread, car je n’ai pas encore bien vu l’intérêt du pool partagé (Executor de Tomcat 6).

DataSource

Je crée les DataSources nécessaires dans GlobalNamingResources.
Les jar sont placés dans libsw, déclaré comme autre répertoire de librairies (pour ne pas mélanger avec les jar d'origine).

Jasper

Désactiver le mode development

Sécurité

Utiliser les valves d’accès, au moins pour manager

Je n’active pas le SecurityManager, bien que ça pourrait être une bonne chose !

Traces

Log4J + valves de traces à la mode Apache + sewatrace