Durch die Erweiterung von Peter Graingers Antwort konnte ich das Mehrschicht-Build nutzen, das seit Docker 17.05 verfügbar ist. Die offizielle Seite besagt:
Mit Mehrschicht-Builds verwendest du mehrere FROM
-Anweisungen in deinem Dockerfile. Jede FROM
-Anweisung kann eine unterschiedliche Basis verwenden, und jede davon startet eine neue Stufe des Builds. Du kannst Artefakte selektiv von einer Stufe zur anderen kopieren und dabei alles zurücklassen, was du nicht im endgültigen Bild haben möchtest.
Unter Berücksichtigung dessen ist hier mein Beispiel eines Dockerfile
mit drei Build-Stufen. Es soll ein Produktionsbild der Client-Webanwendung erstellen.
# Stufe 1: Quellen von npm und git über SSH erhalten
FROM node:carbon AS Quellen
ARG SSH_KEY
ARG SSH_KEY_PASSPHRASE
RUN mkdir -p /root/.ssh && \
chmod 0700 /root/.ssh && \
ssh-keyscan bitbucket.org > /root/.ssh/known_hosts && \
echo "${SSH_KEY}" > /root/.ssh/id_rsa && \
chmod 600 /root/.ssh/id_rsa
WORKDIR /app/
COPY package*.json yarn.lock /app/
RUN eval `ssh-agent -s` && \
printf "${SSH_KEY_PASSPHRASE}\n" | ssh-add $HOME/.ssh/id_rsa && \
yarn --pure-lockfile --mutex file --network-concurrency 1 && \
rm -rf /root/.ssh/
# Stufe 2: Bau des minimierten Produktionscodes
FROM node:carbon AS Produktion
WORKDIR /app/
COPY --from=Quellen /app/ /app/
COPY . /app/
RUN yarn build:prod
# Stufe 3: Enthält nur erstellte Produktionsdateien und hostet sie mit Node Express Server
FROM node:carbon
WORKDIR /app/
RUN yarn add express
COPY --from=Produktion /app/dist/ /app/dist/
COPY server.js /app/
EXPOSE 33330
CMD ["node", "server.js"]
.dockerignore
wiederholt die Inhalte der .gitignore
Datei (es verhindert das Kopieren der Verzeichnisse node_modules
und dist
des Projekts):
.idea
dist
node_modules
*.log
Beispielbefehl zum Erstellen eines Bildes:
$ docker build -t ezze/geoport:0.6.0 \
--build-arg SSH_KEY="$(cat ~/.ssh/id_rsa)" \
--build-arg SSH_KEY_PASSPHRASE="mein_super_geheim" \
./
Wenn dein privater SSH-Schlüssel keine Passphrase hat, gib einfach das leere SSH_KEY_PASSPHRASE
Argument an.
So funktioniert es:
1). In der ersten Stufe werden nur die Dateien package.json
, yarn.lock
Dateien und der private SSH-Schlüssel in das erste Zwischenbild namens Quellen
kopiert. Um weitere Passwortabfragen für den SSH-Schlüssel zu vermeiden, wird er automatisch zu ssh-agent
hinzugefügt. Schließlich installiert der yarn
Befehl alle erforderlichen Abhängigkeiten von NPM und klonen private Git-Repositories von Bitbucket über SSH.
2). Die zweite Stufe baut und minimiert den Quellcode der Webanwendung und platziert ihn im dist
Verzeichnis des nächsten Zwischenbildes namens Produktion
. Beachte, dass der Quellcode der installierten node_modules
vom Bild namens Quellen
kopiert wird, das in der ersten Stufe erzeugt wurde, durch diese Zeile:
COPY --from=Quellen /app/ /app/
Es könnte auch die folgende Zeile sein:
COPY --from=Quellen /app/node_modules/ /app/node_modules/
Hier haben wir nur das Verzeichnis node_modules
aus dem ersten Zwischenbild, keine SSH_KEY
und SSH_KEY_PASSPHRASE
Argumente mehr. Alle restlichen für den Build erforderlichen Dateien werden aus unserem Projektverzeichnis kopiert.
3). In der dritten Stufe reduzieren wir die Größe des endgültigen Bildes, das als ezze/geoport:0.6.0
getaggt wird, indem nur das dist
Verzeichnis aus dem zweiten Zwischenbild namens Produktion
und das Installieren von Node Express für das Starten eines Webservers enthalten ist.
Das Auflisten der Bilder ergibt eine Ausgabe wie diese:
REPOSITORY TAG IMAGE ID CREATED SIZE
ezze/geoport 0.6.0 8e8809c4e996 vor 3 Stunden 717MB
1f6518644324 vor 3 Stunden 1.1GB
fa00f1182917 vor 4 Stunden 1.63GB
node carbon b87c2ad8344d vor 4 Wochen 676MB
wo nicht getaggte Bilder den ersten und den zweiten Zwischenbaustufen entsprechen.
Wenn du
$ docker history ezze/geoport:0.6.0 --no-trunc
ausführst, wirst du keine Erwähnungen von SSH_KEY
und SSH_KEY_PASSPHRASE
im endgültigen Bild sehen.