Docker Compose vs Dockerfile - quel est le meilleur?

385

J'ai lu et appris sur Docker et j'essaie de choisir correctement la configuration de Django à utiliser. Jusqu'à présent, il y a soit:

Docker Compose ou Dockerfile

Je comprends que ce Dockerfilessoit utilisé dans Docker Compose, mais je ne sais pas si c'est une bonne pratique de tout mettre dans un grand Dockerfile avec plusieurs FROMcommandes pour les différentes images?

Je souhaite utiliser plusieurs images différentes, notamment:

uwsgi
nginx
postgres
redis
rabbitmq
celery with cron

Veuillez indiquer les meilleures pratiques de configuration de ce type d'environnement à l'aide de Docker .

Si cela aide, je suis sur un Mac, donc j'utilise boot2docker .

Quelques problèmes que j'ai rencontrés:

  1. Docker Compose n'est pas compatible avec Python3
  2. Je souhaite conteneuriser mon projet, donc si un grand Dockerfile n'est pas idéal, je pense que je devrai le décomposer à l'aide de Docker Compose
  3. Je suis d'accord pour rendre le projet Py2 & Py3 compatible, donc je me tourne vers django-compose
Aaron Lelevier
la source
5
La question serait mieux formulée comme suit: «Dois-je exécuter mon application comme un ou plusieurs conteneurs?» Il semble que cela dépende et que les questions de mise à l'échelle et de séparation des préoccupations (un conteneur par service) soient prises en compte. Ceux-ci pourraient aider: stackoverflow.com/questions/30534939/… et quora.com/…
Fabien Snauwaert
Les documents officiels de démarrage de Docker .
jchook

Réponses:

239

La réponse n'est ni l'un ni l'autre.

Docker Compose (ici appelé composer) utilisera le Dockerfile si vous ajoutez la commande build à celle de votre projet docker-compose.yml.

Votre flux de travail Docker devrait être de créer une Dockerfileimage adaptée à chaque image que vous souhaitez créer, puis d'utiliser la composition pour assembler les images à l'aide de la buildcommande.

Vous pouvez spécifier le chemin d'accès à vos Dockerfiles individuels en utilisant build /path/to/dockerfiles/blah/path/to/dockerfiles/blahse trouve la Dockerfilevie de blah .

booyaa
la source
10
utilisez-vous docker-composeen production ou uniquement en dev? Merci de votre aide.
Aaron Lelevier
18
@booyaa Pourriez-vous nous en dire plus?
Martin Thoma
2
Merci d'avoir répondu! Dockerfile spécifier config pour l' image et docker-compose.yml assembler les images ensemble .. Une chose que je tiens à souligner est que, si docker-compose.ymlutiliser uniquement l' image publique (tirant image à partir du hub Internet / docker), alors on ne ont pas besoin Dockerfile pour exécuter la commande docker-compose up.
Oldyoung
550

Dockerfile

entrez la description de l'image ici

Un Dockerfile est un simple fichier texte qui contient les commandes qu'un utilisateur peut appeler pour assembler une image.

Exemple, Dockerfile

FROM ubuntu:latest
MAINTAINER john doe 

RUN apt-get update
RUN apt-get install -y python python-pip wget
RUN pip install Flask

ADD hello.py /home/hello.py

WORKDIR /home

Docker Compose

entrez la description de l'image ici

Docker Compose

  • est un outil pour définir et exécuter des applications Docker multi-conteneurs.

  • définir les services qui composent votre application docker-compose.ymlafin qu'ils puissent être exécutés ensemble dans un environnement isolé.

  • obtenir une application en cours d'exécution en une seule commande en exécutant simplement docker-compose up

Exemple, docker-compose.yml

version: "3"
services:
  web:
    build: .
    ports:
    - '5000:5000'
    volumes:
    - .:/code
    - logvolume01:/var/log
    links:
    - redis
  redis:
    image: redis
    volumes:
      logvolume01: {}
