Docker Compose so với Dockerfile - cái nào tốt hơn?


384

Tôi đã đọc và tìm hiểu về Docker , và tôi đang cố gắng chọn chính xác thiết lập Django để sử dụng. Cho đến nay cũng có:

Docker Soạn hoặc Dockerfile

Tôi hiểu rằng nó Dockerfilesđược sử dụng Docker Compose, nhưng tôi không chắc có nên đặt mọi thứ vào một Dockerfile lớn với nhiều FROMlệnh cho các hình ảnh khác nhau không?

Tôi muốn sử dụng một số hình ảnh khác nhau bao gồm:

uwsgi
nginx
postgres
redis
rabbitmq
celery with cron

Vui lòng tư vấn về các thực tiễn tốt nhất trong việc thiết lập loại môi trường này bằng Docker .

Nếu nó giúp, tôi đang dùng Mac, nên sử dụng boot2docker .

Một số vấn đề tôi đã có:

  1. Docker Compose không tương thích với Python3
  2. Tôi muốn lưu trữ dự án của mình, vì vậy nếu một Dockerfile lớn không lý tưởng, thì tôi cảm thấy mình cần phải phá vỡ nó bằng cách sử dụng Docker Compose
  3. Tôi ổn để làm cho dự án Py2 & Py3 tương thích, vì vậy tôi đang nghiêng về django-compose

5
Vấn đề sẽ được giải quyết tốt hơn khi tôi nên chạy ứng dụng của mình dưới dạng một hoặc nhiều container? Có vẻ như điều đó phụ thuộc và các vấn đề về nhân rộng và phân tách các mối quan tâm (một container cho mỗi dịch vụ) nên được tính đến. Những thứ này có thể giúp: stackoverflow.com/questions/30534939/ và và quora.com/ khăn
Fabien Snauwaert

Các tài liệu "Bắt đầu" Docker chính thức .
jchook

Câu trả lời:


238

Câu trả lời là không.

Docker Compose (sau đây gọi là compose) sẽ sử dụng Dockerfile nếu bạn thêm lệnh xây dựng vào dự án của bạn docker-compose.yml.

Quy trình làm việc Docker của bạn phải là để xây dựng một Dockerfilehình ảnh phù hợp cho từng hình ảnh bạn muốn tạo, sau đó sử dụng compose để lắp ráp các hình ảnh bằng cách sử dụng buildlệnh.

Bạn có thể chỉ định đường dẫn đến Dockerfiles cá nhân của mình bằng cách sử dụng build /path/to/dockerfiles/blahnơi sống /path/to/dockerfiles/blahcủa blah Dockerfile.


10
Bạn sử dụng docker-composetrong sản xuất hay chỉ dev? Cảm ơn bạn đã giúp đỡ.
Aaron Lelevier

18
@booyaa Bạn có thể vui lòng giải thích về điều đó?
Martin Thoma

2
Cảm ơn câu trả lời! Dockerfile chỉ định cấu hình cho hình ảnh và docker-compose.yml lắp ráp các hình ảnh lại với nhau .. Một điều tôi muốn chỉ ra là, Nếu docker-compose.ymlchỉ sử dụng hình ảnh công cộng (kéo hình ảnh từ trung tâm internet / docker), thì người ta không cần Dockerfile để chạy lệnh docker-compose up.
Oldyoung

549

Dockerfile

nhập mô tả hình ảnh ở đây

Dockerfile là một tệp văn bản đơn giản chứa các lệnh mà người dùng có thể gọi để lắp ráp một hình ảnh.

Ví dụ, 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 Soạn

nhập mô tả hình ảnh ở đây

Docker Soạn

  • là một công cụ để xác định và chạy các ứng dụng Docker đa container.

  • xác định các dịch vụ tạo nên ứng dụng của bạn docker-compose.ymlđể chúng có thể chạy cùng nhau trong một môi trường biệt lập.

  • có được một ứng dụng chạy trong một lệnh chỉ bằng cách chạy docker-compose up

Ví dụ, 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 câu trả lời là câu hỏi không rõ ràng dựa trên sự thiếu hiểu biết về Docker vs Docker Compose. Giải thích ngắn gọn về cách hai người tương tác có lẽ là câu trả lời tốt nhất tôi có thể nghĩ ra.
bắt đầu từ

