Gibt es eine Möglichkeit, Docker-Bilder in einem Container zu kombinieren?


79

Ich habe gerade ein paar Dockerfiles.

Eine ist für Cassandra 3.5 und es ist FROM cassandra:3.5

Ich habe auch eine Docker-Datei für Kafka, aber es ist ziemlich viel komplexer. Es ist FROM java:openjdk-8-freund es führt einen langen Befehl aus, um Kafka und Zookeeper zu installieren.

Schließlich habe ich eine Anwendung in Scala geschrieben, die SBT verwendet.

Für diese Docker-Datei bekomme FROM broadinstitute/scala-baseimageich Java 8, Scala 2.11.7 und STB 0.13.9, die ich brauche.

Vielleicht verstehe ich nicht, wie Docker funktioniert, aber mein Scala-Programm hat Cassandra und Kafka als Abhängigkeiten und für Entwicklungszwecke möchte ich, dass andere mein Repo einfach mit dem klonen Dockerfileund es dann mit Cassandra, Kafka erstellen können , Scala, Java und SBT sind alle eingebrannt, damit sie nur die Quelle kompilieren können. Ich habe jedoch viele Probleme damit.

Wie kombiniere ich diese Docker-Dateien? Wie mache ich einfach eine Umgebung mit diesen eingebrannten Dingen?


6
Sie kombinieren keine Docker-Bilder, sondern
generalhenry

@generalhenry, wenn ich wollte, könnte ich nicht einfach Docker-Inhalte kopieren und einfügen, die für Cassandra 3.5 erforderlich sind, und diese in meine Haupt-Docker-Datei einfügen, die mir Java, Scala und SBT bietet?
David

Während Sie alles in einem einzigen Container zum Laufen bringen könnten, ist dies selten wünschenswert. Mit Containern können Sie Ihr Netzwerk, Ihre Skalierung, Protokollierung, Überwachung usw. Sauber trennen. . .
Generalhenry

1
@generalhenry Klar, das ist oft was du machen willst. Aber was ist, wenn Sie Rost benötigen, um ein binäres Python-Paket aus PyPi zu kompilieren? In diesem Fall möchten Sie möglicherweise Rost- und Python-Docker-Bilder kombinieren. Das Komponieren funktioniert nicht.
Tobias Bergkvist

Antworten:


89

Mit der in Docker 1.17 eingeführten Funktion für mehrstufige Builds können Sie dies tun

Schau dir das an:

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"]  

Erstellen Sie dann das Image normal:

docker build -t alexellis2/href-counter:latest

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

Das Endergebnis ist das gleiche winzige Produktionsbild wie zuvor mit einer signifikanten Reduzierung der Komplexität. Sie müssen keine Zwischenbilder erstellen und Sie müssen überhaupt keine Artefakte auf Ihr lokales System extrahieren.

Wie funktioniert es? Die zweite FROM-Anweisung startet eine neue Build-Phase mit dem alpinen: neuesten Bild als Basis. Die Zeile COPY --from = 0 kopiert nur das erstellte Artefakt aus der vorherigen Stufe in diese neue Stufe. Das Go SDK und alle Zwischenartefakte bleiben zurück und werden nicht im endgültigen Bild gespeichert.


5
Angenommen, ich möchte zwei Basisbilder kombinieren, die viel los sind und nicht von mir gepflegt werden. Wenn ich beispielsweise eine Rust-App mit GPU-Beschleunigung ausführen möchte, möchte ich, dass mein Image aus nvidia-dockerund zusammengeführt wird rustlang/rust:nightly. Diese Bilder werden wiederum auf andere Bilder gelegt. Um dies mit mehrschichtigen Builds zu tun, muss ich alle Dateien von einem der Bilder kennen und angeben, die auf das andere Bild kopiert werden sollen - dies scheint unmöglich, zumal sich dieser Satz ändern kann, wenn sich das Upstream-Bild ändert. Lese ich das richtig
Masonk

3
@masonk Ich hatte Erfolg damit: FROM a/a:latest FROM b/b:latest COPY --from=0 / / Wahrscheinlich schreckliche Übung, aber es funktioniert. Es war hauptsächlich aus eigener Neugier als etwas, das ich in der Produktion verwenden würde.
McP

4
Das verdammte Ding funktioniert bei mir nicht. Es ist, als würde das erste "FROM" komplett ignoriert.
DimiDak

Gleiches hier: Ich möchte es tun FROM image1; CMD image1command; FROM image2; CMD image2command;Es funktioniert überhaupt nicht. Immer nur der 2. Befehl
CGFoX

das macht den Zweck von Containern zunichte, nicht wahr?
Luiz Felipe

22

Sie können Docker-Dateien nicht kombinieren, da Konflikte auftreten können. Sie möchten eine neue Docker-Datei erstellen oder ein benutzerdefiniertes Image erstellen.

TL; DR; Wenn Ihr aktueller Entwicklungscontainer alle Tools enthält, die Sie benötigen und funktionieren, speichern Sie ihn als Image und darauf in einem Repo und erstellen Sie eine Docker-Datei, um dieses Image von diesem Repo abzurufen.

