1. Какво всъщност е Docker Image
Docker Image е неизменяем шаблон, от който се създават containers. Той съдържа filesystem съдържанието, необходимо за приложението, както и metadata, описваща как трябва да бъде стартирано то.
Това е първото разграничение, което държа да е ясно: image не е container. Един image може да бъде използван за създаването на много различни containers.
описание
изграждане
готов шаблон
2. Layers – истинската структура на Image
Docker Image не е един голям монолитен блок. Той е изграден от layers. Всеки layer представлява промяна спрямо предишното състояние на filesystem-а.
FROM debian:bookworm
RUN apt-get update && apt-get install -y nginx
COPY nginx.conf /etc/nginx/nginx.conf
CMD ["nginx", "-g", "daemon off;"]Тук FROM задава базовия image, а filesystem промените от build инструкциите формират слоевете на image-а. CMD описва default command и не трябва да се бърка с filesystem layer.
runtime промени
COPY / ADD
RUN ...
FROM
3. Dockerfile – рецептата за Image
Dockerfile е текстов файл, в който описвам стъпките за изграждане на image. Това е build инструкцията, която превръща source кода и зависимостите в повторяем артефакт.
FROM nginx:alpine
COPY ./html /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]Изграждането е:
docker build -t my-nginx:1.0 .Точката в края определя build context – директорията, чието съдържание е достъпно за build процеса.
.dockerignore не е дреболия.4. Основни Dockerfile инструкции
| Инструкция | Предназначение | Пример |
|---|---|---|
FROM | Задава базовия image. | FROM alpine:3.22 |
RUN | Изпълнява команда по време на build. | RUN apk add --no-cache curl |
COPY | Копира файлове от context-а. | COPY app /app |
WORKDIR | Задава работната директория. | WORKDIR /app |
ENV | Задава environment variable. | ENV APP_ENV=production |
EXPOSE | Документира използван порт. | EXPOSE 8080 |
ENTRYPOINT | Определя основната команда. | ENTRYPOINT ["./app"] |
CMD | Задава default command/arguments. | CMD ["--config", "/etc/app.conf"] |
5. Build Cache – мястото, където Docker печели време
Build cache е една от най-практичните причини да обръщам внимание на реда на инструкциите в Dockerfile.
FROM node:22-alpine
COPY . .
RUN npm install
RUN npm run buildАко променя един малък source файл, COPY . . може да направи cache слоя невалиден и да принуди dependency installation да се изпълни отново.
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build6. .dockerignore – малък файл с голям ефект
.dockerignore определя какво да не влиза в build context. Не искам локалните зависимости, Git историята, логове и временни файлове да се изпращат към build процеса.
.git
.gitignore
node_modules
vendor
*.log
.env
.env.*
tmp
cacheТова има значение и за сигурността. Не искам случайно да попаднат чувствителни или ненужни файлове в image-а.
7. Размерът на Image има значение
„Работи“ не е достатъчен критерий за добър image. Размерът му влияе върху времето за изтегляне, storage потреблението, cache-а и deployment-а.
docker image ls
docker system df
docker system df -vНе гоня минимален размер на всяка цена. По-малък image е полезен, но прекомерното оптимизиране може да направи Dockerfile-а труден за поддръжка.
7.1. Multi-stage build
При multi-stage build компилирам приложението в един stage, а в крайния image копирам само необходимото за runtime.
FROM golang:1.24 AS builder
WORKDIR /src
COPY . .
RUN go build -o /out/app ./cmd/app
FROM alpine:3.22
COPY --from=builder /out/app /usr/local/bin/app
ENTRYPOINT ["/usr/local/bin/app"]8. Как проверявам Image
Когато искам да разбера какво реално използвам, не разчитам само на името и tag-а.
docker image ls
docker image inspect nginx:alpine
docker image history nginx:alpinedocker image inspect дава подробна metadata, а docker image history е особено полезна, когато търся откъде идва размерът на image-а.
9. Tags, Image ID и Digest
Tag-ът е удобен за човека, но не трябва да го приемам като вечна идентичност на image.
nginx:alpine
nginx:1.29
nginx:latestTag може да бъде преместен към друг image. При deployment, където е нужна точно определена версия, digest-ът дава по-прецизна идентификация.
latest. Искам да знам точно какъв артефакт ще бъде стартиран.10. Registry – откъде идват Images
Image може да бъде локално изграден, но в реална инфраструктура често идва от registry. Registry е хранилище, от което images могат да бъдат push-вани и pull-вани.
docker pull
docker pull
docker pull
docker login registry.example.com
docker tag myapp:1.0 registry.example.com/myapp:1.0
docker push registry.example.com/myapp:1.011. Какво се случва при docker pull
При docker pull nginx:alpine Docker получава metadata и необходимите layers от registry. Ако даден layer вече съществува локално, той може да бъде използван повторно.
docker pull nginx:alpineТочно затова layer моделът е важен: общите layers могат да бъдат използвани от множество images.
12. BuildKit и съвременният build процес
Съвременният Docker build процес използва BuildKit. Той добавя възможности за по-ефективно изграждане, cache, parallelism и multi-platform builds.
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t myapp:1.0 \
--push .Не приемам автоматично, че image, изграден на една архитектура, е подходящ за всеки друг host.
13. Security започва още при Image
Ако image съдържа ненужни пакети, инструменти и права, проблемът вече съществува още преди container да бъде стартиран.
- избирам поддържан base image;
- ограничавам ненужните пакети;
- не записвам secrets в Dockerfile;
- проверявам дали приложението трябва да работи като root;
- поддържам dependencies актуални.
14. Когато Images започнат да пълнят диска
Docker натрупва images, stopped containers, volumes и build cache. При host, който се използва дълго време, това може да се превърне в реален проблем.
docker system df
docker image ls
docker ps -aprune като универсално решение.15. Практики, които използвам при Docker Images
- Избирам подходящ и поддържан base image.
- Използвам
.dockerignore. - Подреждам Dockerfile така, че cache-ът да се използва ефективно.
- Използвам multi-stage build, когато приложението го позволява.
- Не записвам secrets в image.
- Не разчитам сляпо на
latestза production deployment. - Проверявам размера и layer историята.
- Поддържам base images и dependencies актуални.
- Разделям build средата от runtime средата.
16. Моето мислене при диагностика на Image
Когато image стане прекалено голям, build-ът стане бавен или container-ът не стартира както очаквам, не започвам да променям произволни инструкции.
Този подход е по-надежден от „пробвам още една команда и гледам дали ще стане“. Image е артефакт от build процес. Ако разбера как е построен, много по-лесно разбирам и поведението му.
17. Най-важното от тази част
- Docker Image е неизменяем шаблон, от който се създават containers.
- Image е изграден от layers.
- Dockerfile описва как се изгражда image.
- Build cache ускорява повторните builds.
- .dockerignore контролира build context.
- Multi-stage builds отделят build средата от runtime.
- Tags са имена, а не гаранция за неизменна идентичност.
- Registry разпространява images между системи.
- Размерът на image-а има значение за storage и deployment.
- Добрата image архитектура е част от security модела.
Заключение
Container-ът е runtime инстанцията. Image е артефактът, от който тя се създава. Ако image-ът е лошо структуриран, прекалено голям, неясен или съдържа ненужни зависимости, проблемът няма да изчезне, когато го стартирам.
За мен добрият Docker Image не е просто image, който работи. Той трябва да бъде предвидим, повторяем, поддържаем и достатъчно малък, без да жертвам надеждността заради няколко мегабайта.
В следващата част ще премина към Docker Containers – как се създават от image, какво се случва с writable layer-а, как се управлява жизненият им цикъл и защо docker run, docker create, docker start и docker exec не са едно и също нещо.