Пошук уроків, статей та іншого контенту
Налаштуємо доступ до сервісу через порти, передамо конфігурацію змінними та розглянемо збереження даних.
Контейнер працює в ізольованому мережевому просторі. Сервіс усередині контейнера може слухати порт, але це не означає, що до нього можна звернутися через localhost хостової системи.
Щоб опублікувати порт контейнера, використовуйте параметр:
docker run -p <порт_хоста>:<порт_контейнера> <образ>Наприклад, запустімо вебсервер Nginx:
docker run --name web -d -p 8080:80 nginxТепер:
Nginx слухає порт 80 усередині контейнера;
порт 80 контейнера доступний через порт 8080 хоста;
відкрити сервіс можна за адресою http://localhost:8080.
Перевірити опубліковані порти можна командою:
docker psУ колонці PORTS буде приблизно такий запис:
0.0.0.0:8080->80/tcpЦе означає, що порт 8080 хоста перенаправляється на порт 80 контейнера.
Зупинити й видалити контейнер можна так:
docker rm -f webEXPOSE і -pУ Dockerfile можна вказати порт, який використовує застосунок:
EXPOSE 3000EXPOSE документує порт контейнера, але сам по собі не робить його доступним із хоста.
Для фактичної публікації порту під час запуску все одно потрібен параметр -p:
docker run --name app -p 8080:3000 my-appПоширена помилка — вважати EXPOSE аналогом -p. Насправді:
EXPOSE описує очікуваний порт;
-p створює доступ між портом хоста й портом контейнера.
За замовчуванням опублікований порт може бути доступний на всіх мережевих інтерфейсах хоста. Щоб обмежити доступ лише локальним комп’ютером, вкажіть адресу 127.0.0.1:
docker run --name web -d -p 127.0.0.1:8080:80 nginxУ такому разі сервіс буде доступний із цього комп’ютера, але не буде напряму доступний з інших пристроїв мережі.
Змінні середовища використовують для передавання конфігурації контейнеру під час запуску. Це дає змогу не змінювати образ для кожного середовища.
Передати одну змінну можна параметром -e:
docker run --rm -e APP_MODE=development alpine printenv APP_MODEРезультат:
developmentУ цьому прикладі:
--rm автоматично видаляє контейнер після завершення;
-e APP_MODE=development створює змінну середовища;
printenv APP_MODE виводить її значення.
Можна передати кілька змінних:
docker run --rm \
-e APP_MODE=production \
-e LOG_LEVEL=info \
alpine sh -c 'echo "mode=$APP_MODE, level=$LOG_LEVEL"'Якщо змінних багато, зручніше зберігати їх у файлі:
# .env.production
APP_MODE=production
LOG_LEVEL=warnПередайте файл за допомогою --env-file:
docker run --rm \
--env-file .env.production \
alpine sh -c 'echo "mode=$APP_MODE, level=$LOG_LEVEL"'Файл має містити рядки у форматі ІМ’Я=ЗНАЧЕННЯ. Порожні рядки та рядки, що починаються з #, можна використовувати для форматування й коментарів.
Файл зі справжніми паролями не слід додавати до Git-репозиторію. Додайте його до .gitignore:
.env.productionЗмінні середовища можна перевірити всередині запущеного контейнера:
docker run --name config-demo -d \
-e APP_MODE=production \
-e LOG_LEVEL=info \
alpine sleep 3600docker exec config-demo printenv APP_MODEРезультат:
productionПереглянути змінні контейнера також можна через:
docker inspect config-demoЗавершивши приклад, видаліть контейнер:
docker rm -f config-demoВажливо: змінні середовища підходять для конфігурації, але не є повноцінним сховищем секретів. Паролі можуть бути видимі в історії команд, конфігурації контейнера або діагностичному виводі.
Офіційний образ PostgreSQL використовує змінні середовища для початкового налаштування бази даних:
POSTGRES_USER — ім’я користувача;
POSTGRES_PASSWORD — пароль;
POSTGRES_DB — назва бази даних.
Запустімо PostgreSQL, опублікувавши стандартний порт 5432:
docker run --name app-db -d \
-p 127.0.0.1:5432:5432 \
-e POSTGRES_USER=app \
-e POSTGRES_PASSWORD=local-password \
-e POSTGRES_DB=app_db \
postgres:16Перевірити стан контейнера:
docker psПереглянути журнали запуску:
docker logs app-dbПісля успішного запуску база даних доступна на хості за такими параметрами:
host: localhost
port: 5432
database: app_db
user: app
password: local-passwordЗначення порту зліва в параметрі -p належить хосту, а значення справа — контейнеру:
127.0.0.1:5432:5432
└─────────┘ └──┘
хост контейнерМожна використати інший порт хоста, якщо 5432 уже зайнятий:
docker run --name app-db -d \
-p 127.0.0.1:55432:5432 \
-e POSTGRES_USER=app \
-e POSTGRES_PASSWORD=local-password \
-e POSTGRES_DB=app_db \
postgres:16Тоді клієнт підключатиметься до localhost:55432, але PostgreSQL усередині контейнера й далі слухатиме порт 5432.
Контейнер має власний файловий шар. Якщо програма записує файли всередину контейнера, вони існують, доки існує цей контейнер.
Видалення контейнера видаляє і його внутрішні зміни:
docker run --name temporary-data alpine \
sh -c 'echo "важливі дані" > /tmp/data.txt'Після завершення контейнер зупинений, але ще існує. Файл можна перевірити так:
docker cp temporary-data:/tmp/data.txt -Якщо видалити контейнер:
docker rm temporary-dataфайл /tmp/data.txt також буде втрачено.
Образи слід сприймати як незмінні шаблони, а контейнери — як тимчасові екземпляри. Дані баз, завантажені файли та іншу інформацію, яку потрібно зберігати, не варто покладати лише на файлову систему контейнера.
Volume — це сховище, яким керує Docker. Воно існує окремо від контейнера й може бути підключене до нового контейнера після видалення старого.
Створімо іменований volume:
docker volume create app-db-dataПідключімо його до PostgreSQL:
docker run --name app-db -d \
-p 127.0.0.1:5432:5432 \
-e POSTGRES_USER=app \
-e POSTGRES_PASSWORD=local-password \
-e POSTGRES_DB=app_db \
-v app-db-data:/var/lib/postgresql/data \
postgres:16Шлях /var/lib/postgresql/data — каталог усередині образу PostgreSQL, де зберігаються файли бази даних. Частина app-db-data — назва volume:
app-db-data:/var/lib/postgresql/data
└───────┘ └────────────────────────┘
volume шлях у контейнеріПеревірити список volume:
docker volume lsПереглянути подробиці:
docker volume inspect app-db-dataПісля запуску бази видаліть контейнер:
docker rm -f app-dbСтворіть новий контейнер із тим самим volume:
docker run --name app-db -d \
-p 127.0.0.1:5432:5432 \
-e POSTGRES_USER=app \
-e POSTGRES_PASSWORD=local-password \
-e POSTGRES_DB=app_db \
-v app-db-data:/var/lib/postgresql/data \
postgres:16PostgreSQL використає вже наявні файли з app-db-data. Дані не залежать від конкретного контейнера.
Volume видаляється окремою командою:
docker rm -f app-db
docker volume rm app-db-dataВидаляйте volume лише тоді, коли його дані більше не потрібні.
Bind mount підключає конкретний каталог або файл хоста до каталогу контейнера:
docker run --name web -d \
-p 8080:80 \
-v "$PWD/site:/usr/share/nginx/html:ro" \
nginxУ прикладі:
site — каталог на хості;
/usr/share/nginx/html — каталог усередині контейнера;
ro означає режим лише для читання.
Створіть файл для перевірки:
mkdir -p site
printf '<h1>Мій сайт</h1>\n' > site/index.htmlПісля запуску Nginx використовує файл із каталогу site на хості. Зміни у файлі можна побачити без створення нового образу:
printf '<h1>Оновлений сайт</h1>\n' > site/index.htmlBind mount зручний для:
локальної розробки;
швидкого редагування конфігурацій;
передавання початкових файлів у контейнер.
Для даних бази зазвичай краще використовувати іменований volume, а не вручну підключати внутрішній каталог бази до довільного каталогу хоста.
Контейнер і хост можуть мати різних власників файлів. Через це процес у контейнері іноді не може читати або записувати дані в bind mount.
Для конфігурацій, які контейнер не повинен змінювати, корисно використовувати режим ro:
docker run --name web -d \
-p 8080:80 \
-v "$PWD/site:/usr/share/nginx/html:ro" \
nginxЦе зменшує ризик випадкової зміни файлів хоста з контейнера.
Команда:
docker run -p 8080:8080 nginxперенаправляє порт 8080 хоста на порт 8080 контейнера. Але Nginx за замовчуванням слухає порт 80, тому така публікація не дасть очікуваного результату.
Правильно:
docker run -p 8080:80 nginxЯкщо порт хоста використовується іншим процесом, Docker не зможе запустити контейнер із таким самим портом.
Оберіть інший порт:
docker run -p 8081:80 nginxУ браузері тоді потрібно відкрити http://localhost:8081.
Якщо база даних запущена без volume, видалення контейнера призведе до втрати даних:
docker run --name app-db -d \
-e POSTGRES_PASSWORD=local-password \
postgres:16Для даних, які потрібно зберегти, підключіть volume:
docker run --name app-db -d \
-e POSTGRES_PASSWORD=local-password \
-v app-db-data:/var/lib/postgresql/data \
postgres:16Змінні середовища задаються під час створення контейнера. Зміна команди запуску не змінює вже створений контейнер. У такому разі контейнер потрібно видалити й створити знову:
docker rm -f app-dbПісля цього запустіть його з потрібними значеннями змінних.
У записі:
8080:80перше число — порт хоста, друге — порт контейнера. Зміна першого числа змінює адресу доступу з хоста, а зміна другого має сенс лише тоді, коли сервіс усередині контейнера слухає інший порт.
-p PORT_HOST:PORT_CONTAINER публікує порт контейнера на хості.
EXPOSE лише описує порт і не публікує його самостійно.
-e NAME=value передає змінну середовища контейнеру.
--env-file дає змогу передавати набір змінних із файлу.
Дані у файловому шарі контейнера втрачаються після його видалення.
Іменований volume зберігає дані незалежно від життєвого циклу контейнера.
Bind mount підключає конкретний каталог хоста й особливо зручний під час локальної розробки.
Порти й змінні конфігурації належать контейнеру, а важливі дані потрібно зберігати у volume або іншому зовнішньому сховищі.