Въведение в Docker (на български)

Реших да пробвам нещо малко по-различно. Ще се опитам да обясня как работят някои от най-добрите и интересни (поне според мен 😅) технологии, които съм ползвал до този момент като софтуерен инженер.

Да, най-често технологиите си имат официална документация, която можеш да прочетеш, но забелязвам, че там нещата в доста случаи не са обяснени достатъчно просто, за да ги разбереш от първо прочитане (на мен лично често ми е нужно да прочета обяснение от поне 3–4 места, за да схвана за какво иде реч). Затова ще се опитам да обясня нещата по максимално прост начин.

А защо на български? Защото ми се струва, че няма достатъчно публично достъпни, безплатни, съвременни и качествени ТЕКСТОВИ материали за програмиране на БЪЛГАРСКИ… Вече за щастие има доста клипове на български за програмиране, но като ТЕКСТ не намирам много. Има някои книги, някои повърхностни статии в Wikipedia и тук-там някой blog пост като този… но като цяло писаните материали на български мисля, че не са много. 😅

В университета срещнах някои по-обстойни текстови материали на български (като онлайн лекции и учебници), но бяха вътрешни за университета, често неактуални и/или платени. Да, вярно, че английският се счита за “официален” език в света на програмирането (и навярно без да имаш някакво поне средно добро владеене на английски, трудно ще се оправиш в програмирането)… обаче това според мен не означава, че трябва изцяло да се отказваме от допринасянето за увеличаването на съдържанието, което е достъпно и на български език.

Както и да е… първата технология, която ще разгледам, е Docker. 😎

===

1. Какво е Docker (и как ти помага)

Docker e инструмент, който (най-просто казано) улеснява ПАКЕТИРАНЕТО, ДОСТАВЯНЕТО и ИЗПЪЛНЕНИЕТО на приложенията, които разработваш.

Под “пакетиране” имам предвид, че чрез Docker можеш лесно да поставиш на едно място всичко, от което приложението ти се нуждае, за да работи правилно. След това става лесно приложението ти да бъде изтеглено и подкарано от потребителя (без главоболия за него). На този потребител му трябва само Docker инсталиран, а всичко свързано с приложението ти ще бъде “доставено” и изпълнено през Docker.

Най-вероятно знаеш, че когато създаваш софтуер, имаш фази като “дизайн”, “тестване”, “поддръжка”, “deployment” (вкарване в употреба на приложението, което си разработил) и т.н. Docker ще ти помогне най-вече в тази “deployment” фаза, но може да ти помогне и в разработката (а даже понякога и в тестването на приложението). 😎

Може да го кажем и по друг начин: Docker ти помага да разрешиш проблема “На моята машина работи!” (на твоята машина всичко си работи добре, но незнайно защо, на някоя друга машина не работи).

Едно приложение има доста части. Frontend компоненти, backend компоненти, база данни, сървъри, библиотеки, зависимости и т.н. Когато имаш толкова много части, понякога става трудно да подкараш приложението на различни платформи (различен хардуер, различен софтуер, различна конфигурация на средата, в която го подкарваш, и др.). Docker те улеснява именно в подкарването на приложението ти на друга машина.

Много компоненти, много нещо…

Понякога може да прочетеш разни инструкции от рода на:

“ОК, за да тръгне приложението, първо инсталирай SQL Server, a след това го стартирай, създай база данни с това име и създай потребител с ей това име (с администраторски права). Ако си на Windows, също инсталирай и конфигурирай това и това, защото иначе няма да работи. След това инсталирай този сървър, пусни го и накрая конфигурирай тези 100 други неща… и след това БИ ТРЯБВАЛО да работи…”

Ако си developer, вероятно ще изпълниш инструкциите, но малко ще се подразниш от неудобния процес. Обаче ако си ПОТРЕБИТЕЛ (някой без някакви дълбоки технически познания), такива инструкции са недопустими и въобще не би се занимавал, освен ако не си пробвал всякакви други алтернативи преди това.

А най-готината част е, когато следваш инструкциите перфектно и накрая ПАК се появяват съобщения за грешки и софтуерът не работи както трябва… 😅

