Docker Compose vs. Dockerfile: ¿cuál es mejor?

385

He estado leyendo y aprendiendo sobre Docker , y estoy tratando de elegir correctamente la configuración de Django para usar. Hasta ahora hay:

Docker Compose o Dockerfile

Entiendo que Dockerfilesse usan Docker Compose, pero no estoy seguro de si es una buena práctica poner todo en un gran Dockerfile con múltiples FROMcomandos para las diferentes imágenes.

Quiero usar varias imágenes diferentes que incluyen:

uwsgi
nginx
postgres
redis
rabbitmq
celery with cron

Indique cuáles son las mejores prácticas para configurar este tipo de entorno con Docker .

Si ayuda, estoy en una Mac, así que estoy usando boot2docker .

Algunos problemas que he tenido:

  1. Docker Compose no es compatible con Python3
  2. Quiero contener mi proyecto en contenedores, por lo que si un Dockerfile grande no es ideal, creo que tendré que romperlo con Docker Compose
  3. Estoy de acuerdo en hacer que el proyecto Py2 y Py3 sean compatibles, así que me estoy inclinando hacia django-compose
Aaron Lelevier
fuente
55
El asunto se redactaría mejor como "¿Debo ejecutar mi aplicación como uno o varios contenedores?" Parece que depende y que las cuestiones de escala y separación de preocupaciones (un contenedor por servicio) deben tenerse en cuenta. Estos pueden ayudar: stackoverflow.com/questions/30534939/… y quora.com/…
Fabien Snauwaert
Los documentos oficiales de Docker "Getting Started" .
jchook

Respuestas:

239

La respuesta es ninguno.

Docker Compose (en lo sucesivo denominado componer) utilizará el Dockerfile si agrega el comando de compilación a su proyecto docker-compose.yml.

Su flujo de trabajo de Docker debe ser para construir una adecuada Dockerfilepara cada imagen que desea crear, luego use componer para ensamblar las imágenes usando el buildcomando.

Puede especificar la ruta a sus Dockerfiles individuales utilizando build /path/to/dockerfiles/blahdónde /path/to/dockerfiles/blahes dónde Dockerfilevive blah .

booyaa
fuente
10
¿Utilizas docker-composeen producción o solo dev? Gracias por tu ayuda.
Aaron Lelevier
18
@booyaa ¿Podría por favor explicar eso?
Martin Thoma
2
¡Gracias por la respuesta! Dockerfile especifica la configuración de la imagen, y docker-compose.yml ensambla las imágenes juntas. Una cosa que quiero señalar es que, si docker-compose.ymlsolo utilizo la imagen pública (extrayendo la imagen de Internet / docker hub), entonces uno no necesita un Dockerfile para ejecutar el comando docker-compose up.
Oldyoung
550

Dockerfile

ingrese la descripción de la imagen aquí

Un Dockerfile es un archivo de texto simple que contiene los comandos que un usuario podría llamar para ensamblar una imagen.

Ejemplo, 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

ingrese la descripción de la imagen aquí

Docker Compose

  • es una herramienta para definir y ejecutar aplicaciones Docker de contenedores múltiples.

  • defina los servicios que componen su aplicación docker-compose.ymlpara que puedan ejecutarse juntos en un entorno aislado.

  • hacer que una aplicación se ejecute en un solo comando simplemente ejecutando docker-compose up

Ejemplo, docker-compose.yml

version: "3"
services:
  web:
    build: .
    ports:
    - '5000:5000'
    volumes:
    - .:/code
    - logvolume01:/var/log
    links:
    - redis
  redis:
    image: redis
    volumes:
      logvolume01: {}
cyber8200
fuente
43
@sg la respuesta es que la pregunta está mal formada debido a la falta de comprensión de Docker vs Docker Compose. Explicar sucintamente cómo interactúan los dos es probablemente la mejor respuesta que se me ocurre.
mpowered
53
No tengo idea de por qué este desglose exacto no está en la página de inicio de Docker. Gracias.
codykochmann
44
Veo este tipo de documentos que faltan en las herramientas / soluciones / marcos lanzados más recientemente en la web. Supongo que es difícil ver por qué alguien lo necesita en caso de que ya conozca / invente la solución usted mismo.
Peter Branforn
36
Lo que falta en esta respuesta es más información sobre componer. ¿El guión de redacción llama al archivo docker? ¿Cómo sabe qué componer? El ejemplo muestra image: redispero ¿es de dockerhub? directorio local? etc ... esto hace que sea confuso para un novato como yo entender lo que realmente está sucediendo
Joe Phillips
55
Esta respuesta insiste en el propósito de varios contenedores de docker compose, pero probablemente hay muchos otros escenarios en los que desea usar docker compose incluso con solo un contenedor, como especificar el puerto en el que desea que se ejecute su contenedor (no es posible en dockerfile afaik).
Pansoul
99