cyber8200
la source
43
@sg la réponse est que la question est mal formée en raison du manque de compréhension de Docker vs Docker Compose. Expliquer succinctement comment les deux interagissent est probablement la meilleure réponse à laquelle je peux penser.
mpowered
53
Je n'ai aucune idée pourquoi cette ventilation exacte ne se trouve pas sur la page d'accueil de Docker. Merci.
codykochmann
4
Je vois ce type de documents manquants dans les outils / solutions / frameworks les plus récemment publiés sur le Web. Je suppose qu'il est difficile de voir pourquoi quelqu'un en a besoin au cas où vous connaissez / inventez déjà la solution vous-même.
Peter Branforn
36
Ce qui manque à cette réponse, c'est plus d'informations sur la composition. Le script de composition appelle-t-il le dockerfile? Comment sait-il quoi composer? L'exemple montre image: redismais est-ce de Dockerhub? répertoire local? etc ... cela rend confus pour un nouveau comme moi de comprendre ce qui se passe vraiment
Joe Phillips
5
Cette réponse insiste sur l'objectif multi-conteneurs de la composition de docker, mais il existe probablement de nombreux autres scénarios pour lesquels vous souhaitez utiliser la composition de docker même avec un seul conteneur, par exemple en spécifiant le port sur lequel vous souhaitez que votre conteneur s'exécute (impossible dans dockerfile afaik).
Pansoul
99

Le fichier Compose décrit le conteneur dans son état en cours d'exécution , laissant les détails sur la façon de créer le conteneur à Dockerfiles . http://deninet.com/blog/1587/docker-scratch-part-4-compose-and-volumes

Lorsque vous définissez votre application avec Compose en développement, vous pouvez utiliser cette définition pour exécuter votre application dans différents environnements tels que CI, le transfert et la production . https://docs.docker.com/compose/production/

Il semble également que Compose soit considéré comme sûr pour la production à partir du 1.11 , car https://docs.docker.com/v1.11/compose/production/ n'a plus d'avertissement de ne pas l'utiliser en production comme https: // docs .docker.com / v1.10 / compose / production / does.

Peeter Kokk
la source
1
Merci d'avoir soulevé le problème. Pouvez-vous s'il vous plaît ajouter un peu plus de ce qui a été fixé pour la sécurité de la production à 1.11?
MA Hossain Tonu
93

docker-compose existe pour vous éviter d'avoir à écrire une tonne de commandes avec docker-cli.

docker-compose permet également de démarrer facilement plusieurs conteneurs en même temps et de les connecter automatiquement avec une certaine forme de mise en réseau.

Le but de docker-compose est de fonctionner comme docker cli mais d'émettre plusieurs commandes beaucoup plus rapidement.

Pour utiliser docker-compose, vous devez encoder les commandes que vous exécutiez auparavant dans un docker-compose.ymlfichier.

Vous n'allez pas simplement les copier coller dans le fichier yaml, il y a une syntaxe spéciale.

Une fois créé, vous devez le nourrir à la cli docker-compose et ce sera à la cli d'analyser le fichier et de créer tous les différents conteneurs avec la configuration correcte que nous spécifions.

Vous aurez donc des conteneurs séparés, disons par exemple, un est redis-serveret le second est node-appet vous voulez que créé à l'aide de Dockerfiledans votre répertoire actuel.

De plus, après avoir créé ce conteneur, vous devez mapper un port du conteneur à la machine locale pour accéder à tout ce qui s'y trouve.

Donc, pour votre docker-compose.ymlfichier, vous voudriez commencer la première ligne comme ceci:

version: '3'

Cela indique à Docker la version que docker-composevous souhaitez utiliser. Après cela, vous devez ajouter:

version: '3'
services: 
  redis-server: 
    image: 'redis'
  node-app:
    build: .

Veuillez noter l'indentation, très importante. Aussi, remarquez pour un service que je saisis une image, mais pour un autre service que je disdocker-compose de regarder à l'intérieur du répertoire courant pour construire l'image qui sera utilisée pour le deuxième conteneur.

