Virtualisez pour plus de reproductibilité
Pour commencer
Vous avez entendu parler de reproductibilité. Vous voulez vous y mettre ? Vous vous dites que la virtualisation vous aiderait à utiliser toujours la même version d'un outil précis. En savoir plus sur Docker vous aiderait bien ? Cet article est donc pour vous. Je profite de l'occasion pour parler aussi de Singularity. Mais pour bien commencer, on va expliquer le concept des Machines Virtuelles.
Une Machine Virtuelle c'est quoi ?
Alors pour tous ceux qui se posent la question, un grille-pain en réalité virtuelle n'est pas une Machine Virtuelle. Une Machine Virtuelle c'est la simulation d'un système informatique qui reproduit son utilisation réelle. Une notion voisine est l'émulation, outil bien connu des retro-gamers, qui va simuler un matériel pour reproduire son utilisation.
Dans notre cas, c'est la virtualisation qui nous intéresse. Le grand intérêt étant de pouvoir faire abstraction de toutes les caractéristiques du système sur lequel on est et de simuler un autre système pour avoir un environnement transportable et donc reproductible d'une machine à une autre.
Java fonctionne sur ce principe de Machine Virtuelle (et oui, JVM c'est pour Java Virtual Machine). Virtual Box est un des outils les plus connus permettant de faire des Machines Virtuelles.
Les environnements virtuels
Alors oui, les Machines Virtuelles c'est bien joli, mais c'est un peu lourd. Du coup si au lieu de simuler le système dans son intégralité, on ne simulait que ce dont on avait besoin, c'est-à-dire les applications. Bon quelques librairies ça peut être pratique aussi, mais vous voyez l'idée.
Le grand intérêt d'utiliser des environnements virtuels c'est aussi de pouvoir compartimenter et isoler ces environnements dans des conteneurs. Et par exemple, de pouvoir installer plusieurs versions de Python et plusieurs outils utilisant plusieurs versions sans trop s'embêter. Les adeptes de Python et de virtualenv se reconnaîtront.
Docker c'est quoi ?
Docker c'est un outil qui s'appuie sur les fonctionnalités du système d'exploitation sous-jacent (le noyau Linux). Docker s'interface avec le noyau Linux et propose plusieurs instances de virtualisation isolées. Ces instances sont appelées conteneurs, et ils sont donc très légers (comparés aux Machines Virtuelles classiques). Une simple recherche sur votre moteur de recherche préféré vous amène facilement sur des tutoriaux si le workshop de l'IFB et le site de Docker ne vous suffisent pas. Pour la petite histoire, Docker a été créé par un franco-américain, et la dessinatrice Laurel y travaille actuellement et elle fait entre autres choses de jolis autocollants.
Les avantages et les inconvénients ?
Le grand avantage de Docker est sa simplicité de mise en place et d'utilisation. Les conteneurs donnent accès à des environnements isolés et contrôlés. Docker-Hub est le site de dépôt de Docker, conçu pour faciliter la recherche et le partage de conteneurs Docker.
Créer son propre conteneur Docker est aussi simple. Il suffit de le construire à partir d'un fichier de configuration Dockerfile qui contient toutes les commandes nécessaires à sa construction. Si votre Dockerfile est versionné sur GitHub, une construction automatique du conteneur peut être réalisée sur les serveurs de Docker à chaque push. Ce qui permet une vérification supplémentaire du bon fonctionnement de votre conteneur.
Le gros inconvénient de Docker est qu'il fonctionne en root sur votre machine. Ce qui signifie qu'il a tous les droits. Ce qui peut potentiellement être un problème de sécurité, et fait que cet outil n'est souvent pas disponible sur les clusters de calculs.
Avant d'utiliser un conteneur, soyez sûr de sa provenance ;-).
Quelles sont les initiatives en Bioinformatique ?
Du coup, maintenant vous vous dites, eh mais ça m'intéresse ça justement, j'aimerais bien avoir un conteneur avec BWA pour aligner mes séquences, et il m'en faudrait aussi un avec GATK pour continuer mes analyses.
Bien évidemment ç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 containers, pas de soucis, Ikea est là.
Euh non, c'est quand même plus simple à monter ;-). Comme expliqué plus haut, vous pouvez chercher sur Docker-Hub. Mais il n'y a pas que ça, BioContainers et BioShadock sont des initiatives qui fournissent des conteneurs d'outils bioinformatiques.
Et Singularity dans tout ça ?
Grosso modo c'est pareil que Docker sans le soucis d'utilisateur root. Et c'est aussi un poil plus compliqué pour rapidement exécuter un conteneur. Mais le projet est récent, et facile d'utilisation. Leur plateforme Singularity-Hub a quasiment les mêmes fonctionnalités que Docker-Hub. Bref, c'est à surveiller.
On peut avoir un exemple ?
J'ai un fichier
1 |
.bam |
sur mon ordi, il me paraît plutôt petit, et je me demande donc ce qu'il s'est passé avec ce fichier. Je voudrais notamment vérifier quel génome de référence a été utilisé lors du traitement de ce fichier. Un simple
1 |
samtools view -H monFichier.bam |
aurait normalement suffit à me donner le header qui répondra à cette question. Mais j'ai réinstallé mon ordi il y a plusieurs mois, et n'ai pas vraiment eu besoin de
1 |
samtools |
depuis, et là c'est le drame… Bon, je pourrais l'installer, c'est facile, mais je pourrais pas faire d'exemple pour cet article… Et puis, si je ne l'ai pas déjà ré-installé, c'est vraisemblablement que j'en ai pas super besoin, on va donc utiliser Docker.
Le début de la commande change un petit peu, et je vais l'expliquer en détail
1 2 |
docker run # Tout simplement pour lancer Docker<br> -v [crayon-67427073c5069001844164 ]pwd |
biocontainers/samtools:1.2 # Pour spécifier le dépot, le conteneur et la version à utiliser.[/crayon]
Ce qui nous donne tout simplement :
1 |
> docker run -v [crayon-67427073c506c484184442 ]pwd |
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
1 |
pwd |
# 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.[/crayon]
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):
1 |
# Base Image<br><br>FROM biocontainers/biocontainers :latest<br><br># Metadata<br>LABEL base.image="biocontainers:latest"<br>LABEL version="2"<br>LABEL software="Samtools"<br>LABEL software.version="1.3.1"<br>LABEL description="Tools for manipulating next-generation sequencing data"<br>LABEL website="https://github.com/samtools/samtools"<br>LABEL documentation="https://github.com/samtools/samtools"<br>LABEL license="https://github.com/samtools/samtools"<br>LABEL tags="Genomics"<br><br># Maintainer<br>MAINTAINER Saulo Alves Aflitos < ;sauloal@gmail.com><br><br>RUN conda install samtools=1.3.1<br><br>WORKDIR /data/<br><br>CMD ["samtools"] |
On peut voir que ce conteneur est basé sur un autre conteneur et que
1 |
samtools |
est ici installé en utilisant
1 |
conda |
. En regardant cet autre conteneur source :
1 |
# Base image<br><br>FROM ubuntu :16.04<br><br># Metadata<br>LABEl base.image="ubuntu:16.04"<br>LABEL version="4"<br>LABEL software="Biocontainers base Image"<br>LABEL software.version="08252016"<br>LABEL description="Base image for BioDocker"<br>LABEL website="http://biocontainers.pro"<br>LABEL documentation="https://github.com/BioContainers/specs/wiki"<br>LABEL license="https://github.com/BioContainers/containers/blob/master/LICENSE"<br>LABEL tags="Genomics,Proteomics,Transcriptomics,General,Metabolomics"<br><br># Maintainer<br>MAINTAINER Felipe da Veiga Leprevost < ;felipe@leprevost.com.br><br><br>ENV DEBIAN_FRONTEND noninteractive<br><br>RUN mv /etc/apt/sources.list /etc/apt/sources.list.bkp & ;& ; \<br>bash -c 'echo ‑e "deb mirror://mirrors.ubuntu.com/mirrors.txt xenial main restricted universe multiverse\n\<br>deb mirror://mirrors.ubuntu.com/mirrors.txt xenial-updates main restricted universe multiverse\n\<br>deb mirror://mirrors.ubuntu.com/mirrors.txt xenial-backports main restricted universe multiverse\n\<br>deb mirror://mirrors.ubuntu.com/mirrors.txt xenial-security main restricted universe multiverse\n\n" > /etc/apt/sources.list' & ;& ; \<br>cat /etc/apt/sources.list.bkp >> /etc/apt/sources.list & ;& ; \<br>cat /etc/apt/sources.list<br><br>RUN apt-get clean all & ;& ; \<br>apt-get update & ;& ; \<br>apt-get upgrade -y & ;& ; \<br>apt-get install -y \<br>autotools-dev \<br>automake \<br>cmake \<br>curl \<br>grep \<br>sed \<br>dpkg \<br>fuse \<br>git \<br>wget \<br>zip \<br>openjdk-8-jre \<br>build-essential \<br>pkg-config \<br>python \<br>python-dev \<br>python-pip \<br>bzip2 \<br>ca-certificates \<br>libglib2.0-0 \<br>libxext6 \<br>libsm6 \<br>libxrender1 \<br>git \<br>mercurial \<br>subversion \<br>zlib1g-dev & ;& ; \<br>apt-get clean & ;& ; \<br>apt-get purge & ;& ; \<br>rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*<br><br>RUN echo 'export PATH=/opt/conda/bin:$PATH' > /etc/profile.d/conda.sh & ;& ; \<br>wget –quiet https ://repo.continuum.io/miniconda/Miniconda2-4.0.5-Linux-x86_64.sh -O ~/miniconda.sh & ;& ; \<br>/bin/bash ~/miniconda.sh -b -p /opt/conda & ;& ; \<br>rm ~/miniconda.sh<br><br>RUN TINI_VERSION=curl https ://github.com/krallin/tini/releases/latest | grep -o "/v.*\"" | sed 's:^..\(.*\).$:\1:' & ;& ; \<br>curl -L "https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini_${TINI_VERSION}.deb" > tini.deb & ;& ; \<br>dpkg -i tini.deb & ;& ; \<br>rm tini.deb & ;& ; \<br>apt-get clean<br><br>RUN mkdir /data /config<br><br># Add user biodocker with password biodocker<br>RUN groupadd fuse & ;& ; \<br>useradd –create-home –shell /bin/bash –user-group –uid 1000 –groups sudo,fuse biodocker & ;& ; \<br>echo echo "biodocker\nbiodocker\n" | passwd biodocker & ;& ; \<br>chown biodocker :biodocker /data & ;& ; \<br>chown biodocker :biodocker /config<br><br># give write permissions to conda folder<br>RUN chmod 777 -R /opt/conda/<br><br># Change user<br>USER biodocker<br><br>ENV PATH=$PATH :/opt/conda/bin<br>ENV PATH=$PATH :/home/biodocker/bin<br>ENV HOME=/home/biodocker<br><br>RUN mkdir /home/biodocker/bin<br><br>RUN conda config –add channels r<br>RUN conda config –add channels bioconda<br><br>RUN conda upgrade conda<br><br>VOLUME ["/data", "/config"]<br><br># Overwrite this with 'CMD []' in a dependent Dockerfile<br>CMD ["/bin/bash"]<br><br>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 :
1 |
FROM debian :8.6<br><br>LABEL author="Maxime Garcia" \<br>description="SAMTools 1.4 image for bioinfo-fr" \<br>maintainer="mon.email@gmail.com"<br><br># Install libraries<br>RUN apt-get update & ;& ; apt-get install -y –no-install-recommends \<br>build-essential \<br>ca-certificates \<br>curl \<br>libbz2-dev \<br>liblzma-dev \<br>libncurses5-dev \<br>libncursesw5-dev \<br>zlib1g-dev \<br>& ;& ; rm -rf /var/lib/apt/lists/*<br><br># Setup ENV variables<br>ENV SAMTOOLS_BIN="samtools‑1.4.tar.bz2" \<br>SAMTOOLS_VERSION="1.4"<br><br># Install SAMTools<br>RUN curl -fsSL https ://github.com/samtools/samtools/releases/download/$SAMTOOLS_VERSION/$SAMTOOLS_BIN -o /opt/$SAMTOOLS_BIN \<br>& ;& ; tar xvjf /opt/$SAMTOOLS_BIN -C /opt/ \<br>& ;& ; cd /opt/samtools-$SAMTOOLS_VERSION \<br>& ;& ; make \<br>& ;& ; make install \<br>& ;& ; rm /opt/$SAMTOOLS_BIN |
J'ai choisi une approche différente, me base sur
1 |
debian :8.6 |
et n'installe que le strict nécessaire pour compiler
1 |
samtools |
avec
1 |
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.
Laisser un commentaire