53
Tôi không biết tại sao sự cố chính xác này không nằm trên trang chủ của Docker. Cảm ơn.
codykochmann

4
Tôi thấy loại tài liệu này bị thiếu trong các công cụ / giải pháp / khung phát hành gần đây nhất trên web. Tôi đoán thật khó để biết tại sao ai đó cần nó trong trường hợp bạn đã biết / tự phát minh ra giải pháp.
Peter Branforn 18/03/18

36
Điều còn thiếu từ câu trả lời này là thông tin thêm về sáng tác. Tập lệnh soạn thảo có gọi dockerfile không? Làm thế nào để nó biết những gì để sáng tác? Ví dụ cho thấy image: redisnhưng đó là từ dockerhub? thư mục địa phương? v.v ... điều này khiến cho một người mới như tôi khó hiểu về những gì đang diễn ra
Joe Phillips

5
Phản hồi này nhấn mạnh vào mục đích đa container của docker compose nhưng có thể có nhiều kịch bản khác mà bạn muốn sử dụng docker compose ngay cả chỉ với một container như chỉ định cổng bạn muốn container của bạn chạy trên (không thể có trong dockerfile afaik).
Pansoul

99

Tệp Compose mô tả vùng chứa ở trạng thái chạy , để lại chi tiết về cách xây dựng vùng chứa vào Dockerfiles . http://deninet.com/blog/1587/docker-scratch-part-4-compose-and-volume

Khi bạn xác định ứng dụng của mình với Compose đang phát triển, bạn có thể sử dụng định nghĩa này để chạy ứng dụng của mình trong các môi trường khác nhau như CI, dàn dựng và sản xuất . https://docs.docker.com/compose/production/

Dường như Compose được coi là sản xuất an toàn kể từ 1.11 , vì https://docs.docker.com/v1.11/compose/production/ không còn cảnh báo không sử dụng nó trong sản xuất như https: // docs .docker.com / v1.10 / soạn / sản xuất / không.


1
Cảm ơn đã đưa ra vấn đề. Bạn có thể vui lòng thêm một số chi tiết đã được sửa cho an toàn sản xuất ở mức 1.11 không?
MA Hossain Tonu

93

docker-compose tồn tại để giữ cho bạn phải viết một tấn lệnh bạn sẽ phải thực hiện với docker-cli.

docker-compose cũng giúp bạn dễ dàng khởi động nhiều container cùng một lúc và tự động kết nối chúng với nhau bằng một số hình thức kết nối mạng.

Mục đích của docker-compose là hoạt động như docker cli nhưng để phát hành nhiều lệnh nhanh hơn nhiều.

Để sử dụng docker-compose, bạn cần mã hóa các lệnh bạn đang chạy trước đó thành một docker-compose.ymltệp.

Bạn sẽ không chỉ sao chép dán chúng vào tập tin yaml, có một cú pháp đặc biệt.

Sau khi tạo xong, bạn phải cung cấp nó cho cler docker-compose và nó sẽ tùy thuộc vào cli để phân tích tệp và tạo tất cả các thùng chứa khác nhau với cấu hình chính xác mà chúng tôi chỉ định.

Vì vậy, bạn sẽ có các thùng chứa riêng biệt, ví dụ, một là redis-servervà thứ hai là node-appvà bạn muốn nó được tạo bằng Dockerfilethư mục hiện tại của bạn.

Ngoài ra, sau khi tạo vùng chứa đó, bạn sẽ ánh xạ một số cổng từ vùng chứa sang máy cục bộ để truy cập mọi thứ chạy bên trong nó.

Vì vậy, đối với docker-compose.ymltệp của bạn, bạn sẽ muốn bắt đầu dòng đầu tiên như vậy:

version: '3'

Điều đó cho Docker biết phiên bản docker-composebạn muốn sử dụng. Sau đó, bạn phải thêm:

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

Xin lưu ý các vết lõm, rất quan trọng. Ngoài ra, thông báo cho một dịch vụ tôi đang lấy một hình ảnh, nhưng đối với một dịch vụ khác tôi đang nói docker-composehãy nhìn vào bên trong thư mục hiện tại để xây dựng hình ảnh sẽ được sử dụng cho vùng chứa thứ hai.

