Аннотация

В этой статье мы разберём ключевые понятия Docker — Dockerfile, Docker image, Docker container и Docker Compose. Вы узнаете, как они работают, как между собой связаны и зачем нужны в современной DevOps- и Self-Hosting-инфраструктуре.


🔧 Что такое Docker?

Docker — это платформа для разработки, доставки и запуска приложений в изолированных средах, называемых контейнерами. Вместо того чтобы устанавливать приложение и его зависимости на хост-систему, Docker позволяет упаковать всё необходимое в легковесный, переносимый контейнер, который будет работать одинаково на любом совместимом хосте.

Официальное определение

“Docker — это платформа с открытым исходным кодом, которая автоматизирует развертывание приложений в легковесных, переносимых контейнерах.”
Docker Documentation

Контейнеризация — не виртуализация. В отличие от виртуальных машин (VM), контейнеры используют ядро хост-системы напрямую, что делает их быстрее, легче и эффективнее по потреблению ресурсов.


🧱 Docker Image — “шаблон” приложения

Что это?

Docker image — это неподвижный (immutable), зафиксированный шаблон, содержащий всё необходимое для запуска приложения: операционную систему, зависимости, приложение, переменные окружения, команды запуска и т.д.

Образы создаются на основе Dockerfile и хранятся в реестрах (registries), например:

Особенности образов

  • Иммутабельны: один раз создан — не меняется.
  • Слоистая структура (layers): каждый шаг в Dockerfile создаёт новый слой. Docker кэширует слои, что ускоряет сборку.
  • Переносимы: образ можно запустить на любом сервере с Docker, независимо от ОС (если архитектура совместима).

Пример: запуск образа

docker run nginx:alpine

Здесь nginx:alpine — это образ, доступный на Docker Hub. Docker скачает его (если ещё не скачан) и запустит контейнер.

Подсказка

Образы часто имеют теги (:latest, :1.21, :alpine). Используйте конкретные теги вместо :latest в production!


📦 Docker Container — запущенный экземпляр образа

Что это?

Контейнер — это запущенный экземпляр Docker-образа. Если образ — это класс в ООП, то контейнер — это объект.

Контейнер:

  • Изолирован от хоста и других контейнеров (сеть, файловая система, процессы).
  • Имеет собственное пространство имён, cgroups и root-файловой системы.
  • Может быть запущен, остановлен, перезапущен, удалён.

Как создаётся контейнер?

docker run ubuntu:22.04 echo "Hello from container!"
  1. Docker проверяет, есть ли образ ubuntu:22.04 локально.
  2. Если нет — скачивает его с Docker Hub.
  3. Запускает контейнер на основе этого образа.
  4. Выполняет команду echo.
  5. Контейнер завершает работу.

Отличие от виртуальной машины

ВМ эмулирует целое железо и ОС. Контейнер использует ядро хоста, но изолирует процессы, сеть и файловую систему. Это делает контейнеры быстрее и экономичнее.


Основные команды Docker

sudo systemctl start docker #start docker demon manually
docker ps #показывает список запущенных контейнеров
docker ps -a #показывает список запущенных и остановленных контейнеров
docker container ls #аналогично
docker images #показывает список локальных образов
docker run hello-world #создание контейнера из образа hellp-world
			--name simple_name #задаем имя контейнеру
			--rm #автоматичесское удаление после остановки
docker rm "ID/name" #удалить контейнер
docker --help #help
docker system prune # удалить из системы контейнеры, которые уже не используются, ненужные сети и образы без имен и меток
docker run -it --rm busybox #подключится интерактивно через терминал sh к контейнеру, который был создан на основе образа  busybox
# --rm автоматическое удаление контейнера после остановки
	hostname #показать ID контейнера
	hostname -i #показывает ip, присвоенный этому контейнеру
docker stop "ID/name" #остановка контейнера
docker kill "ID/name" #убить контейнер
docker attach "ID/name" #подключится в командную оболочку запущенного контейнера
docker container prune #удаляет все остановленные контейнеры

Пример с контейнером nginx

docker run -d nginx #запустить контейнер nginx и подключится к нему в фоновом режиме
docker container inspect "ID/name" #все детали контейнера
docker logs "ID/name" #посмотреть логи
docker exec -it "ID/name" bash #запускаем процесс bash внутри контейнера
	/usr/share/nginx/html/index.html # index page for nginx
