2016-12-04 1 views
9

Ich habe ein Docker wie die folgende Datei:Wie reduziere ich meine Java/Gradle Docker Bildgröße?

FROM openjdk:8 

ADD . /usr/share/app-name-tmp 

WORKDIR /usr/share/app-name-tmp 

RUN ./gradlew build \ 
    mv ./build/libs/app-name*.jar /usr/share/app-name/app-name.jar 

WORKDIR /usr/share/app-name 

RUN rm -rf /usr/share/app-name-tmp 

EXPOSE 8080 

RUN chmod +x ./docker-entry.sh 

ENTRYPOINT [ "./docker-entry.sh" ] 

Das Problem ist, dass die endgültige Bildgröße 1,1 GB ist, ich weiß, geschieht es, weil gradle herunter und speichert alle Abhängigkeiten. Was ist der beste Weg, um diese unnötigen Dateien zu entfernen und nur das Glas zu halten?

Antwort

4

Jede RUN-Anweisung erstellt eine neue Ebene über dem vorhandenen Dateisystem. So maskiert der neue Layer nach der RUN-Anweisung, der Sie löscht app-name-tmp Verzeichnis nur die vorherige Ebene, die die heruntergeladenen Bibliotheken enthält. Daher hat Ihr Docker-Bild immer noch die Größe aller erstellten Ebenen.

Entfernen Sie die separate RUN rm -rf /usr/share/app-name-tmp Anweisung und fügen Sie sie in die gleiche RUN-Anweisung ein, die wie unten gezeigt aufgebaut wird.