Sau đó, bạn muốn chỉ định tất cả các cổng khác nhau mà bạn muốn mở trên container này.

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

Xin lưu ý dấu gạch ngang, dấu gạch ngang trong tệp yaml là cách chúng tôi chỉ định một mảng. Trong ví dụ này, tôi ánh xạ 8081trên máy cục bộ của mình 8081vào container như vậy:

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

Vì vậy, cổng đầu tiên là máy cục bộ của bạn và cổng kia là cổng trên container, bạn cũng có thể phân biệt giữa hai cổng để tránh nhầm lẫn như vậy:

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

Bằng cách phát triển docker-compose.ymltệp của bạn như thế này, nó sẽ tạo ra các thùng chứa này trên cùng một mạng và họ sẽ có quyền truy cập miễn phí để liên lạc với nhau theo bất kỳ cách nào họ muốn và trao đổi nhiều thông tin như họ muốn.

Khi hai container được tạo bằng cách sử dụng, docker-composechúng tôi không cần bất kỳ khai báo cổng nào.

Bây giờ trong ví dụ của tôi, chúng ta cần thực hiện một số cấu hình mã trong ứng dụng Nodejs trông giống như thế này:

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

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

Tôi sử dụng ví dụ này ở trên để làm cho bạn biết rằng có thể có một số cấu hình cụ thể mà bạn sẽ phải thực hiện ngoài docker-compose.ymltệp có thể dành riêng cho dự án của bạn.

Bây giờ, nếu bạn thấy mình làm việc với ứng dụng Nodejs và bạn muốn đảm bảo rằng bạn biết về cổng mặc định mà Nodejs sử dụng, vì vậy tôi sẽ thêm điều này:

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

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

Vì vậy, Docker sẽ thấy rằng ứng dụng Node đang tìm kiếm redis-servervà chuyển hướng kết nối đó đến container đang chạy này.

Toàn bộ thời gian, Dockerfilechỉ có điều này:

FROM node:alpine

WORKDIR '/app'

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

CMD ["npm", "start"]

Vì vậy, trong khi trước đó bạn sẽ phải chạy docker run myimageđể tạo một phiên bản của tất cả các vùng chứa hoặc dịch vụ bên trong tệp mà bạn có thể chạy docker-compose upvà bạn không phải chỉ định một hình ảnh vì Docker sẽ tìm trong thư mục làm việc hiện tại và tìm kiếm một docker-compose.ymltập tin bên trong đó.

Trước đây docker-compose.yml, chúng tôi đã phải đối phó với hai lệnh riêng biệt docker build .docker run myimage, nhưng docker-composetrên thế giới nếu bạn muốn xây dựng lại hình ảnh của mình, bạn viết docker-compose up --build. Điều đó nói với Docker khởi động lại các container nhưng xây dựng lại để có những thay đổi mới nhất.

Vì vậy, docker-composelàm cho nó dễ dàng hơn để làm việc với nhiều container. Lần tới khi bạn cần bắt đầu nhóm container này trong nền bạn có thể làm docker-compose up -dvà để ngăn chặn chúng, bạn có thể làm docker-compose down.


14
@Chris Gần như có 3 năm kiến ​​thức đáng giá giữa câu trả lời này và câu trả lời được chấp nhận.
Naruto Sempai

Tôi tự hỏi nếu có lý do tốt để tôi sử dụng docker-compose upnếu chỉ một dịch vụ trong tình huống của tôi? Một từ khác, so sánh với docker run xxx, bất kỳ lợi ích nếu tôi sử dụng docker-compose up?
trực tuyến

@atline xem phản hồi của Pansoul đối với stackoverflow.com/a/45549372/3366962 về lợi ích của việc sử dụng docker-composecho các container đơn lẻ
go2null

1
@PaulRazvanBerg phần "Hoặc" của bạn là chính xác (và 6379là cổng mặc định của Redis).
KrishPrabakar

1
Các ví dụ cho docker-compose.yml đã giúp tôi trả lời một số câu hỏi tôi có về docker-compose. Câu trả lời được chấp nhận là không hữu ích, đặc biệt đối với những người mới sử dụng docker.
maulik13

