Virtualisez pour plus de reproductibilité

Virtualisez pour plus de reproductibilité

Pour commencer

Vous avez enten­du par­ler de repro­duc­ti­bi­li­té. Vous vou­lez vous y mettre ? Vous vous dites que la vir­tua­li­sa­tion vous aide­rait à uti­li­ser tou­jours la même ver­sion d'un outil pré­cis. En savoir plus sur Docker vous aide­rait bien ? Cet article est donc pour vous. Je pro­fite de l'occasion pour par­ler aus­si de Sin­gu­la­ri­ty. Mais pour bien com­men­cer, on va expli­quer le concept des Machines Vir­tuelles.

Une Machine Virtuelle c'est quoi ?

Alors pour tous ceux qui se posent la ques­tion, un grille-pain en réa­li­té vir­tuelle n'est pas une Machine Vir­tuelle. Une Machine Vir­tuelle c'est la simu­la­tion d'un sys­tème infor­ma­tique qui repro­duit son uti­li­sa­tion réelle. Une notion voi­sine est l'ému­la­tion, outil bien connu des retro-gamers, qui va simu­ler un maté­riel pour repro­duire son uti­li­sa­tion.

Dans notre cas, c'est la vir­tua­li­sa­tion qui nous inté­resse. Le grand inté­rêt étant de pou­voir faire abs­trac­tion de toutes les carac­té­ris­tiques du sys­tème sur lequel on est et de simu­ler un autre sys­tème pour avoir un envi­ron­ne­ment trans­por­table et donc repro­duc­tible d'une machine à une autre.

