Рубріки: Інструменти

Зручніше за віртуальну машину: для чого потрібен Docker і як він працює — розбираємо основні команди

Олег Коваль

Віртуалізація на рівні операційної системи стає все більш популярним рішенням при розгортанні застосунків у різних середовищах. Чи не найбільш вдалим інструментом для цього є Docker.

У двох статтях на Highload я розповім про основні можливості інструменту. Ви дізнаєтесь, як встановити, налаштувати та запустити Docker, а також як працювати з його ключовими елементами: Dockerfile, Docker Image та Docker Container.

Docker та принцип контейнерів — чому так зручніше?

Віртуальна машина виступає як емулятор ПЗ. Припустимо, на комп’ютері вже є Windows і потрібно додатково встановити, наприклад, Ubuntu. Створюємо на тому ж комп’ютері віртуальну машину і вже на неї встановлюємо додаткову ОС. У результаті матимемо ніби два комп’ютери водночас. Однак для віртуальної машини потрібне місце на жорсткому диску, вдосталь оперативної пам’яті та ресурсів процесору.

На противагу цьому з’явився принцип контейнерів, на якому побудований Docker та інші схожі інструменти. Головна відмінність — у власній інфраструктурі та єдиній для всіх середовищ ОС. Зверху цієї основи встановлюється Docker, завдяки якому можна створювати безліч контейнерів, аплікацій тощо.

Docker розділяє єдине ядро ОС на окремі контейнери, під кожний із яких виділяється свій процес. Це набагато зручніше, ніж віртуальна машина. Вам не потрібно шукати ще й пам’ять, диск, оперативку, адже окремий процес витягає значно менше ресурсів.

Коли ви працюєте з багатьма віртуальними машинами, часто вони заважають одна одній. Docker же може запускати в ядрі будь-який застосунок, який буде повністю ізольований від інших. Окрім цього, на фоні конкурентів Docker виграє за рахунок простого синтаксису. Також його можна запустити на всіх популярних платформах: Linux, Windows, Mac.

Як працює Docker

Головний принцип роботи з Docker можна описати у вигляді гасла з трьох слів: Build, Ship, Run. Кожне з них означає певний етап та елемент системи:

  • Build. Тут мається на увазі створення Dockerfile. Це інструкція, за якою весь «корабель» будується та відправляється в «плавання». У файлі ви описуєте образ майбутнього продукту, принципи його роботи та створення.
  • Ship. Наступний етап — Docker Image. Це готовий образ для створення та запуску контейнера. Якщо порівняти Dockerfile з планом кімнати, то Docker Image — це дизайн-проєкт із зображенням майбутнього ремонту, схемами розведення електрики та сантехніки тощо.
  • Run. На останньому етапі з’являється Docker Container — вже запущений у роботу образ на основі Docker Image. І якщо раніше був дизайн-проєкт, то це вже готова до заселення кімната.


Так все і працює: будуєте Dockerfile, з нього створюєте Docker Image, а на його основі запускаєте Docker Container. Далі про кожний елемент системи розповім окремо.

Dockerfile

Dockerfile — це звичайний текстовий документ, який ми називаємо Dockerfile без усіляких крапок в кінці. Цей файл розміщується у папці з проєктом. У ньому ви записуєте команди, за якими буде створюватися Image, а потім — запускатися Container.

На ілюстрації нижче прописані наступні команди:

  • Беремо Python 3.10.2.
  • Робимо директорію та встановлюємо туди Django.
  • Копіюємо весь проєкт, відкриваємо порт 8000 та за допомогою CMD запускаємо runserver нашого Django.

Таким чином ми прописуємо в Dockerfile команди одна за одною. Так само покроково вони будуть виконуватися автоматично згідно цієї інструкції. Як бачите, синтаксис дійсно дуже простий:


Команди CMD та ENTRYPOINT

Може здатися, що вони однакові за функціоналом, та це не зовсім так. CMD — команда, яка прописується в консоль при запуску Dockerfile. Якщо повернутися до попереднього прикладу, то для запуску сервера потрібні python, manage.py, runserver, IP та порт. І все це прописується саме в CMD, після чого запускається сервер.

