JavaRush /Курси /Docker for Spring /Перший запуск контейнера

Перший запуск контейнера

Docker for Spring
Рівень 2 , Лекція 0
Відкрита

1. Docker CLI: сенс

Docker CLI потрібен, щоб перестати вгадувати й почати спиратися на факти. Якщо ви колись намагалися виправити проблему «у мене запускається, у вас — ні», то вже знаєте цей біль: без чітких, спостережуваних кроків усе швидко перетворюється на чаклунство. Docker Desktop — річ зручна, але думати про стан системи він майже не вчить. А Docker CLI вчить: є команди, є стан, є факти. Саме на них і будується діагностика — що завантажили, що запустили, що справді працює.

Відмінності між image, container, registry і Compose ми вже розібрали; тепер цю карту потрібно перенести в повсякденний CLI-сценарій. Базовий робочий мінімум тут такий: отримати образ → запустити контейнер → побачити, що він запущений. Без цього циклу далі не вийде ні контейнеризувати Spring Boot застосунок, ні розбирати поломки, ні виразно пояснювати колегам, що ви взагалі робите. Тому свідомо починаємо з готових образів (ubuntu, nginx), щоб навчитися керувати життєвим циклом контейнера, а не сперечатися з Dockerfile, якого поки ще немає.

Щоб цю модель було простіше тримати в голові, ось коротка аналогія зі світу Java. Уявіть, що image — це «готовий артефакт» (приблизно як jar, який уже зібрали й опублікували), а container — це конкретний запущений процес java -jar ... зі своїм PID, портами й логами. Docker CLI — це ваші jps + ps + kill + tail, тільки в контейнерній термінології.

2. docker pull: отримання образу

Команда docker pull важлива тому, що відокремлює отримання образу від запуску контейнера. Поки вам не доводиться відповідати на питання «звідки в мене цей образ?» і «чому вчора він був одним, а сьогодні іншим?», вона здається нудною. Але в Docker корисно тримати просту думку: спочатку я отримую артефакт, а потім запускаю його. Тоді робота стає осмисленою, а не схожою на «натиснув кнопку — і воно там само щось зробило».

Технічно docker pull завантажує образ із registry (за замовчуванням найчастіше це Docker Hub) і кладе його в локальне сховище Docker Engine. Важливо: після pull у вас ще немає контейнера. Ви лише підготували «шаблон запуску». Це як завантажити залежність із репозиторію Maven: завантажили, але застосунок від цього сам не стартував.

Найперший приклад — максимально чесний і без підводних каменів:

# Завантажуємо образ із явним тегом, щоб приклад був відтворюваним
docker pull ubuntu:22.04

Тут ubuntu — імʼя репозиторію образу, а 22.04 — тег (tag). Можна сприймати тег як «версію». Так, пізніше в курсі ми глибше поговоримо про відтворюваність, але на старті правило просте: якщо хочете, щоб приклади поводилися однаково сьогодні й завтра, пишіть явний тег, як у прикладі вище, і не покладайтеся на те, що зараз latest.

Ще один корисний момент: поведінка docker pull майже ідемпотентна. Якщо образ уже є локально й збігається, Docker не буде заново завантажувати все підряд: він перевірить стан і скаже, що у вас уже все актуальне. Це добре: ви не витрачаєте мережу щоразу, коли повторюєте команду.

3. docker run: запуск контейнера з образу

Команда docker run — це мить, коли абстрактне слово «контейнер» перетворюється на реальний об’єкт: його можна зупинити, видалити, дослідити і, що приємно, керовано зламати. Важливо одразу зафіксувати: docker run робить дві речі одним махом — створює новий контейнер із образу і одразу запускає його. Це як «створити новий процес і тут же запустити», причому кожен виклик run створює новий екземпляр, а не повторно використовує старий.

У цієї команди є дуже корисна «форма», яку варто один раз побачити наочно:

# Шаблон команди: опції → образ → (необов’язково) команда всередині контейнера
docker run [OPTIONS] IMAGE[:TAG] [COMMAND] [ARG...]

Сенс тут такий: ви вибираєте образ, а потім (необов’язково) можете перевизначити команду, яку контейнер виконає. Це особливо добре видно на простому прикладі, де контейнер живе рівно стільки, скільки живе команда всередині нього:

# Одноразовий запуск: контейнер виконає команду і одразу завершиться
docker run ubuntu:22.04 echo "привіт із контейнера"

Цей контейнер створиться, виконає echo "привіт із контейнера" і завершиться. Це не «Docker зламався», а нормальна модель: контейнер живе, доки живе основний процес. Якщо основний процес закінчився, контейнер теж закінчився. Пізніше сьогодні ми навчимося розрізняти «завершився нормально» і «впав», але вже зараз корисно побачити, що одноразові контейнери — абсолютно звичайний сценарій.

