Docker Compose与Dockerfile-哪个更好?


384

我一直在阅读和学习有关Docker的知识,并试图正确选择要使用的Django设置。到目前为止,有:

Docker ComposeDockerfile

我了解在Dockerfiles中使用了Docker Compose,但是我不确定是否将所有内容放入一个大的Dockerfile中并用多个FROM命令处理不同的映像是否是一个好习惯?

我想使用几个不同的图像,包括:

uwsgi
nginx
postgres
redis
rabbitmq
celery with cron

请提供关于使用Docker设置此类环境的最佳实践的建议。

如果有帮助,我在Mac上,请使用boot2docker

我遇到的一些问题:

  1. Docker Compose与Python3不兼容
  2. 我想对我的项目进行容器化,所以如果一个大的Dockerfile不理想,那么我觉得我需要使用Docker Compose分解它
  3. 我可以使项目Py2和Py3兼容,所以倾向于django-compose

5
将此问题更好地表述为“我应该将我的应用作为一个或多个容器运行吗?” 似乎这取决于要考虑的问题,即关注点的扩展和分离(每个服务一个容器)。这些可能帮助:stackoverflow.com/questions/30534939/...quora.com/...
法比安斯基Snauwaert

官方Docker “入门”文档
jchook

Answers:


238

答案都不是。

如果将build命令添加到项目的,则Docker Compose(在本文中称为compose)将使用Dockerfile docker-compose.yml

您的Docker工作流程应该是为要创建的Dockerfile每个映像构建合适的映像,然后使用compose通过build命令组装映像。

您可以使用等等的build /path/to/dockerfiles/blah位置来指定各个Dockerfile的路径。/path/to/dockerfiles/blahDockerfile


10
docker-compose在生产中使用还是仅在dev中使用?谢谢你的帮助。
亚伦·莱里维耶

18
@booyaa请您详细说明一下吗?
马丁·托马

2
感谢您的回答!Dockerfile指定配置的图像,和搬运工,compose.yml组装图像一起..有一两件事我想指出的是,如果docker-compose.yml只使用公众形象(拉从互联网/泊坞窗枢纽图片),然后一个不需要Dockerfile运行命令docker-compose up
Oldyoung

549

Docker文件

在此处输入图片说明

Dockerfile是一个简单的文本文件,其中包含用户可以调用以组装映像的命令。

示例, 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撰写

在此处输入图片说明

Docker撰写

  • 是用于定义和运行多容器Docker应用程序的工具。

  • 定义组成应用程序的服务,docker-compose.yml以便它们可以在隔离的环境中一起运行。

  • 通过仅运行一个命令即可运行应用程序 docker-compose up

例如 docker-compose.yml

version: "3"
services:
  web:
    build: .
    ports:
    - '5000:5000'
    volumes:
    - .:/code
    - logvolume01:/var/log
    links:
    - redis
  redis:
    image: redis
    volumes:
      logvolume01: {}

43
@sg答案是,问题是由于缺乏对Docker vs Docker Compose的了解而形成的。简洁地解释两者之间的相互作用可能是我能想到的最佳答案。
mpower

53
我不知道为什么这个确切的故障不在Docker的主页上。谢谢。
codykochmann

4
我看到网上最新发布的工具/解决方案/框架中缺少此类文档。我想很难知道为什么有人需要它,以防您已经知道/发明了解决方案。
Peter Branforn

36
该答案缺少的是有关compose的更多信息。撰写脚本会调用dockerfile吗?它怎么知道组成什么?该示例显示了,image: redis但是否来自dockerhub?本地目录?等等...这让像我这样的新手很难理解实际发生的情况
Joe Phillips

5
该响应坚持了docker compose的多容器用途,但是即使仅使用一个容器,您可能还有许多其他情况想要使用docker compose,例如指定要运行容器的端口(在dockerfile afaik中是不可能的)。
Pansoul

99

撰写文件描述了在其运行状态的容器,留下怎样的细节容器建立Dockerfileshttp://deninet.com/blog/1587/docker-scratch-part-4-compose-and-volumes

在开发中使用Compose定义应用程序可以使用此定义在不同的环境(例如 CI,登台和生产)中运行应用程序https://docs.docker.com/compose/production/

1.11开始,似乎还认为Compose是生产安全的,因为https://docs.docker.com/v1.11/compose/production/不再像https:// docs那样警告不要在生产中使用它.docker.com / v1.10 / compose / production /可以。


1
感谢您提出这个问题。您能否再添加一些针对1.11的安全生产固定问题?
MA Hossain Tonu

92

