Zum Hauptinhalt springen

Dockerfile

vollständige Referenz unter dockerdocs - Dockerfile reference

Schlüsselwörter

FROM

  • legt das Basisimage fest
FROM ubuntu:20.04
FROM ubuntu
FROM ubuntu:latest

ADD und COPY

  • kopieren Dateien oder Verzeichnisse vom Host ins Imagedateisystem
COPY samplesite/ /var/www/html
ADD myfonts.tgz /usr/local/share/texmf

Unterschied: ADD kann zusätzlich auch

  • eine URL als Quelle verwenden
  • Archivdateien (tar, gz, ...) automatisch entpacken

Beispiel Dockerfile mit ADD:

Hinweis: Hier funktioniert nur ADD, da man Daten von einer URL herunterlädt.

FROM httpd
ADD https://www.gbssg.ch /usr/local/apache2/htdocs/index.html
RUN chmod 755 /usr/local/apache2/htdocs/index.html
ArgumentBedeutung
--chown=<user>:groupfunktioniert nur auf Linux-Containern, Festlegung der Eigentümer und der Gruppe im Linux-Zielsystem

CMD und ENTRYPOINT

  • Angabe des Programmes
  • dieses wird beim Start eines Containers (mit docker run oder docker start) ausgeführt
CMD ["executable","param1","param2"]
CMD shellcommand

executable: vollständiger Pfad des zu ausführenden Programmes

Unterschied mit und ohne eckige Klammern:

  • mit Klammern
    • direkte Ausführung der ausführbaren Datei
    • Beispiel: CMD ["/script", "param"]
  • ohne Klammern
    • Ausführung des Befehls mit einer Shell
    • wenn keine Shell (unter Linux /bin/sh) verfügbar ist, kann der Befehl nicht ausgeführt werden
    • Beispiel: CMD ./script param

Beispiel:

CMD ["/bin/ls", "/var"]
CMD echo Hello World!

CMD ["mysqld"]
ENTRYPOINT ["docker-entrypoint.sh"]

Unterschied:

  • CMD
    • bei docker run übergebenes Kommando wird anstelle von CMD ausgeführt
  • ENTRYPOINT
    • bei docker run übergebenes Kommando wird als weiterer Parameter zu ENTRYPOINT ausgeführt

RUN

  • Befehle
  • werden einmalig beim Erstellen des Images mit docker build ausgeführt
  • erzeugen dadurch neuen Image-Layer
RUN apt-get update -y && \
apt-get install -y --no-install-recommends \
subversion \
joe \
vim \
less && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

Empfehlung der Dockerdokumentation

  • möglichst viele Befehle in einem RUN-Befehl zusammenfassen, damit nicht für jeden Befehl ein neuer Image-Layer erstellt wird

VOLUME

  • definiert Mount Point auf Verzeichnis auf Host oder anderem Container
  • gibt Verzeichnisse an, welche im Hostsystem oder in einem anderen Container gemountet werden
  • je nachdem, wie der Container gestartet wird, werden die Volumes als unbenannte oder benannte Volumes oder in ein eigenes Verzeichnis eingebunden

Folgendes Beispiel bildet drei Verzeichnisse des Containers auf dem Host ab. Diese Verzeichnisse werden beim Erstellen eines Volumes in diesem gespeichert.

VOLUME ["/data"]
VOLUME ["/var/lib/mysql", "/var/log/mysql"]

ENV

  • definiert Umgebungsvariablen
  • können bei docker run mit einem Wert versehen werden
ENV PORT=3000

Beim Erstellen dieses Images kann mit docker run -e PORT=8000 <image> der Wert von der Umgebungsvariablen PORT neu gesetzt werden.

EXPOSE

  • gibt aktive Ports eines Containers an
  • nur zur Dokumentation:
    • es können auch Ports verwendet werden, welche nicht mit EXPOSE angegeben werden
  • Weiterleitung ist mit docker run -p 8080:80 <image> möglich
EXPOSE 1234

LABEL

  • Festhaltung von Metadaten zum Image
LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."
FROM ubuntu:latest
LABEL "website.name"="geeksforgeeks website"
LABEL "website.tutorial-name"="docker"
LABEL website="geeksforgeeks"
LABEL desc="This is docker tutorial with \
geeksforgeeks website"
LABEL tutorial1="Docker" tutorial2="LABEL INSTRUCTION"