Для Java-розробника це особливо важливо. Spring Boot сервіс — це довгоживучий процес, тобто сервер. Отже, контейнер нам теж потрібно запускати так, щоб усередині жив «довгограючий» процес, наприклад java -jar .... Але зараз ми тренуємося на готових образах, щоб не змішувати дві складності одразу.

4. --name: осмислені імена контейнерів

Перші запуски Docker дуже легко проходять у режимі «я запустив щось... а тепер як мені це зупинити?». Docker уміє сам придумувати контейнеру імʼя (часто кумедне), але для навчання і для нормальної командної роботи краще одразу привчити себе до простої дисципліни: давати контейнеру явне імʼя.

Імʼя — це не просто зручність, а спосіб зробити команди читабельними й повторюваними. Якщо ви називаєте контейнер demo-nginx, то наступні кроки виглядають як нормальний людський сценарій: «зупинити demo-nginx», «подивитися demo-nginx», «видалити demo-nginx». Якщо ж імʼя випадкове, ви починаєте копіювати ID контейнера, плутатися, і за якихось пʼятнадцять хвилин починає здаватися, що Docker вас не поважає. (Він поважає. Просто мовчки.)

Приклад запуску контейнера з іменем:

# -d: запускаємо у фоновому режимі (термінал одразу повертається)
# --name: даємо контейнеру зрозуміле імʼя для подальших команд
docker run -d --name demo-nginx nginx:alpine

Тут ми вже додали -d (фоновий режим), але поки що не заглиблюємося: просто фіксуємо, що --name спокійно поєднується з іншими опціями.

Практична звичка на майбутнє: вибирайте імена, які відображають роль. demo-nginx краще, ніж server. А catalog-app (коли ми дійдемо до нашого навчального сервісу) краще, ніж mycontainer2-final-final.

5. -d: фоновий режим

Прапорець -d (detached mode) потрібен для дуже простої речі: якщо контейнер — це довгоживучий процес (вебсервер, база, брокер), ви не хочете, щоб він блокував ваш термінал. Ви хочете повернути собі керування терміналом і продовжувати працювати: дивитися статус, запускати curl, перевіряти API. Для цього і існує -d.

Тут є важливий момент для новачка: коли ви запускаєте контейнер з -d, термінал справді повертається одразу, і Docker виводить вам довгий ідентифікатор контейнера. Дуже легко дійти хибного висновку: «він уже завершився». Ні, він просто пішов працювати у фоні. Перевіряти, чи живий контейнер, ми будемо через docker ps — це наступний крок лекції.

Зробимо простий фоновий запуск:

# Той самий запуск, але тут спеціально фіксуємо ідею: контейнер працює у фоні
docker run -d --name demo-nginx nginx:alpine

Після цього команда поверне щось на кшталт довгого ID, схожого на хеш. Цей ID можна використовувати, але новачку простіше спиратися на імʼя — тому ми й дали --name.

Важливо: поки ми не публікуємо порти і не намагаємося відкрити nginx у браузері. Це окрема велика тема (і вона буде пізніше сьогодні). Зараз нам потрібно зрозуміти механіку: контейнер запущено, але підтвердити це ми повинні інструментом спостереження, а не надією.

6. docker ps: що реально працює зараз

Одна з найкорисніших звичок, яких навчає Docker, — не гадати. Вам не потрібно «відчувати контейнер»: його потрібно побачити у списку запущених. Для цього є docker ps — команда, яка показує лише контейнери, що працюють зараз.

Після запуску demo-nginx виконайте:

# Показує лише контейнери, які прямо зараз запущені
docker ps

Зазвичай ви побачите таблицю зі стовпцями на кшталт CONTAINER ID, IMAGE, COMMAND, STATUS, PORTS, NAMES. Навіть якщо половина цих слів поки виглядає як «англійська для дорослих», ви вже можете витягти головне: чи є контейнер з іменем demo-nginx у списку і який у нього статус.

Зверніть увагу: у виводі docker ps часто видно, скільки часу контейнер працює, наприклад Up 10 seconds. Це дуже корисний швидкий сигнал. Якщо ви очікували, що контейнер буде жити довго, а в списку його немає, — це привід не панікувати, а перейти до наступного кроку діагностики (який буде далі в курсі).

Ще один важливий момент: docker ps показує лише контейнери, що працюють. Якщо контейнер швидко завершився, ви його тут не побачите. І це не баг, а частина моделі. Для повної картини існує docker ps -a, але це вже наступна лекція — не будемо забігати наперед. Зараз достатньо прийняти правило: docker ps відповідає на запитання “що живе прямо зараз?”.

7. Базовий цикл pull → run → ps

Міні-схема pull → run → ps

