Docker Compose vs. Dockerfile - o que é melhor?

384

Eu tenho lido e aprendido sobre o Docker e estou tentando escolher corretamente a configuração do Django a ser usada. Até agora, existe:

Docker Compose ou Dockerfile

Entendo que Dockerfilessão usadas Docker Compose, mas não tenho certeza se é uma boa prática colocar tudo em um Dockerfile grande com vários FROMcomandos para as diferentes imagens?

Quero usar várias imagens diferentes que incluem:

uwsgi
nginx
postgres
redis
rabbitmq
celery with cron

Informe sobre quais são as práticas recomendadas para configurar esse tipo de ambiente usando o Docker .

Se ajudar, estou em um Mac, então use o boot2docker .

Alguns problemas que tive:

  1. O Docker Compose não é compatível com Python3
  2. Quero colocar em contêiner meu projeto, portanto, se um Dockerfile grande não for o ideal, acho que precisarei dividi-lo usando o Docker Compose
  3. Eu estou bem para tornar o projeto Py2 e Py3 compatível, então estou inclinado a django-compose
Aaron Lelevier
fonte
5
O problema seria melhor formulado como "Devo executar meu aplicativo como um único ou vários contêineres?" Parece que depende e que questões de escala e separação de preocupações (um contêiner por serviço) devem ser levadas em consideração. Isso pode ajudar: stackoverflow.com/questions/30534939/… e quora.com/…
Fabien Snauwaert
Os documentos oficiais do " Docker " Getting Started .
jchook

Respostas:

239

A resposta é nenhuma.

O Docker Compose (aqui chamado de composição) usará o Dockerfile se você adicionar o comando build ao projeto docker-compose.yml.

Seu fluxo de trabalho do Docker deve criar um adequado Dockerfilepara cada imagem que você deseja criar e, em seguida, usar a composição para montar as imagens usando o buildcomando

Você pode especificar o caminho para seus Dockerfiles individuais usando build /path/to/dockerfiles/blahonde /path/to/dockerfiles/blahé o lugar de onde blah Dockerfilemora.

booyaa
fonte
10
você usa docker-composeem produção ou apenas dev? Obrigado pela ajuda.
Aaron Lelevier
18
@booyaa Você poderia, por favor, falar sobre isso?
Martin Thoma
2
Obrigado pela resposta! O Dockerfile especifica a configuração da imagem e o docker-compose.yml monta imagens juntos. Uma coisa que quero destacar é que, se você docker-compose.ymlusar apenas a imagem pública (puxando a imagem do hub da Internet / docker), não será necessário Dockerfile para executar o comando docker-compose up.
Oldyoung 17/09/19
549

Dockerfile

insira a descrição da imagem aqui

Um Dockerfile é um arquivo de texto simples que contém os comandos que um usuário pode chamar para montar uma imagem.

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

insira a descrição da imagem aqui

Docker Compose

  • é uma ferramenta para definir e executar aplicativos Docker de vários contêineres.

  • defina os serviços que compõem seu aplicativo docker-compose.ymlpara que possam ser executados juntos em um ambiente isolado.

  • obtenha um aplicativo em execução em um comando apenas executando docker-compose up

Exemplo, docker-compose.yml

version: "3"
services:
  web:
    build: .
    ports:
    - '5000:5000'
    volumes:
    - .:/code
    - logvolume01:/var/log
    links:
    - redis
  redis:
    image: redis
    volumes:
      logvolume01: {}
cyber8200
fonte
43
@sg a resposta é que a pergunta está mal formada, com base na falta de entendimento do Docker vs Docker Compose. Explicar sucintamente como os dois interagem é provavelmente a melhor resposta que consigo pensar.
mpowered
53
Não tenho ideia de por que esse colapso exato não está na página inicial do Docker. Obrigado.
Codykochmann 11/0318
4
Vejo esse tipo de documentação ausente nas ferramentas / soluções / estruturas lançadas mais recentemente na Web. Eu acho que é difícil entender por que alguém precisa disso, caso você já saiba / invente a solução.
Peter Branforn 18/03/19
36
O que falta nesta resposta é mais informações sobre composição. O script de composição chama o dockerfile? Como ele sabe o que compor? O exemplo mostra, image: redismas é o do dockerhub? diretório local? etc ... isso torna confuso para um newb como eu para entender o que está realmente acontecendo
Joe Phillips
5
Essa resposta insiste no propósito de vários contêineres de composição do docker, mas provavelmente existem muitos outros cenários nos quais você deseja usar o docker compose, mesmo com apenas um contêiner, como especificar a porta na qual o contêiner deve ser executado (não é possível no dockerfile afaik).
Pansoul 16/05/19
99

