Лекция (PRO): Контейнеры в Linux

Docker без страшных слов: Углубленное погружение.

🚀 Цель лекции

Понять не только ЧТО такое контейнер, но и ПОЧЕМУ он работает так быстро и эффективно. Мы разберем концепцию слоев и научимся базовым, но самым нужным командам.

1. Проблема: "Ад Окружений"

Вы уже знаете классику: "У меня на машине все работает!". Давайте копнем глубже, почему так происходит?

  • Разные версии библиотек: У вас `openssl` версии 3.x, а на сервере 1.1.x. Ваша программа, использующая новые функции шифрования, падает.
  • Разные системные пути: Ваша программа ищет конфиг в `/home/user/app/config.ini`, а на сервере ее запускают из-под `www-data` и конфиг лежит в `/var/www/config.ini`.
  • Разные "скрытые" зависимости: Ваша программа использует утилиту `imagemagick` для обработки картинок. Вы ее себе поставили и забыли. На сервере ее нет — программа падает с невнятной ошибкой.

Проблема: Приложение — это не только ваш код. Это "код + зависимости + конфиги + файловая структура". Этот клубок называется Окружение. Docker "запаковывает" весь этот клубок в один стандартный ящик.

2. Контейнер vs. Виртуальная Машина (Глубже)

Оба решают проблему изоляции. Но цена решения — разная.

Аналогия: Дом vs. Квартира (Pro)

🏠 Виртуальная Машина (Дом)
Вы строите полноценный дом с нуля. Вам нужен свой фундамент (эмуляция железа), свои трубы, свой генератор, свои стены (целая Гостевая ОС — Windows Server, Ubuntu и т.д.). Вы тратите кучу ресурсов (диск, память) на то, чтобы просто "стоял дом", еще до того, как "завезли мебель" (ваше приложение).

📦 Контейнер (Квартира)
Вы арендуете квартиру в готовом здании. Здание — это ваш компьютер (Хост-система). Фундамент и коммуникации (вода, свет, канализация) — общие. В роли "коммуникаций" выступает Ядро Linux.

Контейнер — это просто изолированная комната (процесс), которая пользуется общим ядром. Docker — это "домоуправ", который следит, чтобы жилец из квартиры 1 не ходил в квартиру 2 и не видел, что там происходит.

Параметр Виртуальная Машина (VM) Контейнер (Docker)
Что изолирует? Полностью Аппаратное Обеспечение Процессы, Файлы, Сеть (на уровне ОС)
Что запускает? Целую Гостевую ОС (со своим ядром) Только Приложение (использует ядро Хоста)
Размер Гигабайты (ГБ) Мегабайты (МБ)
Время запуска Минуты Секунды (или доли секунд)
Накладные расходы Высокие (Память/CPU на целую ОС) Очень низкие

3. Анатомия Docker ("Три кита")

Повторим "трех китов" (рецепт, торт, текст), но детальнее.

  • 1. Dockerfile — Текст Рецепта
    Это файл с именем `Dockerfile` (без расширения). Он — ваш план по сборке "коробки".

    # Базовый "слой". Берем готовый рецепт Python
    # Нам не нужно ставить Ubuntu, потом Python...
    # Берем готовый образ из Docker Hub
    FROM python:3.10-slim
    
    # Устанавливаем "рабочую папку" внутри контейнера
    WORKDIR /app
    
    # Копируем файл с зависимостями
    # (снаружи из . в /app внутри)
    COPY requirements.txt .
    
    # Устанавливаем зависимости ВНУТРИ контейнера
    RUN pip install -r requirements.txt
    
    # Копируем ВЕСЬ наш код (снаружи из . в /app внутри)
    COPY . .
    
    # Сообщаем Docker, что приложение будет "слушать" порт 5000
    EXPOSE 5000
    
    # Команда, которая запустится, когда "включат" контейнер
    CMD ["python", "app.py"]
    
  • 2. Image (Образ) — Рецепт
    Когда вы запускаете команду `docker build -t my-app .`, Docker читает `Dockerfile` и создает Образ.
    Образ — это неизменяемый (read-only), упакованный шаблон. Он как `*.iso` файл или слепок системы. Он лежит у вас на диске и ничего не делает, пока его не попросят.

  • 3. Container (Контейнер) — Торт
    Когда вы запускаете `docker run my-app`, Docker берет неизменяемый Образ `my-app`, создает поверх него тонкий "записываемый" слой и запускает процесс (вашу команду `CMD`).
    Все, что ваше приложение будет писать на диск (логи, временные файлы), попадет в этот верхний "записываемый" слой. Сам Образ (`my-app`) остается нетронутым.