Java fonc­tionne sur ce prin­cipe de Machine Vir­tuelle (et oui, JVM c'est pour Java Vir­tual Machine). Vir­tual Box est un des outils les plus connus per­met­tant de faire des Machines Vir­tuelles.

Les environnements virtuels

Alors oui, les Machines Vir­tuelles c'est bien joli, mais c'est un peu lourd. Du coup si au lieu de simu­ler le sys­tème dans son inté­gra­li­té, on ne simu­lait que ce dont on avait besoin, c'est-à-dire les appli­ca­tions. Bon quelques librai­ries ça peut être pra­tique aus­si, mais vous voyez l'idée.

Le grand inté­rêt d'utiliser des envi­ron­ne­ments vir­tuels c'est aus­si de pou­voir com­par­ti­men­ter et iso­ler ces envi­ron­ne­ments dans des conte­neurs. Et par exemple, de pou­voir ins­tal­ler plu­sieurs ver­sions de Python et plu­sieurs outils uti­li­sant plu­sieurs ver­sions sans trop s'embêter. Les adeptes de Python et de vir­tua­lenv se recon­naî­tront.

Docker c'est quoi ?

Docker c'est un outil qui s'appuie sur les fonc­tion­na­li­tés du sys­tème d'exploitation sous-jacent (le noyau Linux). Docker s'interface avec le noyau Linux et pro­pose plu­sieurs ins­tances de vir­tua­li­sa­tion iso­lées. Ces ins­tances sont appe­lées conte­neurs, et ils sont donc très légers (com­pa­rés aux Machines Vir­tuelles clas­siques). Une simple recherche sur votre moteur de recherche pré­fé­ré vous amène faci­le­ment sur des tuto­riaux si le work­shop de l'IFB et le site de Docker ne vous suf­fisent pas. Pour la petite his­toire, Docker a été créé par un fran­co-amé­ri­cain, et la des­si­na­trice Lau­rel y tra­vaille actuel­le­ment et elle fait entre autres choses de jolis auto­col­lants.

Les avantages et les inconvénients ?

Le grand avan­tage de Docker est sa sim­pli­ci­té de mise en place et d'utilisation. Les conte­neurs donnent accès à des envi­ron­ne­ments iso­lés et contrô­lés. Docker-Hub est le site de dépôt de Docker, conçu pour faci­li­ter la recherche et le par­tage de conte­neurs Docker.

Créer son propre conte­neur Docker est aus­si simple. Il suf­fit de le construire à par­tir d'un fichier de confi­gu­ra­tion Docker­file qui contient toutes les com­mandes néces­saires à sa construc­tion. Si votre Docker­file est ver­sion­né sur GitHub, une construc­tion auto­ma­tique du conte­neur peut être réa­li­sée sur les ser­veurs de Docker à chaque push. Ce qui per­met une véri­fi­ca­tion sup­plé­men­taire du bon fonc­tion­ne­ment de votre conte­neur.

Le gros incon­vé­nient de Docker est qu'il fonc­tionne en root sur votre machine. Ce qui signi­fie qu'il a tous les droits. Ce qui peut poten­tiel­le­ment être un pro­blème de sécu­ri­té, et fait que cet outil n'est sou­vent pas dis­po­nible sur les clus­ters de cal­culs.

Avant d'utiliser un conte­neur, soyez sûr de sa pro­ve­nance ;-).

Quelles sont les initiatives en Bioinformatique ?

Du coup, main­te­nant vous vous dites, eh mais ça m'intéresse ça jus­te­ment, j'aimerais bien avoir un conte­neur avec BWA pour ali­gner mes séquences, et il m'en fau­drait aus­si un avec GATK pour conti­nuer mes ana­lyses.

Bien évi­dem­ment ça marche avec n'importe quoi d'autre. Mais si vous n'avez pas envie de vous prendre la tête à créer vos propres contai­ners, pas de sou­cis, Ikea est là.

Euh non, c'est quand même plus simple à mon­ter ;-). Comme expli­qué plus haut, vous pou­vez cher­cher sur Docker-Hub. Mais il n'y a pas que ça, Bio­Con­tai­ners et Bio­Sha­dock sont des ini­tia­tives qui four­nissent des conte­neurs d'outils bio­in­for­ma­tiques.

Et Singularity dans tout ça ?

Gros­so modo c'est pareil que Docker sans le sou­cis d'utilisateur root. Et c'est aus­si un poil plus com­pli­qué pour rapi­de­ment exé­cu­ter un conte­neur. Mais le pro­jet est récent, et facile d'utilisation. Leur pla­te­forme Sin­gu­la­ri­ty-Hub a qua­si­ment les mêmes fonc­tion­na­li­tés que Docker-Hub. Bref, c'est à sur­veiller.

On peut avoir un exemple ?

J'ai un fichier

.bam

sur mon ordi, il me paraît plu­tôt petit, et je me demande donc ce qu'il s'est pas­sé avec ce fichier. Je vou­drais notam­ment véri­fier quel génome de réfé­rence a été uti­li­sé lors du trai­te­ment de ce fichier. Un simple

samtools view -H monFichier.bam

aurait nor­ma­le­ment suf­fit à me don­ner le hea­der qui répon­dra à cette ques­tion. Mais j'ai réins­tal­lé mon ordi il y a plu­sieurs mois, et n'ai pas vrai­ment eu besoin de

samtools

depuis, et là c'est le drame… Bon, je pour­rais l'installer, c'est facile, mais je pour­rais pas faire d'exemple pour cet article… Et puis, si je ne l'ai pas déjà ré-ins­tal­lé, c'est vrai­sem­bla­ble­ment que j'en ai pas super besoin, on va donc uti­li­ser Docker.
Le début de la com­mande change un petit peu, et je vais l'expliquer en détail

docker run # Tout simplement pour lancer Docker
-v pwd:/tmp -w /tmp # Pour spécifier un volume à monter depuis le conteneur, et à utiliser.
biocontainers/samtools:1.2 # Pour spécifier le dépot, le conteneur et la version à utiliser.

Ce qui nous donne tout simplement:

> docker run -v pwd:/tmp -w /tmp biocontainers/samtools:1.2 samtools view -H 1234N_0.md.bam
Unable to find image 'biocontainers/samtools:1.2' locally
# Le conteneur n'étant pas déjà sur mon ordinateur, Docker le télécharge
# La version 1.2 du conteneur ayant été demandé, c'est celle là qui est téléchargée
1.2: Pulling from biocontainers/samtools
# Les différentes couches sont téléchargées.
c62795f78da9: Pull complete
d4fceeeb758e: Pull complete
5c9125a401ae: Pull complete
0062f774e994: Pull complete
6b33fd031fac: Pull complete
af6fedb9c521: Pull complete
fd673780b023: Pull complete
6126667f3f67: Pull complete
bb944ca99002: Pull complete
c40c4efd2448: Pull complete
3ddbf72562fd: Pull complete
8e7e9c932556: Pull complete
46c6dd154e56: Pull complete
d1bcaa2afb2e: Pull complete
17063abba50e: Pull complete
a90ebfcb0e1f: Pull complete
bda5ce9124fe: Pull complete
Digest: sha256:e303bc7271392d0553b3f7782fd40bd009a7c85351dc64c58ba597857b26bd76
Status: Downloaded newer image for biocontainers/samtools:1.2
# Le téchargement ayant réussi, la commande est alors exécutée
# Voici donc notre fameux header
@HD VN:1.5 SO:coordinate
# On a donc quatre chromosomes
@SQ SN:1 LN:200000
@SQ SN:2 LN:200000
@SQ SN:3 LN:200000
@SQ SN:X LN:200000
@RG ID:1234N_7 PU:1234N_7 SM:1234N LB:1234N PL:illumina
@RG ID:1234N_8 PU:1234N_8 SM:1234N LB:1234N PL:illumina
@RG ID:1234N_4 PU:1234N_4 SM:1234N LB:1234N PL:illumina
@RG ID:1234N_1 PU:1234N_1 SM:1234N LB:1234N PL:illumina
@RG ID:1234N_2 PU:1234N_2 SM:1234N LB:1234N PL:illumina
@PG ID:bwa PN:bwa VN:0.7.8-r455 CL:bwa mem -R @RG\tID:1234N_7\tPU:1234N_7\tSM:1234N\tLB:1234N\tPL:illumina -t 2 -M human_g1k_v37_decoy.small.fasta tiny_normal_L007_R1.fastq.gz tiny_normal_L007_R2.fastq.gz
@PG ID:bwa-38484E5B PN:bwa VN:0.7.8-r455 CL:bwa mem -R @RG\tID:1234N_8\tPU:1234N_8\tSM:1234N\tLB:1234N\tPL:illumina -t 2 -M human_g1k_v37_decoy.small.fasta tiny_normal_L008_R1.fastq.gz tiny_normal_L008_R2.fastq.gz
@PG ID:bwa-DA88A9 PN:bwa VN:0.7.8-r455 CL:bwa mem -R @RG\tID:1234N_4\tPU:1234N_4\tSM:1234N\tLB:1234N\tPL:illumina -t 2 -M human_g1k_v37_decoy.small.fasta tiny_normal_L004_R1.fastq.gz tiny_normal_L004_R2.fastq.gz
@PG ID:bwa-5111873F PN:bwa VN:0.7.8-r455 CL:bwa mem -R @RG\tID:1234N_1\tPU:1234N_1\tSM:1234N\tLB:1234N\tPL:illumina -t 2 -M human_g1k_v37_decoy.small.fasta tiny_normal_L001_R1.fastq.gz tiny_normal_L001_R2.fastq.gz
@PG ID:bwa-7F33CF22 PN:bwa VN:0.7.8-r455 CL:bwa mem -R @RG\tID:1234N_2\tPU:1234N_2\tSM:1234N\tLB:1234N\tPL:illumina -t 2 -M human_g1k_v37_decoy.small.fasta tiny_normal_L002_R1.fastq.gz tiny_normal_L002_R2.fastq.gz
@PG ID:MarkDuplicates VN:2.0.1(fe51f432e4b918385037e6d15e958f0298203e28_1449251266) CL:picard.sam.markduplicates.MarkDuplicates INPUT=[1234N.bam] OUTPUT=1234N_0.md.bam METRICS_FILE=1234N.bam.metrics ASSUME_SORTED=true TMP_DIR=[.] VALIDATION_STRINGENCY=LENIENT CREATE_INDEX=true MAX_SEQUENCES_FOR_DISK_READ_ENDS_MAP=50000 MAX_FILE_HANDLES_FOR_READ_ENDS_MAP=8000 SORTING_COLLECTION_SIZE_RATIO=0.25 REMOVE_DUPLICATES=false DUPLICATE_SCORING_STRATEGY=SUM_OF_BASE_QUALITIES PROGRAM_RECORD_ID=MarkDuplicates PROGRAM_GROUP_NAME=MarkDuplicates READ_NAME_REGEX=[a-zA-Z0-9]+:[0-9]:([0-9]+):([0-9]+):([0-9]+).* OPTICAL_DUPLICATE_PIXEL_DISTANCE=100 VERBOSITY=INFO QUIET=false COMPRESSION_LEVEL=5 MAX_RECORDS_IN_RAM=500000 CREATE_MD5_FILE=false GA4GH_CLIENT_SECRETS=client_secrets.json PN:MarkDuplicates
# Le fichier fasta source de la référence est human_g1k_v37_decoy.small.fasta
# C'est donc une version light du génome humain faite pour des tests rapides.

# Si nous essayons une autre version de samtools.
> docker run -v pwd:/tmp -w /tmp biocontainers/samtools:1.3.1 samtools view -H 1234N_0.md.bam
# C'est la version 1.3.1 qui a été demandée ici
Unable to find image 'biocontainers/samtools:1.3.1' locally
1.3.1: Pulling from biocontainers/samtools
c62795f78da9: Already exists
d4fceeeb758e: Already exists
5c9125a401ae: Already exists
0062f774e994: Already exists
6b33fd031fac: Already exists
af6fedb9c521: Already exists
fd673780b023: Already exists
6126667f3f67: Already exists
bb944ca99002: Already exists
c40c4efd2448: Already exists
3ddbf72562fd: Already exists
8e7e9c932556: Already exists
46c6dd154e56: Already exists
d1bcaa2afb2e: Already exists
17063abba50e: Already exists
a90ebfcb0e1f: Already exists
d5d1e4532146: Pull complete
# Seule la dernière couche étant différente, c'est la seule qui est à nouveau téléchargée
Digest: sha256:8ba8a7dedbeef7ba8f9f2b99305cdba48590b4c9a2edf354cbd9d591dde62323
Status: Downloaded newer image for biocontainers/samtools:1.3.1
# Le résultat de la commande étant la même, je ne le remet pas.

Et voilà, en deux relativement simples commandes, on a pu utiliser deux versions d'un même programme en moins de 5 min.

En regardant plus en détail le fichier de configuration du conteneur Docker utilisé (cf BioContainers/samtools/1.3.1/Dockerfile):

# Base Image
FROM biocontainers/biocontainers:latest

# Metadata
LABEL base.image="biocontainers:latest"
LABEL version="2"
LABEL software="Samtools"
LABEL software.version="1.3.1"
LABEL description="Tools for manipulating next-generation sequencing data"
LABEL website="https://github.com/samtools/samtools"
LABEL documentation="https://github.com/samtools/samtools"
LABEL license="https://github.com/samtools/samtools"
LABEL tags="Genomics"

# Maintainer
MAINTAINER Saulo Alves Aflitos <sauloal@gmail.com>

RUN conda install samtools=1.3.1

WORKDIR /data/

CMD ["samtools"]

On peut voir que ce conteneur est basé sur un autre conteneur et que

samtools

est ici installé en utilisant

conda

. En regardant cet autre conteneur source:

# Base image
FROM ubuntu:16.04

# Metadata
LABEl base.image="ubuntu:16.04"
LABEL version="4"
LABEL software="Biocontainers base Image"
LABEL software.version="08252016"
LABEL description="Base image for BioDocker"
LABEL website="http://biocontainers.pro"
LABEL documentation="https://github.com/BioContainers/specs/wiki"
LABEL license="https://github.com/BioContainers/containers/blob/master/LICENSE"
LABEL tags="Genomics,Proteomics,Transcriptomics,General,Metabolomics"

# Maintainer
MAINTAINER Felipe da Veiga Leprevost <felipe@leprevost.com.br>

ENV DEBIAN_FRONTEND noninteractive

RUN mv /etc/apt/sources.list /etc/apt/sources.list.bkp && \
bash -c 'echo -e "deb mirror://mirrors.ubuntu.com/mirrors.txt xenial main restricted universe multiverse\n\
deb mirror://mirrors.ubuntu.com/mirrors.txt xenial-updates main restricted universe multiverse\n\
deb mirror://mirrors.ubuntu.com/mirrors.txt xenial-backports main restricted universe multiverse\n\
deb mirror://mirrors.ubuntu.com/mirrors.txt xenial-security main restricted universe multiverse\n\n" > /etc/apt/sources.list' && \
cat /etc/apt/sources.list.bkp >> /etc/apt/sources.list && \
cat /etc/apt/sources.list

RUN apt-get clean all && \
apt-get update && \
apt-get upgrade -y && \
apt-get install -y \
autotools-dev \
automake \
cmake \
curl \
grep \
sed \
dpkg \
fuse \
git \
wget \
zip \
openjdk-8-jre \
build-essential \
pkg-config \
python \
python-dev \
python-pip \
bzip2 \
ca-certificates \
libglib2.0-0 \
libxext6 \
libsm6 \
libxrender1 \
git \
mercurial \
subversion \
zlib1g-dev && \
apt-get clean && \
apt-get purge && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

RUN echo 'export PATH=/opt/conda/bin:$PATH' > /etc/profile.d/conda.sh && \
wget --quiet https://repo.continuum.io/miniconda/Miniconda2-4.0.5-Linux-x86_64.sh -O ~/miniconda.sh && \
/bin/bash ~/miniconda.sh -b -p /opt/conda && \
rm ~/miniconda.sh

RUN TINI_VERSION=curl https://github.com/krallin/tini/releases/latest | grep -o "/v.*\"" | sed 's:^..\(.*\).$:\1:' && \
curl -L "https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini_${TINI_VERSION}.deb" > tini.deb && \
dpkg -i tini.deb && \
rm tini.deb && \
apt-get clean

RUN mkdir /data /config

# Add user biodocker with password biodocker
RUN groupadd fuse && \
useradd --create-home --shell /bin/bash --user-group --uid 1000 --groups sudo,fuse biodocker && \
echo echo "biodocker\nbiodocker\n" | passwd biodocker && \
chown biodocker:biodocker /data && \
chown biodocker:biodocker /config

# give write permissions to conda folder
RUN chmod 777 -R /opt/conda/

# Change user
USER biodocker

ENV PATH=$PATH:/opt/conda/bin
ENV PATH=$PATH:/home/biodocker/bin
ENV HOME=/home/biodocker

RUN mkdir /home/biodocker/bin

RUN conda config --add channels r
RUN conda config --add channels bioconda

RUN conda upgrade conda

VOLUME ["/data", "/config"]

# Overwrite this with 'CMD []' in a dependent Dockerfile
CMD ["/bin/bash"]

WORKDIR /data

On se rend compte qu'il contient la plupart des outils pour compiler et installer des outils. J'ai donc envie d'utiliser une autre image plus légere que je vais réaliser moi même:

FROM debian:8.6

LABEL author="Maxime Garcia" \
description="SAMTools 1.4 image for bioinfo-fr" \
maintainer="mon.email@gmail.com"

# Install libraries
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
ca-certificates \
curl \
libbz2-dev \
liblzma-dev \
libncurses5-dev \
libncursesw5-dev \
zlib1g-dev \
&& rm -rf /var/lib/apt/lists/*

# Setup ENV variables
ENV SAMTOOLS_BIN="samtools-1.4.tar.bz2" \
SAMTOOLS_VERSION="1.4"

# Install SAMTools
RUN curl -fsSL https://github.com/samtools/samtools/releases/download/$SAMTOOLS_VERSION/$SAMTOOLS_BIN -o /opt/$SAMTOOLS_BIN \
&& tar xvjf /opt/$SAMTOOLS_BIN -C /opt/ \
&& cd /opt/samtools-$SAMTOOLS_VERSION \
&& make \
&& make install \
&& rm /opt/$SAMTOOLS_BIN

J'ai choisi une approche différente, me base sur

debian:8.6

et n'installe que le strict nécessaire pour compiler

samtools

avec

make

. Mon conteneur est donc plus léger que celui de biocontainers. Je n'ai construit ici qu'un seul simple conteneur, et n'utilise pas un conteneur servant de base à plus de 50 conteneurs différents. L'approche de biocontainers est explicable par le nombre de conteneurs à gérer, et j'aurai probablement la même approche pour un projet de grande ampleur.

Quelque soit le conteneur que vous utilisez, l'important est que vous puissiez être sur de toujours utiliser le même, et de le faire utiliser à vos collaborateurs ou vos utilisateurs. C'est l'essentiel de la reproductibilité.

Conflits d'intérêts

Aucun.

Remerciements

Je remercie Yoann M. pour sa motivation concernant cet article, ainsi que Norore, M4rsu et Lroy bien-aimés relecteurs pour leurs avis et discussions.



Pour continuer la lecture :


Commentaires

5 réponses à “Virtualisez pour plus de reproductibilité”

  1. Avatar de Alice

    Mer­ci pour l'article !! Vrai­ment très inté­res­sant. J'attendais des infos sur Docker car on m'en parle tout le temps et que vu que la pla­te­forme bioin­fo de l'AP-HP a déci­dé de baser leurs pipe­line sur Docker, je savais que c'était à suivre !
    Dès que j'ai du temps je me forme là des­sus…

    1. Content que l'article t'ait plu. Pour ma part j'utilise essen­tiel­le­ment Docker avec Next­flow. Vous uti­li­sez quoi à l'APHP pour vos pipe­lines ?

  2. Avatar de Alice

    Je suis pas à l'APHP, j'ai assis­té à une de leur pré­sen­ta­tion quand la pla­te­forme venait d'être créer il y a quelques mois. Et comme c'est une domaine qui m'est encore plu­tôt incon­nu je vais pas m'avancer pour eux.

  3. Mer­ci pour cet article super inté­res­sant ! Je ne connais­sais pas du tout les contai­ners, et ça semble vrai­ment révo­lu­tion­naire sur pas mal d'aspects : repro­du­ci­bi­li­té, par­tage, et liber­té d'utiliser n'importe quel pro­gramme sur un ser­veur (pour Sin­gu­la­ri­ty du moins). Je m'y mets de ce pas !

    1. Content que ça te plaise ;-).
      Si tu veux un peu plus de lec­ture tu peux aus­si jeter un coup d'œil à l'article que j'ai rédi­gé pour le blog de Next­flow sur com­ment j'ai mis en place Sin­gu­la­ri­ty sur notre pipe­line : https://​www​.next​flow​.io/​b​l​o​g​/​2​0​1​7​/​c​a​w​-​a​n​d​-​s​i​n​g​u​l​a​r​i​t​y​.​h​tml
      Et si t'as d'autres ques­tions, n'hésite pas 😉

Laisser un commentaire