RUN ./gradlew build \ 
    mv ./build/libs/app-name*.jar /usr/share/app-name/app-name.jar \ 
    rm -rf /usr/share/app-name-tmp/* 

Also, Ihre endgültige Dockerfile würde

FROM openjdk:8 

ADD . /usr/share/app-name-tmp 
WORKDIR /usr/share/app-name-tmp 

RUN ./gradlew build \ 
    mv ./build/libs/app-name*.jar /usr/share/app-name/app-name.jar \ 
    rm -rf /usr/share/app-name-tmp/* 

WORKDIR /usr/share/app-name 

EXPOSE 8080 
RUN chmod +x ./docker-entry.sh 
ENTRYPOINT [ "./docker-entry.sh" ] 

Das Bild aufgebaut wird, summiert sich sein noch Größe aus dem Verzeichnis/usr/share/app-name-tmp.

+0

Das Basisbild könnte ein wenig beitragen, aber das ist die echte Antwort. Leider hat Docker die "verschachtelten Builds" nicht angesprochen (https://github.com/docker/docker/issues/7115). Die Art und Weise, wie ich mich im Allgemeinen damit beschäftigt habe, hat getrennte "Build" - und "Runtime" -Bilder, um die Docker-Beschränkungen zu handhaben. Sehen Sie [diesen Artikel] (https://www.fpcomplete.com/blog/2015/12/docker-split-images) für einen möglichen Weg, mit dem Problem umzugehen. – mkobit

+0

@mkobit Sie können jetzt mehrstufige Builds verwenden, um dieses Problem zu adressieren https://docs.docker.com/engine/userguide/eng-image/multistage-build/ –

+1

@ GuidoGarcía guten Punkt! Könnte eine gute Gelegenheit für eine neue Antwort sein oder um diese zu verbessern. – mkobit

1

Es scheint, Ihr Bild stammt aus

FROM openjdk:8

so von

https://github.com/docker-library/openjdk/blob/e6e9cf8b21516ba764189916d35be57486203c95/8-jdk/Dockerfile

und in der Tat ein Debian

FROM buildpack-deps:jessie-scm

Sie s hould versuchen, eine Alpine Basis

https://github.com/docker-library/openjdk/blob/9a0822673dffd3e5ba66f18a8547aa60faed6d08/8-jdk/alpine/Dockerfile

ich dein Bild Hälfte zumindest sein erraten zu verwenden, um die Größe

+0

Ich weiß über Alpine, aber ich möchte weiterhin das Bild 'openjdk: 8' verwenden. Es ist ~ 650MB, aber meine Anwendung fügt im Build-Schritt ./gradlew etwa 500MB hinzu. – diugalde

6

Ich bin wirklich verwirrt über Ihre Bildgröße. Ich habe typische Spring Boot-Anwendungen, die einen REST-Service mit einem eingebetteten Servlet-Container in weniger als 200 MB bieten! Ihre Projektabhängigkeiten können und sollten optimiert werden.

Docker Bild

Die openjdk:8 (243MB komprimiert) durch eine mit einem reduzierten Alpine Unix-Bild wie openjdk:8-jdk-alpine (52MB) als Basisbild ersetzt werden, aber wenn Sie benötigen Compiler-Funktionen nicht (zB don Wenn Sie keine JSPs verwenden, können Sie auch openjdk:8-jre-alpine (42MB) wählen, was nur die Laufzeit einschließt. Schauen Sie in Docker Hub. Ich verwende das für Spring Boot-basierte REST-Dienste, die großartig funktionieren.

Java Abhängigkeiten

Die Java benötigt Abhängigkeiten für Kompilierung und Laufzeit haben eingeschlossen werden, aber Sie können nicht verwendete Abhängigkeiten enthalten:

  • Ihre Abhängigkeiten überprüfen, sind die aktuellen Kompilierung/runtime Abhängigkeiten wirklich verwendet oder kann möglicherweise entfernt oder verschoben werden, um zu testen, siehe Gradle Java Plugin
  • einige Abhängigkeiten haben eine Vielzahl von transitiven Abhängigkeiten (Anzeige mit gradle dependencies), check out für unnötige andere und schließen sie aus, wenn sie nicht benutzt werden, siehe Gradle Dependency Management. Stellen Sie sicher, dass Sie Integrationstests durchführen, bevor Sie sich endgültig bewerben. Einige transitive Abhängigkeiten sind nicht gut dokumentiert, können aber wesentlich sein!
+1

Wenn ich ./gradlew build ausführen, ist die resultierende jar nur 95 MB, aber die Bildgröße ist um 1GB – diugalde

+0

Warum Sie Gradle von Andockfenster ausführen und was ist in den Verzeichnissen, die Sie hinzufügen? Ich benutze grddle docker plugin und nur hinzufügen, das Glas, um das Bild Aufruf Docker von Gradle und nicht umgekehrt –

0

Ist dies der Container, den Sie in der Produktion bereitstellen? Wenn ja, verwende es nicht für den eigentlichen Build. Mach das Build (und das Testen) woanders und kopiere nur das JAR in deinen Docker-Produktionscontainer, sobald es gesegnet ist.

3

Mit Docker 17.05+ können Sie multi-stage builds verwenden.

„Mit mehrstufigen baut, mehrere FROM-Anweisungen in Ihrem Dockerfile verwenden. Jede FROM-Anweisung eine andere Basis verwenden können, und jeder von ihnen beginnt eine neue Phase des Build. Sie können Artefakte aus einer selektiv kopieren Bühne zu anderen, hinter allem, was Sie nicht im endgültigen Bild wollen. "

So Ihre Dockerfile könnte wie folgt aussehen:

# 
# first stage (build) 
# 
FROM openjdk:8 as build 

ADD . /usr/share/app-name-tmp 

WORKDIR /usr/share/app-name-tmp 

RUN ./gradlew build && \ 
    mv ./build/libs/app-name*.jar /usr/share/app-name/app-name.jar 

# 
# second stage. use alpine to reduce the image size 
# 
FROM openjdk:8-jre-alpine 

WORKDIR /usr/share/app-name 

COPY --from=build /usr/share/app-name/app-name.jar . 

EXPOSE 8080 

RUN chmod +x ./docker-entry.sh 

ENTRYPOINT [ "./docker-entry.sh" ] 

diese Weise können Sie halten nur das Glas und alle nicht benötigten Dateien werden nicht im endgültigen Bild enthalten.

+1

Sollte es nicht "COPY --from = build" sein, da die erste Stufe 'build' heißt (nicht' builder')? –

Verwandte Themen