Docker kann mehrere Build-Contexte. Damit kann man dann shared-Directorys haben, ohne den Build-Context auf den gemeinsamen Root zu legen.
Posts mit Tag "docker"
Docker kann beim Bauen linten. Vielleicht ist euch mal eine Warning aufgefallen, wenn gebaut wird. Wenn man z. B. FROM x as y schreibt, gibt es eine Warning, die besagt, dass das as in einem anderen Casing als FROM ist.
Das kann man jetzt zu einem Fehler machen. Dazu entweder docker build mit --check aufrufen oder den Anfang der Dockerfile ein bisschen konfigurieren;
# syntax=docker/dockerfile:1
# check=error=true
Diese Checks gibt es aktuell.
Zu Docker hab ich noch was neues gelernt. Man kann jetzt (mit DOCKER_BUILDKIT=1) auch bei einzelnen RUN-Commands Dinge mounten. Das ist ganz praktisch für Lockfiles oder Dinge, die man nur ein Mal braucht. Dazu gibt es neben Bind-Mounts auch Cahce-Mounts, womit man ein Cache-Verzeichnis in den Build-Container mounten kann. Nimmt natürlich etwas Reproduzierbarkeit, aber in gewissen Fällen (npm, rust) kann man damit echt viel Zeit sparen:
Aus
COPY package.json package-lock.json ./
RUN npm ci
COPY ./Cargo.toml ./Cargo.toml
RUN cargo fetch
COPY ./clitool.c /clitool.c
RUN g++ -O3 -o /bin/clitool /clitool.c
Wird:
RUN --mount=type=bind,source=package.json,target=package.json \
--mount=type=bind,source=package-lock.json,target=package-lock.json \
--mount=type=cache,target=/root/.npm \ # mit cache des globalen npm-caches
npm ci
RUN --mount=type=bind,source=Cargo.toml,target=Cargo.toml \
cargo fetch
RUN --mount=type=bind,source=clitool.c,target=/clitool.c \
g++ -O3 -o /bin/clitool /clitool.c
Je nach Fall kann man sich damit sogar eine Multi-Stage-Dockerfile ersparen.
TIL docker system df:
# docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 5 5 1.318GB 858.6MB (65%)
Containers 5 5 3.416kB 0B (0%)
Local Volumes 5 1 442B 354B (80%)
Build Cache 0 0 0B 0B Man kennt ja aus Docker-Multistage-Builds das COPY --from=build, um eine Datei aus einer anderen Stage zu kopieren.
Gerade habe ich beim Docker-Image von composer gesehen, dass das nicht nur beschränkt auf Images im selben Multi-stage-Build ist. Man kann dort jedes Image angeben.
Also kann man statt dem hier:
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
&& php composer-setup.php --install-dir=/usr/local/bin --filename=composer \
&& php -r "unlink('composer-setup.php');" \
&& composer --version
Auch das hier machen und die Binary aus dem offiziellen composer-Image kopieren:
COPY --from=composer /usr/bin/composer /usr/bin/composer
Nachteil dabei ist, dass der Builder dafür das komplette Image runterladen muss. Ist in manchen Situationen vielleicht ganz praktisch.
TIL docker wait.
Letztens hatte ich einen Post zu selten verwendeten Features bei docker-compose. Hier ein guter, aber oberflächlicher Artikel: 6 Docker Compose Best Practices for Dev and Prod
Daraufhin hat sich noch ein weiteres Feature aufgetan: profiles. Beispiel:
version: "3.9"
services:
frontend:
image: frontend
profiles: ["frontend"]
phpmyadmin:
image: phpmyadmin
depends_on:
- db
profiles:
- debug
backend:
image: backend
db:
image: mysql
Here the services
frontendandphpmyadminare assigned to the profilesfrontendanddebugrespectively and as such are only started when their respective profiles are enabled.
In den Kommentaren auf HN gibt es auch noch weitere Tipps.
Heute habe ich gelernt: In docker-compose kann man sich sowas basteln, was ähnlich zu den Init-Containern aus k8s ist. Verwenden tut man dafür die depends_on-Property des Services.
Bisher ging ich davon aus, dass man mit der Property nur festlegen kann, in welcher Reihenfolge die Container gestartet werden. Das bringt einem aber nicht viel, weil die Container üblicherweise unterschiedlich lange brauchen, um zu starten. Das geht mittlerweile besser, nur die Dokumentation erwähnt es (noch) nicht:
Bei den Elementen von depends_on kann man conditions angeben. Dort kann man sagen, in welchem Zustand die Abhängigkeit sein soll, bevor der Container gestartet wird.
services:
db:
image: mariadb:10
ports:
- "3306:3306"
init_db:
image: mariadb:10
command: /init-db.sh
volumes:
- ./init-db.sh:/init-db.sh
env_file:
- credentials.env
depends_on:
db:
condition: service_started
application:
# ...
depends_on:
init_db:
condition: service_completed_successfully
Durch das service_completed_successfully sagt man, dass application erst startet, wenn init_db mit einem 0-Exit-Code beendet ist.
service_started ist offenbar das, was sonst auch immer der Fall war (die Doku nennt es “legacy behaviour”).
Ich hab dann noch ein bisschen Recherche betrieben und rausgefunden:
Da geht noch mehr! Definiert man z. B. die Healthchecks, über die ich mal berichtet habe, kann man den Condition service_healthy angeben. Diesen Status erhält ein Container, wenn er hochgefahren und sich durch den Healthcheck als “gesund” erkannt wurde.
Definiert man das in der Dockerfile oder in der docker-compose.yml, kann man damit sogar ein ./wait-for-it.sh loswerden.
Da hat sich ja echt was getan bei docker-compose.
Heute lernte ich die HEALTHCHECK-Instruktion bei Dockerfiles. Damit kann ein Container einen Befehl definieren, mit dem man rausbekommen kann, ob der Container gerade “Healthy” ist. Erinnert ein bisschen an die Probes aus K8s.
HEALTHCHECK --start-period=10s --timeout=10s \
CMD curl --fail http://localhost:80 || exit 1
Man kann das auch in einer Compose-File definieren[hinweis].