Есть ли способ объединить образы Docker в 1 контейнер?


86

У меня сейчас есть несколько Dockerfiles.

Один для Cassandra 3.5, и это FROM cassandra:3.5

У меня также есть Dockerfile для Kafka, но это немного сложнее. Это FROM java:openjdk-8-freи запускает длинную команду для установки Kafka и Zookeeper.

Наконец, у меня есть приложение, написанное на Scala, которое использует SBT.

Это для этого Dockerfile, FROM broadinstitute/scala-baseimageкоторый дает мне Java 8, Scala 2.11.7 и STB 0.13.9, что мне и нужно.

Возможно, я не понимаю, как работает Docker, но моя программа Scala имеет Cassandra и Kafka в качестве зависимостей, и для целей разработки я хочу, чтобы другие могли просто клонировать мое репо с помощью, Dockerfileа затем иметь возможность создавать его с помощью Cassandra, Kafka , Scala, Java и SBT встроены, так что они могут просто скомпилировать исходный код. Хотя у меня с этим много проблем.

Как мне объединить эти Dockerfiles? Как мне просто создать среду из этих вещей?


6
Вы не объединяете образы докеров
— generalhenry

@generalhenry, если бы я хотел, не мог бы я просто скопировать и вставить докеры, необходимые для получения Cassandra 3.5, и поместить их в свой основной файл Docker, который дает мне Java, Scala и SBT?
— Дэвид

Хотя вы можете запустить все в одном контейнере, это редко бывает желательно. Контейнеры позволяют четко разделить вашу сеть, масштабирование, ведение журнала, мониторинг и т. Д. . .
— Generalhenry

2
@generalhenry Конечно, часто это то, чем вы хотите заниматься. Но что, если вам понадобится ржавчина для компиляции двоичного пакета python из PyPi? В этом случае вы можете объединить образы докеров rust и python. Составить их не получится.
— Тобиас Бергквист

Ответы:


92

Вы можете с помощью функции многоэтапных сборок, представленной в Docker 1.17

Взгляните на это:

FROM golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]  

Затем создайте образ как обычно:

docker build -t alexellis2/href-counter:latest

От: https://docs.docker.com/develop/develop-images/multistage-build/

Конечный результат - тот же крошечный производственный образ, что и раньше, со значительным уменьшением сложности. Вам не нужно создавать какие-либо промежуточные изображения, и вам вообще не нужно извлекать какие-либо артефакты в вашу локальную систему.

Как это работает? Вторая инструкция FROM запускает новый этап сборки с образом alpine: latest в качестве основы. Строка COPY --from = 0 копирует только построенный артефакт из предыдущего этапа в этот новый этап. Go SDK и любые промежуточные артефакты остаются позади и не сохраняются в конечном изображении.


7
Предположим, я хочу объединить два базовых изображения, в которых много чего происходит и которые я не поддерживаю. Например, если я хочу запустить приложение Rust с ускорением графического процессора, я хочу, чтобы мое изображение было объединением nvidia-dockerи rustlang/rust:nightly. Эти изображения, в свою очередь, накладываются поверх других изображений. Чтобы сделать это с использованием многослойных сборок, я должен знать и указать все файлы из одного из изображений, которые я хочу скопировать на другое изображение - это кажется невозможным, особенно потому, что этот набор может изменяться всякий раз, когда изменяется исходное изображение. Я правильно читаю?
— masonk

3
@masonk Я добился успеха: FROM a/a:latest FROM b/b:latest COPY --from=0 / / Наверное, ужасная практика, но она работает. Это было в основном из моего собственного любопытства, чем из того, что я использовал бы в производстве.
— McP

4
У меня ни хрена не работает. Как будто первое "ОТ" полностью игнорируется.
— DimiDak 05

То же самое здесь: Я хочу сделать FROM image1; CMD image1command; FROM image2; CMD image2command;Это вообще не работает. Всегда только 2-я команда
— CGFoX

это побеждает цель иметь контейнеры, не так ли?
— Луис Фелипе

22

Вы не можете комбинировать файлы докеров, так как могут возникнуть конфликты. Что вы хотите сделать, так это создать новый файл докеров или создать собственный образ.

TL; DR; Если ваш текущий контейнер разработки содержит все необходимые инструменты и работает, то сохраните его как изображение, а затем в репо и создайте файл докеров для извлечения из этого образа из репозитория.

Подробности: создание собственного образа намного проще, чем создание файла докеров с использованием общедоступного образа, поскольку вы можете хранить в образе любые хаки и моды. Для этого запустите пустой контейнер с базовым образом Linux (или broadinstitute / scala-baseimage), установите все необходимые инструменты и настройте их, пока все не будет работать правильно, а затем сохраните его (контейнер) как образ. Создайте новый контейнер из этого образа и проверьте, можете ли вы построить свой код поверх него с помощью docker-compose (или как вы хотите это сделать / построить). Если это работает, значит, у вас есть рабочий базовый образ, который вы можете загрузить в репо, чтобы другие могли его вытащить.

