Есть ли способ объединить образы 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. Контейнер должен включать только драйверы.

CloudStax
источник
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перед нажатием

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

Михаил Белкин
источник