El archivo Compose describe el contenedor en su estado de ejecución , dejando los detalles sobre cómo construir el contenedor en Dockerfiles . http://deninet.com/blog/1587/docker-scratch-part-4-compose-and-volumes

Cuando define su aplicación con Compose en desarrollo, puede usar esta definición para ejecutar su aplicación en diferentes entornos como CI, almacenamiento provisional y producción . https://docs.docker.com/compose/production/

También parece que Compose se considera seguro para la producción a partir de 1.11 , ya que https://docs.docker.com/v1.11/compose/production/ ya no tiene una advertencia de no usarlo en producción como https: // docs .docker.com / v1.10 / compose / production / does.

Peeter Kokk
fuente
1
Gracias por mencionar el problema. ¿Puede agregar algo más de lo que se arregló para la seguridad de producción en 1.11?
MA Hossain Tonu
93

docker-compose existe para evitar que tengas que escribir una tonelada de comandos que tendrías que hacer con docker-cli.

docker-compose también facilita el inicio de varios contenedores al mismo tiempo y los conecta automáticamente con alguna forma de red.

El propósito de docker-compose es funcionar como docker cli pero emitir múltiples comandos mucho más rápido.

Para utilizar Docker-compose, debe codificar los comandos que estaba ejecutando antes en un docker-compose.ymlarchivo.

No solo va a copiar pegarlos en el archivo yaml, hay una sintaxis especial.

Una vez creado, debe alimentarlo al cli docker-compose y dependerá del cli analizar el archivo y crear todos los diferentes contenedores con la configuración correcta que especifiquemos.

Por lo tanto, tendrá contenedores separados, digamos, por ejemplo, uno es redis-servery el segundo es node-appy desea que se cree usando el Dockerfileen su directorio actual.

Además, después de hacer ese contenedor, debería asignar algún puerto desde el contenedor a la máquina local para acceder a todo lo que se ejecuta dentro de él.

Entonces, para su docker-compose.ymlarchivo, querrá comenzar la primera línea de esta manera:

version: '3'

Eso le dice a Docker la versión docker-composeque quieres usar. Después de eso tienes que agregar:

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

Tenga en cuenta la sangría, muy importante. Además, observe que para un servicio estoy tomando una imagen, pero para otro servicio le digo docker-composeque mire dentro del directorio actual para construir la imagen que se usará para el segundo contenedor.

Luego, desea especificar todos los puertos diferentes que desea abrir en este contenedor.

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

Tenga en cuenta el guión, un guión en un archivo yaml es cómo especificamos una matriz. En este ejemplo, estoy mapeando 8081en mi máquina local 8081en el contenedor de esta manera:

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

Entonces, el primer puerto es su máquina local, y el otro es el puerto en el contenedor, también puede distinguir entre los dos para evitar confusión de la siguiente manera:

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

Al desarrollar un docker-compose.ymlarchivo como este, creará estos contenedores esencialmente en la misma red y tendrán acceso gratuito para comunicarse entre ellos de la forma que deseen e intercambiar la información que deseen.

Cuando los dos contenedores se crean usando docker-composeno necesitamos ninguna declaración de puerto.

Ahora, en mi ejemplo, necesitamos hacer una configuración de código en la aplicación Nodejs que se vea así:

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

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

Utilizo este ejemplo anterior para hacerle saber que puede haber alguna configuración específica que tendría que hacer además del docker-compose.ymlarchivo que puede ser específico para su proyecto.

Ahora, si alguna vez te encuentras trabajando con una aplicación Nodejs y redis, quieres asegurarte de que conoces el puerto predeterminado que Nodejs usa, así que agregaré esto:

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

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

Entonces, Docker verá que la aplicación Node está buscando redis-servery redirigirá esa conexión a este contenedor en ejecución.

