Docker image layers
Docker/OCI image — стек tar.gz слоёв. Overlayfs объединяет их в единый rootfs. Каждая инструкция Dockerfile создаёт новый слой. Кеш работает на уровне слоёв.
Что создаёт слой
RUN— слой с изменениями FS после командыCOPY,ADD— слой с файламиFROM— начальные слои от base image
Что НЕ создаёт
ENV, WORKDIR, USER, EXPOSE, LABEL, ARG, CMD, ENTRYPOINT — только в config, не в слой.
Overlayfs
lowerdir=layer1:layer2:layer3 # read-only
upperdir=container-writable # изменения контейнера
merged=/ # то что видит процесс
Удаление файла в контейнере? Overlayfs создаёт whiteout в upperdir. Файл существует ниже, но "не виден".
Порядок в Dockerfile
# ПЛОХО — код меняется часто, deps пере-инсталлится
COPY . /app
RUN cd /app && npm install
# ХОРОШО — deps кешируются, код отдельно
COPY package.json package-lock.json /app/
RUN cd /app && npm install
COPY . /app
Уменьшение размера
1. Объединяй RUN
# -100 МБ apt cache
RUN apt update && apt install -y curl && rm -rf /var/lib/apt/lists/*
2. Multi-stage builds
FROM golang:1.22 AS build
COPY . /src
RUN cd /src && go build -o /app
FROM alpine:3.19
COPY --from=build /app /usr/local/bin/app
CMD ["/usr/local/bin/app"]
3. distroless / scratch
FROM scratch
COPY --from=build /app /app
ENTRYPOINT ["/app"]
scratch = 0 байт. Для static binary. distroless — только glibc + сертификаты.
Что НЕ удалить
Файл удалённый в следующем слое — всё равно в образе!
RUN wget big.tar
RUN tar xf big.tar
RUN rm big.tar ← в отдельном слое: файл остался!
Правильно — && в одном RUN.
Inspect
docker history nginx:alpine
docker inspect nginx:alpine
dive nginx:alpine # interactive TUI (best)