Нещо такова ми се беше случило и на работа. Трябваше да настроя средата си, за да мога да работя по проекта. За целта ми трябваше SQL Server и затова аз го изтеглих (май беше >1.0GB), инсталирах, настройвах… даже трябваше и специален инструмент за връзка към базата данни да инсталирам и конфигурирам.

А в крайна сметка открих, че в проекта има специален файл, чрез който през Docker автоматично се изтегля и изпълнява всичко нужно, за да работи SQL Server както ми трябва на мен. И на практика нямаше нужда да минавам през всичко това в началото (трябваше ми просто да сложа Docker и да изпълня файла с инструкциите в проекта).

2. Как работи Docker?

За да разбереш как работи Docker, нека да вземем няколко примера.

В транспортната индустрия се чудили какъв е най-добрият начин за пренасяне на различни предмети. Тези предмети имат различен размер, форма, изисквания (например някои от тях са по-чупливи). Стигнали до решението да използват т.нар. “контейнери”. Тоест поставят предметите в една кутия, изпращат кутията (без значение дали по въздух, вода и т.н.) и накрая получателят просто отваря кутията и може да използва предметите в нея. Docker работи на същия принцип.

Друг пример: дискетите за игри на 8-битови конзоли като NES/Famicom (още наричани “телевизионна игра” 😅) от миналото. Дискетата съдържа всичко, което ти трябва, за да може играта просто да тръгне, когато я сложиш в конзолата. Може да дадеш дискетата на някой твой приятел, а ако той има конзолата, също може да си пусне играта без проблем. В този пример дискетата е “контейнерът”, а конзолата играе ролята на Docker.

Още един пример (специално за Java разработчици 😅): един JAR файл. Този файл съдържа всичките класове на Java приложението ти. За да стартираш приложението, трябва просто да имаш Java инсталирана на машината си. В този пример JAR файлът е “контейнерът”, а Java (JRE) играе ролята на Docker.

Последно, нека да видим как тази идея работи в самия Docker…

В Docker имаме контейнери (Docker containers), които съдържат всичките неща (компоненти, библиотеки, сървъри, бази данни и т.н.), от които приложението ни се нуждае, за да работи. Стартираме тези контейнери и приложението ни директно работи. Така приложението ни може да работи навсякъде където е инсталиран Docker.

А ето как работи целият процес на практика:

1) За да имаме пуснат контейнер с приложението ни, първо трябва да създадем т.нар. Docker “имидж” (Docker image). Един имидж съдържа всичките библиотеки, компоненти и така нататък, които използва приложението ни. Тези имиджи могат да се съхраняват в онлайн хранилища (repositories) като Docker Hub. От там можеш да изтеглиш имиджи (или да ги “pull-неш” 😅) и да ги използваш в контейнерите, които си създаваш. Docker също предлага управляване на версиите на имиджите (подобно на Git, можеш да публикуваш промени по тях или иначе казано да “commit-ваш”).

Скрийншот от Docker Hub (интерфейсът може и да се измени, но принципът на работа си остава един и същ 😎).

2) За да създадеш имидж, трябва да създадеш файл с името “Dockerfile” (без разширение е). Този “Dockerfile” представлява прост текстов файл, в който описваме стъпките за създаването на имиджа ни. След това пускаме build през Docker и имиджът ни е създаден.

Представи си го така: Dockerfile e РЕЦЕПТАТА, а имиджът е СГОТВЕНАТА ХРАНА след следването на стъпките в тази рецепта. 😉

Примерно съдържание на един Dockerfile

3) Накрая стартираме Docker контейнер от имиджа, който сме създали преди това. Контейнерът е СТАРТИРАНА ИНСТАНЦИЯ на нашия имидж. Когато стартираш контейнер, приложението ти работи и можеш да го използваш. Също така можеш да спреш контейнера и да го пуснеш пак по-късно

Представи си го така (пример от програмирането): ако Docker имиджът е КЛАС, то контейнерът е ИНСТАНЦИЯ на този клас. 😎

Примерни контейнери, които включват различни компоненти.

3. Архитектура на Docker