docker-compose的存在使您不得不编写大量使用docker-cli所需的命令。

docker-compose还使您可以轻松地同时启动多个容器,并通过某种形式的网络将它们自动连接在一起。

docker-compose的目的是充当docker cli,但能更快地发出多个命令。

要使用docker-compose,您需要将之前运行的命令编码为docker-compose.yml文件。

您不仅要将它们复制粘贴到yaml文件中,还有一种特殊的语法。

创建完成后,您必须将其提供给docker-compose cli,并由cli来解析文件并使用我们指定的正确配置创建所有不同的容器。

因此,您将拥有单独的容器,例如,一个是容器,redis-server第二个是容器,node-app并且希望Dockerfile在当前目录中使用创建的容器。

此外,在制作完该容器后,您需要将一些端口从该容器映射到本地计算机,以访问其中运行的所有内容。

因此,对于您的docker-compose.yml文件,您希望像这样开始第一行:

version: '3'

这会告诉Docker docker-compose您要使用的版本。之后,您必须添加:

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

请注意缩进,非常重要。另外,请注意,对于一项服务,我正在抓取图像,但是对于另一项服务,则是告诉我docker-compose查看当前目录以构建将用于第二个容器的图像。

然后,您要指定要在此容器上打开的所有不同端口。

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

请注意破折号,yaml文件中的破折号是我们指定数组的方式。在此示例中,我将8081本地计算机8081上的映射到容器上,如下所示:

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

因此,第一个端口是您的本地计算机,另一个是容器上的端口,您也可以在这两个端口之间进行区分,以避免混淆,如下所示:

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

通过docker-compose.yml像这样开发您的文件,它将在基本上相同的网络上创建这些容器,并且它们将可以自由访问,以他们希望的任何方式相互通信,并根据需要交换尽可能多的信息。

使用创建两个容器时,docker-compose我们不需要任何端口声明。

现在在我的示例中,我们需要在Nodejs应用中进行一些代码配置,如下所示:

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

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

我在上面使用此示例使您意识到,除了docker-compose.yml可能特定于您的项目的文件之外,您还需要做一些特定的配置。

现在,如果您发现自己正在使用Nodejs应用程序并进行Redis操作,则要确保您知道Nodejs使用的默认端口,因此我将添加以下内容:

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

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

因此,Docker将看到Node应用正在查找redis-server并将该连接重定向到此正在运行的容器。

在整个时间中,Dockerfile仅包含以下内容:

FROM node:alpine

WORKDIR '/app'

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

CMD ["npm", "start"]

因此,在不得不运行docker run myimage以创建文件中所有容器或服务的实例之前,您可以运行,docker-compose up而不必指定映像,因为Docker会在当前工作目录中查找并寻找一个docker-compose.yml里面的文件。

以前docker-compose.yml,我们不得不处理docker build .and的两个单独的命令docker run myimage,但实际上,docker-compose如果您想重建自己编写的图像,就必须这样做docker-compose up --build。这告诉Docker重新启动容器,但要对其进行重建以获取最新更改。

因此docker-compose,使用多个容器变得更加容易。下次需要在后台启动这组容器时,可以执行此操作,docker-compose up -d并在停止它们时可以执行docker-compose down


13
@Chris在这个和被接受的答案之间,好像好像有3年的知识。
火影忍者神庙

我想知道是否有充分的理由让我使用docker-compose up我的情况下的一项服务?换句话说,docker run xxx如果使用,有什么好处docker-compose up
ATLINE

@atline 有关使用单个容器的好处,请参阅Pansoul对stackoverflow.com/a/45549372/3366962的回复docker-compose
go2null19年

1
@PaulRazvanBerg您的“或”部分是正确的(并且6379是Redis的默认端口)。
KrishPrabakar

1
docker-compose.yml的示例帮助我回答了有关do​​cker-compose的一些问题。接受的答案没有用,特别是对于Docker新手而言。
maulik13

43

在我的工作流程中,我为系统的每个部分添加一个Dockerfile并将其配置为每个部分都可以单独运行。然后,我添加一个docker-compose.yml将它们放在一起并进行链接。

最大的优点(我认为):链接容器时,您可以定义一个名称并使用该名称ping您的容器。因此,您可以使用名称访问数据库,db而不再可以通过其IP 访问该数据库。


您能详细说明通过名称访问数据库吗?
Vedran Maricevic。

在哪一部分?在docker-compose中,这是微不足道的,因为这是定义服务时为其赋予名称并使其无需配置即可访问的常规方法。在我们的CI中,我正在创建一个网络,在该网络中创建容器并为其命名。然后,您也可以通过容器内的名称访问它们(而不是从主机)
n2o