Іноді новачку простіше запам’ятати не команди окремо, а короткий сценарій. Для цієї лекції він такий: «отримати образ → запустити контейнер → переконатися, що він справді запущений». Цей цикл схожий на нормальний інженерний ритуал: спочатку підготовка артефакту, потім запуск, потім перевірка стану.

Ось схема у вигляді простого flowchart:

flowchart TD
    A["docker pull ubuntu:22.04 — отримали образ"] --> B["docker run ... — створили й запустили контейнер"]
    B --> C["docker ps — переконалися, що він живий"]
    C --> D["Далі в курсі: stop/rm, logs, inspect, порти..."]

Сенс схеми не в гарних стрілочках, а в дисципліні. У Docker дуже багато магії зникає, коли ви ставите собі просте запитання: «На якому кроці я зараз? Я вже завантажив образ? Я вже запустив контейнер? Я точно перевірив, що він працює?»

Якщо зловите себе на думці «ну я наче запускав...», повертайтеся до цієї схеми. Вона справді рятує нерви.

Модель у голові Java-розробника

Коли ви почнете контейнеризувати наш Container-Ready Catalog Service (пізніше, не сьогодні), ці самі команди будуть використовуватися буквально щодня. Просто замість nginx:alpine у вас буде образ вашого сервісу. Але мисленнєва модель залишиться тією ж: образ як артефакт, контейнер як запущений процес, docker ps як факт, а не думка.

Дуже важливо: ми не вивчаємо Docker як окрему релігію. Ми вивчаємо Docker як шар над звичною розробкою. Ви вже вмієте запускати Spring Boot локально, уже знаєте, що сервер — це процес, який повинен жити й слухати порт. Docker додає до цього відтворюваність і зручність керування оточенням, але починати все одно потрібно з бази: навчитися руками керувати контейнером, не плутаючи його з образом і не втрачаючи контейнер після першого запуску.

І ще одна думка, яка потім сильно спростить життя. У Docker вам постійно доведеться розрізняти ситуації «я працюю з шаблоном» і «я працюю із запущеним екземпляром». У світі Java це приблизно як відрізняти jar на диску від процесу JVM, який просто зараз крутиться. Якщо ви це розрізнення відчуваєте, Docker стає набагато простішим.

8. Типові помилки в pull/run/ps

Помилка № 1: плутати образ і контейнер.
Це найчастіша плутанина на старті. Здається, що «я завантажив ubuntu» — значить «у мене є ubuntu, який працює». Але pull нічого не запускає. Образ — це лише заготовка. Контейнер з’являється тільки після run. Гарна самоперевірка: поставте собі запитання «я зараз хочу завантажити чи запустити?» — і команда майже завжди стає очевидною.

Помилка № 2: не вказувати тег і випадково жити на latest.
Новачок часто пише docker pull ubuntu або docker run nginx і отримує «щось, що працює». А потім через тиждень приклад починає поводитися інакше. Річ у тім, що без тега Docker зазвичай припускає latest, а він може змінюватися. На старті курсу достатньо простої дисципліни: пишіть явний тег у навчальних командах (ubuntu:22.04, nginx:alpine), щоб менше ловити неочікувані відмінності.

Помилка № 3: вважати, що docker run «повторно використовує» старий контейнер.
У голові часто живе звичка «запустити ще раз». Але docker run створює новий контейнер. Якщо ви двічі виконаєте docker run ..., у вас буде два різні контейнери, навіть якщо образ один і той самий. Це не погано і не добре — це просто модель. Пізніше ми навчимося зупинятися й прибирати, але вже зараз корисно не очікувати «повторного запуску того самого екземпляра».

Помилка № 4: запустити з -d і вирішити, що контейнер завершився, раз термінал повернувся.
Термінал повертається, тому що контейнер працює у фоні. Перевірка тут завжди одна: docker ps. Якщо контейнер є в списку і статус Up ..., значить він живий. Якщо ні — значить, він завершився, і далі вже потрібно зʼясувати, чому.

Помилка № 5: не давати контейнеру імʼя й потім тонути в випадкових ідентифікаторах.
Спочатку здається, що імʼя не потрібне: «я й так бачу один контейнер». А потім з’являється другий, третій, десятий — і ви починаєте плутати, який із них ваш. --name — це дешевий спосіб зробити світ зрозумілішим. Особливо коли ви запускатимете не demo-nginx, а свій сервіс і залежність поруч.

1
Задача
Docker for Spring, 2 рівень, 0 лекція
Недоступна
Явне отримання образу та одноразовий запуск
Явне отримання образу та одноразовий запуск
1
Задача
Docker for Spring, 2 рівень, 0 лекція
Недоступна
Фоновий контейнер і список працюючих екземплярів
Фоновий контейнер і список працюючих екземплярів
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