На този етап може да се чудиш “Това не е ли същото като да пусна виртуална машина?” или “Защо просто не използвам виртуална машина?”. За да отговорим на тези въпроси, трябва първо да разберем вътрешната структура на Docker. A за да разберем нея, трябва да разберем разликите между термините “виртуализация” (virtualization) и “контейнеризация” (containerization).

Първо имаме ВИРТУАЛИЗАЦИЯ, която се използва във виртуалните машини (VM):
- Имаме Host OS (операционна система “домакин”), което е операционната система, която използваме, за да стартираме VM.
- Имаме Hypervisor, който представлява емулатор, който ни позволява да стартираме виртуални машини с различна операционна система (Guest OS или операционна система “гост”).
- Когато стартираме VM, Guest OS-ът не използва компонентите (файловете, приложенията и така нататък), които се намират на Host OS-a.

След това имаме КОНТЕЙНЕРИЗАЦИЯ, която използваме в Docker:
- Host OS-ът е операционната система, която използваме, за стартиране на контейнери.
- Вместо Hypervisor и VM с Guest OS, използваме Container Engine, който използва компонентите на Host OS-a ни, за да стартира нашите приложения (заедно със зависимостите им) в контейнери.

ВИРТУАЛИЗАЦИЯ (отляво) и КОНТЕЙНЕРИЗАЦИЯ (отдясно)

Когато използваме ВИРТУАЛИЗАЦИЯ, размерът на заделените ресурси (пространство, памет) за виртуалните машини е фиксиран и не се променя според специфичните изисквания на нашето приложение. Има доста overhead (тоест излишно хабим ресурси, за да подкараме приложението си).

Когато използваме КОНТЕЙНЕРИЗАЦИЯ, размерът на заделените ресурси НЕ Е фиксиран и може да се промени според нуждите на приложението ни. Контейнеризацията е лека (не товари много от гледна точка на ресурси) и бърза. Поради тази причина Docker e доста по-подходящ за нашите цели.

Все пак трябва да се отбележи, че Docker НЕ Е магическо решение за съвместимост! Например ако се опитваш да пуснеш Windows приложение през Docker на Linux, ще трябва първо да добавиш виртуална машина с Windows, за да се получат нещата. Ако се опитваш да стартираш Linux приложение под Windows, същото важи (хубавото е, че Docker предоставя вградена Linux виртуална машина, която може да използваш; даже още по-добре, може да използваш новата технология WSL2 на Microsoft).

Една много готина възможност на контейнеризацията и Docker e т.нар. “изолация”. Това означава, че всяко приложение работи в собствен контейнер и не влияе на други Docker приложения/контейнери или на компонентите на Host OS-a. В резултат на това, дори когато неминуемо трябва да използваш виртуална машина, няма да ти се налага да създаваш отделна такава за всяко приложение, което стартираш.

Docker има “клиент-сървър” архитектура. Клиентът е Docker CLI, а сървърът се нарича Docker Daemon. Този Daemon получава инструкции от CLI под формата на команди в конзолата или REST API заявки. Ако си спомняш от написаното горе, в контейнеризацията имахме “Container Engine”. E, при Docker това е Docker Engine, който съдържа CLI и Daemon. Една интересна особеност е, че Docker клиентът и сървъра могат да са на една машина, но могат да бъдат и на различни такива.

4. Задълбаване в Docker

Ако си developer, най-вероятно ще ти е достатъчно да знаеш за споменатите вече имиджи, контейнери и общата архитектура на Docker. Обаче ако искаш да задълбаеш в Docker за забавление (или ако искаш да поемеш по “DevOps” пътя), ето още малко информация за някои по-сложни концепции, които ще ти помогнат да стигнеш следващото ниво. 😉

Ще разгледаме набързо Docker Volumes, Docker Compose и Docker Swarm Mode.

4.1. Docker Volumes

Когато създаваш Docker контейнери, често тези контейнери ще съдържат някакви данни (например имаш контейнер за база данни).

Тези данни се съхраняват във виртуална файлова система (Virtual File System или накратко “VFS”), която е вътре в самия контейнер.

Обаче ако изтриеш контейнера, данните ти също се изтриват, а това очевидно не е добре. Механизмът на Docker Volumes ти предоставя решение именно за този проблем.