ENTRYPOINT так само запускає команду, яку ми хочемо прописати. Але він виконує це перед CMD, якщо ми використовуємо їх разом. Саме тому ENTRYPOINT і називається «точкою входу» — бо це буде перша команда.

Для розбору процесу Running CMD розглянемо приклад.

Беремо Debian, копіюємо проєкт, запускаємо apt-get update і зводимо CMD. Якщо нам потрібно змінити цю команду, то при запуску Docker можна прописати docker run image. Тоді виконається команда, прописана в Dockerfile по дефолту.

Якщо ж ми хочемо виконати іншу команду, то пишемо docker run my-image і вказуємо нову команду. Це може бути, наприклад, вказівка перевірити список усіх елементів на Ubuntu. У результаті попередня команда буде замінена в CMD на ту, яку ми вказали:

Якщо ENTRYPOINT та CMD використовувати разом, то перша завжди стартує швидше. Вона може знадобитися, коли до основних команд з CMD потрібно запустити ще якусь команду. До прикладу, певна перевірка проєкту. В такому разі ви прописуєте відповідну команду ENTRYPOINT, а потім — основні параметри в CMD. Цей процес наведений на ілюстрації нижче:

Також ви можете переписати певні параметри. При вказівці docker run my-container запишуться параметри та ENTRYPOINT, які вже є в Dockerfile. А якщо потрібно запустити інші CMD-команди, то знадобиться docker run my-container cmd:

Щоб переписати ENTRYPOINT, потрібно написати команду docker run --entrypoint і шлях до entrypoint.sh (це entrypoint, який буде змінюватися), а також назву контейнера. Зверніть увагу: ви маєте вказати, що переписуєте саме ENTRYPOINT:

Обираючи між CMD та ENTRYPOINT, я раджу саме CMD. Як на мене, з ним легше працювати. ENTRYPOINT краще залишити для тих випадків, коли контейнер має робити щось вже на старті: перевіряти процеси або чекати чогось. Тоді поєднання цих команд буде виправданим.

Dockerignore

Розповідаючи про Dockerfile, варто згадати і про Dockerignore. Це аналог .gitignore в Git. Завдяки цьому функціоналу при копіюванні проєкту в контейнер ви можете вказати певні файли, які не хочете переносити разом з іншими. Це може стосуватися pycache, логів, environments, docs тощо. У такому разі прописуєте назви файлів у dockerignore, і вони будуть просто ігноруватися при копіюванні проєкту.


Dockerfile створюється за принципом Layers — шар за шаром

Спочатку ви прописуєте основу майбутнього контейнера. Наприклад, при FROM python це буде Python певної версії, і він стає на базовий рівень усієї схеми. У нашому випадку далі йде Django, але можуть бути й потрібні для проєкту бібліотеки, requirements.txt, залежності тощо. Все це формує середній шар документу. Наприкінці маємо верхній шар, який власне запускає застосунок — це CMD-команда:

Цей процес можна порівняти з будівництвом дому. У якості фундаменту виступає найбільша частина: Python, Ubuntu, Anaconda тощо. Далі йдуть основні поверхи, більш компактні за розміром — бібліотеки та залежності. І вже на горищі розміщується найменша та найлегша частина — run проєкту контейнера.

Щоб усі шари були зрозумілими, раджу ретельно прописувати Layers. Порівняйте на наступній ілюстрації приклади поганого та гарного виконання шарів у Dockerfile. Код у лівій та правій частинах зображення виконує по суті одне й те саме, проте розміри відрізняються чи не вдвічі. Розібратися складно, особливо якщо немає достатнього досвіду з Docker. 

В іншому прикладі одразу зрозуміло, що й до чого. Тут чітко видно встановлені Python, Java та virtual environment, а також їх активацію. В поганому ж прикладі безліч записів про оновлення, інсталяцію та ребілд Python, встановлення залежностей, активацію virtual environments та багато іншого. Це не тільки важче читати. Це ще й складніше виконувати. Тому Dockerfile із безліччю шарів запускатиметься довше.

Docker Image