Todo el tiempo, el Dockerfileúnico contiene esto:

FROM node:alpine

WORKDIR '/app'

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

CMD ["npm", "start"]

Entonces, mientras que antes tendría que ejecutar docker run myimagepara crear una instancia de todos los contenedores o servicios dentro del archivo, puede ejecutar, docker-compose upy no tiene que especificar una imagen porque Docker buscará en el directorio de trabajo actual y buscará un docker-compose.ymlarchivo dentro de allí.

Antes docker-compose.yml, teníamos que lidiar con dos comandos separados de docker build .y docker run myimage, pero en el docker-composemundo si quieres reconstruir tus imágenes, escribes docker-compose up --build. Eso le dice a Docker que vuelva a iniciar los contenedores pero que lo reconstruya para obtener los últimos cambios.

Por docker-composelo tanto, es más fácil trabajar con múltiples contenedores. La próxima vez que necesite iniciar este grupo de contenedores en segundo plano puede hacerlo docker-compose up -dy detenerlos puede hacerlo docker-compose down.

Daniel
fuente
14
@ Chris Es casi como si hubiera 3 años de conocimiento entre esto y la respuesta aceptada.
Naruto Sempai
Me pregunto si hay alguna buena razón para usar docker-compose upsi solo un servicio en mi situación. Otra palabra, comparar con docker run xxx, ¿algún beneficio si lo uso docker-compose up?
el
@atline vea la respuesta de Pansoul a stackoverflow.com/a/45549372/3366962 sobre los beneficios de usar docker-composecontenedores individuales
go2null
1
@PaulRazvanBerg tu parte "O" es correcta (y 6379es el puerto predeterminado de Redis).
KrishPrabakar
1
Los ejemplos de docker-compose.yml me ayudaron a responder algunas de las preguntas que tenía sobre docker-compose. La respuesta aceptada no es útil, especialmente para las personas que son nuevas en Docker.
maulik13
43

En mi flujo de trabajo, agrego un Dockerfile para cada parte de mi sistema y lo configuro para que cada parte pueda ejecutarse individualmente. Luego agrego un docker-compose.yml para reunirlos y vincularlos.

Mayor ventaja (en mi opinión): al vincular los contenedores , puede definir un nombre y hacer ping a sus contenedores con este nombre. Por lo tanto, su base de datos podría ser accesible con el nombre dby ya no por su IP.

n2o
fuente
¿Podría elaborar más sobre cómo acceder a la base de datos por el nombre?
Vedran Maricevic.
De que parte En docker-compose es trivial, porque es la forma normal al definir sus servicios para darle un nombre y tenerlo accesible sin necesidad de configurarlo. En nuestro CI estoy creando una red, creo el contenedor en esta red y asígneles un nombre. Luego los tiene también accesibles por su nombre dentro de los contenedores (no desde el host)
n2o
En compositor quiero decir. Así que vinculo las imágenes en Composer, y en la configuración de mi aplicación en lugar de IP, apunto a MySQL por el nombre que le haya dado en el archivo Composer.
Vedran Maricevic.
Eso es correcto. Ni siquiera tiene que especificar un enlace. Están vinculados por defecto si la red no se especifica de manera diferente. En este ejemplo, el servicio "web" puede hacer ping al host "redis" por su nombre "redis"
n2o
37

"mejor" es relativo. Todo depende de cuáles sean sus necesidades. Docker compose es para orquestar múltiples contenedores. Si estas imágenes ya existen en el registro de Docker, es mejor enumerarlas en el archivo de redacción. Si estas imágenes u otras imágenes tienen que construirse a partir de archivos en su computadora, entonces puede describir los procesos para construir esas imágenes en un Dockerfile.

Entiendo que los Dockerfiles se usan en Docker Compose, pero no estoy seguro de si es una buena práctica poner todo en un gran Dockerfile con múltiples comandos FROM para las diferentes imágenes.

El uso de múltiples FROM en un solo dockerfile no es una muy buena idea porque hay una propuesta para eliminar la función. 13026

Si, por ejemplo, desea acoplar una aplicación que usa una base de datos y tener los archivos de la aplicación en su computadora, puede usar un archivo de composición junto con un dockerfile de la siguiente manera

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
fuente
30