Ето как работи механизмът:

  1. Твоят Host OS си има своя файлова система (Host File System или наркратко “HFS”). Този “HFS” съдържа всичките папки и файлове, които имаш на компютъра си.
  2. Свързваме папка от HFS с VFS (или казано по-точно, “mount”-ваме HFS папката във VFS). Така, когато имаме някакви файлови промени на VFS, тези промени автоматично се добавят и на HFS-a (същото важи и наобратно).
  3. Данните ти си остават налични и ползваеми, дори и да изтриеш контейнера, на който са били.

Също така можеш да СПОДЕЛЯШ данни между контейнери като свържеш папка от HFS с множество контейнери.

Обобщено казано, Docker Volumes e функция на Docker, която се използва за отделяне на данни генерирани в контейнер и за споделяне на тези данни с други контейнери.

А как да използваш Docker Volumes? Просто изпълняваш Docker команди (които ще видиш по-надолу 😉).

4.2. Docker Compose

Вече научихме, че с Docker стартираме контейнери, които съдържат компонентите на приложенията ни. Обаче понякога един контейнер има нужда да комуникира с ДРУГ контейнер (както например в софтуерното инженерство имаме microservices, т.е. малки приложения, които комуникират помежду си и заедно постигат някаква обща цел).

Docker Compose е инструмент, който ни позволява лесно да стартираме приложения, които се състоят от множество контейнери, които работят заедно.

Също така Docker Compose е доста полезен за настройване на локална среда за разработка (точно това използвах и в проекта, който споменах в началото горе 😁).

Ето как да го използваме:

  1. Създаваме текстов (YAML) файл наречен “docker-compose.yml
  2. Във файла дефинираме “services” на нашето приложение, използвайки специален синтаксис.
    Може да си представиш тези “services” като различни части на приложението ти. За всеки service описваш какво трябва да се случи, когато цялото приложение стартира.
  3. Изпълняваме командата “docker-compose up”, за да стартираме приложението ни, което се състои от множество контейнери (и изпълняваме “docker-compose down”, за да го спрем).
Съдържание на примерен “docker-compose.yaml” файл (Wordpress и база данни, която използва).

4.3. Docker Swarm Mode

Следващото ниво е различни Docker машини да комуникират помежду си.

Docker Swarm Mode e механизъм за управляване на група от машини (наричана “cluster”), които използват Docker и работят заедно (а тази група се нарича “swarm”).

Това е инструмент за управляване на контейнери (“container orchestration” инструмент, подобен на Kubernetes) и по-точно инструмент за управляване на МНОГО контейнери. 😅 Той улеснява правенето на неща с контейнери в по-голям мащаб (като наблюдаване на “здравето” на контейнерите ни, актуализации на контейнерите, сигурност, разпределение на ресурси, връщане към стара версия, deployment, scheduling и т.н.).

Ето как работи:

  1. Всеки swarm се състои от “nodes” (машини, на които работи Docker и които са част от cluster-a).
    Има 2 типа:
    — A) “manager node” (мениджър) — машина, която казва на “worker nodes” какво да правят и следи прогреса им по различните задачи (т.е. тази машина управлява нашия swarm).
    — B) “worker nodes” (работници) — машини, които стартират контейнери на нашето приложение; те получават инструкции от manager node-a и му докладват за статуса на задачите.
  2. Изпращаме “services” на manager node-a.
    Тези services са дефиниции на това, което искаме да постигнем (т.е. кои Docker имиджи да използваме и какво да правим с тях след това).
  3. Manager node-ът изпраща “tasks” (задачи) на worker node-овете, а те ги изпълняват.
    Тези tasks са самите стъпки за постигане на това, което сме дефинирали в нашите services (т.е. това са Docker контейнерите и командите, които трябва да се изпълнят в тези контейнери).
Забележи, че и мениджърът може да има задачи, защото по подразбиране той също е и работник. 👀

А как да използваш Docker Swarm Mode на практика? Отново, просто изпълняваш някои Docker команди (някои от тях са споменати надолу 😉).

5. Практически примери