43

Trong quy trình làm việc của mình, tôi thêm Dockerfile cho từng phần trong hệ thống của mình và định cấu hình nó để mỗi phần có thể chạy riêng lẻ. Sau đó, tôi thêm một docker-compose.yml để mang chúng lại với nhau và liên kết chúng.

Lợi thế lớn nhất (theo ý kiến ​​của tôi): khi liên kết các container , bạn có thể xác định tên và ping các container của mình bằng tên này. Do đó, cơ sở dữ liệu của bạn có thể được truy cập bằng tên dbvà không còn bằng IP của nó.


Bạn có thể giải thích thêm về việc truy cập db theo tên không?
Vedran Maricevic.

Trên phần nào? Trong docker-compose, nó là tầm thường, bởi vì đó là cách thông thường khi xác định dịch vụ của bạn để đặt tên và có thể truy cập mà không cần phải định cấu hình. Trong CI của chúng tôi, tôi đang tạo một mạng, tạo container trong mạng này và đặt tên cho chúng. Sau đó, bạn cũng có thể truy cập chúng bằng tên của chúng bên trong các thùng chứa (không phải từ máy chủ lưu trữ)
n2o

Ý tôi là trong nhà soạn nhạc. Vì vậy, tôi liên kết các hình ảnh trong trình soạn thảo và trong cấu hình Ứng dụng của tôi thay vì IP, tôi nhắm mục tiêu MySQL bằng bất kỳ tên nào tôi đã đặt nó trong tệp soạn thảo?
Vedran Maricevic.

Đúng rồi. Bạn thậm chí không phải chỉ định một liên kết. Chúng được liên kết theo mặc định nếu mạng không được chỉ định khác nhau. Trong ví dụ này , dịch vụ "web" có thể ping máy chủ "redis" bằng tên "redis"
n2o

37

"tốt hơn" là tương đối. Tất cả phụ thuộc vào nhu cầu của bạn là gì. Docker compose là để phối hợp nhiều container. Nếu những hình ảnh này đã tồn tại trong sổ đăng ký docker, thì tốt hơn là liệt kê chúng trong tệp soạn thảo. Nếu những hình ảnh này hoặc một số hình ảnh khác phải được xây dựng từ các tệp trên máy tính của bạn, thì bạn có thể mô tả các quy trình xây dựng những hình ảnh đó trong Dockerfile.

Tôi hiểu rằng Dockerfiles được sử dụng trong Docker Compose, nhưng tôi không chắc liệu có nên thực hiện mọi thứ trong một Dockerfile lớn với nhiều lệnh TỪ cho các hình ảnh khác nhau không?

Sử dụng nhiều TỪ trong một dockerfile không phải là một ý tưởng hay vì có một đề xuất để loại bỏ tính năng này. 13026

Ví dụ: bạn muốn dockerize một ứng dụng sử dụng cơ sở dữ liệu và có các tệp ứng dụng trên máy tính của bạn, bạn có thể sử dụng một tệp soạn thảo cùng với một dockerfile như sau

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

30

Dockerfile và Docker Compose là hai khái niệm khác nhau trong Dockerland. Khi chúng ta nói về Docker, những điều đầu tiên xuất hiện là phối hợp, ảo hóa cấp độ hệ điều hành, hình ảnh, thùng chứa, v.v. Tôi sẽ cố gắng giải thích từng vấn đề như sau:

Hình ảnh: Hình ảnh là một tập tin bất biến, có thể chia sẻ được lưu trữ trong sổ đăng ký tin cậy Docker. Một hình ảnh Docker được xây dựng từ một loạt các lớp chỉ đọc. Mỗi lớp đại diện cho một hướng dẫn đang được đưa ra trong Dockerfile của hình ảnh. Một hình ảnh chứa tất cả các nhị phân cần thiết để chạy.

nhập mô tả hình ảnh ở đây

Container: Một thể hiện của hình ảnh được gọi là container . Một container chỉ là một nhị phân hình ảnh thực thi được chạy bởi hệ điều hành máy chủ. Một hình ảnh đang chạy là một container.

nhập mô tả hình ảnh ở đây