O arquivo Compor descreve o contêiner em seu estado de execução , deixando os detalhes de como criar o contêiner no Dockerfiles . http://deninet.com/blog/1587/docker-scratch-part-4-compose-and-volumes

Ao definir seu aplicativo com o Redigir no desenvolvimento, você pode usar essa definição para executar seu aplicativo em diferentes ambientes, como IC, preparo e produção . https://docs.docker.com/compose/production/

Também parece que o Compose é considerado seguro para produção a partir de 1.11 , pois https://docs.docker.com/v1.11/compose/production/ não possui mais um aviso para não usá-lo na produção como https: // docs .docker.com / v1.10 / compose / production / does.

Peeter Kokk
fonte
11
Obrigado por abordar a questão. Você pode adicionar um pouco mais do que foi corrigido para a segurança da produção em 1,11?
MA Hossain Tonu
93

O docker-compose existe para impedir que você escreva uma tonelada de comandos que você precisaria com o docker-cli.

O docker-compose também facilita a inicialização de vários contêineres ao mesmo tempo e os conecta automaticamente a alguma forma de rede.

O objetivo do docker-compose é funcionar como docker cli, mas emitir vários comandos muito mais rapidamente.

Para usar o docker-compose, é necessário codificar os comandos que você estava executando antes em um docker-compose.ymlarquivo.

Você não apenas copiará colá-los no arquivo yaml, há uma sintaxe especial.

Depois de criado, você deve alimentá-lo com o docker-composi cli e caberá ao cli analisar o arquivo e criar todos os diferentes contêineres com a configuração correta especificada.

Portanto, você terá contêineres separados, digamos, por exemplo, um é redis-servere o segundo é node-appe você deseja que seja criado usando oDockerfile diretório atual.

Além disso, depois de criar esse contêiner, você mapeia alguma porta do contêiner para a máquina local para acessar tudo o que está sendo executado dentro dele.

Portanto, para o seu docker-compose.ymlarquivo, você deseja iniciar a primeira linha da seguinte maneira:

version: '3'

Isso informa ao Docker a versão que docker-composevocê deseja usar. Depois disso, você deve adicionar:

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

Por favor, observe o recuo, muito importante. Além disso, observe que, para um serviço, estou capturando uma imagem, mas para outro serviço, digo docker-composepara procurar dentro do diretório atual para criar a imagem que será usada para o segundo contêiner.

Então você deseja especificar todas as portas diferentes que deseja abrir neste contêiner.

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

Observe o traço, um traço em um arquivo yaml é como especificamos uma matriz. Neste exemplo, estou mapeando 8081na minha máquina local para 8081o contêiner da seguinte forma:

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

Portanto, a primeira porta é sua máquina local e a outra é a porta do contêiner, você também pode distinguir entre as duas para evitar confusão da seguinte maneira:

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

Ao desenvolver seu docker-compose.ymlarquivo como este, ele criará esses contêineres essencialmente na mesma rede e eles terão acesso livre para se comunicarem da maneira que quiserem e trocarão as informações que desejarem.

Quando os dois contêineres são criados docker-compose, não precisamos de nenhuma declaração de porta.

Agora, no meu exemplo, precisamos fazer alguma configuração de código no aplicativo Nodejs que se parece com isso:

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

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

Eu uso este exemplo acima para informá-lo de que pode haver alguma configuração específica que você precisaria fazer além do docker-compose.yml arquivo que pode ser específico ao seu projeto.

Agora, se você se encontrar trabalhando com um aplicativo Nodejs e redis, desejará garantir que você esteja ciente da porta padrão que o Nodejs usa, então adicionarei isto:

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

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

Portanto, o Docker verá que o aplicativo Node está procurando redis-servere redireciona essa conexão para esse contêiner em execução.