Нека да видим:
5.1) Някои основни команди в Docker
5.2) Как да използваме имиджи
5.3) Kaк да използваме контейнери
5.4) Как да използваме “Dockerfile”
5.5) Как да използваме volumes
5.6) Бърз поглед към Docker Compose & Docker Swarm Mode
5.7) Бърз поглед към Docker Desktop, Docker под Windows (с WSL2) и Podman

5.1. Някои основни команди в Docker

docker

Всяка команда в Docker започва с docker. Ако напишеш само docker и изпълниш командата (в CMD/PowerShell или каквото ползваш като терминал), ще видиш списък с възможните изпълними команди в Docker.

docker version

Показва коя е инсталираната версия на Docker и информация за някои компоненти, които се използват от Docker.

docker -v (или docker --version)

Показва само версията на инсталирания Docker.

docker info

Показва системна информация свързана с Docker

docker images --help

Като добавим --help в края на някоя команда, можем да видим за какво и как се използва тя.

docker system df

Показва колко на брой имиджа, контейнера и т.н. имаме (както и размера им).

5.2. Как да използваме имиджи

За най-простия пример можем да изпълним просто docker run hello-world. С тази команда директно стартираме контейнер от имиджа “hello-world”. Понеже все още нямаме този имидж, Docker първо го търси локално, а след това го изтегля от Docker Hub и стартира контейнер от него. Накрая виждаме съобщение от самия контейнер, който успешно е бил пуснат.

Ако искаме да видим всички имиджи, които имаме изтеглени в момента, можем да изпълним командата docker images. Там се вижда размера на всеки имидж, версия и т.н.

Ако желаем да изтеглим някой специфичен имидж, просто изпълняваме docker pull my-image (където “my-image” e името на имиджа, който искаме да изтеглим). Например ако искаме да изтеглим имиджа на Ubuntu, изпълняваме docker pull ubuntu. Ако искаме да изтеглим специфична версия на този имидж, изпълняваме docker pull ubuntu:18.04 (двоеточие и версия, за която сме видели в Docker Hub страницата, че съществува).

Обикновено всеки имидж си има някакъв специфичен начин, по който се изпълнява след това, за да може контейнерът да работи както очакваме. Например за Ubuntu командата е docker run -it ubuntu (в случая казваме да се стартира контейнер от Ubuntu имиджа в интерактивен режим, за да можем да въвеждаме команди след това).

Ако искаме да изтрием някой имидж, просто изпълняваме docker rmi image-name. Ако съществува контейнер, който ползва този имидж, тази команда няма да проработи и ще трябва да изпълним docker rmi -f image-name (алтернативно можем първо да махнем контейнера и след това отново да изпълним първата команда за изтриване на имидж).

5.3. Kaк да използваме контейнери

Две полезни команди са docker ps (показва стартираните контейнери в момента) и docker ps -a (показва всички контейнери, които имаме).

Стартирането на контейнер става както вече споменахме (използваме docker run my-image). По подразбиране получаваме случайно име на контейнера, а затова можем сами да си зададем име, ако желаем, с docker run --name my-container my-image (където “my-container” e името, което сме избрали: отделните думи обикновено ги разграничаваме с тире или долна черта).

Ако сме спряли контейнера, можем по-късно да го пуснем отново чрез docker start my-container. Ако искаме да спрем контейнера, използваме docker stop my-container (за “грациозно” спиране, тоест контролирано такова, подобно на спиране на програма през “Exit” или “X” бутона й) или docker kill my-ubuntu (за рязко спиране, подобно на това да спреш някоя програма през Task Manager на Windows 😅).

Ако например си изпълнявал командите с примера за Ubuntu, може да забележиш, че макар с docker start да стартираш контейнера отново, не влизаш в самия контейнер и не можеш да правиш неща вътре в него… Затова трябва да използваш docker attach my-ubuntu-container, за да се “прикачиш” към контейнера и да влезеш в него (алтернативно можеш да изпълниш и docker exec -it my-ubuntu-container bash, което ще изпълни командата “bash” в Ubuntu контейнера и отново ще стигнеш точката, в която се зарежда терминала).

