Blog

  • Intellij consomme de la CPU

    J’ai rencontré un problème récemment de consommation CPU élevée de la part d’Intellij sous Windows.

    Après quelques recherches sur internet, il semble que cela soit un problème de mémoire pas assez important.

    voici comment faire pour améliorer les choses:

    Fermer Intellij

    Dans le répertoire %USER_HOME%\.IntelliJIdea14\config\options éditer le fichier project.default.xml

    et modifier la ligne

    name="VM_PARAMETERS" value="-Xmx512m -Xms256m -XX:MaxPermSize=250m -ea" />

    pour augmenter la taille max de la mémoire

    name="VM_PARAMETERS" value="-Xmx2048m -Xms256m -XX:MaxPermSize=250m -ea" />

    Relancer Intellij. La consommation CPU devrait baissée drastiquement.

     

  • Docker compose

    En assistant à une présentation à Devoxx France, j’ai pû voir docker-compose en action.
    J’étais passé à côté mais docker-compose permet de faire ce que j’ai fait de façon artisanale dans les scripts startAll.sh et stopAll.sh de mon application demo (session-webapp).

    J’ai donc mis à jour les sources pour tester cette fonctionnalité.

    Il faut dans un premier temps définir un fichier docker-compose.yml qui va décrire nos services.

    haproxy:
      build: src/main/haproxy
      links:
       - app1
       - app2
      environment:
        - UPSTREAMS=2
      ports:
        - "2080:80"
    
    app2:
     build: .
     links:
        - db
    
    app1:
     build: .
     links:
      - db
    
    
    db:
      image: dockerfile/redis
      volumes:
      - /tmp/data:/data

    Pour faire simple, je définis une image haproxy, 2 webapps et 1 backend. Et j’indique les liens entre container (links).

    Pour lancer, tous les containers, il faut juste taper:

    docker-compose up

    Cette commande va builder et lancer les containers qui ne sont pas déjà lancé.

    Pour arrêter, il faut taper:

    docker-compose stop

    Le service va démarrer ou arrêter d’un seul coup tous les services décrit dans le fichier.yml. Cela peut être pratique dans une architecture fortement distribuée.
    Il va aussi exposer automatiquement les ports entre containers qui sont dépendant les uns des autres.

    Une option intéressante de docker-compose est la fonction scale qui permet de provisionner facilement une application. Je reviendrais sur cette fonctionnalité sans un prochain article.

    Les sources de l’exemple sont ici.

  • Envoi de mail en developpement

    Au détour d’un article sur linux pratique (sur l’installation d’un forum discourse), je suis tombé sur un container docker permettant de tester localement l’envoi de mail. Cela peut être utile en développement pour que les mails ne partent pas aux clients finaux ou parce qu’il y a des restrictions sur les serveurs smtps.

    L’utilisation est plutôt simple. Il faut démarrer le container et exporter les 8080 et 25 du container.
    Le port 25 est pour l’envoi smtp et le 8080 est l’interface web de consultation des emails.

    docker run --name mailc -p 8080:80 -p 25:25 -d simpledrupalcloud/mailcatcher:dev

    Il faut récupérer l’ip du container:

    $ docker inspect mailc| grep IPAddress
    "IPAddress": "172.17.0.2",

    On peut déjà essayer l’envoi de mail via un telnet:

    telnet 172.17.0.2 25
    Trying 172.17.0.2...
    Connected to 172.17.0.2.
    Escape character is '^]'.
    220 EventMachine SMTP Server
    HELO
    250 Ok EventMachine SMTP Server
    MAIL FROM: test@from.com
    250 Ok
    RCPT TO:test@to.com
    250 Ok
    DATA
    354 Send it
    this is data
    
    
    Send it
    
    .
    250 Message accepted

    On peut ensuite accéder à l’interface web pour vérifier si le mail est bien reçu (http://172.17.0.2 dans mon cas):

    mailcatcher

    Et voila, il est maintenant possible de tester l’envoi de mail dans ses programmes de façon autonome.

  • Partage de session avec spring-session

    Un collègue m’a fait découvrir spring-session lors d’un échange sur la façon de stocker les sessions dans un tiers.

    J’ai donc décidé de reprendre mon poc pour l’adapter à cette librairie.

    La mise en place est assez simple. Il faut juste créer 2 classes.

    1 pour la configuration (Config) et 1 pour que spring initialise mon application (Initializer). Dans une application existante la dernière classe n’est pas obligatoire. Il suffira de déclarer le bean config dans le fichier de context XML spring.

    • configuration:
    @Configuration
    @EnableRedisHttpSession
    public class Config {
    
          @Bean
          public JedisConnectionFactory connectionFactory() {
                JedisConnectionFactory factory = new JedisConnectionFactory();
                factory.setHostName("db");
                return factory;
          }
    }

    Il suffit de placer l’annotation EnableRedisHttpSession et de déclarer un bean pour la connectionFactory. Par defaut JedisConnectionFactory se connecte sur la base redis en localhost. Dans mon cas, j’ai surchargé pour aller sur le host db (container redis)

    Il faut supprimer aussi le fichier context.xml qui n’est plus nécessaire.
    Il faut passer en servlet 3.0 pour que l’initialisation fonctionne.

    et voilà, c’est tout.

    On peut tester le tout avec les commandes:

    mvn clean install
    ./start_all.sh

     

    • Changements:

    Par rapport au précédent article, le poc a subi quelques modifications pour fonctionner:

    – passage à tomcat 8
    – inclusion de spring 4
    – inclusion de spring web
    – inclusion de spring-data
    – servlet 3.0

    Les sources sont disponibles ici

    Merci Raphaël pour l’info.

     

  • Crawler facile

    Il y a quelque temps, j’avais mis de côté cet article http://korben.info/extraire-donnee-pages-web.html. Comme je vais pas mal de crawling, en ce moment je m’y suis intéressé.

    Voici déjà la marche à suivre pour installer scrappy sur ubuntu:

    sudo apt-get install pyhton-pip
    sudo apt-get install python-dev
    sudo pip install scrapy
    sudo apt-get install python-scrapy
    
    

    Il est maintenant possible de faire fonctionner l’exemple:

    from scrapy import Spider, Item, Field
    
    class Post(Item):
    title = Field()
    
    class BlogSpider(Spider):
    name, start_urls = 'blogspider', ['http://www.axioconsulting.fr']
    
    def parse(self, response):
    return [Post(title=e.extract()) for e in response.css("h1 a::text")]

     

    pip install scrapy
    cat > myspider.py <

    Ce qui donne

    2014-12-18 10:15:19+0100 [blogspider] DEBUG: Crawled (200) <GET http://www.axioconsulting.fr> (referer: None)
    2014-12-18 10:15:19+0100 [blogspider] DEBUG: Scraped from <200 http://www.axioconsulting.fr>
     {'title': u'Veille technologique et autres'}
    2014-12-18 10:15:19+0100 [blogspider] DEBUG: Scraped from <200 http://www.axioconsulting.fr>
     {'title': u'Erreur de commit SVN avec intellij'}
    2014-12-18 10:15:19+0100 [blogspider] DEBUG: Scraped from <200 http://www.axioconsulting.fr>
     {'title': u'Configurer Selenium par annotations'}
    2014-12-18 10:15:19+0100 [blogspider] DEBUG: Scraped from <200 http://www.axioconsulting.fr>
     {'title': u'Configurer spring sans fichier XML'}
    2014-12-18 10:15:19+0100 [blogspider] DEBUG: Scraped from <200 http://www.axioconsulting.fr>
     {'title': u'docker \u2013 liens entre container suite'}
    2014-12-18 10:15:19+0100 [blogspider] DEBUG: Scraped from <200 http://www.axioconsulting.fr>
     {'title': u'Mettre \xe0 jour docker sous ubuntu'}
    2014-12-18 10:15:19+0100 [blogspider] DEBUG: Scraped from <200 http://www.axioconsulting.fr>
     {'title': u'docker \u2013 liens entre container'}
    2014-12-18 10:15:19+0100 [blogspider] DEBUG: Scraped from <200 http://www.axioconsulting.fr>
     {'title': u'Partage de session avec redis, tomcat et docker'}
    2014-12-18 10:15:19+0100 [blogspider] DEBUG: Scraped from <200 http://www.axioconsulting.fr>
     {'title': u'load balancing haproxy sous docker'}
    2014-12-18 10:15:19+0100 [blogspider] DEBUG: Scraped from <200 http://www.axioconsulting.fr>
     {'title': u'Contruire une image docker \xe0 la suite d\u2019un build maven'}
    2014-12-18 10:15:19+0100 [blogspider] DEBUG: Scraped from <200 http://www.axioconsulting.fr>
     {'title': u'installation de docker sur ubuntu'}

    A première vue, ça a l’air plus facile pour crawler qu’avec un script shell surtout si on a besoin de parser la page.

  • Erreur de commit SVN avec intellij

    Si vous rencontrez l’erreur suivante lors d’un commit SVN :

    wrong committed revision number: -1

    Il s’agit apparemment de problème lié à localisation de SVN.

    pour solutionner le problème, il faut ajouter au fichier idea.sh

    export LANG=C
    export LC_MESSAGES=C

    Solution trouvée ici

  • Configurer Selenium par annotations

    Pour faire suite à l’article précédent sur la configuration spring, voici le même type de configuration pour Selenium (outil de test d’intégration pilotant un navigateur).

    On va pouvoir lancer les tests avec seulement 3 classes et 0 xml.

    1 – on définit une classe de configuration qui va contenir l’url de base du site et le driver du navigateur à tester:

    @Configuration
    public class TestConfig {
    
    @Bean
    public URI getSiteBase() throws URISyntaxException {
    return new URI("http://localhost:10001/demo-spring-1.0-SNAPSHOT");
    }
    
    @Bean(destroyMethod = "quit")
    public FirefoxDriver getDrv() {
    return new FirefoxDriver();
    }
    }

    2 – on définit ensuite une classe abstraite qui va référencer la configuration et va contenir un petit « tips » pour ne pas avoir plusieurs processus de firefox en même temps, lorsque qu’on lance plusieurs tests

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes={ TestConfig.class })
    public abstract class AbstractTestIT {
    
    @Autowired
    protected URI siteBase;
    
    @Autowired
    protected WebDriver drv;
    
    {
    Runtime.getRuntime().addShutdownHook(new Thread() {
    @Override
    public void run() {
    drv.close();
    }
    });
    }
    
    }

    3- et enfin la classe de test qui vérifie que le code du controller est correcte:

    public class HelloControllerTestIT extends AbstractTestIT {
    
    @Test
    public void testHello() {
    drv.get(siteBase.toString()+"/hello");
    assertTrue(drv.getPageSource().contains("Welcome anonymous"));
    }
    
    }

    4- pour que tout s’enchaîne correctement, il faut modifier le pom.xml

    <build>
    <plugins>
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.12</version>
    <executions>
    <execution>
    <id>default</id>
    <goals>
    <goal>integration-test</goal>
    <goal>verify</goal>
    </goals>
    </execution>
    </executions>
    </plugin>
    <plugin>
    <groupId>org.codehaus.cargo</groupId>
    <artifactId>cargo-maven2-plugin</artifactId>
    <version>1.2.0</version>
    <configuration>
    <type>standalone</type>
    <configuration>
    <properties>
    <cargo.servlet.port>10001</cargo.servlet.port>
    </properties>
    </configuration>
    </configuration>
    <executions>
    <execution>
    <id>start</id>
    <phase>pre-integration-test</phase>
    <goals>
    <goal>start</goal>
    </goals>
    </execution>
    <execution>
    <id>stop</id>
    <phase>post-integration-test</phase>
    <goals>
    <goal>stop</goal>
    </goals>
    </execution>
    </executions>
    </plugin>
    </plugins>
    </build>

    et ajouter les dépendances suivantes:

    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-firefox-driver</artifactId>
    <version>2.43.1</version>
    <scope>test</scope>
    </dependency>
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
    </dependency>

    Attention: La version de selenium est fortement lié à la version de firefox. Si l’exemple ne marche pas, il faut vérifier qu’une nouvelle version n’est pas disponible.

    Le lancement de la commande

    mvn verify

    devrait donner un résultat du type:

    Results :
    
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

     

    Les sources sont ici: github

    références:

  • Configurer spring sans fichier XML

    Pour changer un peu de docker, voici un petit article pour initier un projet spring sans fichier de configuration XML.

    Je vais créer une petite application avec un Controller Spring MVC.

    Tout d’abord, on ajoute les dépendances. Servlet 3.1, spring-context , spring mvc suffisent:

    <properties>
    <spring.version>4.1.0.RELEASE</spring.version>
    </properties>
    
    <dependencies>
    <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
    </dependency>
    </dependencies>

    On va ensuite créer une classe qui va permettre de gérer l’initialisation de la configuration spring. Pour cela, j’utilise une nouveauté de servlet 3.0 qui est  l’interface WebApplicationInitializer:

    public interface WebApplicationInitializer {
    void onStartup(javax.servlet.ServletContext servletContext) throws javax.servlet.ServletException;
    }

    En implémentant une classe avec la méthode onStartup, on peut faire l’initialisation de son application. C’est plus simple que de faire une « fausse » servlet avec un paramètre loadOnStartup dans le fichier web.xml

    Voici le code de la classe que j’utilise:

    public class MyWebAppInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
    WebApplicationContext context = getContext();
    
    servletContext.addListener(new ContextLoaderListener(context));
    ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet", new DispatcherServlet(context));
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/*");
    }
    
    private AnnotationConfigWebApplicationContext getContext() {
    AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
    context.setConfigLocation("com.axioconsulting.demo.spring.config");
    return context;
    }
    }

    La méthode getContext va permettre de gérer la configuration par annotation en commençant par le package com.axioconsulting.demo.spring.config.

    Dans ce package, j’ai défini 2 classes.

    @Configuration
    @ComponentScan("com.axioconsulting.demo.spring.controller")
    public class AppConfig {
    }

    L’annotation @Configuration permet à Spring de savoir que cette classe est à prendre en compte pour la configuration. Dans notre cas, on précise juste qu’il faut scanner le package com.axioconsulting.demo.spring.controller (c’est là que va se trouver le controller)

    @Configuration
    @EnableWebMvc
    public class WebMvcConfig {
    }

    Cette classe permet d’importer la configuration spring MVC.

    NB: On aurait pu fusionner les 2 classes.

    Il ne reste plus qu’à mettre en place le controller.

    @Controller
    public class HelloController {
    @RequestMapping("/hello")
    @ResponseBody
    public String hello(@RequestParam(required = false) String name){
    if (StringUtils.isEmpty(name)){
    return "Welcome anonymous";
    }
    return "Hello "+name;
    }
    }

    Il s’agit d’un controller basic qui va répondre un message sur /hello ou sur /hello?name=monNom

    anonyme monNom

    Et voila, on a réussi à initier une appli spring MVC en manipulant seulement des annotations ce qui me parait plus simple.

    A voir sur le long terme et sur un projet un peu plus gros si les annotations sont suffisantes.

    Les sources sont ici:  https://github.com/BenoitCharret/demoSpring

     

     

  • docker – liens entre container suite

    Maintenant que nous avons la bonne version de docker, nous pouvons modifier le fichier context.xml de l’application pour pointer sur le hostname de redis :

    className="com.radiadesign.catalina.session.RedisSessionManager"
    host="db"
    port="6379"

    On va aussi modifier le démarrage du serveur d’applications pour créer un lien vers redis:

    docker run -i -t --link redis:db session-webapp:1.0-SNAPSHOT

    tomcat et redis sont maintenant connectée sans avoir besoin de connaître l’ip de chacun.

    Et voici le script de démarrage complet :

    docker run --rm --name redis -p 6379:6379 -v /tmp/data:/data dockerfile/redis &
    
    sleep 5
    
    docker run --rm --name appA --link redis:db session-webapp:1.0-SNAPSHOT &
    
    docker run --rm --name appB --link redis:db session-webapp:1.0-SNAPSHOT &
    
    sleep 10
    
    docker run --rm --name haproxy --link appA:app1 --link appB:app2 --env "UPSTREAMS=2" bcharret/haproxy &

    Nous avons donc réussi à déployer des applications qui sont connectées entre elles, sans connaître les ips de chacune à l’avance. En termes de scalabilité, il devient aisé de rajouter un serveur d’application. Il faut juste démarrer un nouveau conteneur et le linker au haproxy.

    Dans un prochain article, nous essayerons de voir comment faire fonctionner un cluster de redis avec docker.

    Les sources sont à jour ici: https://github.com/BenoitCharret/session-webapp/tree/article_3

  • Mettre à jour docker sous ubuntu

    Pour faire suite au précédent article, je voulais utiliser la fonctionnalité du link qui modifie le /etc/hosts du conteneur parent pour ajouter le nom et l’ip du conteneur fils. Mais cette fonctionnalité est arrivée avec docker 0.11.

    Si vous êtes comme moi sous ubuntu 14.04, mon premier réflmexe a été comme indiqué dans la documentation, d’installer docker à partir d’un des dépôts d’ubuntu:

    $ sudo apt-get update
    $ sudo apt-get install docker.io 
    $ sudo apt-cache madison docker.io
     docker.io | 0.9.1~dfsg1-2 | http://fr.archive.ubuntu.com/ubuntu/ trusty/universe amd64 Packages
     docker.io | 0.9.1~dfsg1-2 | http://fr.archive.ubuntu.com/ubuntu/ trusty/universe Sources

    Or dans ce dépôt la version ne suit pas les différentes releases du projet.

    Si vous voulez mettre à jour docker dans une version plus récente (1.0.0 aujourd’hui), voila ce qu’il faut faire:

    sudo sh -c "wget -qO- https://get.docker.io/gpg | apt-key add -"
    sudo sh -c "echo deb http://get.docker.io/ubuntu docker main\ > /etc/apt/sources.list.d/docker.list"
    $ sudo apt-get update
    $ sudo apt-get install lxc-docker

    Ce qui nous donne une version :

    $ sudo apt-cache madison lxc-docker
    lxc-docker | 1.0.0 | http://get.docker.io/ubuntu/ docker/main amd64 Packages

    On peut donc maintenant vérifier que la fonctionnalité est bien présente:

    pc:~/session-webapp$ ./run_redis-server.sh 
    85c5a0a51fe3df1dcb678b6bccbee7c9bc8db54232c100be03e1b4aa22e49050
    pc:~/session-webapp$ docker run -i -t --link redis:redis dockerfile/ubuntu /bin/bash
    [ root@c9cee8eddad7:~ ]$ more /etc/hosts
    172.17.0.3 c9cee8eddad7
    127.0.0.1 localhost
    ::1 localhost ip6-localhost ip6-loopback
    fe00::0 ip6-localnet
    ff00::0 ip6-mcastprefix
    ff02::1 ip6-allnodes
    ff02::2 ip6-allrouters
    172.17.0.2 redis

    J’ai lancé le serveur redis et l’ai linké à un conteneur de test. On voit bien que dans le /etc/hosts, l’ip du conteneur redis est ajouté. Dans le prochain article, nous allons donc pouvoir lié la datasource et les serveurs applicatifs sans avoir a connaitre à l’avance l’ip de la datasource.