O tempo todo, o Dockerfileúnico contém isso:

FROM node:alpine

WORKDIR '/app'

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

CMD ["npm", "start"]

Portanto, enquanto antes você precisaria executar docker run myimagepara criar uma instância de todos os contêineres ou serviços dentro do arquivo, você pode executar docker-compose upe não precisa especificar uma imagem porque o Docker procurará no diretório de trabalho atual e procurará umdocker-compose.yml arquivo dentro de lá.

Antes docker-compose.yml, tínhamos que lidar com dois comandos separados de docker build .e docker run myimage, mas no docker-composemundo, se você deseja reconstruir suas imagens que escreve docker-compose up --build. Isso diz ao Docker para reiniciar os contêineres, mas reconstruí-lo para obter as alterações mais recentes.

Isso docker-composefacilita o trabalho com vários contêineres. Na próxima vez que você precisar iniciar esse grupo de contêineres em segundo plano, poderá fazer docker-compose up -de pará-los docker-compose down.

Daniel
fonte
14
@ Chris É quase como se houvesse 3 anos de conhecimento entre isso e a resposta aceita.
Naruto Sempai
Gostaria de saber se existe alguma boa razão para eu usar docker-compose upse apenas um serviço na minha situação? Outra palavra, compare com docker run xxx, algum benefício se eu usar docker-compose up?
atline 02/09/19
@atline ver a resposta de Pansoul para stackoverflow.com/a/45549372/3366962 sobre os benefícios do uso docker-composede recipientes individuais
go2null
11
@PaulRazvanBerg, a parte "Or" está correta (e 6379é a porta padrão do Redis).
KrishPrabakar
11
Os exemplos de docker-compose.yml me ajudaram a responder a algumas das perguntas que eu tinha sobre o docker-compose. A resposta aceita não é útil, especialmente para pessoas novas no docker.
maulik13 24/03
43

No meu fluxo de trabalho, adiciono um Dockerfile para cada parte do meu sistema e configuro que cada parte possa ser executada individualmente. Em seguida, adiciono um docker-compose.yml para reuni-los e vinculá-los.

Maior vantagem (na minha opinião): ao vincular os contêineres , você pode definir um nome e executar ping nos contêineres com esse nome. Portanto, seu banco de dados pode estar acessível com o nome dbe não mais com seu IP.

n2o
fonte
Você poderia elaborar mais sobre como acessar o banco de dados pelo nome?
Vedran Maricevic.
De qual parte? Na composição do docker, isso é trivial, porque é a maneira normal ao definir seus serviços para dar um nome e acessá-lo sem a necessidade de configurá-lo. No nosso IC, estou criando uma rede, crie o contêiner nessa rede e dê um nome a eles. Então você tê-los também acessível pelo seu nome no interior dos recipientes (não do host)
N2O
No compositor, quero dizer. Então, eu vinculo as imagens no compositor e, na minha configuração de aplicativo, em vez de IP, alterno o MySQL com o nome que eu dei no arquivo do compositor?
Vedran Maricevic.
Está correto. Você nem precisa especificar um link. Eles são vinculados por padrão se a rede não for especificada de maneira diferente. Neste exemplo o "web" serviço pode ping do host "Redis" pelo seu nome "Redis"
N2O
37

"melhor" é relativo. Tudo depende de quais são suas necessidades. O Docker compose é para orquestrar vários contêineres. Se essas imagens já existirem no registro da janela de encaixe, é melhor listá-las no arquivo de composição. Se essas imagens ou outras imagens precisarem ser criadas a partir de arquivos no seu computador, você poderá descrever os processos de criação dessas imagens em um Dockerfile.

Entendo que os Dockerfiles são usados ​​no Docker Compose, mas não tenho certeza se é uma boa prática colocar tudo em um Dockerfile grande com vários comandos FROM para as diferentes imagens?

Usar vários FROM em um único arquivo docker não é uma boa ideia, porque existe uma proposta para remover o recurso. 13026

Se, por exemplo, você deseja dockerizar um aplicativo que usa um banco de dados e ter os arquivos do aplicativo no seu computador, você pode usar um arquivo de composição juntamente com um arquivo docker da seguinte maneira

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