Можеш също така да паузираш някой контейнер. Ако например си отворил Ubuntu контейнера (заредил си терминала и можеш да въвеждаш команди там), а след това в нов прозорец изпълниш docker pause my-ubuntu-container и накрая се върнеш към отворения контейнер, ще забележиш, че в терминала не виждаш въведени букви, защото контейнерът е в пауза. Ако махнеш паузата с docker unpause my-ubuntu-container, буквите ще се покажат и отново ще можеш да изпълняваш команди в контейнера.

Изтриването на контейнер става с docker rm my-container. С docker stats my-container можем да видим полезна статистика за контейнера ни.

5.4. Как да използваме “Dockerfile”

Dockerfile, както споменахме, е просто текстов файл с инструкции за изграждане на имидж. Този файл използва специален синтаксис, който можеш да видиш тук: https://docs.docker.com/engine/reference/builder

Съдържанието на един изключително прост такъв файл може да изглежда ето така:

FROM ubuntu
RUN apt-get update
CMD [“echo”, “Hello from my new image!”]

Какво се случва? С FROM поставяме началната точка за имиджа ни. Започваме от вече съществуващия имидж “ubuntu” (ако искаме да започнем от нулата, можем да използваме специалния имидж “scratch”) и след това чрез RUN казваме “Изпълни ей тази команда, докато се build-ва моя нов имидж!”, а чрез CMD казваме “Изпълни ей тази команда с ей тази стойност, когато стартирам контейнер с новосъздадения ми имидж!”.

Самото създаване на имиджа става чрез командата docker build -t my-image:1.0 . (посочваме име и версия на имиджа ни, а с точката казваме, че Dockerfile се намира в текущата ни директория). След това можем да стартираме контейнер от имиджа ни по вече познатия ни начин с docker run.

5.5. Как да използваме volumes

Командите свързани с Docker Volumes започват с docker volume (изпълнявайки тази команда може да видим какво реално можем да правим с тези volumes). Можем лесно да създадем volume чрез docker volume create my-vol (където “my-vol” е името на нашия volume), a след това да получим информация за този volume чрез docker volume inspect my-vol. Можем да видим и списък с всичките налични volumes чрез docker volume ls.

Когато изпълним командата за получаване на информация за даден volume, най-интересната част е “Mountpoint”, която ни показва директорията, в която на нашия HFS се пазят данните на този volume (трябва да се отбележи, че на Windows директорията се различава от това, което изписва Docker; директорията всъщност е \\wsl$\docker-desktop-data\version-pack-data\community\docker\volumes\).

А сега как да използваме този volume? Лесно. Просто стартираме контейнер по вече познатия ни начин с docker run, но подаваме -v аргумент (или --volume). Ето един пример с BusyBox:

docker run --name my-busybox -it -v my-vol:/app busybox

Забележи частта my-vol:/app, чрез която свързваме директория от HFS с директория от VFS. Първо подаваме директорията на HFS (в случая просто подаваме името на нашия volume, но може да подадем и някава директория като /path/on/host), a след : подаваме директория от VFS (в случая това е папката app, която съществува вътре в BusyBox контейнера).

Ако си стартирал контейнера, може да отидеш в app папката (като изпълниш cd app вътре в контейнера) и да създадеш един прост текстов файл там (чрез echo "Hello World!" >> hello-world.txt). Изпълни и ls след това, за да се убедиш, че файлът е бил създаден. Накрая излез от контейнера чрез командата exit и отвори HFS директорията на твоя volume (тази, която получихме горе чрез docker volume inspect). Какво ще видиш там? Именно файла, който току-що създаде в контейнера! Готино, нали? 😁

А сега пробвай следното: изтрий контейнера, който създаде (изпълни docker rm my-busybox), и стартирай нов по същия начин (например docker run --name my-new-busybox -it -v my-vol:/app busybox). Отиди отново в app папката чрез cd app и какво ще откриеш? Файлът, който създаде по-рано (hello-world.txt), все още си е там! Това е така, защото ние изтрихме първия контейнер, но нашият volume все още си съществува и съответно данните в него също (и тези данни могат да бъдат преизползвани в нов контейнер).

