12 décembre 2015

Un chaîne Youtube consacrée à Docker

Comme le prouvent les vidéos que nous publions chaque année pour faire la promotion du BreizhCamp, je prend un grand plaisir à manipuler la vidéo comme média de communication.

Je suis impressionné par le succès des chaînes Youtube des pointures du Net Français : JoueurDuGrenier, e-Penser, Axolot, Salut les Geeks ou Antoine Daniel apportent tous à leur manière une expression libre sur le web avec un talent certain.

Je n'ai pas la prétention de me comparer à ces références, mais le format employé m'attire sans conteste. Aussi, je lance une chaîne Youtube, sur un sujet de niche : Docker ...

"de niche" parce que pas du tout grand public. Oublions donc tout de suite les millions de vues, promesse de toucher un chèque signé "Youtube". L'idée est ici de présenter Docker et son écosystème, comme je le fais en conférence, mais en exploitant le média vidéo, c'est à dire pas sous forme de conférence filmée, linéaire, mais en exploitant les possibilités données par le montage et la mise en scène.

La chaîne est encore naissante et a donc pour le moment une URL à chier, il faudra attendre 500 abonnés pour régler ça, mais pour ça il faut déjà proposer du contenu.

Ce contenu est déjà en préparation, mais je veux profiter de cette occasion pour aller plus loin que ce que j'ai produit jusqu'ici, en particulier en raison des limitations de la caméra que j'ai à ma disposition via le BreizhCamp. J'aimerais passer au tournage sur boitier Reflex, profiter de l'expérience en photo de plusieurs collègues pour choisir les bons objectifs et trouver des astuces de cadrage, etc.

Bref, il va falloir investir, et pour cela je fais appel aux bonnes volontés, via un financement participatif sur Ulule : http://fr.ulule.com/neuf-docker/

Je prépare un premier épisode pilote en tant que "proof of concept" et pour montrer ce que j'ai en tête, en espérant que cela déliera les portefeuilles. J'ai placé le premier niveau de contribution à 5€ en espérant que cela motivera ceux qui ne sont pas des connaissances directes, comme on dit "les petits ruisseaux font les grandes rizières"

Bref, à vot' bon coeur.

Je viens de publier un épisode pilote, pas vraiment technique, mais qui donne une idée de ce que j'ai en tête. j'espère qu'il vous amusera.

04 décembre 2015

Docker Garbage Collector

When you play a bit with Docker, you end up after some time with a very classic filesystem full issue.

The first time you hit this issue, you learn the docker rm command and start using --rm option to launch containers. The issue here is container aren't destroyed when stopped/killed. Most of us do even have some cleanup alias/script to run something like

docker rm $(docker ps --filter status=exited -q)

You also can hit such an abusive disk usage issue as you get lot's of obsolete image stored on your disk after you tested various things pulled from DockerHub. Same cause usually has the same effect, so you add to your script some :

docker rmi $(docker images | grep “^” | awk ‘{print $3}’)