Dockerfile y Docker Compose son dos conceptos diferentes en Dockerland. Cuando hablamos de Docker, lo primero que viene a la mente es la orquestación, la virtualización a nivel del sistema operativo, las imágenes, los contenedores, etc. Trataré de explicar cada uno de los siguientes:

Imagen: una imagen es un archivo inmutable y compartible que se almacena en un registro confiable de Docker. Una imagen de Docker se crea a partir de una serie de capas de solo lectura. Cada capa representa una instrucción que se da en el Dockerfile de la imagen. Una imagen contiene todos los archivos binarios necesarios para ejecutarse.

ingrese la descripción de la imagen aquí

Contenedor: una instancia de una imagen se denomina contenedor . Un contenedor es solo un binario de imagen ejecutable que debe ejecutar el sistema operativo host. Una imagen en ejecución es un contenedor.

ingrese la descripción de la imagen aquí

Dockerfile: un Dockerfile es un documento de texto que contiene todos los comandos / instrucciones de compilación, un usuario puede llamar a la línea de comandos para ensamblar una imagen. Esto se guardará como a Dockerfile. (Tenga en cuenta la minúscula 'f').

ingrese la descripción de la imagen aquí

Docker-Compose: Compose es una herramienta para definir y ejecutar aplicaciones Docker de contenedores múltiples. Con Compose, utiliza un archivo YAML para configurar los servicios (contenedores) de su aplicación. Luego, con un solo comando, crea e inicia todos los servicios desde su configuración. El archivo de composición se guardará como docker-compose.yml.

Waqas Ahmed
fuente
14

Imagina que eres el gerente de una compañía de software y acabas de comprar un nuevo servidor. Solo el hardware.

Piense Dockerfileen un conjunto de instrucciones que le diría a su administrador de sistema qué instalar en este nuevo servidor. Por ejemplo:

  • Necesitamos un linux Debian
  • agregar un servidor web apache
  • también necesitamos postgresql
  • instalar el comandante de medianoche
  • cuando todo esté listo, copie todos los archivos * .php, * .jpg, etc. de nuestro proyecto en la raíz web del servidor web ( /var/www)

Por el contrario, piense docker-compose.ymlen un conjunto de instrucciones que le diría al administrador de su sistema cómo el servidor puede interactuar con el resto del mundo. Por ejemplo,

  • tiene acceso a una carpeta compartida desde otra computadora,
  • su puerto 80 es el mismo que el puerto 8000 de la computadora host,
  • y así.

(Esta no es una explicación precisa, pero es lo suficientemente buena para comenzar).

Csongor Halmai
fuente
4

Los Dockerfiles son para construir una imagen, por ejemplo, desde un Ubuntu simple, puede agregar mysqlllamado mySQLen una imagen y mywordpressen una segunda imagen llamada mywordpress.

Componer archivos YAML son para tomar estas imágenes y ejecutarlas de manera coherente. por ejemplo, si tiene en su docker-compose.ymlarchivo una llamada de servicio db:

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

y un servicio llamado worpress como:

wordpress: 
    image: mywordpress

luego dentro del contenedor mywordpress puede usar dbpara conectarse a su contenedor mySQL. Esta magia es posible porque su host Docker crea un puente de red (superposición de red).

Hugo R
fuente
0

En el mundo de los microservicios (que tiene una base de código compartida común), cada microservicio tendría un Dockerfilemientras que en el nivel raíz (generalmente fuera de todos los microservicios y donde reside su POM principal) definiría un docker-compose.ymlgrupo para agrupar todos los microservicios en una aplicación completa.

En su caso, se prefiere "Docker Compose" sobre "Dockerfile". Piense "Aplicación" Piense "Componer".

KrishPrabakar
fuente
0

Dockerfile es un archivo que contiene comandos de texto para ensamblar una imagen.

Docker compose se usa para ejecutar un entorno de contenedores múltiples.

En su escenario específico, si tiene múltiples servicios para cada tecnología que mencionó (servicio 1 usando reddis, servicio 2 usando rabbit mq, etc.), entonces puede tener un Dockerfile para cada uno de los servicios y un docker-compose.yml común para ejecutar todo el "Dockerfile" como contenedores.

Si los quiere a todos en un solo servicio, docker-compose será una opción viable.

Mudassir Shahzad
fuente