Details: Das Erstellen eines benutzerdefinierten Images ist weitaus einfacher als das Erstellen einer Docker-Datei mit einem öffentlichen Image, da Sie alle Hacks und Mods im Image speichern können. Starten Sie dazu einen leeren Container mit einem einfachen Linux-Image (oder Broadinstitute / Scala-Baseimage), installieren Sie alle benötigten Tools und konfigurieren Sie sie, bis alles ordnungsgemäß funktioniert, und speichern Sie sie (den Container) als Image. Erstellen Sie einen neuen Container aus diesem Image und testen Sie, ob Sie Ihren Code über Docker-Compose darauf aufbauen können (oder wie auch immer Sie ihn erstellen möchten). Wenn es funktioniert, haben Sie ein funktionierendes Basis-Image, das Sie in ein Repo hochladen können, damit andere es abrufen können.

Um eine Docker-Datei mit einem öffentlichen Image zu erstellen, müssen Sie alle Hacks, Mods und Setups in die Docker-Datei selbst einfügen. Das heißt, Sie müssen jede Befehlszeile, die Sie verwendet haben, in eine Textdatei einfügen und alle Hacks, Mods und Einstellungen in Befehlszeilen reduzieren. Am Ende erstellt Ihre Docker-Datei automatisch ein Bild und Sie müssen dieses Bild nicht in einem Repo speichern. Sie müssen lediglich anderen die Docker-Datei geben und sie können das Bild in ihrem eigenen Docker hochfahren.

Beachten Sie, dass Sie eine funktionierende Docker-Datei einfach anpassen können, sobald Sie eine Docker-Datei verwenden. Bei einem benutzerdefinierten Image können Probleme auftreten, bei denen Sie das Image aufgrund von Konflikten neu erstellen müssen. Beispielsweise arbeiten alle Ihre Tools mit openjdk, bis Sie eines installieren, das nicht funktioniert. Das Update beinhaltet möglicherweise die Deinstallation von openjdk und die Verwendung von Oracle One, aber alle Konfigurationen, die Sie für alle von Ihnen installierten Tools vorgenommen haben, sind fehlerhaft.


9

Die folgende Antwort gilt für Docker 1.7 und höher:

Ich würde es vorziehen zu verwenden --from=NAMEund from image as NAME warum? Sie können --from=0und höher verwenden, aber dies kann etwas schwierig zu verwalten sein, wenn Sie viele Docker-Phasen in Docker-Datei haben.

Beispielbeispiel:

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"]

Hinweis: Wenn Sie die Docker-Datei ordnungsgemäß verwalten, kann ein Docker-Image schneller erstellt werden. Intern verwendet Docker Docker-Layer-Caching, um diesen Prozess zu unterstützen, falls das Image neu erstellt werden muss.


6

Ja, Sie können eine ganze Menge Software in ein einzelnes Docker-Image rollen ( GitLab tut dies mit einem Image, das Postgres und alles andere enthält), aber Generalhenry ist richtig - das ist nicht die typische Art, Docker zu verwenden.

Wie Sie sagen, sind Cassandra und Kafka Abhängigkeiten für Ihre Scala-App. Sie sind nicht Teil der App, daher gehören nicht alle zum selben Bild.

Wenn Sie viele Container mit Docker Compose orchestrieren müssen, wird eine zusätzliche Administratorebene hinzugefügt, die Ihnen jedoch viel mehr Flexibilität bietet:

  • Ihre Container können unterschiedliche Lebensdauern haben. Wenn Sie also eine neue Version Ihrer App bereitstellen möchten, müssen Sie nur einen neuen App-Container ausführen. Sie können die Abhängigkeiten laufen lassen.
  • Sie können dasselbe App-Image in jeder Umgebung verwenden und unterschiedliche Konfigurationen für Ihre Abhängigkeiten verwenden. In dev können Sie beispielsweise einen einfachen Kafka-Container ausführen und in prod auf vielen Knoten gruppieren. Ihr App-Container ist derselbe.
  • Ihre Abhängigkeiten können auch von anderen Apps verwendet werden. So können mehrere Verbraucher in unterschiedlichen Containern ausgeführt werden und alle arbeiten mit denselben Kafka- und Cassandra-Containern.
  • plus all die bereits erwähnten Skalierbarkeit, Protokollierung usw.

3

Sie konnten Docker-Bilder nicht in einem Container kombinieren. Sehen Sie die Detail Diskussionen in Moby Frage, Wie kann ich mehrere Bilder zu einem über Dockerfile kombinieren .

Für Ihren Fall ist es besser, nicht die gesamten Bilder von Cassandra und Kafka einzuschließen. Die Anwendung würde nur den Cassandra Scala-Treiber und den Kafka Scala-Treiber benötigen. Der Container sollte nur die Treiber enthalten.


2

Docker führt keine Zusammenführungen der Bilder durch, aber nichts hindert Sie daran, die Docker-Dateien, falls verfügbar, zu kombinieren und in sie zu einem fetten Bild zu rollen, das Sie erstellen müssten. Es gibt jedoch Zeiten, in denen dies sinnvoll ist, da für die Ausführung mehrerer Prozesse in einem Container die meisten Docker-Dogmen darauf hinweisen, dass dies insbesondere bei der Microservice-Architektur weniger wünschenswert ist (jedoch müssen Regeln gebrochen werden, oder?).


1

Ich brauchte Docker: Neueste und Python: Neueste Bilder für Gitlab CI. Folgendes habe ich mir ausgedacht:

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

Nachdem ich es erstellt und in mein Docker Hub-Repo verschoben habe:

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

Vergessen Sie nicht, docker loginbevor Sie drücken

Ich hoffe es hilft

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.