Docker Image — це блок, створений за інструкцією з Dockerfile, що виступає шаблоном запуску контейнерів. За допомогою цього документу можна побудувати безліч однакових контейнерів.

Припустимо, ви створюєте один шаблон, який має встановити Python і певні залежності на нього, і вам потрібно п’ять однакових контейнерів. У такому випадку не потрібно прописувати п’ять Dockerfile. Достатньо одного такого файлу для створення Docker Image, який ви будете ранити п’ять разів.

Уявімо іншу ситуацію. Ви створюєте образ на основі CentOS, який може інсталювати вебсервіс nginx, але вам потрібен ще один CentOS вже з іншим ПЗ. У такому випадку не потрібно робити два різних Dockerfile та Docker Image. Ви просто берете Docker Image CentOS, запускаєте його і в окремих контейнерах встановлюєте необхідне ПЗ.

Основні команди Docker Image

При роботі з Docker Image виділяють декілька найбільш використовуваних команд:

  • docker image --help показує основні команди в Image з їх коротким описом.

  • docker image build [OPTIONS] PATH. Білдить сам Image для подальшого запуску Container. За допомогою цієї команди ви можете назвати свій Image. Для цього додайте тег -t, а за ним вкажіть бажану назву (у моєму прикладі test). Вам залишається прописати шлях до директорії (крапка у наведеному прикладі означає поточну директорію). Після запуску команди і почне будуватися Image: від створення директорії, встановлення Django, whitenoise, gunicorn до копіювання.

У моєму випадку Docker image збілджений на основі цього Dockerfile:

  • docker image inspect [OPTIONS] IMAGE. Ця команда видає всю інформацію про Image. Це можуть бути ID, дата створення, пов’язані контейнери та енвайроменти, версія Python, наявні pip і get pip, CMD і ENTRYPOINT, Volumes, директорії тощо. При запуску команди вказуйте назву Image, який вас цікавить.

  • docker image ls показує список усіх Image, які є в Docker. На прикладі зображено перелік із декількох тестових Docker Image:

  • docker image rm [OPTIONS] IMAGE призначена для видалення Image. Нижче на ілюстрації я зобразив типовий сценарій такої процедури. Спочатку за допомогою docker image ls отримав перелік усіх Image. Далі прописав docker image rm, зазначивши назву Image, який потрібно видалити — dockertest2. Ще одна перевірка docker image ls показала: того Image більше немає у Docker.

  • docker image tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]. За допомогою цієї команди ви можете затегати Docker Image. Це знадобиться при використанні Docker Hub, де всі зібрані Images мають теги. У наступній статті поговоримо про нього детальніше.

Продовження статті про можливості Docker читайте згодом на Highload.

Читайте також: Робимо розробку зручною: як використовувати Docker у роботі з мікросервісами

Якщо ви знайшли помилку, будь ласка, виділіть фрагмент тексту та натисніть Ctrl+Enter.

Останні статті

IT в Україні йде до свого фінального кінця. І потраплятимуть туди виключно за покликом душі

Коротко про українську IT-сферу у 2024 році Це коли на одну вакансію Middle розробника по…

26.03.2024

Блокчейн-розробка сьогодні: зарплати і перспективи на ринку праці

Формування криптовалютної галузі в Україні почалося ще у 2014 – саме тоді з'явилися перші стартапи,…

18.03.2024

Скільки рішень ухвалює розробник? Погляд новачка, який запускає продукт

Автор цього блогу — Python-девелопер Сергій Солдатов, який вирішив створити досить унікальний продукт. І це…

12.03.2024

Чи треба готуватись до співбесіди?

Думки шукачів діляться на: «так, однозначно» і «ні, не вартує, я все і так про…

04.03.2024

Відкладаєте до останнього? Що таке «синдром студента» і як з ним боротися

Синдром студента — це форма прокрастинації, яка полягає в тому, що людина, якій дали завдання,…

23.02.2024

Вчимося працювати з Git: основи конфігурації, гілки, додавання файлів та директорій

Git — це найпопулярніша CVS прямо зараз, яка дозволяє відстежувати історію розробки і спільно працювати.…

20.02.2024