Bash Dockerfile: Anweisung nach Mount und vor CMD möglich?

CyborgBeta

Captain
Registriert
Jan. 2021
Beiträge
3.370
Hallo,

mein Dockerfile sieht strukturell so aus:

Bash:
FROM debian:12

ENV TZ=Europe/Berlin

EXPOSE ...

RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt update
RUN apt upgrade -y
RUN apt install ... -y

RUN adduser --disabled-password --gecos "" headless
RUN echo "root:no"|chpasswd

RUN apt clean

USER headless
WORKDIR /home/headless
RUN git -C noVNC pull || git clone https://github.com/novnc/noVNC.git noVNC

CMD ...

Das Problem ist Zeile 19. Wenn es den Ordner noVNC noch nicht gibt, soll gecloned werden, ansonsten nur gepulled. (Diese RUN-Anweisung sollte eigentlich semantisch richtig sein.)

Das Verzeichnis /home/headless wird aber durch docker compose erst später gemountet (nach dem RUN). Sprich, ich gehe davon aus, dass das Clone bzw. Pull zurzeit keinen Effekt hat.

Darf ein Dockerfile mehrere CMD-Anweisungen haben, oder wie umgehe ich den Schlamassel?

Ich weiß leider auch nicht, ob der Container beim Mounten Sklave ist oder nicht. Vermutlich wird der Host immer als Master fungieren.

Tipps?
 
Eine gängige Lösung für solche Szenarien ist es, ein entsprechendes Bash-Skript mit mit der nötigen Logik zu schreiben, dieses ins Image zu integrieren und dann statt der ganzen Einzelbefehle aufzurufen.

Edit: gerade bemerkt, dass es ja ums Bauen des Images geht.
 
noVNC soll ja persistiert werden. Sprich, es soll Rebuilds überstehen.
 
Sowas ist aber meiner Meinung nach nicht die Aufgabe eines Images bzw. dessen Buildprozesses.
 
  • Gefällt mir
Reaktionen: wirelessy
Das passiert beim Initial-Build:

docker compose build --no-cache --progress plain novnc-debian

Code:
#16 [novnc-debian 13/13] RUN git -C noVNC pull || git clone https://github.com/novnc/noVNC.git noVNC
#16 0.365 fatal: cannot change to 'noVNC': No such file or directory
#16 0.366 Cloning into 'noVNC'...
#16 DONE 1.4s

Das passiert beim Rebuild:

docker compose build --progress plain novnc-debian

Code:
#16 [novnc-debian 13/13] RUN git -C noVNC pull || git clone https://github.com/novnc/noVNC.git noVNC
#16 CACHED
Ergänzung ()

mibbio schrieb:
nicht die Aufgabe eines Images bzw. dessen Buildprozesses.
Nein? Wo soll das sonst geschehen?
 
CyborgBeta schrieb:
Nein? Wo soll das sonst geschehen?
Alles was du persistieren willst, solltest du in "das" Docker-Filesystem packen.

Alles womit du arbeiten willst, kannst du dann bequem in andere Verzeichnisse mounten. Dein "philosophischer Fehler" ist also, dass du dein git pull in ein "Arbeitsverzeichnis", statt in ein persistentes machen willst.
 
Wohoo, so funktioniert es:

Bash:
USER headless
WORKDIR /home/headless

CMD [ "sh", "-c", "cd /home/headless/ \
&& (if cd noVNC; then git pull; else git clone https://github.com/novnc/noVNC.git noVNC; fi) \
&& cd /home/headless/ \
&& rm -rfv /tmp/.X1* \
&& tigervncserver -localhost yes -SecurityTypes None -geometry 1600x900 -autokill \
&& cd noVNC/ && (nohup ./utils/novnc_proxy --vnc localhost:5901 --listen 6901 &) \
&& trap 'tigervncserver -kill :*; exit' INT; echo waiting; while : ; do sleep 1 ; done" ]

Möglicherweise funktioniert es auch ohne die absoluten Pfade, das hab ich jetzt nicht ausprobiert.
Ergänzung ()

stefan92x schrieb:
Dein "philosophischer Fehler" ist also, dass du dein git pull in ein "Arbeitsverzeichnis", statt in ein persistentes machen willst.
Das Arbeitsverzeichnis ist doch persistent.
 
Ja, es geht.

Insgesamt habe ich jetzt:

Bash:
FROM debian:12

ENV TZ=Europe/Berlin

RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt update
RUN apt upgrade -y
RUN apt install nano net-tools git -y

RUN adduser --disabled-password --gecos "" headless
RUN echo "root:no"|chpasswd

RUN apt install <...> -y

RUN apt clean

CMD [ "sh", "-c", "(if cd noVNC; then git pull; else git clone https://github.com/novnc/noVNC.git noVNC; fi) \
&& cd ~ \
&& <...>" ]

Der Trick war, die Anweisung in das CMD zu verschieben.

Das EXPOSE war überflüssig.

Den Rest regelt dann docker compose bzw. traefik sichert ab:

Code:
  novnc-debian:
    build: ./novnc-debian
    init: true
    stop_signal: SIGINT
    user: 1000:1000
    volumes: <...>
Ergänzung ()

Bitopium schrieb:
Das nennt man cachen
Stimmt, war kein Rebuild.

Bitopium schrieb:
Und das ist was fundamental Anderes als zur docker build Zeit
Das stimmt. Es kommt in meinem Fall aber aufs Gleiche heraus, wenn ich den Container neu starte, dann soll sich das Teil die Updates ziehen.
 
Zuletzt bearbeitet:
CyborgBeta schrieb:
Der Trick war, die Anweisung in das CMD zu verschieben.
Das CMD wird aber eben nicht beim Build ausgeführt, sondern beim Starten eines entsprechenden Containers.

The CMD instruction sets the command to be executed when running a container from an image.
https://docs.docker.com/reference/dockerfile/#cmd

Das Ergebnis des Befehls bzw. deiner Befehlskette wird also nicht Teil des Images, sondern ist im Dateisystem des gestarteten Containers. Wird der Container beendet (und gelöscht), ist auch wieder alles weg, was der Befehl erzeugt hat. Außer es liegt in einem persistenten Volume, welches man wiederverwendet.

Und bei der Gelegenheit verweise ich auch mal auf meine erste Antwort. Es ist eigentlich Best Practice, im CMD nicht endlos Befehle zu verketten. Stattdessen schreibt man sich ein Skript, bspw. "startup.sh", mit den ganzen notwendigen Befehlen, baut dieses dann ins Image mit ein und gibt bei CMD oder ENTRYPOINT das Skript an.
 
  • Gefällt mir
Reaktionen: CyborgBeta
Danke, ja, das siehst du richtig. Die CMD-Anweisung läuft bei mir inzwischen etwas aus dem Ruder.

Ich wollte es von der Komplexität her aber möglichst einfach halten ... Wenn es ginge, hätte ich auch alles ins docker-compose.yml file gepackt.
 

Ähnliche Themen

Zurück
Oben