Курс по Docker — пакетирай услуга и я управлявай в реални сценарии

Контейнери и облакСредно ниво

От · основател и главен изпълнителен директор на Hábil. Така обучаваме тези, които изграждат системи, които не могат да се провалят.

За кого е: за този, който вече е програмирал нещо —revisor от курсовете по Go, Rust или TypeScript на Hábil, или собствена услуга— и има нужда да го пакетира, пусне и управлява в контейнери, без да копира команди слепешката. Средно ниво: предполага се, че работиш уверено с терминал и че знаеш какво е HTTP сървър. Не се предполага да си пипал Docker: всяко понятие се обяснява, когато се появи, и се обяснява защо съществува, не само как се пише. И не е нужно да програмираш нищо ново: курсът ти дава услугата готова.

Какво ще знаеш в края: да превърнеш една услуга в малък образ, без привилегии и възпроизводим; да го пускаш с ограничения, с проверка на състоянието (health check) и с коректно спиране; да управляваш конфигурацията и тайните му, без да ги оставяш вътре в образа; да стартираш няколко контейнера, които си говорят по име, с една-единствена команда; и да четеш какво ти казва Docker, когато нещо се провали, вместо да търсиш отговора слепешката.

Къде продължава: този курс е стъпалото преди курса по Kubernetes с kind на Hábil, който взима образа, с който завършваш тук, и го разгръща, конфигурира, мащабира и защитава в локален клъстер.

Какво ти трябва, преди да започнеш: компютър с Linux Mint 22.x и администраторски права (sudo). Урок 1 инсталира Docker от нулата. Ако идваш от курса по Go, Rust или TypeScript, вече познаваш задачата, която решава revisor; ако не, урок 0 я представя в два абзаца.

Проектът, който ще изградиш

revisor: HTTP сървър, който проверява едновременно списък от услуги и връща чрез GET /api/estados отчет с името, състоянието и времето за отговор на всяка една; а чрез GET /salud — краткия отговор, който казва дали самият процес е жив. Конфигурира се с променливи на средата (порта, списъка с услуги, пътя, където запазва отчета, и токен за достъп). Сървърът на revisor е написан на Go (идва от курса по Go на Hábil) и се компилира до статичен двоичен файл; слуша на порт 8080, обслужва GET /salud и GET /api/estados, конфигурира се чрез променливи на средата и носи подкоманда healthcheck, за да може да се наблюдава сам без curl. Не ти трябва да знаеш Go: курсът ти го дава, а ти го пакетираш.

Курсът ти го дава вече готов, заедно с тестова услуга, която се проваля нарочно в три режима —здрав, бавен и паднал—. С тези две части вършиш цялата работа в курса: да пакетираш, подсилваш сигурността, конфигурираш, добавяш health check, запазваш данни, свързваш и предаваш. Това е същата задача като в курсовете по Go, Rust и TypeScript на Hábil: вече знаеш какво прави revisor, така че цялото ти внимание остава върху новото, а то е как се разпространява и как се управлява.

Единайсетте урока

Урок Какво изграждаш Какво научаваш
0 Какво е контейнер и какво НЕ е засега нищо (четене) контейнерът е изолиран процес, а не виртуална машина; образ срещу контейнер; клиентът и демонът; какво се споделя с хоста и защо това е решаващо за сигурността
1 Инсталиране на Docker на твоя Linux Mint средата и първия ти контейнер Docker Engine от официалното хранилище; Mint не е официална платформа и какво да правиш; премахване на конфликтните пакети; групата docker се равнява на root
2 Контейнерите в ежедневната работа тестовата услуга — стартирана, проверена и почистена run, ps, logs, exec, stop, rm, inspect; публикуване на портове само на 127.0.0.1; ограничения за памет и CPU; да не се оставят остатъци
3 Твоят първи Dockerfile curso-docker-revisor:1.x.0 в един-единствен етап инструкции на Dockerfile; форма exec срещу форма shell; .dockerignore; USER; тагове с версия; docker build --check
4 Слоеве, кеш и контекст същият образ, изграден наново за секунди как се сглобява образ слой по слой; редът на инструкциите; --progress=plain и docker history; кеш на компилацията (--mount=type=cache); какво пътува в контекста
5 Multi-stage: от гигабайти до мегабайти крайният минимален образ без привилегии етапи на компилиране, на тестове и краен; минимален базов образ без shell; версия и digest на базовия образ; двоичният файл, който не стартира, защото не е статичен
6 Конфигурация и тайни revisor, конфигуриран без повторно изграждане променливи на средата; ARG срещу ENV; тайни при изграждане; тайни при изпълнение чрез файл; да видиш с очите си какво остава вътре в образа
7 Проверка на състоянието и жизнен цикъл контейнер, който казва как е и умира коректно PID 1 и сигнали; срокът на docker stop; HEALTHCHECK без curl; политики за рестартиране; файлова система само за четене; --cap-drop; no-new-privileges
8 Томове и мрежи отчетът, който оцелява, и два контейнера, които си говорят именувани томове, bind mounts и tmpfs; собственикът на файловете при потребител без привилегии; мрежи, дефинирани от потребителя; DNS по име; вътрешни мрежи
9 Compose: цялата система compose.yaml с revisor и неговата услуга, която се проваля услуги, мрежи, томове и тайни в един файл; depends_on със service_healthy; compose config; сравняване на твоя файл с този от docker init
10 Предаване на образа образът, публикуван по digest, със своя списък на софтуерните компоненти и с прегледано сканиране, зареден в клъстер kind тагове и digest; локален регистър; сканиране за уязвимости с Trivy; списък на софтуерните компоненти (SBOM) и произход; няколко платформи; мостът към kind load docker-image