Чтобы создать файл докеров с общедоступным образом, вам нужно будет разместить все хаки, моды и настройки в самом файле докеров. То есть вам нужно будет поместить каждую используемую вами командную строку в текстовый файл и сократить количество хаков, модов и настроек до командных строк. В конце ваш dockerfile создаст образ автоматически, и вам не нужно хранить этот образ в репо, и все, что вам нужно сделать, это предоставить другим dockerfile, и они смогут развернуть образ в своем собственном докере.

Обратите внимание: если у вас есть рабочий файл докеров, вы можете легко настроить его, поскольку он будет создавать новый образ каждый раз, когда вы используете файл докеров. С настраиваемым образом вы можете столкнуться с проблемами, когда вам потребуется перестроить образ из-за конфликтов. Например, все ваши инструменты работают с openjdk, пока вы не установите тот, который не работает. Исправление может включать удаление openjdk и использование oracle one, но вся конфигурация, которую вы выполняли для всех установленных вами инструментов, сломалась.


9

Следующий ответ относится к докеру 1.7 и выше:

Я бы предпочел использовать --from=NAMEи from image as NAME почему? Вы можете использовать --from=0и выше, но это может быть немного сложно, если у вас много этапов докера в файле dockerfile.

примерный пример:

FROM golang:1.7.3 as backend
WORKDIR /backend
RUN go get -d -v golang.org/x/net/html  
COPY app.go .
RUN  #install some stuff, compile assets....

FROM golang:1.7.3 as assets
WORKDIR /assets
RUN ./getassets.sh

FROM nodejs:latest as frontend 
RUN npm install
WORKDIR /assets
COPY --from=assets /asets .
CMD ["./app"] 

FROM alpine:latest as mergedassets
WORKDIR /root/
COPY --from=merge ./
COPY --from=backend ./backend .
CMD ["./app"]

Примечание. Правильное управление файлом dockerfile поможет быстрее создать образ докера. Внутренний докер использует кеширование уровня докера, чтобы помочь в этом процессе, на случай, если изображение придется перестраивать.


7

Да, вы можете свернуть большое количество программного обеспечения в один образ Docker ( GitLab делает это с одним образом, который включает Postgres и все остальное), но в целом Генри прав - это не типичный способ использования Docker.

Как вы говорите, Cassandra и Kafka являются зависимостями для вашего приложения Scala, они не являются частью приложения, поэтому не все принадлежат одному образу.

Необходимость координировать множество контейнеров с помощью Docker Compose добавляет дополнительный уровень администрирования, но дает гораздо больше гибкости:

  • ваши контейнеры могут иметь разный срок службы, поэтому, когда у вас есть новая версия приложения для развертывания, вам нужно только запустить новый контейнер приложения, вы можете оставить все зависимости запущенными;
  • вы можете использовать один и тот же образ приложения в любой среде, используя разные конфигурации для ваших зависимостей - например, в dev вы можете запустить базовый контейнер Kafka, а в prod он будет кластеризован на многих узлах, ваш контейнер приложения такой же;
  • ваши зависимости могут использоваться и другими приложениями, поэтому несколько потребителей могут работать в разных контейнерах, и все они работают с одними и теми же контейнерами Kafka и Cassandra;
  • плюс уже упомянутая масштабируемость, ведение журнала и т. д.

4

Вы не могли объединить образы докеров в 1 контейнер. См. Подробное обсуждение в выпуске Moby, как объединить несколько изображений в один с помощью Dockerfile .

В вашем случае лучше не включать все изображения Cassandra и Kafka. Приложению потребуются только драйвер Cassandra Scala и драйвер Kafka Scala. Контейнер должен включать только драйверы.


2

Docker не выполняет слияние образов, но ничто не мешает вам объединить файлы докеров, если они доступны, и превратить их в толстый образ, который вам нужно будет создать. Однако есть моменты, когда это имеет смысл, поскольку для запуска нескольких процессов в контейнере большинство догм Docker будет указывать на это как на менее желательное, особенно с архитектурой микросервисов (однако правила должны быть нарушены, верно?)


1

Мне понадобились образы docker: latest и python: latest для Gitlab CI. Вот что я придумал:

FROM ubuntu:latest
RUN apt update
RUN apt install -y sudo
RUN sudo apt install -y docker.io
RUN sudo apt install -y python3-pip
RUN sudo apt install -y python3
RUN docker --version
RUN pip3 --version
RUN python3 --version

После того, как я собрал и отправил его в репозиторий Docker Hub:

docker build -t docker-hub-repo/image-name:latest path/to/Dockerfile
docker push docker-hub-repo/image-name:latest

Не забудьте docker loginперед нажатием

Надеюсь, поможет

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.