docker cp server.py $CONTAINER_ID:/app #скопировать файл server.py в дирректорию app $CONTAINER_ID
docker cp $CONTAINER_ID:/app/server.py . #скопировать файл из контейнера на локальную машину

Mapping ports

Для открытия сервиса по определенному порту внутри контейнера

docker run -d -p 8080:80 nginx
# -p позволяет открыть порт 8080(внешний) на компе и пробросить его на порт 80(внутренний) внутри контейнера!

После этого можно в браузере переходить по 127.0.0.1:8080 и мы увидим index page for nginx

Mapping томов (valumes)

Замена содержимого папки /usr/share/nginx/html в контейнере на содержимое из ${PWD} на локальной машине

docker run -d -v ${PWD}:/usr/share/nginx/html nginx
# -v подлючение тома ${PWD} в контейнер по этому пути /usr/share/nginx/html
# PWD - переменная, содержащая текуший расположение в терминале, так же можно использовать абсолютные и относительные пути

Перенос строк

docker run \
--name simple_name \
-v ${PWD}:/usr/share/nginx/html \
-p 8080:80 \
-d \
--rm \
nginx

🛠️ Dockerfile — “рецепт” для сборки образа

Что это?

Dockerfile — это текстовый файл с инструкциями, по которым Docker строит образ.

Каждая строка — это слой в образе. Docker кэширует слои, поэтому при повторной сборке не пересобирает всё с нуля.

Пример Dockerfile

# Базовый образ
FROM alpine:3.18
 
# Автор/владелец
LABEL maintainer="admin@selfops.ru"
 
# Установка зависимостей
RUN apk add --no-cache nginx
 
# Копируем конфиг
COPY nginx.conf /etc/nginx/nginx.conf
 
# Создаём директорию для статики
RUN mkdir -p /var/www/html
 
# Копируем HTML-файл
COPY index.html /var/www/html/
 
# Открываем порт
EXPOSE 80
 
# Команда запуска
CMD ["nginx", "-g", "daemon off;"]

Основные инструкции

ИнструкцияНазначение
FROMБазовый образ (обязательно первая)
RUNВыполняет команду во время сборки
COPY / ADDКопирует файлы из хоста в образ
CMDКоманда по умолчанию при запуске контейнера
ENTRYPOINTФиксирует исполняемый файл (можно дополнять аргументами)
ENVУстанавливает переменные окружения
EXPOSEДокументирует, что контейнер слушает порт (не открывает!)
WORKDIRУстанавливает рабочую директорию

Важно

EXPOSE не открывает порт на хосте. Для этого нужно использовать -p при docker run.


Создание Dockerfile

Docker image создается на основе Dockerfile (файл с инструкциями по созданию образа). Обычно Dockerfile помещают в корень приложения. При создании образа желательно указать имя и тег для образа. Используем Dockerfile когда билдим свой Docer image.

FROM python:alpine # базовый образ, alpine(тэг) - минимальная версия образа
 
WORKDIR /app # создаем рабочую дирректорию app в корне приложения
 
COPY . . # копирование фалов из локальной текущей папки в WORKDIR, и WORKDIR станет текущей папкой для всех последующих команд
 
CMD ["python", "main.py"] # команда, которая будет выполнена. Запустится процесс python с аргументом main.py

Сборка образа

docker build . -t my-calendar:4.1.3 # созданин image с именем my-calendar и тэгом 4.1.3 на основе Dockerfile в текщей директории
docker run my-calendar:4.1.3 # запустить контейнер на основе образа my-calendar:4.1.3
docker build . -t my-calendar:4.1.3; docker run my-calendar:4.1.3 # так же можно объединить команды для удобства
  • -t — задаёт имя и тег образа.
  • . — путь к контексту сборки (где лежит Dockerfile).

🔄 Docker Compose — оркестрация нескольких контейнеров

Зачем он нужен?

Когда приложение состоит из нескольких сервисов (например, веб-сервер, база данных, кэш), удобно управлять ими единым файлом конфигурации. Вот тут и приходит на помощь Docker Compose.

Что такое docker-compose.yml?

Это YAML-файл, описывающий:

  • Какие сервисы запускать
  • Какие образы использовать
  • Порты, тома, переменные окружения
  • Сети и зависимости между сервисами