Имена с представка. Всичко, което курсът създава на твоята машина (образи, контейнери, мрежи, томове), носи представката curso-docker-; затова образът от урок 3 се казва curso-docker-revisor:1.x.0, а не revisor. Така не се сблъсква с нищо, което вече имаш, и можеш да изтриеш само нещата на курса, без да пипаш останалото.

В края на всеки урок има упражнения с решенията им. А дневникът е твой: записвай в него какво ти струва усилия.

Три принципа, които минават през целия курс

Сигурността не е урок, а навик. Няма финален модул за сигурност. Има по един навик на урок и всеки се упражнява върху revisor, а не върху отделен пример:

Урок Навикът, който се изгражда
0 да знаеш какво споделя един контейнер с машината (ядрото) и какво не
1 групата docker се равнява на root: дава се съзнателно
2 портове, публикувани само на 127.0.0.1; ограничения за памет и CPU; никога --privileged, нито сокетът на Docker вътре в контейнер
3 още първият Dockerfile съдържа USER; .dockerignore от първия ден; тагове с версия, никога latest
4 контекстът на изграждане не носи .git, .env, нито ключове; инструментът за проверка на Dockerfile се пуска винаги
5 минимален базов образ без shell; базовият образ се фиксира по версия и по digest; етапът на тестовете се изпълнява преди пакетиране
6 тайните не минават през ARG, нито през ENV; проверява се с docker history и docker inspect, че не са останали
7 файлова система само за четене, без Linux capabilities, които не се ползват, без повишаване на привилегиите, с init
8 томове с правилния собственик; вътрешни мрежи; никога мрежата на хоста
9 крайният compose.yaml се ражда с всичко гореизброено, а тайните му живеят извън файла
10 онова, което се публикува, се сканира, носи своя списък на софтуерните компоненти (SBOM) и се референцира по digest

Тема, която се оставя за накрая, е тема, която не се научава.

„Работещ“ контейнер не е здрава услуга. Почти всички експлоатационни повреди по тази тема се раждат от смесването на двете неща: процесът съществува, но не обслужва. Тестовата услуга се проваля нарочно и всеки урок те учи да различаваш онова, което Docker си мисли, от онова, което наистина се случва.

Преподава се само актуалното, а остарялото се назовава, за да го разпознаваш. Compose е docker compose (плъгинът), файлът се казва compose.yaml и няма version:; MAINTAINER е излязъл от употреба. Когато нещо старо се появи в урок в интернет, на който така или иначе ще попаднеш, курсът ти казва какво е и защо вече не се ползва. И всяка версия се дава с датата ѝ: тези в този курс са измерени на 7 октомври 2026 г. (Docker Engine 29.8.2, Compose v5.6.0).

Как разбираш, че си приключил

Курсът не свършва, когато си прочел урок 10, а когато твоят проект изпълнява тези шест неща. Числата са проектни цели: измерват се и се напасват при писането на уроците, а всеки урок повтаря тази, която му се пада, вече измерена.

  1. docker compose up стартира всичко от нулата и отчетът показва падналата тестова услуга като FALLA, без да се налага да рестартираш нищо ръчно.
  2. Крайният образ тежи десетки мегабайти (цел), а не стотици, не носи shell нито компилатор и не работи като root (проверяваш го с docker exec и с docker inspect).
  3. Никаква тайна не се появява в docker history, в docker inspect, нито в променливите на средата на контейнера.
  4. docker stop прекратява контейнера за няколко секунди (цел: под две), защото процесът получава сигнала и се спира коректно; а docker ps показва (healthy) и, когато счупиш услугата, (unhealthy).
  5. Отчетът оцелява след docker rm и revisor намира другия контейнер по името му.
  6. Публикуваният образ се референцира по digest, преминава сканирането с Trivy с прага, който си задал, и се зарежда в клъстер kind без нито една грешка при изтегляне.

Уроци

  1. Урок 0 — Какво е контейнер и какво НЕ е
  2. Урок 1 — Инсталиране на Docker на твоя Linux Mint
  3. Урок 2 — Контейнерите в ежедневната работа
  4. Урок 3 — Твоят първи Dockerfile
  5. Урок 4 — Слоеве, кеш и контекст
  6. Урок 5 — Multi-stage: от гигабайти до мегабайти
  7. Урок 6 — Конфигурация и тайни
  8. Урок 7 — Проверка на състоянието и жизнен цикъл
  9. Урок 8 — Томове и мрежи
  10. Урок 9 — Compose: цялата система
  11. Урок 10 — Предаване на образа