Ако стартираме още един такъв контейнер (docker run --name my-last-busybox -it -v my-vol:/app busybox) и повторим горната процедура, ще забележиш, че и третият контейнер има достъп до данните в нашия volume. По този начин можем да споделяме данни между нашите контейнери.

Вече имаме постигната синхронизация между HFS и VFS. Пробвай например да преименуваш файла в HFS директорията: ще откриеш, че след това е преименуван и вътре в контейнерите, които го ползват. Аналогично можеш да му правиш промени вътре в контейнерите и след това тези промени ще бъдат отразени в HFS директорията.

Ако изтрием последните два контейнера (чрез docker rm my-new-busybox и docker rm my-last-busybox), данните си остават налични. Чак когато изтрием самия volume (чрез docker volume rm my-vol), данните също ще изчезнат и след това няма да можем да ги използваме в бъдещи контейнери.

5.6. Бърз поглед към Docker Compose & Docker Swarm Mode

5.6.1. Docker Compose

Този инструмент, както споменах, може да е доста полезен за настройване на среда за разработка. И както вече загатнахме горе, просто създаваш един файл наречен docker-compose.yaml и в него описваш какво и как искаш да се стартира. Използва се YAML (повече за структурата на файла може да прочетете тук: https://docs.docker.com/compose)

Ето още един примерен файл:

Какво се случва? Общо взето казваме, че искаме да стартираме SQL Server база данни и Mailhog (инструмент за тестване на email изпращане). Казваме кои портове ще използваме, кои имиджи точно ни трябват и т.н. Сега можем да изпълним този файл и да си ползваме настроеното, без да се налага да правим други неща ръчно. Стартираме и можем например да достъпим Mailhog през http://localhost:8025 и да се свържем към базата данни през нашето приложение.

Самото стартиране става чрез изпълняването на командата docker-compose up (в директорията където се намира файла), а спирането става с docker-compose down.

5.6.2. Docker Swarm Mode

Docker Swarm Mode командите започват с docker swarm (и изпълнявайки тази команда ще видиш списък с нещата, които можеш да правиш с този Swarm Mode).

Първата команда, която най-вероятно ще използваш, е docker swarm init, чрез която инициализираш swarm и машината, която е изпълнила командата, се превръща в manager node. След като изпълниш командата ще видиш, че Docker ти изписва как друга машина може да се присъедини като worker (чрез командата docker swarm join) или като manager (чрез docker swarm join-token manager) в новосъздадения swarm.

След това можеш да създаваш services чрез docker service create и да получиш информация за даден service чрез docker service inspect.

Ако искаш да задълбаеш в Docker Swarm Mode, може да следваш урока в сайта на Docker: https://docs.docker.com/engine/swarm/swarm-tutorial/

5.7. Бърз поглед към Docker Desktop, Docker под Windows (с WSL2) и Podman

Docker предоставя графичен инструмент наречен Docker Desktop, който прави лесно управляването на контейнерите, които имаме (с него не ни се налага да изпълняваме никакви команди ръчно). Минусът е, че отскоро този инструмент не е безплатен за enterprise приложения (но ако просто си правиш някое твое лично проектче, можеш да си го ползваш без проблем). 😅 Повече за Docker Desktop тук: https://www.docker.com/products/docker-desktop

Заради това, че Docker започнаха да искат пари от фирми, които го ползват за собствените си приложения, сега все по-често хората преминават към Podman. Podman e като заместител на Docker и работи по същия начин (командите са същите, просто не използваме docker, a podman, т.е. например podman ps, podman images и така нататък). Повече за Podman тук: https://podman.io/

Под Windows интересното е, че Docker може или да използва вградена Linux виртуална машина, или новата WSL2 технология на Microsoft, която се счита за по-добрия избор. Струва си да се прочете малко и за това, защото WSL2 като цяло прави подкарването на Linux приложения от Windows значително по-лесно (макар все още да има дразнещи бъгове). Освен това подкарването на Podman под Windows разчита на WSL2. Повече за WSL2 тук: https://docs.microsoft.com/en-us/windows/wsl/about

===

Това е! Дано е било полезно и ако имате някакви въпроси или забележите някоя неточност, напишете коментар. 😉

--

--