4. Секрет скорости: Концепция Слоев

Это самое важное, что нужно понять о Docker. Почему он такой быстрый и эффективный?

Каждая команда в `Dockerfile` (FROM, RUN, COPY) создает новый слой (layer) в Образе.

Представьте, что Образ — это стопка прозрачных пленок:

  • Слой 1 (FROM): Пленка с файлами ОС Ubuntu.
  • Слой 2 (RUN apt install): Пленка, где *добавлен* Python.
  • Слой 3 (COPY .): Пленка, где *добавлен* ваш `app.py`.

Все эти слои неизменяемы (read-only). Когда вы смотрите на "собранный" Образ, вы видите их все, как будто они — единое целое.

В чем магия? (Кэширование)

Допустим, вы собрали Образ. Теперь вы поменяли одну строчку в `app.py` и запускаете `docker build` снова.

Docker смотрит на `Dockerfile`:

  • Слой 1 (FROM): "Команда `FROM python:3.10` не менялась? Беру готовый слой из кэша."
  • Слой 2 (RUN pip install): "Команда `RUN pip install...` не менялась? И `requirements.txt` не менялся? Беру готовый слой из кэша." (Установка пакетов пропускается!)
  • Слой 3 (COPY . .): "Ага! Файл `app.py` изменился. Этот слой нужно пересобрать."

Результат: Вместо полной пересборки (10 минут), сборка занимает 2 секунды (только копирование вашего кода). Это и есть кэширование слоев.

5. Реальная польза (Pro)

  • Воспроизводимость (Reproducibility)
    `Dockerfile` — это текстовый файл. Вы кладете его в Git вместе с кодом. Любой разработчик в мире, сделав `git pull` и `docker build`, получит байт-в-байт такое же окружение, как у вас. Проблема "у меня работает" решена полностью.
  • Скорость развертывания
    На сервер не нужно ставить Python, Nginx, и т.д. На сервер нужно поставить только Docker. А потом просто запустить команду `docker run my-app`. Развертывание нового сервера занимает секунды.
  • Чистота Хост-системы
    Больше никакого "мусора" в вашей основной ОС. Вы можете попробовать 10 разных баз данных (MySQL, Postgre, Mongo, Redis), каждая в своем контейнере. Когда они не нужны, вы удаляете контейнеры и образы. В системе не остается ни одного лишнего файла.

6. Практика (Pro-команды)

Команды, которые вы будете использовать 90% времени.

  • Собрать Образ (из `Dockerfile`):

    # -t my-app (tag, "дать имя" my-app)
    # . (точка в конце) "искать Dockerfile в этой папке"
    docker build -t my-app .
  • Запустить веб-сервер (Самая важная команда):

    docker run -d -p 8080:80 --name my-nginx nginx
    Разбор флагов: -d -p --name
    • -d (Detached): Запустить в фоне (не занимать терминал).
    • -p 8080:80 (Port): "Пробросить" порт. Соединить порт 8080 на моем компьютере (Хосте) с портом 80 внутри контейнера (где Nginx слушает).
    • --name my-nginx: Дать контейнеру "человеческое" имя, чтобы не запоминать ID.
    • nginx: Имя Образа, который нужно запустить (Docker сам скачает его из Docker Hub).

    После этой команды откройте в браузере `http://localhost:8080` и увидите "Welcome to Nginx!".

  • Посмотреть логи (что происходит внутри `-d` контейнера):

    docker logs my-nginx
  • Посмотреть запущенные контейнеры:

    docker ps
  • Остановить и Удалить контейнер:

    docker stop my-nginx
    docker rm my-nginx
  • Удалить Образ (чтобы освободить место):

    docker rmi nginx
  • "Прибраться" (Удалить все остановленные контейнеры):

    docker container prune

7. В чем подвох? (Маленькая правда)

Я сказал, что контейнеры "используют Ядро Хоста". Но что, если у вас Windows или macOS? У них же нет ядра Linux!

Подвох: Docker для Windows и Mac все равно запускает Linux.

При установке Docker Desktop он ставит сверх-легкую, оптимизированную виртуальную машину Linux (используя WSL2 в Windows или HyperKit в Mac). Она запускается быстро и "прячется" от вас.

Все ваши контейнеры на самом деле запускаются внутри этой скрытой VM. Docker Desktop просто "пробрасывает" команды и порты из вашей Windows/Mac в эту VM.

Поэтому Docker "роднее" всего чувствует себя именно на Linux-серверах, где ему не нужна прослойка в виде VM. Но для разработки на Windows/Mac это почти незаметно.