USER

  • setzt Benutzer für folgenden RUN, CMD und ENTRYPOINT Anweisungen
USER patrick

WORKDIR

  • setzt Arbeitsverzeichnis für folgende RUN, CMD, ENTRYPOINT, COPY und ADD Anweisungen
  • nicht existierende Verzeichnisse werden automatisch erstellt
  • eigentlich cd
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

Der Befehl pwd im obigen Beispiel würde /a/b/c ausgeben.

Beispiele Single Stage Image

Beispiel C-Konsolen-Anwendung

FROM gcc:4.9
WORKDIR /app
COPY . .
RUN gcc -o hello -static hello.c
CMD ["./hello"]

Beispiel C#-Konsolen-Anwendung

FROM mcr.microsoft.com/dotnet/sdk:9.0

COPY . /

RUN ["dotnet", "restore"]
RUN ["dotnet", "publish", "-c", "Release", "-o", "out"]

ENTRYPOINT ["out/project-name"]

Damit es funktioniert, muss eventuell noch die ItemGroup zur .proj-Datei hinzufügt werden:


<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<Compile Include="Program.cs"/>
</ItemGroup>
</Project>

Multistage Image

Ein Multistage Image besteht aus mehreren Images, welche nacheinander erstellt werden und welche Daten dann an das nächste Image weitergeben. Alle diese Images befinden sich nacheinander im gleichen Dockerfile. Am Schluss wird nur das letzte Image endgültig erstellt und die Daten der vorherigen werden gelöscht. Dies ermöglicht das Vorbereiten von Dateien in vorherigen Images, damit das End-Image dann kompakter ist.

Beispiel C-Konsolen-Anwendung

FROM gcc:4.9 AS build
COPY . .
RUN gcc -o hello -static hello.c

FROM scratch AS runtime
COPY --from=build /hello /
CMD ["/hello"]

Beispiel C#-Web-Anwendung

  • ENTRYPOINT muss auf die DLL zeigen, die gestartet werden soll
  • WORKDIR sollte besser explizit gesetzt werden, damit die Applikation auch wirklich im richtigen Verzeichnis gestartet wird
# first stage for the build of the application
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS dotnet-build

WORKDIR /build
COPY . .

RUN ["dotnet", "restore"]
RUN ["dotnet", "publish", "-c", "Release", "-o", "out"]

# second stage for the runtime
FROM mcr.microsoft.com/dotnet/aspnet:8.0

# or WORKDIR run, the absolut path is better, because it is not dependent on the current working directory of the
WORKDIR /run
COPY --from=dotnet-build /build/out .

# optional: change the default port (8080) for the web server
ENV ASPNETCORE_URLS=http://+:5000

EXPOSE 5000

ENTRYPOINT ["dotnet", "mywebapp.dll"]

LABEL description="Dotnet WebApp with Racer"
LABEL author="Lorin Steiner"

Absolute vs. relative Pfadangabe

im oberen Beispiel:

  • WORKDIR /run vs. WORKDIR run
  • WORKDIR /build vs. WORKDIR build

Unterschied:

  • Ausgabe von dotnet build -t mywebapp . mit WORKDIR run:
    1 warning found (use docker --debug to expand):
    - WorkdirRelativePath: Relative workdir "run" can have unexpected results if the base image changes (line 11)
  • bei relativer Pfadangabe kann es zu Problemen kommen, wenn das Basis-Image und das Arbeitsverzeichnis geändert wird

Fehlerbehebung

Lösungsvorschläge, falls es nicht funktioniert:

  1. alle Ordner, Images und Container löschen, welche mit diesem Beispiel zu tun haben → neu beginnen

  2. Ordner des Dotnet-Projektes namens obj löschen

    • obj-Ordner ist im Docker-Image nicht nötig, da er nur für den Build-Prozess gebraucht wird
    • obj-Ordner wird bei jedem Build neu im ersten Image/Stage erstellt
  3. Im .proj-File muss man eventuell auch noch die Haupt-Klasse für den Einstieg definieren:

    <Project Sdk="Microsoft.NET.Sdk.Web">

    <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    </PropertyGroup>

    <ItemGroup>
    <Compile Include="Program.cs" />
    </ItemGroup>
    </Project>