在作曲家中,我的意思是。所以我将图像链接到composer中,并在我的App配置中而不是IP中,用在composer文件中给它命名的名称来标记MySQL吗?
Vedran Maricevic。

没错 您甚至不必指定链接。如果未指定其他网络,则默认情况下会链接它们。在此示例中,服务“ web”可以通过名称“ redis”对主机“ redis”执行ping操作
n2o

37

“更好”是相对的。这完全取决于您的需求。Docker compose用于编排多个容器。如果这些图像已经存在于docker注册表中,那么最好将它们列出在compose文件中。如果必须从计算机上的文件中构建这些映像或其他映像,则可以描述在Dockerfile中构建这些映像的过程。

我了解Docker Compose中使用了Dockerfile,但是我不确定是否将所有内容放入一个大Dockerfile中,并使用多个FROM命令来处理不同的映像?

在单个dockerfile中使用多个FROM不是一个好主意,因为有人建议删除该功能。13026

例如,如果要对使用数据库的应用程序进行泊坞化,并在计算机上存储该应用程序文件,则可以将compose文件与dockerfile一起使用,如下所示

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

Docker文件

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

30

Dockerfile和Docker Compose是Dockerland中的两个不同概念。当我们谈论Docker时,首先想到的是业务流程,操作系统级虚拟化,映像,容器等。我将尝试对它们进行如下解释:

映像: 映像是存储在受Docker信任的注册表中的不可变,可共享的文件。Docker映像由一系列只读层构建而成。每一层代表在映像的Dockerfile中给出的一条指令。映像包含运行所需的所有二进制文件。

在此处输入图片说明

容器: 图像的实例称为容器。容器只是要由主机OS运行的可执行映像二进制文件。运行的图像是一个容器。

在此处输入图片说明

Dockerfile: Dockerfile是一个文本文档,其中包含所有命令/构建指令,用户可以在命令行上调用以组装映像。这将另存为Dockerfile。(请注意小写的“ f”。)

在此处输入图片说明

Docker-Compose: Compose是用于定义和运行多容器Docker应用程序的工具。通过Compose,您可以使用YAML文件来配置应用程序的服务(容器)。然后,使用一个命令,就可以从配置中创建并启动所有服务。撰写文件将另存为docker-compose.yml


14

假设您是一家软件公司的经理,而您刚购买了一台全新的服务器。只是硬件。

想想Dockerfile作为一组指令你能告诉你的系统管理员如何安装这个全新的服务器上。例如:

  • 我们需要一个Debian Linux
  • 添加一个Apache Web服务器
  • 我们也需要postgresql
  • 安装午夜指挥官
  • 完成后,将我们项目的所有* .php,*。jpg等文件复制到网络服务器的webroot中(/var/www

相比之下,可以考虑将docker-compose.yml一组说明告诉系统管理员,服务器如何与世界其他地方进行交互。例如,

  • 它可以从另一台计算机访问共享文件夹,
  • 端口80与主机的端口8000相同,
  • 等等。

(这不是一个精确的解释,但是足以作为开始。)


4

Dockerfiles是从裸骨Ubuntu的建设,例如图像,你可以添加mysql呼吁mySQL在一个图像和mywordpress称为第二图像mywordpress

编写YAML文件是要获取这些图像并使其内聚地运行。例如,如果您的docker-compose.yml文件中有一个服务电话db

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

以及称为worpress的服务,例如:

wordpress: 
    image: mywordpress

然后在mywordpress容器内,您可以db用来连接到mySQL容器。之所以如此,是因为您的Docker主机创建了一个网桥(网络覆盖)。


0

在微服务世界(具有通用的共享代码库)中,每个微服务都会有一个,Dockerfile而在根级别(通常在所有微服务之外以及您的父POM所在的位置),您将定义一个docker-compose.yml将所有微服务分组为一个成熟的应用程序。

在您的情况下,“ Docker Compose”优于“ Dockerfile”。考虑“应用程序”考虑“撰写”。


0

Dockerfile是一个包含用于组装映像的文本命令的文件。

Docker compose用于运行多容器环境。

在您的特定情况下,如果您提到的每种技术都具有多种服务(使用reddis的服务1,使用Rabbit mq的服务2等),那么您可以为每个服务使用一个Dockerfile并运行一个通用的docker-compose.yml将所有“ Dockerfile”作为容器。

如果您希望将它们全部放在一个服务中,则docker-compose将是一个可行的选择。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.