Ensuite, vous souhaitez spécifier tous les différents ports que vous souhaitez ouvrir sur ce conteneur.

version: '3'
services: 
  redis-server: 
    image: 'redis'
  node-app:
    build: .
    ports:
      -

Veuillez noter le tiret, un tiret dans un fichier yaml est la façon dont nous spécifions un tableau. Dans cet exemple, je mappe 8081sur ma machine locale 8081sur le conteneur comme ceci:

version: '3'
services: 
  redis-server: 
    image: 'redis'
  node-app:
    build: .
    ports:
      - "8081:8081"

Ainsi, le premier port est votre machine locale, et l'autre est le port sur le conteneur, vous pouvez également faire la distinction entre les deux pour éviter toute confusion comme ceci:

version: '3'
services:
  redis-server:
    image: 'redis'
  node-app:
    build: .
    ports:
      - "4001:8081"

En développant votre docker-compose.yml fichier comme celui-ci, il créera ces conteneurs sur essentiellement le même réseau et ils auront un accès gratuit pour communiquer entre eux comme bon leur semble et échanger autant d'informations qu'ils le souhaitent.

Lorsque les deux conteneurs sont créés à l'aide de docker-compose nous n'avons besoin d'aucune déclaration de port.

Maintenant, dans mon exemple, nous devons faire une configuration de code dans l'application Nodejs qui ressemble à ceci:

const express = require('express');
const redis = require('redis');

const app = express();
const client = redis.createClient({
  host: 'redis-server'
});

J'utilise cet exemple ci-dessus pour vous faire savoir qu'il peut y avoir une configuration spécifique que vous auriez à faire en plus du docker-compose.yml fichier qui peut être spécifique à votre projet.

Maintenant, si vous vous retrouvez à travailler avec une application Nodejs et redis, vous voulez vous assurer que vous êtes au courant du port par défaut que Nodejs utilise, donc j'ajouterai ceci:

const express = require('express');
const redis = require('redis');

const app = express();
const client = redis.createClient({
  host: 'redis-server',
  port: 6379
});

Docker va donc voir que l'application Node recherche redis-serveret redirige cette connexion vers ce conteneur en cours d'exécution.

Tout le temps, le Dockerfileseul contient ceci:

FROM node:alpine

WORKDIR '/app'

COPY /package.json ./
RUN npm install
COPY . .

CMD ["npm", "start"]

Donc, alors qu'avant, vous devriez exécuter docker run myimagepour créer une instance de tous les conteneurs ou services à l'intérieur du fichier, vous pouvez exécuter à la place, docker-compose upet vous n'avez pas besoin de spécifier une image car Docker recherchera dans le répertoire de travail actuel et recherchera un docker-compose.ymldéposer à l'intérieur de là.

Avant docker-compose.yml, nous devions traiter deux commandes distinctes de docker build .et docker run myimage, mais dans le docker-composemonde si vous voulez reconstruire vos images, vous écrivez docker-compose up --build. Cela indique à Docker de redémarrer les conteneurs mais de le reconstruire pour obtenir les dernières modifications.

Il docker-composeest donc plus facile de travailler avec plusieurs conteneurs. La prochaine fois que vous devez démarrer ce groupe de conteneurs en arrière-plan, vous pouvez le faire docker-compose up -det les arrêter, vous pouvez le faire docker-compose down.

Daniel
la source
14
@Chris C'est presque comme s'il y avait 3 ans de connaissances entre cela et la réponse acceptée.
Naruto Sempai
Je me demande s'il y a une bonne raison pour moi d'utiliser docker-compose upun seul service dans ma situation? Un autre mot, comparer avec docker run xxx, tout avantage si j'utilise docker-compose up?
ligne du
@atline voir la réponse de Pansoul à stackoverflow.com/a/45549372/3366962 sur les avantages de l'utilisation docker-composepour les conteneurs simples
go2null
1
@PaulRazvanBerg votre partie "Ou" est correcte (et 6379est le port par défaut de Redis).
KrishPrabakar
1
Les exemples de docker-compose.yml m'ont aidé à répondre à certaines des questions que j'avais sur docker-compose. La réponse acceptée n'est pas utile, en particulier pour les personnes débutantes dans Docker.
maulik13
43