(based on https://gist.github.com/ngpestelos/4fc2e31e19f86b9cf10b)

So, what's next ?
First issue with such a script is you have to run it by yourself when something goes wrong.
Second issue is such a script do remove untagged images, but not tagged ones you won't use anymore. Some other script could remove all unused images, but will then in many cases force you to re-pull few images you use on a daily basis, but weren't running at the time you ran the cleanup.

To avoid such an issue, I've created a small tool : docker-gc

This tool do listen docker daemon for destroy events, so it knows when a container is removed, and can capture the image it used. This information is used, when the gc process list the unused images, to determine which one where used recently and should be kept - as I assume you will reuse the same image on a regular basis - and which one weren't used for a long time and should be removed.

I'm sure there's many ways to improve the actual GC algorithm efficiency.

For convenience, tool is distributed as a docker image (what else ?) as ndeloof/docker-gc, just need to bind mount docker unix socket so it can interact with DockerHost daemon.

docker run -d -v /var/run/docker.sock:/var/run/docker.sock ndeloof/docker-gc

As a cool project needs a cool logo, I created one using a Jellyfish as a mascot to cleanup docker's ocean. 

Please note docker legal terms totally prohibit such a logo usage, so don't do such crazy logo hijack if you don't want Solomon's advocates to knock at your door. I'll welcome Laurel's pull-request to suggest another one :P

27 novembre 2015

a Dockerfile-based Continuous Delivery Pipeline

I've seen a bunch of project with a Dockerfile to package some app into a production docker image. Most of them do rely on some pre-existing binary they just ADD / curl into the image. This demonstrates some missing piece in the equation, as this binary has to be built from source, and as such you loose the traceability of your built image.

On the other side, some try to setup a full "build from source" Dockerfile, but as a result end with source code and many unnecessary dependencies and intermediate files present in the image: compiler, test libraries, binary intermediate objects, etc. This isn't pleasant, and makes your docker image bigger.

#7115 is a proposal to offer a multi-step Dockerfile, which could solve this issue but introduce some significant complexity in Dockerfile syntax. Also, this is still discussed and I don't expect this to be implemented in a near future.

So, here's my way to handle such a Continuous Delivery Pipeline based on Dockerfiles.

Here is my "build phase" Dockerfile, which I name by convention Dockerfile.build :

FROM maven:3.3.3-jdk-8

ADD / /work


RUN curl -SL "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz" | tar xz -C /usr/local --strip-components=1 

RUN npm install -g bower gulp
RUN npm install
RUN bower --allow-root install
RUN gulp build
RUN mvn package

CMD cp /work/target/*.war /out/app.war

This Dockerfile do define my build environment, relying on Maven and NodeJS to build a modern java application. Such a Dockerfile is designed to fix the build requirements and offer an isolated, reproducible build script, not to create an actual docker image to be ran. But I also added a CMD, which role is to let me export the built binary to a pre-defined location. So I can run :

docker build -f Dockerfile.build -t build .
docker run -v $(pwd):/out build

I also tried to output the war to stdout, so I can run docker run build > app.war,  but got some odd extra character in the stream, and didn't investigated more. I could also rely on docker cp to extract binaries form a container created from build image.

Doing this, I'm building from source and after completion get the application binary for a further step. Next step is for me to create my deployment docker image, using Dockerfile.prod :

FROM jetty:9
ADD application.war /var/lib/jetty

And my full pipeline execution script become

docker build -f Dockerfile.build -t build .
docker run -v $(pwd):/out build
docker build -f Dockerfile.prod -t application .

I could just push the build application image to my repository, but can also have further steps to run it with required middleware (database, etc) and execute some additional automated tests.

For this purpose I rely on docker-compose, to setup the test environment and execute my test suite

  build: .
  dockerfile: Dockerfile.tests
    - application
    - selenium

  image: selenium/standalone-firefox

  image: application
    - "80:8080"
    - database

  image: mysql

Running docker-compose up will (build and) run my test suite based on selenium acceptance tests.

Last step is just to tag and push the image to my registry.

A future improvement is for me to find a cool way to integrate this in Jenkins as a declarative syntax, vs a plain shell script. Wait and see.

20 novembre 2015

DockerCon'15 Lego Moby Dock

I went to DockerCon Europe'15, and will post some feedback about this conference on this blog later next week, but in the meantime I'd like to share with you a major information from Docker Inc :

They updated the Lego Moby Dock design !

Last year at DockerCon Europe, they offered all keynote attendees a lego set to build a small docker whale. You could then pick up "containers" to plug on it from sponsors booth. Was lot's of fun.

At Barcelona, they did the same, but used a more advanced Moby Dock model, bigger and with rounded body. This one is another proof of nice Lego design expertise, but as the previous model I'm disappointed by the tail design. Due to it's shape and angle with whale body it's hard to find adequate lego brick for this job.

Back from Barcelona, I spent some time (don't tell my boss) searching in kid's legos for the adequate block. Here is the result :


Tail is a bit to big compared to original design, but looks better imho. As I wasn't able to find where to send a pull-request for this, here is the instructions for you to do the same.

You'll need those extra block :

  • Remove existing tail, drop the 2x1 plate you won't need. 
  • Plug the two roof tile 45° blocks (304023) into the special angular 1x1 brick (407023). One on the standard mounting hole, the other on the back, which on this brick is a square hole with adequate weight to plug a brick. 
  • Add the two opposite slopping block from original set to complete the tail.

I made a lego digital designer model as this isn't such a trivial thing to explain this :)

If you can't find the angle brick, you also can use a 1x1 brick with two round slots (4583862) and plug the upper tail in opposite side.

I also made larger containers, to mimic the Docker logo. They're a bit too large for the model, but look nice. Just need to get some profile 2x1 brick (4210636) for the adequate container look.

Building instruction is left as an exercise to the reader :)

06 novembre 2015

Learning Go (from Java)

Ca fait un moment que je me dis qu'il faut que j'apprenne à coder en Go.

Pourquoi ?

Déjà, pourquoi apprendre un autre langage ? 15 ans à faire du Java pour en comprendre les rouages et l'écosystème, pourquoi changer ? J'ai par exemple suivi le cours Scala sur coursera, qui m'a permis plus de comprendre les concepts fonctionnels que d'apprendre à faire du Scala, que je n'ai jamais pratiqué ensuite. Et voilà que Java 8 vient saupoudrer un peu de fonctionnel dans un langage objet impératif. Donc oui, connaître un autre langage aide à mieux appréhender les nouveautés et les différences entre langages, et donc ce qui et bien ou ce qui manque à notre langage de prédilection.

Pourquoi Go ? Go est à la mode, surtout depuis que le monde sait que Docker est fait avec. Mais ce n'est pas qu'un effet de mode. Go est un langage assez bas niveau, sans pour autant être aussi pénible que du C. Typiquement, il a un garbage collector. Il mixe donc des concepts plutôt bas niveau avec une approche moderne. Il n'a pas d'héritage mais uniquement de la composition et des interfaces. Go est donc un langage très opinionated et c'est ça qui m'intéresse. Les choix qui sont fait dans Go imposent une façon de concevoir le code, et c'est découvrir ce que cela implique qui m'intéresse.

Par contre, pour être significatif il faut avoir un projet sous le coude. Professionnellement ce n'est pas évident. Si on parle de Jenkins 2.0 il n'est pas pour le moment question de tout recoder en Go. Du coup j'ai pris un petit projet, le backend du système de vote du BreizhCamp, soit un serveur REST avec 5 endpoints. Le recoder en Go est un exercice concret sans nécessiter des jours de travail pour avoir un résultat.

Premiers pas

Commencez bien sur par "a tour of go", le tuto officiel de Go. Ca donne les bases et de premier petits exercices pour se faire à la syntaxe. 

Bon alors soyons honnête, quand on vient du monde Java, l'éditeur de texte vi on se sent un peu à poil avec. Donc pour la suite prenez tout de suite IDEA avec le plugin Go, ça vous simplifiera la vie et ça vous évitera des prises de tête.

Niveau littérature, il existe aussi plusieurs bouquins - dont des gratuits - qui sont très bien.

Première chose à noter dans Go, le langage vient avec un outillage assez complet : gestion de dépendance (même si elle est naïve), build, test, packaging. Pas besoin donc de réfléchir à quel outil de build utiliser. Ca permet de démarrer vite et de prendre pied rapidement dans un projet existant.

Deuxième chose que je note, Go se débarrasse de nombreux problèmes de formatage. D'une part gofmt gère l'indentation du code pour vous (et de manière intelligente), ensuite le compilateur ne vous laisse pas le choix et refuse certaines mises en formes (comme mettre l'accolade sur la ligne suivante). Les structures sont aussi prévues pour éviter les délimiteurs qui font merder vos commits : typiquement, en Java, quand on ajoute un élément à une liste, on modifie la ligne d'au dessus pour y ajouter un ','. En Go, soit il n'y a pas de délimiteur de fin de ligne, soit ce caractère doit être présent sur chaque ligne, même la dernière, supprimant ce "défaut". 

text := LinesOfText{
 []byte("Now is the time"),
 []byte("for all good gophers"),
 []byte("to bring some fun to the party."),

Le compilo fait aussi de l'inférence de type et tout ce genre de choses qui font de Go un langage peu verbeux comparé à Java, sans pour autant être un langage dynamique : la compilation vous rappellera à l'ordre, pas besoin d'attendre un crash en production. Et du coup IDEA vous propose également la complétion du code, et ça moi j'aime.

Enfin, la compilation Go est super rapide. Un cas d'usage très simple de Go, c'est pour le scripting : la compilation est tellement rapide qu'on peut écrire ses scripts en go et les lancer avec un go run truc.go. Ca permet de s'y mettre tranquillement, et potentiellement ce code pourra être regroupé et compilé dans un binaire portable qui vous servira de SDK interne.

Le compilo TGV c'est entre autre la raison pour laquelle la gestion des dépendances repose sur un bête git clone, recompillant donc tout à chaque fois (comme en Erlang d'ailleurs). Ca marche bien, mais on récupère donc le HEAD de chaque dépendance, pas une version bien identifiée. En termes Maven, tout est en SNAPSHOT :) On trouve donc des outils alternatifs, mais bon pour démarrer ce n'est pas un gros soucis, au pire vous aurez l'impression de faire du NodeJS... Go 1.6 devrait gérer des objets binaire par package, ce qui ouvre la voie pour une gestion un peu plus stricte.

Au fil des heures

Premier projet en Go pour moi donc, et j'ai pu plier ça en deux soirées, content du résultat. Les librairies standard de go sont bien foutues, ce qui me fait constater que le plus gros du travail d'un développeur Java est de trouver la lib qui marchera là ou le standard java.xx.yy est juste bon à jeter. Qui utilise java.util.logging - à part Jenkins, mais ça compte pas ? Ne soyons pas aveugle, c'est l'avantage d'un langage jeune, et avec le temps les même travers risquent d'apparaître. Cependant, le principe de Go - produire un binaire unique et autonome - permet de dégager du code obsolète, ce que tente de faire JigSaw depuis des années.

Bref, après quelques heures on a un truc qui fonctionne, on a donc atteint le niveau "je suis ok avec la syntaxe et les API de base". Parce que la syntaxe est pas complètement naturelle pour un dev Java, entre autre je bute encore régulièrement sur l'inversion de l'orde paramètre : type

J'ai donc un truc qui marche.

J'ai ensuite repris mon code morceau par morceau en utilisant des libs plus adaptées (drone/routes par exemple pour les services REST plutôt que du net/http standard). Il n'y a pas encore pléthore de librairies, tout en ayant du choix, c'est donc le bon moment pour s'y mettre sans se noyer dans la masse.

Là on découvre l'écosystème, on regarde le code des librairies qui nous apprennent plein de trucs qu'on ne connaissait pas. Clairement, une fois la barrière syntaxique franchie, lire le code des autres est un excellent moyen d'appréhender le langage. Au final mon code fait rapidement un "divisé par deux" et au passage plusieurs reprises structurelles pour corriger des erreurs de jeunesse. Autrement dis, je fais des progrès.

Enfin, j'ai voulu faire mon David Gageot en écrivant des tests (oui, le vrai David écrit ses tests en premier, mais bon hein ho). Là aussi, on a peu de librairies disponibles mais tout de même de quoi rendre les choses sympathiques.

Tester, c'est ici surtout l'occasion de découvrir les patterns Go pour rendre le code testable, dans un contexte ou nous n'avons ni programmation orientée objet, ni injection de dépendance, ni librairie de mock dynamiques. Et bien ça se fait plutôt bien :P Là la littérature disponible et divers blogs m'ont bien aidé pour expérimenter et comprendre les approches possibles. Et là ça fait du bien d'avoir un peu de bouteille parce qu'on reconnait tout de suite certains patterns d'autres langages/frameworks, et on connait leurs limites, donc on peut comparer/confirmer/se faire rapidement une opinion.

Objectif atteint donc à 100%
Note: oui, je met des images de beauf sur ce billet, vous plaignez pas j'aurais aussi bien pu poser en bikini.

Et donc ?

Bref, passer à Go n'a pas été très difficile, bien moins que mes heures de Scala, en rien à voir avec mes déprimantes tentatives en Ruby (sic). Evidemment j'ai un niveau Padawan 101, mais c'est déjà intéressant et ça m'encourage à pratiquer plus.

Vous l'aurez compris, si vous avez quelques heures de libre, je vous conseille de vous y mettre !

21 octobre 2015

First experiment with Tutum

I heard about Tutum from the time CloudBees was still a PaaS company and I considered them a newcomer competitor. I just read today announcement they have been acquired by Docker Inc, so wanted to know more. 

Tutum is actually not a PaaS but a deployment orchestrator and infrastructure manager you plug to your IaaS account(s). As I'm using Google Compute and this provider isn't supported, online help guided me to "bring your own node" option. This one installed an agent and immediately appeared connected on Tutum web UI.

First impression is important in IT for adoption, and Tutum do offer an awesome UX. Within few seconds I had my account setup and have found the adequate configuration informations. Need to admit they made an impressive work here.

So I have my infra setup and ready to host my app. Next step for me is to reproduce my environment, as I'm using docker-compose for local testing. 

Kubernetes or Amazon ECS both do offer the concept of running a set of containers as a single entity. Tutum has comparable concepts with Services (N replicas of a docker image) and Stacks (composition of services).  But all of them do rely on custom descriptor I would have to keep in sync and can't test locally. But according to announcement blog, Tutum also do support docker-compose so I could just use my existing setup, especially as my application does not require horizontal scaling nor replicas. 

After looking into details, Tutum stack syntax is actually the same (maybe a subset/superset ?) or docker-compose yaml syntax. 

So, I can see two significant benefits of Tutum :

1. no IaaS lock-in. I can rely on support Cloud providers or run my app on my own nodes, but still will benefit node management by Tutum. This looks to me like a real "private PaaS" i.e. my own hardware but still "as-a-service" experience.

2. same bits from dev to production. Both my docker image and stack definition are used on my development laptop and on my production service. So I can reproduce what happens on production at any time.

Need to experiment more, but looks very promising so far.

How to run 2500 webservers on a Raspberry Pi

If you didn't saw the announcement, I'm part of the winner team for DockerCon RPi Challenge. This blog post is about giving some details on our setup to get such a high number of webservers on a small device.

Some might thing you have to make your Docker image as small as possible, but this isn't actually the case. The image will result into space on disk for /var/lib/docker but not memory consumption. Also, a big process loaded into memory would only consume memory once, then kernel will share code page between equivalent processes, so hundred of them would only consume memory once. My first idea was to build a webserver to include the html and image content into source code. But then Yoann explained me sendfile can be used to fully delegate this to kernel and make the process even simpler. For Java developers, consider sendfile as some kernel-level IOUtils.copy(File, OutputStream).

We used hypriot's nano http image. This one is a webserver developped in assembly code to just serve files from disk using kernel sendfile call. Such a program as a minimal memory footprint and a 1-depth stack. The memory allocation for kernel to handle such a process can then be as compact as possible.

Next step was to run some tests and tweak Docker to run as much webservers as possible. We applied various strategies, without any methodology but just apply various recipes we had in mind and check the result (it takes hours to run thousand servers...)

Free memory

We tweaked the Raspberry and OS to reduce memory usage. Some low level tweaks allow to disable useless features at boot, some system level one are used to disable linux feature we don't need for this challenge.

Swap !

Yoann tried to explain me what zRAM is and I probably didn't got it right, but the general idea is that classic swap on disk is incredibly slow, and is only your last chance to free memory. A better, modern approach is to compress memory, which CPU can do very efficiently, a lot faster than accessing disk (especially on a RPi as disk is a SD card).

So our setup do use 5 zram 4 of them for swap (on per CPU, to allow concurrent access) + one for /var/lib/docker filesystem

What? Yes, we use a RamDisk for /var/lib/docker, even we did all those efforts to reduce memory usage... Main issue for this challenge is that running a test and start thousands containers takes hours. Having /var/lib/docker on the SD card made it terribly slow. If we had to get further on the challenge we would have used an external USB SSD disk.

Tweak docker command

Web servers are started by docker from a script. We selected docker options to reduce resource consumed by each web server. Especially, running with a a dedicated IP stack per container involve a huge resource usage, so a key hack was to run with --net=host. We also disabled log driver so docker don't have to collect logs and as such uses less resources. This seem to not work as expected (read later)

Tweak docker process

Linux also allows to tweak the way a process is managed in kernel, we used it to ensure docker run with minimal required resources and use swap

Tweak docker daemon config

Docker is ran by systemd on hypriot OS image, so we had to tweak it a few to unlock limitations. My naive understanding of Linux was that being ran as root, docker deamon could do anything. This isn't the case and it actually can't run more than few dozen processes with default configuration.

Docker daemon has many options we used to reduce it's memory usage.  Generally speaking we tried to disable everything that is not required to run a webserver with docker engine. logs, network, proxies. We expected this to prevent Docker daemon to run threads to collect logs or proxy signals to the contained processes.

2499 Limit

Then we hit the 2499 limit, with this in daemon.log :

docker[307]: runtime: program exceeds 10000-thread limit

Go language did introduce a thread limit to prevent misuse of threading. 10000 was considered enough for any reasonable usage. I indeed would not consider running so much thread a correct design, but here we hit such a limit because docker daemon do run 4 threads per container. It's not yet clear to me what those threads are used for. 

Using Go thread dump (SIGQUIT) I noticed some of them are related to logging, even we ran with --log-driver=none as an attempt to get further. I guess docker design here is to always collect then dispatch to "none" log driver which is NoOp, not to fully disable logging feature.

 So, 2499 is our best official score considering the RpiDocker Challenge rules.


We also wanted to know the upper limit. We made experiments running the plain httpd webserver without docker, and were able to run 27000 of them on the Raspberry. Docker daemon actually grows in memory usage and at some point as some bad impact on the system so you can't run more process. Please note this isn't relevant for arguments against docker on production system, until your business is to run thousands containers on a extra small server.

So, we hacked docker source code to force the MaxThread limit to 12000, built ARM docker executable and ran the script. We were able to run ~2740 web servers before we reach our first, real OOM

[21112.371259] INFO: rcu_preempt detected stalls on CPUs/tasks:

[21112.377124]  Tasks blocked on level-0 rcu_node (CPUs 0-3):

What's next ?

We'd like to better understand Docker threading model, and discuss this issue with docker core team. Using Non-Blocking IO might be an option to rely on a minimal set of threads. I have no idea yet how Golang do handle NIO, I just know it's a pain in Java so I wouldn't do it until I have good reasons to... 

08 octobre 2015

RPiDocker Challenge

On Tuesday evening, we met with some of the BreizhCamp team and friends for our first "BreizhCamp Hacking Party". Our plan was to give the RPiDocker challenge a try.

At DockerCon, hypriot folks demonstrated running 500 (basic) web servers on a Raspberry Pi. This was the starter for hackers to do more, and Damien Duportal reached actual record of ... 2334 webservers running on a Raspberry Pi 2.

So, we met together with various ideas to make a better score...

  1. don't use a IP stack per container, but --net=host
  2. configure RPi hardware for max performances
  3. use swap on disk and/or zram - tweak vm.swapiness 
  4. disable everything (kernel modules and services) that we don't need. I even considered disabling sshd and connect to the RPi using serial console.
  5. enable memory overcommit
  6. use a tmpfs for /var/lib/docker so creating containers is faster and we don't spend hours waiting for thousands containers to start
  7. rebuild docker binary with Go 1.5, to benefit improved garbage collector
  8. run without docker. Really ? Yes! We wanted to know the system limits and then get some metrics on docker overhead.

And the result was .... 70 containers running.

During the 4 hours of our hacking party we were not able to get more than 70 containers, whatever configuration change is made.

We later discovered Damien's hack recipe which is comparable in many ways, but do configure docker daemon LimitNPROC (max number of child processes) to infinity. It's odd this isn't the default. My naive vision of a Unix system is root can do anything, and don't have any restrictions. With capabilities this isn't the case - lesson learned.

Remaining question is to know how we should have understood deamon was blocked by some systemd settings. daemon.log didn't told us much, not sure what we should have been looking for.

Anyway, we now have a set of recipes to setup a RPiDocker system and experiment. We share our tweaks and still experiment on them to mix with Damien's ones. I don't have (yet) a RPi2 so can't give actual challenge metrics, but so far on my RPi 1BRev1 I can run up to 1400 web servers.

And we have some more ideas to get more :P
Wait and see ...

22 septembre 2015

As announced yesterday, we developped a new jenkins plugin during Docker Hack Day

This competition will elect a hacker team to be invited at DockerCon europe, and we need you for this to happen to us !

Please go to https://www.docker.com/community/hackathon?destination=node/4606
search for "Jenkins Docker Slave" if the link doesn't directly point to our hack, and vote using the social media links

Last but not least, share with your friends !

Contributing to Docker

At some time, the hack you build with docker do hit some limitations, and you have few options :

  • give up
  • complain
  • work around
  • contribute

On this blog post I'll focus on the last one.

Working on CloudBees Docker Custom Build Environment Plugin (aka "oki docki"), I had to use docker exec and pass extra environment variables, but it doesn't offer such an option. To get my work done I used a workaround assuming env is available in the target container, but was not pleased by this option.

So on my spare time (sic) I've looked into Docker code, and understood this option isn't supported because ... nobody asked for it so far - actually, IIUC, the underlying RunC container engine fully support passing environment from exec, as the plumbing code is actually shared with docker run.

Getting the project

I made few mistakes before I understood Go programming conventions. So, created ~/go and declared GOPATH accordingly, then cloned docker git repo under $GOPATH/src/github.com/docker. With this setup, I can open the project root in Intellij Idea with Go plugin installed, and get a nice development environment.

I'm far from being fluent in Go language, but docker source code is modular so make it pretty simple to search, and Idea can be used to lookup method usage and such things.

As a result, I added few lines of code


Docker builds inside Docker - and docker is running on my machine inside boot2docker. This Russian dolls setup makes the build process a bit complex.

First, prepare a development environment. For this purpose simply use the Dockerfile present at docker project root:

docker build -t dry-run-test .

Use this docker image, bind mounting the project source, to cross-compile docker binary

docker run --privileged --rm -ti -v `pwd`:/go/src/github.com/docker/docker docker-dev hack/make.sh binary cross

You will get the binary for all platforms created under bundles/1.9.0-dev/cross


As I'm a both lazy and a Java developer I can't read ngrep output and learn how to, so installed Charles Proxy and ran :


http_proxy= ./bundles/1.9.0-dev/cross/darwin/amd64/docker exec --env FOO=BAR 1234 bash

Cool, now have to build and run the docker daemon and check how to get this new option passed to the container engine. Time to get back to work :)

21 septembre 2015

Introducing docker-slaves jenkins plugin

I was at DockerHackDay with Yoann on Thursday, and we implemented together a hack we had in mind for a while without time to actually work on it. So, 48 hours later we are proud to announce: 

Jenkins Docker Slaves Plugin

Why yet another Jenkins / Docker plugin ? Actually, there's at least 3 of them, including one I created last year, but all of them do rely on Docker as plain old virtual machines.

For this projet, we wanted to embrace Docker and the container paradigm. Don't run more than one process in a container. Have containers to communicate through links you explicitly setup. Rely on volumes for persistent data.

Docker Slaves plugin do workaround some Jenkins API that haven't been designed to manage Containers. 

The most obvious of them is the Cloud API, which uses a NodeProvisioner to determine when a new node is required, and when to shut it down. This API has been designed for virtual machines, as costly resources which are slow to setup and as such have to be kept online for few builds. Containers are lightweight, start in milliseconds, and there's no reason to reuse one vs create a fresh new dedicated one for another task. 

Another API mismatch is how Jenkins do launch commands on build executor. Jenkins do rely on the slave agent to some way run `System.exec()`. So Jenkins remoting act as a remote process executor. But what's Docker after all ? It's a remote process launcher (with some extra features) ! So we just bypass the Jenkins Remote Launcher to run a plain `docker run` from Jenkins master. In future, we could run this in detached mode, then Jenkins would not even need to stay online as the job is running, and could be restarted... 

Last but not least, there's no need to use the same container to run all commands. This actually prevent some plugin to apply new environment variables setup by build wrappers, or require some terrible hacks as a workaround. Our plugin is just launching a fresh new container for all command, so can setup the adequate environment. The UI does not (yet) offer this option, but one could imagine user can run some build steps with a docker image and some later steps with another one.

This also means running some background process as part of the build, which used to be a hack in build script, with various cleanup issues - Xvnc plugin, I'm looking at you - isn't necessary anymore. If you want to run Selenium tests, then just run a Selenium container side by side with your build container(s), and thanks to shared network setup you can run selenium tests without any extra configuration.

See the plugin repo README for more details, give it a try, and let you know how it goes !

14 septembre 2015

Giving Windows Docker containers a try

I've been experimenting a few with Windows Docker Containers, aka "Windows Server Containers Technical Preview 3". Windows 2016 will offer kernel-level container capabilities and the adequate glue code to offer Docker API (actually, RunC) so we can use Docker to create and run containerized Windows applications.

Please note : this is all about Windows applications running on Windows 2016, Docker is not a Virtual Machine runtime, so you won't get existing Linux images running on Windows 2016, neither can you run some Windows software on your Linux system.

So, I've created a Windows 2016 VM on Azure (which was simpler than downloading 6Gb from MSDN), following https://msdn.microsoft.com/virtualization/windowscontainers

The VM comes with a single image pre-installed : windowsservercore. We will use this base image to create our own images, just like we used to do starting our Dockerfile with FROM ubuntu. Most significant difference is this base image is 9Gb large, but hopefully you will never have to download it as it will come pre-installed on container-enabled windows releases.

First thing I noticed, starting a new container takes some significant time. Starting a linux docker container takes few tenths of a seconds, so that you feel like your program started without delay. Running a windows container takes 14s on my experiment (running on an Azure D3 box : 4 core 14Gb).

Second thing, my plan was to experiment by creating a windows jenkins-slave container, and for this purpose I need to download a JDK. I had to google a few then switch to PowerShell so I can run wget command to download Oracle JDK windows 64 installer.

Then I used notepad.exe (sic) to edit a Dockerfile, to install JDK in a container. My experiments stopped here, as I can't find how to launch the installer, always get weird error "

The directory name is invalid.
The command 'cmd /S /C C:\install\jdk.exe' returned a non-zero code: 1

Tried also with unix style path, same issue.

I also got a container I can't stop. I have no idea about this container state, but it's annoying I can't kill it, as docker daemon is supposed to have super-power on all container running and can force a SIGKILL, or windows equivalent, which seems to be only partially implemented. But let's remember we are running on a beta preview here.

Conclusion : considering Microsoft commitment to provide a container solution on Windows is just one year old, this is an encouraging preview. There's also lot's we have to learn to adapt the habits we have for Linux-based docker image to Windows, it seems the windows docker runtime do use Unix paths, which might results in some confusion when running windows commands in a Dockerfile. But the feeling I have after this experiment is I'll come back in few months when this get polished a few.

As suggested by David, I've tried to use Chocolatey and use it to install a JDK. And this works well !

C:\Users\nicolas\dock  docker build -t java .
Sending build context to Docker daemon 2.048 kB
Step 0 : FROM windowsservercore
 --- 0d53944cb84d
Step 1 : RUN @powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin
 --- Using cache
 --- 82076c2bad03
Step 2 : RUN chocolatey install -y jdk8
 --- Using cache
 --- 84f6a8356fe3
Successfully built 84f6a8356fe3

C:\Users\nicolas\dock  docker run -it --rm java cmd

C:\Windows\system32  java -version
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)


Next step is for me to use this to setup a JNLP windows jenkins slave and check how it goes compared to a classic windows VM.

Moving my demo to Docker

Last Thursday I went to local Java User Group for the very first run of my new talk "(Docker, Jenkins) -> { Orchestrating Continuous Delivery }".

I've planned for this talk since june, but actually started to work on it on ... Tuesday, and got demo setup on Thursday in the morning :-\ As an expected result, the demo all failed, while the talk was mostly appreciated afaict.

How to make my demo more reproducible ? Hey, this is what the conference is talking about after all : setup reproducible build environment using Docker containers ! So let's use the same technique to host the demo itself.

The demo is using Cloudbees Jenkins Enterprise docker image, jetty to deploy built web apps, and docker registry to deploy docker images. I could run them by hand, but sounds better to rely on docker-compose to handle all the plumbing !

# Jenkins master, running on default http 80 port
  image: cloudbees/jenkins-enterprise
    - "80:8080"
    - "50000:50000"
    # JENKINS_HOME, from host with pre-defined demo jobs
    - ./jenkins-home:/var/jenkins_home
    # Required host stuff so jenkins can run `docker` command to start containers
    - /var/run/docker.sock:/var/run/docker.sock
    - /usr/local/bin/docker:/usr/local/bin/docker
    # We "deploy" to jetty with a plain `cp`
    - webserver    
    - webserver
    - docker-registry
  user: jenkins:100 # 'docker' group, required to access docker.sock  

# Jetty web server to run tests, staging and production
  image: jetty:9
    - "8080:8080"
    - ./webapps:/var/lib/jetty/webapps

# Our private docker registry
  image: registry
    - "5000:5000"

The demo relies on a set of preconfigured jobs, so jenkin-home is bind mounted from the demo root directory. I had to configure bunch of .gitignore rules so I can share this config but not the build history and all other local jenkins stuff.

Webserver webapps directory could not be bind mounted, just relying on volumes, but then I get a permission error when Jenkins jobs tries to copy the war to jetty's volume. This could be fixed if we have #7198 resolved.

As the demo do run some docker tasks, I'm bind-mounting docker unix socket and cli executable in jenkins container, so it can build and start new containers. Docker Workflow plugin demo do use Docker-in-Docker for this, but I wanted to avoid using this hack (also read this). But a side effect is I need to configure the jenkins user with adequate permission so it can access the docker daemon socket, which means it has to be in the docker group. I'd like to use user: jenkins:docker, but the later doesn't work as --user do expect either a numeric ID, or user name for a declared user in the container, but not a host user/group name (I haven't found a related docker issue).

Last but not least, docker demo failed. I eventually understood the issue comes from bind mounted volumes.

JENKINS_HOME is set in jenkins container as /var/jenkins_home; this path is bind mounted from current directory /Users/nicolas/demo/jenkins-home. When docker-workflow creates as container to run continuous delivery pipeline steps inside containers, it tries to bind mount this exact same directory, but with my setup it does this on a side container (not a nested one, as in the original demo). As a result, this build container get some /var/jenkins_home/job/demo/workspace bind mounted, expecting to get there the project source files; but such a file doesn't exists on host, resulting in JENKINS-28821. This could be fixed if workflow can detect it's running inside a container, and uses --volume-from. I'll investigate such a fix. In the meantime, I've created a symlink on host as an ugly workaround.

Ok, so this was not such a trivial thing, and there's few things to get polished, but with this setup I now can share my demo, cleanup my environment with git clean -fdx, and get it up and running with a simple docker-compose up.

03 août 2015

Docker Zombies

Un intérêt principal pour moi à maintenir l'image Docker de Jenkins c'est que j'apprend plein de choses, entre autre sur la partie Système/Linux pour laquelle j'ai une bonne marge de progression :)

Récemment, on m'a rapporté des problèmes de zombies avec l'image Jenkins, que j'ai dans un premier temps rejeté en demandant de montrer que ce problème est propre à l'utilisation de Docker et non un problème Jenkins général - je reçois en effet pas mal de bug report de ce style qui n'ont rien à voir avec Docker.

Sauf que pour une fois il y avait bien un loup.

Quel est le problème ?

Jenkins lance pas mal de process externes à la JVM, par exemple pour faire le checkout ou tout simplement pour exécuter les outils de build. Lorsque ce process-fils se termine, il passe dans l'état defunct (zombie) et le noyau le faire savoir à son parent via un signal SIG_CHLD, parent qui va faire un wait pour acquitter la fin de vie de son fils et permettre au process d'être éliminé complètement.  

Suite a un arrêt brutal d'un process (KILL), les process fils se retrouvent orphelins et l'OS n'a plus de parent à notifier pour prendre en charge le nettoyage, aussi il les propose pour l'adoption à init, le process d'id 1. Ce mécanisme est un peu le garbage collector du système. Dans le cas de Jenkins, on peut par exemple considérer le plantage d'un build qui laisse tout un graphe de processus fils dans la nature.

init est prévu pour ça et fait donc tout ce qu'il faut, mais ... mais nous sommes dans un conteneur Docker, et via le mécanismes des namespaces le process d'ID 1 n'est pas un init, mais le shell script qui sert de point d'entrée à l'image. Et bien sur bash n'est pas du tout conçu pour adopter des process zombie et les enterrer proprement.

La solution ?

Ce problème de terminaison correcte des processus est expliqué sur cet article et montre qu'il faut faire pas mal de chose pour bien traiter les signaux. Le problème évidement c'est qu'on est pas du tout habitués à devoir gérer ce genre de choses vu qu'on a en temps normal un OS et son init pour s'en charger.

Pour l'image Docker Jenkins j'ai utilisé tini, un petit bout de programme qui fait juste ce qu'il faut comme un init normal dans le contexte d'un conteneur : passer les signaux, adopter et terminer les processus orphelins. Ca ajoute quelques Mb à l'image Docker (mais bon, avec Debian + JDK + Jenkins on est plus vraiment à ça près) et ça règle le soucis. 

Quelque soit votre appli Docker je vous encourage donc à adopter ce petit bout de code qui vous évitera des surprises.

La vraie solution ?

Idéalement Docker devrait rendre tout ça transparent pour qu'on ai pas à s'en soucier nous développeurs qui n'avons pas lu le guide du noyau Linux. #11529 débat par exemple d'une implémentation globale au niveau de Docker pour remplacer la simple exécution d'une command externe au lancement du conteneur par un mécanisme plus avancé prenant en charge l'adoption des process orphelins.

Ce point (et de nombreux autres) on été décrits dans un article très populaire et bien documenté que je vous recommande vivement : http://sirupsen.com/production-docker/

Si cet article ne vous aidera pas à convaincre vos Ops de passer à Docker, en tout cas il pose de vraies bonnes questions et vous pousse donc à réfléchir à la façon dont vous devrez penser votre infra ou vos images Docker. Bonne lecture.

01 juin 2015

filmer une conférence (suite)

Ce billet fait suite à celui-ci.

Je vais faire ici un focus sur la capture de ce que le conférencier présente. Si ce ne sont que des slides, il est bien sur plus simple de lui demander son support à la fin de la session (en PDF s'il craint une réutilisation sans autorisation). Par contre s'il y a des démos ou du live coding, la session n'a pas grand intérêt une fois mise en ligne sans capture de ce que le public suit sur l'écran.

J'évacue l'idée de filmer l'écran de projection, ce qui donne une image blanche, sans contraste, déformée - bref "dégueulasse". On va dire que ce sera notre plan B si le reste échoue et d'ailleurs on part là dessus pour la keynote BreizhCamp :\

La solution : capturer le signal vidéo tel qu'il est envoyé au vidéo-projecteur.

Pendant deux années, sur les conseils de l'équipe Devoxx, nous avons utilisé un boitier Epiphan vga2usb, pas trop cher et qui marche plutôt bien. La qualité est assez moyenne (résolution limitée, peu d'images/s) mais au moins le contraste et le piqué sont au rendez-vous. 

Mais nous sommes en 2015, aussi les salles bien équipées sont passées au HDMI.

Challenge : trouver du matériel d'acquisition/enregistrement HDMI adapté.

Il existe des solutions est assez comparable à ce que nous faisions avec le VGA2USB : un boitier qui reçoit le flux vidéo, le capture, et transmet l'image capturée au un PC - j'en parlerais dans un prochain billet - pour encodage / stockage / diffusion. C'est fonctionnel, mais mon expérience avec le vga2usb montre que ça reste lourd à mettre en oeuvre. Donc, pour une soirée JUG c'est faisable, mais pour une conférence comme le BreizhCamp, enchaîner tous les talks devient vraiment compliqué.

Heureusement, l'explosion du jeu vidéo et des chaînes youtube associé nous aide, aussi on trouve plein de solutions grand public.

Nous avons donc fait l'acquisition d'un Avermedia GameCapture HD II (120€), solution que j'ai choisi pour son disque dur intégré. Un bouton rouge "record" et basta, la session commence - pas de PC raccordé et d'enregistrement à lancer depuis une appli Windows propriétaire.

Premier essai - première déception : c'était sans compter sur le côté "HD" du HDMI et donc son pendant, le HDCP - protection anti-copie.

Le HDMI véhiculant l'image numérique en haute définition, nos majors ont eu très peur qu'il soit la source d'un nouveau mode de piratage, et ont donc planché sur une protection. Si votre lecteur blue-ray diffuse un contenu HD ayant des droits à protéger, il demandera à l'écran raccordé à l'autre bout de montrer pate blanche. La sécurité a évidemment été rapidement cassée, mais bon c'est un autre sujet.

La sortie HDMI du Mac respecte HDCP, ce qui en soit est logique, mais il a la bonne idée de le faire même lorsque vous ne lisez pas un film payant sur iTunes. En effet, la négociation de la qualité de restitution se fait à la connection du câble HDMI, aussi impossible pour le Mac de dire tout d'un coup "hey, ta vidéo d'Iron Man 4 est protégée! donc je passe en SD". Résultat, vous ne pouvez pas enregistrer votre propre flux vidéo, c'est cool les DRM.

Un MacMini raccordé au GameCapture, on appuie sur sur "record", et m...

Inutile de chercher côté configuration soft, c'est peut être possible mais je ne vais pas demander à chaque speaker de bricoler sa machine pour désactiver une option graphique bas niveau. Si je devais partir là dessus je leur demanderais simplement d'installer un soft de screen-recording ! 

Il existe une solution un hack plus "intéressant" : un splitter HDMi bas de gamme made in China.

Je vous vois venir : "mais euh, ton splitter il n'a qu'une seule sortie ?" - ce boitier est en effet en principe conçu pour dupliquer le signal sur deux sorties, mais nous n'utilisons pas cette fonction (quoi qu'elle pourrait servir pour brancher un écran de contrôle). Non, l'intérêt de ce boitier c'est qu'il implémente HDCP avec le pieds.

En gros, quand on branche deux équipements HDMI, la source négocie avec l'écran pour vérifier qu'il est conforme et activer la HD 1080, et sinon dégrader la résolution, voir bloquer complètement l'affichage. Mais les développeurs de ce boîtier n'ont du lire que le titre de la spec, et du coup il se prend les pieds dans le tapis et dans le doute renvoie "ok, tout va bien" à la source vidéo.

Coup de bol me direz vous - en effet - si vous doutez, prenez un HDFury (convertisseur HDMI -> analogique HD -> HDMI) c'est un peu plus cher mais sans doute plus déterministe :)

Donc bref, nous n'utilisons pas le splitter comme splitter mais pour ça ... euh ... capacité à faire sauter le HDCP - et du coup permettre au Avermedia de faire son boulot. Le speaker n'a plus qu'à brancher le câble HDMI, on appuie sur record, et on récupère un fichier mp4 en HD1080, comme sur cet exemple :

Ce matos arrive malheureusement un peu tard et je ne suis pas sur qu'on puisse l'exploiter correctement pour le BreizhCamp faute d'expérience. Dans un prochain article je vous parlerais d'un autre boitier de capture HDMI : le BlackMagic Intensity Extreme.

14 mai 2015

"Mon talk a été rejeté"

Nous avons reçu 206 propositions au Call-for-Papers du BreizhCamp, pour n'en retenir que 86.

J'ai moi aussi plusieurs fois vécu l'attente d'un CfP et les messages "your talk has been rejected". Aussi je vais faire un point pour vous expliquer comment se déroule la sélection.

1. la phase de collecte

Le "Call-for-Papers" permet à des conférenciers du tout poils de nous proposer leur sujet. Cette appli web est ouverte pendant 1 mois et nous tentons de la faire connaître dans toutes les communautés, pour obtenir un maximum de sujets sur des thématiques aussi variées que possible.

Une proposition comporte un titre et un "pitch" que vous retrouvez sur le programme, la sélection d'un track et d'un format, ainsi qu'un message privé destiné aux organisateurs.

Les tracks permettent de donner des thématiques à la conférence. Certains speakers s'y retrouvent mal et nous demandent donc de l'aide, et c'est normal, car cette catégorisation est un peu artificielle. Elle permet aussi dans certains cas de comprendre qu'un sujet n'est pas adapté à la conférence et/ou à son public.

Les formats vont du quickie (15 minutes pendant la pause déjeuner) à la Keynote d'ouverture. Certains speakers proposent un sujet en nous disant pouvoir s'adapter. Disons les choses clairement : cela ne va pas en leur faveur, ça nous fait comprendre qu'il y a une intention, mais que ce sujet n'a jamais été présenté ni même imaginé pour un format précis.

Le CFP permet aussi à l'équipe organisatrice de poser des questions, de faire des remarques sur le pitch ou de proposer un changement de track / format. Soyons clair, certains speakers ne savent pas où ils mettent les pieds donc ils ont besoin de ce petit coup de pouce pour "coller" à ce qu'attend notre public. 

Cette étape d'échange n'est pas systématique, mais est importante. C'est à ce moment que l'équipe découvre les propositions et peut en jauger la valeur. Nous avons reçu près de 30 propositions le dernier jour du CfP. Si certains de ces speakers étaient dans notre Wish-list et ont en fait répondu à nos relances, d'autres se sont juste réveillés très tardivement; Et ce n'est pas un bon calcul : très clairement, ces sujets nous les découvrons au dernier moment après en avoir peut être vu des similaires depuis quelques semaines, ils ne seront pas notre premier choix.

2. la phase de vote

Chaque membre de l'équipe donne son avis sur les propositions sous forme d'un vote entre 1 et 10. Il peut aussi s'abstenir si le sujet n'est pas dans son domaine de compétence. Voter nécessite de comparer des propositions similaires, de tenir compte du speaker qu'on a pu déjà voir sur scène, de sa légitimité sur un sujet précis, de la qualité du pitch et des notes privées qui nous ont été fournies pour nous indiquer ce que le titre peut cacher.

Les votes dans certains cas sont plutôt dispersés, comme dans cet exemple :

Ce type de résultat montre qu'une partie de l'équipe a été très intéressée tandis que l'autre n'y voit qu'un intérêt mitigé. Si nous considérons être représentatif de notre public, cela signifie que ce talk pourra trouver son public mais avec un effectif réduit. Selon la densité de propositions sur ce track / format, ce talk pourra être retenu et placé dans une "petite" salle, ou être écarté au profit d'un autre sujet plus populaire. 

Le détail d'un vote n'est pas accessible aux speakers, entre autre parce que l'interprétation est très délicate. Dans l'exemple ci-dessus, le talk est clairement bon, mais peut être pas adapté à la conférence. Il serait probablement un excellent sujet pour une conférence plus spécifique au thème considéré, ou bien pour un User-Group.

3. le dépouillement

La moyenne des votes donne un classement dans le CFP qui définie en grande partie le programme. Le programme, c'est une grille avec trois fois moins de cases que de fiches "proposition" entre nos mains; C'est donc un jeu de remplissage.

  • 1/3 du programme est directement dicté par les votes
  • le second tier est issue du tri par vote, mais tient compte des sujets déjà retenus pour éviter des doublons, assurer un certain équilibre sur les thèmes proposés.
  • le troisième tiers est lui aussi défini en se basant sur les votes, mais en allant chercher bien plus loin dans la pile, pour vérifier qu'il n'y a pas un sujet original qu'on ne veut pas laisser de côté

Evidemment ce dépouillement n'est pas automatique, et donne lieu à divers débats, mais globalement nous n'avons pas eu besoin d'en venir aux mains.

En sortie du dépouillement il nous reste quelques talks qui ont été exclus de peu. Sur le votes, on est en général un voir deux chiffres après la virgule en note moyenne. Ces sujets, on en garde quelques-uns en "backup", surtout si le speaker est déjà retenu et/ou est un "local". Ils nous permettent de rattraper le coup en cas d'aléa pendant les semaines qui précèdent la conférence : speaker retenu ailleurs, etc...

4. publication

La publication du programme est une étape très attendue, et nous avons du ressortir des bouts de code de 2014 pour publier notre agenda et les greffer dans l'application CfP de 2015, un clone de Devoxx - d'où un petit retard.

Cette publication est aussi le début d'un savant jeu de taquin pour tenir compte des contraintes de chaque speaker, entre celui qui doit être rentré jeudi soir à Paris, celui qui enchaine une autre conf qui par manque de bol tombe en même temps, celui qui ne peut pas arriver avant jeudi midi, celui qui ...
Et bien sur, nous essayons autant que possible de ne pas caller des speakers venus de loin sur un créneau du vendredi soir à 18h !

Si votre talk n'a pas été retenu, c'est souvent à peu de choses près. Soit votre sujet ne colle pas avec la conférence, soit il y a déjà du monde (réputé) sur ce thème. Pour vous donner une idée, la semaine d'ouverture du CfP, une proposition sur deux contenait le mot "Spark". J'ai eu peur qu'on finisse avec un BigDataCamp. Donc votre sujet est peut être très bon, mais clairement en tant qu'organisateur il se retrouve filtré dans l'avalanche. 

06 mai 2015

Gilet Rouge

Cette année, j'ai participé 3 fois à DevoxxFrance :

  • en tant que participants, en allant voir quelques conférences dont les sujets me tenaient à coeur (Mesos, Kubernetes, Java8)
  • en tant que speaker, en présentant un sujet sur l'évolution de l'infra CloudBees :
  • ... et en tant qu'organisateur, en mettant à disposition mes deux bras
Pour ce billet, je vais m'attarder sur le dernier point, les autres étant très bien résumés par d'autres.

J'ai donc cette année enfilé pour la première fois le fameux gilet rouge. Cela faisait plusieurs années que je proposait mon aide à l'ami Antonio qui me répondait avec malice "Oh non, surtout pas lui".

Cette année, j'ai débarqué avec ma caméra et j'ai voulu immortaliser la journée de préparation de DevoxxFrance, celle où tout le monde arpente les (immenses) couloirs du palais des congrès chargé de scotch, multiprises, feuilles de planning, etc. Le résultat est .

Par ailleurs, organiser une conf, j'ai ça dans le sang (d'ailleurs j'en organise une sur Rennes si vous ne saviez pas) aussi j'ai tout naturellement prêté mes deux mains pour faire avancer le schmilblick, et c'est ainsi que je me suis retrouvé mardi soir avec la team à écouter les consignes du Big Boss : "rendez-vous demain matin, 7h pour les plus motivés"

Mercredi, arrivé à 7h sur les lieux pour donner un coup de main.  Seul.
Bon en fait ils sont arrivés 2 minutes après, mais en tout cas j'étais remonté à bloc :P

5 heures et 2500 T-Shirts plus tard, Nico Martignole me demande "mais dis, ça te tenterais de devenir gilet rouge ?". L'anecdote du "surtout pas lui" l'a bien fait marrer, et il m'a alors proposé d'endosser son gilet rouge "Nicolas" de 2011, gardé bien au chaud à l'hotel.

Voilà pour la petite histoire, du comment on se retrouve sur la photo officielle.

Quel intérêt pour moi d'être côté staff ?

  1. des relations privilégiées avec l'équipe, une expérience inoubliable
  2. plein d'astuces pour ma propre orga
  3. la fierté de contribuer à quelque chose qui a de la gueule
  4. et un repas gratuit !

ok, ça peut paraître court, mais demandez à chaque membre de l'orga combien de talk il a vu, vous constaterez qu'on compte sur les doigts d'une main, et pourtant tous sont ravis. Parce que les conférences, pour beaucoup d'entre nous, c'est plus côtoyer des personnes qu'on ne rencontre qu'une fois par an au mieux, des speakers célèbres, des tech-lead de projets majeurs. C'est donc de longues discussions, bien plus que 50 minutes dans un fauteuil à écouter un talk (qui est dispo en vidéo).

Parce que les conférences, pour certains d'entre nous, c'est un réseau de copains organisateurs, qui s'interrogent sur la marque d'un pied caméra qu'ils verraient bien dans leur propre amphi, et qui vivent pleinement leur passion

Parce que les conférences, pour vous tous, c'est un rendez-vous annuel qui doit être à la hauteur de vos attentes, et vos applaudissement nous prouvent que notre sacrifice (si c'en est un) en vaut la peine.

Si on y réfléchit bien, le gilet rouge, c'est un peu une drogue - légale.

13 mars 2015

filmer une conférence

Ce billet fait suite à mon article sur la prise de son au BreizhJUG

J'ai donc bien insisté sur le fait que la qualité du son est l'élément clé pour diffuser une conférence, ceci dit ce n'est pas une raison pour faire n'importe quoi avec l'image.


La majorité des sessions historiques du BreizhJUG sur Parleys sont d'une qualité "passable". La raison : le publisher Parleys limite la vidéo à 300Mo, ce qui pour 90minutes de présentation nécessite de régler le codec avec amour, et de lui imposer un débit max raz des pâquerettes. Le résultat n'est pas sans conséquences. Je n'ai pas creusé très loin les options d'encodage ni les divers codecs disponibles, mais ça semble délicat de faire rentrer une qualité vidéo correcte dans 300Mo, même les films qu'on trouve sur bittorent font 700Mo pour la même durée - enfin il parait, moi j'ai jamais téléchargé de film illégalement et je ne regarde que Arté.

La version actuelle permet d'utiliser une vidéo YouTube, donc on a plus cette limitation;

à nous les HD, 1080p et autres 4K ! 

Le débit est donc un élément important sur la qualité de la vidéo que verrons nos auditeurs, ceci dit sur une conférence, filmer en 50p full HD n'a pas un grand intérêt, à moins de vouloir capturer image par image le moindre détail du sensuel geste d'Amira se recoiffant ... ce que peu de gens font (non, moi non plus, quelle idée enfin). 

Pour ne pas pénaliser ceux qui ont un débit réduit (toi qui partage une livebox à 50 dans l'openspace tu me comprend) mais aussi pour que l'upload ne prenne pas 72h, il faut encoder avec un débit adapté, et plus on a une haute résolution à encoder, plus le fichier va être lourd, donc plus on est obligé de dégrader au niveau de la compression ... Bref, j'ai retenu le 720p qui permet de faire du plein écran sans exploser la taille des fichiers - et ça permet au Ch'tiJUG de passer nos vidéos quand ils sont en manque de speaker :P

Je capture en full HD 50p puis j'exporte en 720p avec un débit "raisonnable" de 2.5Mb/s. Je fait la capture dans ce mode "haute qualité" car je préfère dégrader à la post-production une image de qualité que de travailler sur une image déjà dégradée. Un filtre d'élimination du bruit de fond par exemple applique une moyenne / flou sur le fond considéré uniforme mais qui subit un bruit numérique. Sur une image HD il dispose de nombreux points donc cette moyenne est pertinente. La réduction d'échelle en 720 est alors appliquée sur une image "propre".


Vous noterez sans doute entre ces deux captures une grande différence de contraste / luminosité. C'est ici que l'autre bout de la chaine intervient : la qualité de la capture vidéo. La première date de 2010 avec notre "vieux" caméscope et la seconde date de février avec notre caméra HD achetée l'an dernier. Mais ce n'est pas la seule explication.

Le lieu de prise de vue n'est pas le même. En général un problème dans les salles de conférence c'est qu'on éclaire peu pour avoir un bon contraste sur l'écran de vidéo-projection, alors que la caméra elle exige un max de lumière sur le speaker. On a la chance à l'ISTIC d'avoir un compromis très correct de ce point de vue. Les grandes conférences n'hésitent pas à installer du matériel de scène pour éclairer le speaker. C'est aussi ce que j'envisage pour le BreizhCamp 2015. 

Au passage attention si ça vous tente, les lampes n'ont pas toutes la même couleur de blanc ('température'). Le risque avec un éclairage type néon, une lumière très "bleue", c'est de rendre l'image blafarde, alors qu'un halogène donnera une image très (trop?) "chaude". Sur le caméscope on peut régler la "balance des blancs" en conséquence, et on peut aussi corriger cela au montage - cette correction est surtout nécessaire sous éclairage néon, assez blafards. Sous Final Cut Pro, il suffit de laisser tourner le soft en analyse de la balance des couleurs et de cocher une case... 

Si la lumière n'est pas géniale, et même si elle est suffisante, une bonne qualité de capture vidéo reste nécessaire. J'ai déjà évoqué le cas de la GoPro. Cette micro-caméra de sport corrige les défauts de ses capacités physiques par de l'extrapolation et du renforcement des contrastes qui lui donnent une image qui pète un max. Que les choses soient claires: l'objectif d'une GoPro, comme celui de votre téléphone, ne pourra jamais rivaliser avec un objectif de type photographie en termes de lumière captée, ne serait-ce qu'en considérant sa section de collecte de la lumière - ce qui n'est qu'un des nombreux facteurs à envisager.

Un autre point à considérer avec la GoPro c'est son effet fish-eye : le grand angle déforme la géométrie de prise de vue. C'est l'effet "immersion" voulu quand on filme du base-jump, par contre pour une conférence, c'est plutôt dérangeant. 

Evidemment, on est pas obligé d'investir dans un Canon 5D avec un objectif à 2000€ pour filmer un talk sur Cassandra. Un caméscope correct fait très bien le travail, le tout est de bien évaluer ce qu'on entent par "correct".

Un caméscope est par définition un "tout terrain automatique". Pour filmer en conférence, on filme sur pied, sans mouvement important, sans changement de lumière, sans changement de focus, et souvent avec une lumière assez faible. Si vous devez choisir un modèle, je vous conseille vivement de lire les tests du site les numériques qui sont très complets, et testent souvent le comportement en faible luminosité (test encore plus complet si vous choisissez un DSLR). Les défauts qu'ils révèlent sont ceux qui vous feront ch.. lors de vos prise de vue en conférence. Sur cet exemple, on a d'un côté beaucoup de bruit numérique et de l'autre une image certes moins lumineuse, mais plus propre.

Nous avons un Sony HDR CX740 qui a une image que je trouve très correcte, et réagit plutôt bien au manque de lumière. 


Entre la prise de vue et la diffusion il y a le "montage", ce qui veut dire en gros "passer des heures sous Final Cut à chercher le bon filtre et le réglage qui va bien".

Pour un film de conférence, c'est une étape qui se fait rapidement puisqu'il n'y a pas à proprement parler de montage : on détermine le début et la fin de la présentation, basta. Je débute encore sous FCP mais je sais qu'on peut aussi ajuster le rendu de l'image pour corriger la luminosité et le rendu des couleurs et rendre l'image plus sympa. Tout dépend du temps libre dont on dispose :P

Bon, ça c'était la partie facile - ok, on a donc le film de notre speaker qui porte la bonne parole. Mais manquent les slides, ou pire les démos / live coding. Parce que sans ça, nos vidéos ne servent pas à grand chose.

Filmer l'écran

On voit souvent des sessions où le speaker est filmé de loin avec l'écran de projection. C'est malheureusement la fausse bonne idée. Les stats Youtube qui indique le moment où notre lecteur d'Internet nous quitte (durée moyenne de visionnage) est assez révélateur pour cela.

Autant la qualité d'image pour regarder Julien nous expliquer JHipster n'est pas un point clé, autant celle de la capture de son écran quand il tape du code l'est, car toute notre concentration est portée sur l'image à ce moment là. 

Or, filmer une image projetée sur écran, ça donne souvent un grand carré blanc flou, à peine lisible, très fatigant. Sauf à avoir un sujet qui déchire, personne ne restera devant cette vidéo jusqu'à la fin.

En tant que speaker on m'a parfois demandé d'installer un truc qui va enregistrer tout ce qui se passe sur mon écran. Ca parait pas mal comme solution, et c'est clairement à considérer si vous n'avez pas le budget pour la solution suivante, mais ...

  1. le speaker (moi le premier) est souvent réticent à installer un truc sur sa machine, il a peur que ça fasse planter ça démo qu'il a préparé depuis 2 mois
  2. ça bouffe souvent pas mal de CPU et en effet, ça fait planter la démo
  3. ça peut bouffer pas mal de disque, se gaufrer en plein milieu (ça m'est arrivé), et en plus planter la démo
  4. si on oublie de récupérer le fichier à la fin de la session, alors que le speaker se dépêche de remballer, harcelé de questions ... on ne verra jamais la vidéo.
  5. y'a toujours un mec qui n'a rien trouvé de mieux que d'installer ArchLinux ou Windows 10
  6. si on utilise pas le mode "recopie vidéo", qu'il y a des changements de résolution à un moment donné, ou toute autre manip' de ce genre, il y a une incertitude sur ce qui est enregistré.

Variante intéressante, on m'a proposé à BDX.io la capture à distance. Je lance un soft depuis une clé USB (pas d'installation donc) et il est sensé permettre à l'opérateur de capturer mon écran. Evidemment, un truc quelque part bloquait le port, et comme on mettait ça en place 5 minutes avant mon intervention, c'était mort

Bref, c'est globalement fragile, stressant pour tout le monde, et pas sans risques même en dehors de foirer la capture. C'est donc à considérer comme un plan B, pour une salle annexe, ou pour sa propre utilisation.

Que faire alors ? 

Capturer le signal vidéo.

Au BreizhJUG nous avons dès 2009 utilisé un boitier "VGA2USB" qui marche pas trop mal mais est vite limité. Sur la session live-coding de David Gageot par exemple, on obtient une résolution 1024x768 avec quelque chose comme 20 images/seconde, et une image correcte. C'est suffisant pour suivre les refactoring qui s'enchaînent sans avoir mal au crâne (ou du moins, ce n'est pas la faute de la capture vidéo). Ce boitier coute quelques centaines d'euro et nécessite un PC connecté pour récolter la capture, ce qui est plutôt contraignant. Raison pour laquelle on ne l'a utilisé que quelques fois, et jamais pendant le BreizhCamp.

Il faut croire qu'on était en avance sur notre temps vu qu'on est référencé sur leur site maintenant !

En 2015 le HDMI devient de plus en plus présent, et simplifie beaucoup les choses. En effet, le problème du VGA c'est que c'est un signal analogique, donc le système de capture doit recomposer le signal écran pour l'échantillonner. Le HDMI par contre véhicule directement un signal numérique. Cerise sur le gateau, avec l'explosion du social gaming sur Youtube, on dispose aujourd'hui de boitiers de capture HDMI autonomes conçu pour permettre au gamers de capturer leurs moments d'anthologie.

Je viens de faire l'acquisition d'un AVerMedia Game Capture HD II. Equipé d'un disque 2.5", c'est un boitier autonome qu'on intercale entre le speaker et le vidéo projecteur. On appuie sur le bouton rouge et c'est parti pour 1h30 de capture vidéo. Je vous dirais ce que ça donne sur le terrain dans un prochain billet :) 

Ce type d'appareil est très orienté Gamer et du coup on pourra lui préférer du matos plus "vidéo" - Epiphan propose par exemple un boitier dédié à ce cas d'usage, mais pas pour le même tarif !

Au montage
Si vous publiez sur Parleys, la question ne devrait pas se poser vu que c'est le publisher parleys qui va vous permettre de mixer la vidéo du speaker avec la capture écran. Sauf qu'il faut tout de même que la bande son soit la même sur les deux vidéos, donc vous vous coltinerez tout de même l'étape "montage" pour avoir la même bande son sur les deux.

Au montage, on peut choisir d'intercaler cette vidéo avec l'image du speaker comme le fait Parleys, ou faire de l'incrustation comme par exemple sur les vidéos de la DockerCon ou l'inverse pour la Jenkins User Conférence - selon qu'on préfère voir le code ou le speaker :P.


Voilà, donc amis organisateur de conférence, y'a plus qu'à !

n'hésitez pas si vous avez des questions/remarques => @ndeloof