Dockerfile: Dockerfile là một tài liệu văn bản chứa tất cả các lệnh / hướng dẫn xây dựng, người dùng có thể gọi trên dòng lệnh để lắp ráp một hình ảnh. Điều này sẽ được lưu dưới dạng a Dockerfile. (Lưu ý chữ thường 'f'.)

nhập mô tả hình ảnh ở đây

Docker-Compose: Compose là một công cụ để xác định và chạy các ứng dụng Docker đa container. Với Compose, bạn sử dụng tệp YAML để định cấu hình dịch vụ (bộ chứa) của ứng dụng. Sau đó, với một lệnh duy nhất, bạn tạo và bắt đầu tất cả các dịch vụ từ cấu hình của mình. Tệp Soạn sẽ được lưu dưới dạng docker-compose.yml.


14

Hãy tưởng tượng bạn là người quản lý của một công ty phần mềm và bạn vừa mua một máy chủ hoàn toàn mới. Chỉ là phần cứng.

Hãy nghĩ về Dockerfilemột bộ hướng dẫn mà bạn sẽ nói với người quản trị hệ thống của mình những gì cần cài đặt trên máy chủ hoàn toàn mới này. Ví dụ:

  • Chúng tôi cần một linux Debian
  • thêm một máy chủ web apache
  • chúng ta cũng cần postgresql
  • cài đặt chỉ huy nửa đêm
  • khi hoàn tất, hãy sao chép tất cả các tệp * .php, * .jpg, v.v. của dự án của chúng tôi vào webroot của máy chủ web ( /var/www)

Ngược lại, hãy nghĩ về docker-compose.ymlmột bộ hướng dẫn bạn sẽ nói với quản trị viên hệ thống của mình về cách máy chủ có thể tương tác với phần còn lại của thế giới. Ví dụ,

  • nó có quyền truy cập vào một thư mục được chia sẻ từ một máy tính khác,
  • Cổng 80 giống với cổng 8000 của máy tính chủ,
  • và như thế.

(Đây không phải là một lời giải thích chính xác nhưng đủ tốt để bắt đầu.)


4

Dockerfiles là để xây dựng một hình ảnh ví dụ từ Ubuntu xương trần, bạn có thể thêm mysqlđược gọi mySQLtrên một hình ảnh và mywordpresstrên một hình ảnh thứ hai được gọi mywordpress.

Soạn các tệp YAML là để chụp những hình ảnh này và chạy chúng một cách cố kết. ví dụ: nếu bạn có trong docker-compose.ymltệp của mình một cuộc gọi dịch vụ db:

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

và một dịch vụ được gọi là worpress như:

wordpress: 
    image: mywordpress

sau đó bên trong bộ chứa mywordpress bạn có thể sử dụng dbđể kết nối với bộ chứa myQuery của bạn. Điều kỳ diệu này là có thể bởi vì máy chủ docker của bạn tạo ra một cầu nối mạng (lớp phủ mạng).


0

Trong thế giới microservice (có một cơ sở mã hóa chung), mỗi microservice sẽ có một Dockerfilecấp độ gốc (thường nằm ngoài tất cả các Dịch vụ của micros và nơi POM cha mẹ của bạn cư trú), bạn sẽ xác định một docker-compose.ymlnhóm tất cả các Dịch vụ của microsoft thành một ứng dụng toàn diện.

Trong trường hợp của bạn, "Docker Compose" được ưu tiên hơn "Dockerfile". Hãy nghĩ "Ứng dụng" Hãy nghĩ "Soạn".


0

Dockerfile là một tệp chứa các lệnh văn bản để lắp ráp một hình ảnh.

Docker compose được sử dụng để chạy một môi trường nhiều container.

Trong kịch bản cụ thể của bạn, nếu bạn có nhiều dịch vụ cho mỗi công nghệ bạn đã đề cập (dịch vụ 1 sử dụng reddis, dịch vụ 2 sử dụng thỏ mq, v.v.), thì bạn có thể có Dockerfile cho mỗi dịch vụ và một docker-compose.yml chung để chạy tất cả "Dockerfile" là container.

Nếu bạn muốn tất cả chúng trong một dịch vụ duy nhất, docker-compose sẽ là một lựa chọn khả thi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.