Dans mon flux de travail, j'ajoute un Dockerfile pour chaque partie de mon système et je le configure pour que chaque partie puisse s'exécuter individuellement. Ensuite, j'ajoute un docker-compose.yml pour les rassembler et les lier.

Le plus grand avantage (à mon avis): lors de la liaison des conteneurs , vous pouvez définir un nom et envoyer une requête ping à vos conteneurs avec ce nom. Par conséquent, votre base de données peut être accessible avec le nom dbet non plus par son IP.

n2o
la source
Pourriez-vous nous en dire plus sur l'accès à la base de données par son nom?
Vedran Maricevic.
Sur quelle partie? Dans docker-compose, c'est trivial, car c'est la manière normale lors de la définition de vos services de lui donner un nom et de le rendre accessible sans avoir besoin de le configurer. Dans notre CI, je crée un réseau, crée le conteneur dans ce réseau et leur donne un nom. Ensuite, vous les avez également accessibles par leur nom à l'intérieur des conteneurs (pas depuis l'hôte)
n2o
En compositeur, je veux dire. Donc, je lie les images dans le compositeur, et dans ma configuration d'application au lieu de l'IP, je targe le MySQL par le nom que je lui ai donné dans le fichier du compositeur?
Vedran Maricevic.
C'est correct. Vous n'avez même pas besoin de spécifier un lien. Ils sont liés par défaut si le réseau n'est pas spécifié différemment. Dans cet exemple, le service "web" peut envoyer une requête ping à l'hôte "redis" par son nom "redis"
n2o
37

"mieux" est relatif. Tout dépend de vos besoins. Docker compose sert à orchestrer plusieurs conteneurs. Si ces images existent déjà dans le registre Docker, il est préférable de les répertorier dans le fichier de composition. Si ces images ou d'autres images doivent être créées à partir de fichiers sur votre ordinateur, vous pouvez décrire les processus de création de ces images dans un Dockerfile.

Je comprends que les Dockerfiles sont utilisés dans Docker Compose, mais je ne sais pas si c'est une bonne pratique de tout mettre dans un grand Dockerfile avec plusieurs commandes FROM pour les différentes images?

L'utilisation de plusieurs FROM dans un seul dockerfile n'est pas une très bonne idée car il est proposé de supprimer la fonctionnalité. 13026

Si, par exemple, vous souhaitez ancrer une application qui utilise une base de données et avoir les fichiers d'application sur votre ordinateur, vous pouvez utiliser un fichier de composition avec un dockerfile comme suit

docker-compose.yml

mysql:
  image: mysql:5.7
  volumes:
    - ./db-data:/var/lib/mysql
  environment:
    - "MYSQL_ROOT_PASSWORD=secret"
    - "MYSQL_DATABASE=homestead"
    - "MYSQL_USER=homestead"
  ports:
    - "3307:3306"
app:
  build:
    context: ./path/to/Dockerfile
    dockerfile: Dockerfile
  volumes:
    - ./:/app
  working_dir: /app

Dockerfile

FROM php:7.1-fpm 
RUN apt-get update && apt-get install -y libmcrypt-dev \
  mysql-client libmagickwand-dev --no-install-recommends \
  && pecl install imagick \
  && docker-php-ext-enable imagick \
  && docker-php-ext-install pdo_mysql \
  && curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
Akongnwi Devert
la source
30

Dockerfile et Docker Compose sont deux concepts différents dans Dockerland. Lorsque nous parlons de Docker, les premières choses qui me viennent à l'esprit sont l'orchestration, la virtualisation au niveau du système d'exploitation, les images, les conteneurs, etc. Je vais essayer de les expliquer comme suit:

Image: une image est un fichier immuable et partageable qui est stocké dans un registre approuvé par Docker. Une image Docker est constituée d'une série de couches en lecture seule. Chaque couche représente une instruction donnée dans le Dockerfile de l'image. Une image contient tous les fichiers binaires nécessaires à l'exécution.

entrez la description de l'image ici

Conteneur: une instance d'une image est appelée conteneur . Un conteneur est juste un binaire d'image exécutable qui doit être exécuté par le système d'exploitation hôte. Une image en cours d'exécution est un conteneur.

entrez la description de l'image ici

Dockerfile: Un Dockerfile est un document texte qui contient toutes les commandes / instructions de construction, un utilisateur peut appeler sur la ligne de commande pour assembler une image. Cela sera enregistré en tant que Dockerfile. (Notez le «f» en minuscule.)

entrez la description de l'image ici

Docker-Compose: Compose est un outil pour définir et exécuter des applications Docker multi-conteneurs. Avec Compose, vous utilisez un fichier YAML pour configurer les services de votre application (conteneurs). Ensuite, avec une seule commande, vous créez et démarrez tous les services à partir de votre configuration. Le fichier de composition serait enregistré sous docker-compose.yml.

Waqas Ahmed
la source
14

Imaginez que vous êtes le directeur d'une société de logiciels et que vous venez d'acheter un tout nouveau serveur. Juste le matériel.

Considérez Dockerfilecomme un ensemble d'instructions que vous diriez à votre administrateur système ce qu'il faut installer sur ce nouveau serveur. Par exemple:

  • Nous avons besoin d'un Linux Debian
  • ajouter un serveur web apache
  • nous avons aussi besoin de postgresql
  • installer le commandant de minuit
  • une fois terminé, copiez tous les fichiers * .php, * .jpg, etc. de notre projet dans la racine Web du serveur web ( /var/www)

En revanche, pensez docker-compose.ymlà un ensemble d'instructions que vous diriez à votre administrateur système comment le serveur peut interagir avec le reste du monde. Par exemple,

  • il a accès à un dossier partagé depuis un autre ordinateur,
  • son port 80 est le même que le port 8000 de l'ordinateur hôte,
  • etc.

(Ce n'est pas une explication précise mais assez bonne pour commencer.)

Csongor Halmai
la source
4

Les Dockerfiles sont pour construire une image par exemple à partir d'un Ubuntu sans os, vous pouvez ajouter mysqlappelé mySQLsur une image et mywordpresssur une deuxième image appelée mywordpress.

Composer des fichiers YAML consiste à prendre ces images et à les exécuter de manière cohérente. par exemple si vous avez dans votre docker-compose.ymldossier un appel de service db:

services:
   db:
     image: mySQL  --- image that you built.

et un service appelé worpress tel que:

wordpress: 
    image: mywordpress

puis à l'intérieur du conteneur mywordpress, vous pouvez utiliser dbpour vous connecter à votre conteneur mySQL. Cette magie est possible car votre hôte docker crée un pont réseau (superposition réseau).

Hugo R
la source
0

Dans le monde des microservices (ayant une base de code partagée commune), chaque microservice aurait un Dockerfilealors qu'au niveau racine (généralement en dehors de tous les microservices et où réside votre POM parent), vous définiriez un docker-compose.ymlpour regrouper tous les microservices dans une application à part entière.

Dans votre cas, "Docker Compose" est préféré à "Dockerfile". Pensez «App» Pensez «Composer».

KrishPrabakar
la source
0

Dockerfile est un fichier qui contient des commandes de texte pour assembler une image.

Docker compose est utilisé pour exécuter un environnement multi-conteneurs.

Dans votre scénario spécifique, si vous avez plusieurs services pour chaque technologie que vous avez mentionnée (service 1 en utilisant reddis, service 2 en utilisant rabbit mq, etc.), vous pouvez avoir un Dockerfile pour chacun des services et un docker-compose.yml commun à exécuter tous les "Dockerfile" comme conteneurs.

Si vous les voulez tous dans un seul service, docker-compose sera une option viable.

Mudassir Shahzad
la source