Курс по Docker — пакетирай услуга и я управлявай в реални сценарии
Контейнери и облакСредно ниво
От Dorian Chávez · основател и главен изпълнителен директор на 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, а когато твоят проект изпълнява тези шест неща. Числата са проектни цели: измерват се и се напасват при писането на уроците, а всеки урок повтаря тази, която му се пада, вече измерена.
docker compose upстартира всичко от нулата и отчетът показва падналата тестова услуга катоFALLA, без да се налага да рестартираш нищо ръчно.- Крайният образ тежи десетки мегабайти (цел), а не стотици, не носи shell нито компилатор и не работи като
root(проверяваш го сdocker execи сdocker inspect). - Никаква тайна не се появява в
docker history, вdocker inspect, нито в променливите на средата на контейнера. docker stopпрекратява контейнера за няколко секунди (цел: под две), защото процесът получава сигнала и се спира коректно; аdocker psпоказва(healthy)и, когато счупиш услугата,(unhealthy).- Отчетът оцелява след
docker rmиrevisorнамира другия контейнер по името му. - Публикуваният образ се референцира по digest, преминава сканирането с Trivy с прага, който си задал, и се зарежда в клъстер
kindбез нито една грешка при изтегляне.
Уроци
- Урок 0 — Какво е контейнер и какво НЕ е
- Урок 1 — Инсталиране на Docker на твоя Linux Mint
- Урок 2 — Контейнерите в ежедневната работа
- Урок 3 — Твоят първи Dockerfile
- Урок 4 — Слоеве, кеш и контекст
- Урок 5 — Multi-stage: от гигабайти до мегабайти
- Урок 6 — Конфигурация и тайни
- Урок 7 — Проверка на състоянието и жизнен цикъл
- Урок 8 — Томове и мрежи
- Урок 9 — Compose: цялата система
- Урок 10 — Предаване на образа