Теория
Немного терминов
Образ (Image)
Это шаблон, из которого запускаются контейнеры. В нём уже есть всё, что нужно приложению: системные библиотеки, зависимости, код и настройки.
Образ не меняется — Docker использует его как основу и добавляет поверх слой, куда попадают изменения, сделанные во время работы. Так один и тот же образ можно использовать многократно, не затрагивая исходное содержимое.
Контейнер (Container)
Это изолированная среда, в которой работает приложение. Контейнер можно запускать, останавливать и удалять, не затрагивая исходный образ.
Когда он удаляется, его данные исчезают — поэтому для постоянного хранения используется следующий механизм.
Том (Volume)
Это место для данных, которые должны сохраняться между перезапусками. Тома подключаются к контейнерам как внешние диски: всё, что записано в них, остаётся даже после удаления контейнера.
Так обычно хранят базы данных, логи и другие важные файлы.
Сеть (Network)
Отвечает за взаимодействие контейнеров между собой и с внешним миром. Docker автоматически создаёт bridge-сеть, где каждый контейнер получает свой IP-адрес.
Можно объединять контейнеры в собственные сети или, наоборот, изолировать их, если требуется полная автономность.
Реестр (Registry)
Реестр — это место, где хранятся Docker-образы.
Публичный вариант — Docker Hub, в нём размещены миллионы готовых сборок, включая официальные (nginx, Redis, Python). Если образы должны оставаться внутри компании, разворачивают собственный Docker Registry — тот же сервер хранения, но с ограниченным доступом.
Сеть
-p 8080:80 делает порт 80 контейнера доступным по адресу 8080 на хосте).
Кроме стандартной сети есть и другие режимы:
-
host — контейнер работает в сетевом пространстве хоста и использует его IP-адрес и интерфейсы. Режим без изоляции, зато с максимальной производительностью. Подходит, если сервису нужен прямой доступ к сети.
-
none — сеть полностью отключена. Контейнер не получает IP, не выходит в интернет и не принимает входящие запросы. Подходит для задач, которые работают изолированно и не используют сеть.
-
overlay — объединяет контейнеры, запущенные на разных машинах, в одну виртуальную сеть. Такой тип используется, когда приложение развёрнуто на нескольких серверах и между ними нужно наладить связь.
-
macvlan — каждому контейнеру назначается собственный MAC-адрес, и в локальной сети он виден как отдельное устройство. Это удобно для тестирования сетевых сервисов или если контейнер должен работать наравне с другими машинами.
Логи
docker logs
В продакшене часто выбирают другие драйверы:
-
journald — чтобы писать логи в системный журнал Linux;
-
syslog — для отправки логов на внешний сервер;
-
fluentd — для сбора и анализа данных в распределённых системах.
Помимо логов Docker фиксирует события — всё, что происходит в системе: запуск или остановка контейнера, создание или удаление, загрузка образа, подключение тома. Эти данные доступны через API или команду docker events.
Практика?
База
Установка
apt install docker-io -y
Проверка работа докера
Должен скачать контейнер, после чего вывести приветственное сообщение.
docker run hello-world
Установка nginx
docker run -d -p 8080:80 nginx
Что здесь происходит:
docker run— создаёт контейнер из указанного образа (в данном случаеnginx);- если образа нет локально, Docker автоматически скачает его с Docker Hub;
- флаг
-dзапускает контейнер в фоновом режиме (detached); -p 8080:80пробрасывает порт 80 внутри контейнера на порт 8080 вашей машины.
Посмотреть контейнеры
docker ps -a
Зайти в контейнер
При создании
docker run -it ubuntu bash
После создания
docker exec -it <id> bash
Логи и т.д
Чтобы узнать подробнее, как запущен контейнер и какие у него настройки, выполните:
docker inspect <id>
Если нужно быстро понять, что происходит внутри контейнера, не заходя в него вручную (например, просмотреть вывод приложения), используйте команду:
docker logs <id>
Управление контейнерами
Если контейнер нужно приостановить, используйте:
docker stop <id>
Контейнер останется в списке и при желании его можно снова запустить командой:
docker start <id>
Когда контейнер больше не нужен, его можно удалить:
docker rm -f <id>
-f Это принудительное удаление ( даже если запущен)
Образы
Посмотреть список локальных образов можно так:
docker images
А удалить ненужные с помощью команды:
docker rmi <image>
Чтобы быстро очистить всё, что не используется (остановленные контейнеры, старые образы, неактивные сети), есть команда:
docker system prune
Создание своего образа
Пример простого Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
Что здесь происходит:
FROM— задаёт базовый образ, от которого наследуется ваш;WORKDIR— создаёт рабочую директорию внутри контейнера;COPY— копирует файлы проекта с компьютера в образ;RUN— выполняет команды при сборке (например, установка библиотек);CMD— указывает, что делать при запуске контейнера.
Важно: когда контейнер запускается, процессы внутри него по умолчанию работают с правами root. Чтобы снизить эти риски, в Dockerfile часто добавляют собственного пользователя и запускают приложение уже от его имени. Сделать это можно буквально в пару строк:
RUN useradd -m appuser
USER appuser
ENTRYPOINT: второй способ задать команду запуска
Чем отличаются:
-
CMD — это команда по умолчанию. Если при запуске контейнера (
docker run) вы передаёте свои аргументы, Docker заменяет CMD на то, что вы указали. -
ENTRYPOINT — это фиксированная основа команды. Она всегда выполняется, а аргументы из
docker runпросто добавляются к ней.
ENTRYPOINT ["python", "app.py"]
CMD ["--port", "8000"]
ENTRYPOINT задаёт программу, которую контейнер запускает всегда —
в нашем случае это python app.py. CMD добавляет аргументы по умолчанию.
То есть Docker склеивает их и при обычном запуске выполнит:
python app.py --port 8000
Если при запуске указать свои параметры. Docker возьмёт ENTRYPOINT и добавит ваши аргументы, заменив CMD:
docker run myapp --port 9000
Примеры посложнее
Сначала в папке проекта должны лежать три файла:
myapp/
├─ app.py
├─ requirements.txt
└─ Dockerfile
В app.py напишем простейшее приложение на Python. Оно будет показывать строку “Hello from Docker!”, когда вы откроете страницу в браузере:
from http.server import HTTPServer, BaseHTTPRequestHandler
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
self.wfile.write(b"Hello from Docker!")
if __name__ == "__main__":
HTTPServer(("0.0.0.0", 8000), Handler).serve_forever()
Файл requirements.txt нужен, чтобы перечислить зависимости проекта. Если их нет — можно оставить его пустым.
Собираем образ
Теперь откройте терминал, перейдите в папку myapp и выполните:
docker build -t myapp .
Флаг -t задаёт имя образа, а точка в конце указывает путь к контексту сборки — папке, где лежит Dockerfile и файлы проекта. После выполнения команды Docker по шагам прочитает Dockerfile и соберёт новый образ.
Запускаем контейнер
Мы уже пробовали запускать контейнер с Nginx. Теперь сделаем то же самое, но с собственным образом:
docker run -d -p 8000:8000 myapp
Тег — это просто метка версии. Если его не указать, Docker присвоит latest, но лучше явно обозначать версии:
docker build -t myapp:1.0 .
Docker Hub
1. Создайте репозиторий на Docker Hub
Зайдите в свой аккаунт на https://hub.docker.com/ и вручную создайте новый репозиторий — так же, как создают новый проект на GitHub.
Название репозитория должно совпадать с тем, что вы будете использовать в команде docker push.
Это важный шаг: Docker не создаёт репозитории автоматически.
2. Переименуйте образ
Перед загрузкой образ нужно оформить в правильном формате:
username/repository:tag
где:
-
username— ваш логин на Docker Hub, -
repository— имя проекта, -
tag— версия образа (например,1.0).
Пример:
docker tag myapp:1.0 username/myapp:1.0
3. Войдите в Docker Hub
Авторизуйтесь через команду:
docker login
Docker попросит ввести логин и пароль от вашего аккаунта. После успешного входа появится сообщение вроде Login Succeeded.
4. Отправьте образ в репозиторий
Выполните команду:
docker push username/myapp:1.0
Docker начнёт загружать образ в ваш репозиторий на Docker Hub.
Когда загрузка закончится, образ появится в вашем профиле и станет доступен другим (если репозиторий публичный).
5. Загрузите образ на другом компьютере
Чтобы использовать тот же образ на другой машине, выполните:
docker pull username/myapp:1.0
Docker скачает только нужные слои — если часть уже есть локально, она не будет загружаться заново.
После этого образ можно запустить как обычно:
docker run -d -p 8000:8000 username/myapp:1.0
Docker Compose
Docker Compose позволяет описать все нужные контейнеры и их настройки в одном файле — docker-compose.yml. После этого весь проект можно запустить одной командой.
Пример простого docker-compose.yml:
services:
web:
build: .
ports:
- "8000:8000"
redis:
image: redis:alpineЧто здесь происходит:
-
services— список контейнеров, которые нужно запустить; -
web— наш основной сервис, собирается из текущей директории (build: .) и открывает порт 8000; -
redis— дополнительный контейнер, разворачивается из готового образаredis:alpine.
Как это работает
Сохраните файл и выполните команду:
docker compose up
Docker соберёт образы, создаст контейнеры, подключит сеть и запустит всё вместе.
Чтобы остановить проект, выполните команду:
docker compose down