Пример: WordPress + MySQL

version: '3.8'
 
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: example
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - wp-network
 
  wordpress:
    image: wordpress:latest
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
    depends_on:
      - db
    networks:
      - wp-network
 
volumes:
  db_data:
 
networks:
  wp-network:
    driver: bridge

Запуск

docker-compose up -d
  • -d — в фоновом режиме (detached).
  • Все сервисы запускаются, сети и тома создаются автоматически.

Еще пример

docker-compose необходим для запуска и настройки нескольких контейнеров в одном файле, позволяет автоматически создать образ на основе Dockerfile.

Важно

docker-compose автоматически создает изолированную сеть для взаимодействия контейнеров и поднимает DNS для взаимодействия между контейнерами используя имена сервисов а не ip

version: '3'
services:
  app:
    build: ./app
    restart: always
  mongo:
    image: mongo
    restart: always
services:
	frontend:
		build: .
		command: python3 server.py
		volumes:
			- type: bind
			  source: .
			  target: /app
		environment:
			PYTHONDONTWRITEBYTECODE: 1
		ports:
			- "8080:80"
docker-compose up -d # для запуска docker-compose и подключение к нему в фоновом режиме
docker-compose down # остановка и удаление всех контейнеров docker-compose
docker-compose up -d --build # перебилдить образы при изменении приложения
restart: always #перезапускать контейнер, если процесс остановился
docker compose build; docker compose up #собрать образ и запустить контейнер находясь в одной дирректории с docker-compose docker-compose

Еще раз про Mapping volumes

Для сохранения данных после перезапуска контейнеров используется Mapping volumes в одной из двух вариаций:

  1. расшарить папку из Хоста ОС (чтение - запись). Данный вариант называется “bind mounts”
  2. Создать и расшарить папку внутри Docker (чтение - запись), в таком случае возможно расшарить папку для разных контейнеров. В этом случае обычно “Mountpoint”: “var/lib/docker/volumes/…”
#подключение по варианту 1
version: '3'
services:
  ...
  mysql:
    image:mysql
    ...
    volumes:
	  - /var/lib/mysql/exception_dir #папка иключение, которую не хотим перезапиывать
	  - ./mysql_data:/var/lib/mysql #mysql_data - папка на хосте
	...
#подключение по варианту 2
version: '3'
services:
  ...
  mysql:
    image:mysql
    ...
    volumes:
	  - /var/lib/mysql/exception_dir #папка иключение, которую не хотим перезапиывать
	  - mysql_data:/var/lib/mysql
	...
  volumes:
    mysql_data: #создаем том внутри Docker
docker volume ls #показать все тома внутри Docker
docker inspect name_of_tom #детали о томе

🔗 Как всё это связано?

graph TB
    A[Dockerfile] -->|docker build| B[Docker Image]
    B -->|docker run| C[Docker Container]
    D[docker-compose.yml] -->|docker-compose up| C
    C -->|изолированно| E[Хост-система]
  • Dockerfile → создаёт → Docker image
  • Docker image → запускается как → Docker container
  • docker-compose.yml → управляет несколькими → Docker containers

✅ Преимущества Docker в Self-Hosting

ПлюсОбъяснение
ИзолированностьСервисы не мешают друг другу
ПереносимостьРаботает на любом Linux-сервере
ВоспроизводимостьОдин и тот же образ везде работает одинаково
Простота обновленияПересобрал образ — перезапустил контейнер
Экономия ресурсовНет накладных расходов виртуализации

Для SelfOps

Используйте Docker + Docker Compose для развертывания таких сервисов, как:


📚 Полезные ресурсы


🏁 Заключение

Docker — это не просто модная технология, а фундамент современной автоматизации и self-hosting. Понимание разницы между Dockerfile, образом, контейнером и Docker Compose — первый шаг к уверенному управлению своей инфраструктурой.

Success

Совет от SelfOps:
Начинайте с простого. Разверните nginx в контейнере, потом добавьте docker-compose, потом — базу данных. Постепенно вы построите свою домашнюю облачную платформу.


Quote

“Сначала ты учишься Docker. Потом он учит тебя архитектуре, автоматизации и терпению.”
— Анонимный админ, 2025