Dockerfile e Docker Compose são dois conceitos diferentes no Dockerland. Quando falamos sobre o Docker, as primeiras coisas que vêm à mente são orquestração, virtualização no nível do SO, imagens, contêineres, etc. Tentarei explicar cada um da seguinte maneira:

Imagem: uma imagem é um arquivo imutável e compartilhável que é armazenado em um registro confiável do Docker. Uma imagem do Docker é criada a partir de uma série de camadas somente leitura. Cada camada representa uma instrução que está sendo fornecida no Dockerfile da imagem. Uma imagem contém todos os binários necessários para execução.

insira a descrição da imagem aqui

Contêiner: uma instância de uma imagem é chamada de contêiner . Um contêiner é apenas um binário de imagem executável que deve ser executado pelo sistema operacional host. Uma imagem em execução é um contêiner.

insira a descrição da imagem aqui

Dockerfile: um Dockerfile é um documento de texto que contém todos os comandos / instruções de construção que um usuário pode chamar na linha de comando para montar uma imagem. Isso será salvo como um Dockerfile. (Observe a letra minúscula 'f'.)

insira a descrição da imagem aqui

Docker-Compose: O Compose é uma ferramenta para definir e executar aplicativos Docker de vários contêineres. Com o Compose, você usa um arquivo YAML para configurar os serviços do aplicativo (contêineres). Em seguida, com um único comando, você cria e inicia todos os serviços da sua configuração. O arquivo de composição seria salvo como docker-compose.yml.

Waqas Ahmed
fonte
14

Imagine que você é o gerente de uma empresa de software e acabou de comprar um servidor novo. Apenas o hardware.

Pense Dockerfilecomo um conjunto de instruções que você diria ao administrador do sistema o que instalar neste novo servidor. Por exemplo:

  • Nós precisamos de um Linux Debian
  • adicionar um servidor web apache
  • precisamos do postgresql também
  • instalar comandante da meia-noite
  • quando tudo estiver pronto, copie todos os arquivos * .php, * .jpg etc. do nosso projeto na raiz da web do servidor da web ( /var/www)

Por outro lado, pense docker-compose.ymlem um conjunto de instruções que você diria ao administrador do sistema como o servidor pode interagir com o resto do mundo. Por exemplo,

  • ele tem acesso a uma pasta compartilhada de outro computador,
  • a porta 80 é igual à porta 8000 do computador host,
  • e assim por diante.

(Esta não é uma explicação precisa, mas é boa o suficiente para começar.)

Csongor Halmai
fonte
4

Os Dockerfiles devem criar uma imagem, por exemplo, a partir de um Ubuntu básico, você pode adicionar uma imagem mysqlchamada mySQLe mywordpressuma segunda imagem chamada mywordpress.

Os arquivos de composição YAML devem capturar essas imagens e executá-las de forma coesa. por exemplo, se você tiver em seu docker-compose.ymlarquivo uma chamada de serviço db:

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

e um serviço chamado worpress, como:

wordpress: 
    image: mywordpress

depois, dentro do contêiner mywordpress, você pode usar dbpara se conectar ao seu contêiner mySQL. Essa mágica é possível porque o host do docker cria uma ponte de rede (sobreposição de rede).

Hugo R
fonte
0

No mundo dos microsserviços (com uma base de código compartilhada comum), cada microsserviço teria um tempo Dockerfileno nível raiz (geralmente fora de todos os microsserviços e onde reside o POM pai), você definiria um docker-compose.ymlpara agrupar todos os microsserviços em um aplicativo completo.

No seu caso, "Docker Compose" é preferível a "Dockerfile". Pense "App" Pense "Compor".

KrishPrabakar
fonte
0

Dockerfile é um arquivo que contém comandos de texto para montar uma imagem.

A composição do Docker é usada para executar um ambiente com vários contêineres.

No seu cenário específico, se você tiver vários serviços para cada tecnologia mencionada (serviço 1 usando reddis, serviço 2 usando rabbit mq etc.), poderá ter um Dockerfile para cada um dos serviços e um docker-compose.yml comum para executar todo o "Dockerfile" como contêineres.

Se você desejar todos eles em um único serviço, o docker-compose será uma opção viável.

Mudassir Shahzad
fonte