Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Docker Compose Lab: Flask + PostgreSQL + pgAdmin на Ubuntu Server 24.04 LTS

Практический курс в одном README

Эта лабораторная работа объясняет Docker через небольшой backend-проект. Внутри виртуальной машины Ubuntu Server 24.04 LTS запускаются три контейнера: Flask-приложение, PostgreSQL и pgAdmin.

Рабочая среда:

  • Основная машина: Windows, Linux или macOS.
  • Платформа виртуализации: Oracle VirtualBox.
  • Гостевая операционная система: Ubuntu Server 24.04 LTS.
  • Приложение: Flask-приложение на Python.
  • База данных: PostgreSQL.
  • Web-интерфейс базы данных: pgAdmin.
  • Инструменты контейнеризации: Docker Engine и Docker Compose plugin.

Оглавление


Быстрый старт после подготовки файлов

Если Docker уже установлен, а все файлы проекта созданы, минимальный запуск выглядит так:

cp .env.example .env
docker compose config
docker compose up -d --build
curl http://localhost:8000/health
curl http://localhost:8000/visits

Ожидаемая идея результата: Flask отвечает на HTTP-запросы, PostgreSQL принимает подключения, а endpoint /visits записывает данные в таблицу visits.


1. Цель лабораторной работы

После выполнения этой работы вы сможете:

  1. Подготовить Ubuntu Server 24.04 LTS в Oracle VirtualBox для работы с Docker.
  2. Установить Docker Engine и Docker Compose plugin официальным способом.
  3. Создать простое Flask-приложение.
  4. Собрать Docker image на основе Dockerfile.
  5. Запустить несколько контейнеров через docker compose.
  6. Подключить Flask-контейнер к PostgreSQL-контейнеру через внутреннюю Docker-сеть.
  7. Сохранить данные PostgreSQL с помощью Docker volume.
  8. Проверить приложение через curl, браузер, PostgreSQL CLI и pgAdmin.
  9. Использовать ежедневные Docker-команды для диагностики и управления контейнерами.
  10. Понять связь между Docker, Docker Compose, Docker Hub и Kubernetes.

Главная идея: Docker помогает запускать приложение одинаково на разных машинах. Вы получаете управляемую среду, где Python, зависимости, база данных и web-интерфейс запускаются предсказуемо и очищаются безопасно.


2. Что будет создано

В проекте будут работать 3 сервиса.

Сервис Имя контейнера Назначение Внешний порт на Ubuntu VM
web flask_web Flask-приложение на Python 8000
db postgres_db PostgreSQL database 5432
pgadmin pgadmin_web Web-интерфейс для управления PostgreSQL 5050

После запуска доступны следующие адреса:

http://localhost:8000
http://localhost:8000/health
http://localhost:8000/visits
http://localhost:8000/visits/count
http://localhost:8000/info

Если доступ выполняется с основной машины через Host-Only adapter, вместо localhost нужно использовать Host-Only IP Ubuntu Server:

http://UBUNTU_HOST_ONLY_IP:8000
http://UBUNTU_HOST_ONLY_IP:5050

Например:

http://192.168.56.101:8000
http://192.168.56.101:5050

2.1. Визуальная карта лабораторной работы

flowchart TD
    A[Ubuntu Server 24.04 LTS<br/>Oracle VirtualBox] --> B[Установка Docker Engine]
    B --> C[Проверка docker и docker compose]
    C --> D[Создание файлов проекта]
    D --> E[Dockerfile<br/>сборка Flask image]
    D --> F[docker-compose.yml<br/>web + db + pgAdmin]
    E --> G[docker compose up -d --build]
    F --> G
    G --> H[Проверка Flask через curl/browser]
    H --> I[Запись и чтение visits в PostgreSQL]
    I --> J[Проверка данных через psql и pgAdmin]
    J --> K[Понимание network, volume, logs, exec]
    K --> L[Docker Hub: tag, login, push, pull]
    L --> M[Kubernetes как следующий уровень]

    classDef host fill:#eef2ff,stroke:#4338ca,stroke-width:2px,color:#111827;
    classDef docker fill:#ecfeff,stroke:#0891b2,stroke-width:2px,color:#111827;
    classDef app fill:#f0fdf4,stroke:#16a34a,stroke-width:2px,color:#111827;
    classDef check fill:#fff7ed,stroke:#ea580c,stroke-width:2px,color:#111827;

    class A host;
    class B,C,D,E,F,G docker;
    class H,I,J app;
    class K,L,M check;
Loading

2.2. Архитектура лабораторной среды

flowchart LR
    subgraph HOST[Основная машина]
        Browser[Browser или curl]
    end

    subgraph VM[Ubuntu Server 24.04 LTS<br/>Oracle VirtualBox]
        Docker[Docker Engine]

        subgraph Compose[Docker Compose project]
            subgraph Net[lab_network bridge]
                Web[web<br/>Flask app<br/>container: flask_web<br/>port: 8000]
                DB[db<br/>PostgreSQL<br/>container: postgres_db<br/>port: 5432]
                PGA[pgadmin<br/>pgAdmin<br/>container: pgadmin_web<br/>port: 80]
            end
            Vol[(postgres_data volume<br/>/var/lib/postgresql/data)]
        end
    end

    Browser -->|HTTP :8000| Web
    Browser -->|HTTP :5050| PGA
    Docker --> Compose
    Web -->|DB_HOST=db<br/>TCP 5432| DB
    PGA -->|Host=db<br/>TCP 5432| DB
    DB --> Vol

    classDef outside fill:#f8fafc,stroke:#64748b,stroke-width:2px,color:#0f172a;
    classDef vm fill:#eef2ff,stroke:#4f46e5,stroke-width:2px,color:#0f172a;
    classDef net fill:#ecfeff,stroke:#06b6d4,stroke-width:2px,color:#0f172a;
    classDef service fill:#f0fdf4,stroke:#22c55e,stroke-width:2px,color:#052e16;
    classDef data fill:#fef3c7,stroke:#d97706,stroke-width:2px,color:#451a03;

    class Browser outside;
    class VM,Docker vm;
    class Compose,Net net;
    class Web,DB,PGA service;
    class Vol data;
Loading

3. Простая теория: зачем нужен Docker

Без Docker учебные и реальные проекты часто сталкиваются с проблемами:

  • на одной машине Python 3.10, на другой Python 3.12;
  • у одного установлены нужные библиотеки, у другого нет;
  • PostgreSQL установлен с другой версией или другой настройкой;
  • приложение работает на одной машине, но не работает на другой;
  • после экспериментов трудно полностью очистить систему.

Docker решает эти проблемы через контейнеры. Контейнер содержит приложение и его зависимости. Если image собран правильно, его можно запускать одинаково на разных машинах, где установлен Docker.

В этой лабораторной работе Docker особенно полезен потому, что не нужно устанавливать PostgreSQL и pgAdmin напрямую в Ubuntu. Они запускаются как отдельные контейнеры. Это чище, проще для удаления и ближе к реальным DevOps-практикам.


4. Основные понятия Docker

4.1. Docker image

Docker image — это шаблон для создания контейнера. Его можно сравнить с готовым пакетом, где уже описано, какие файлы и зависимости нужны приложению.

В этой работе image для Flask содержит:

  • Python 3.11;
  • библиотеки из requirements.txt;
  • файл app.py;
  • команду запуска приложения.

Команда для просмотра локальных images:

docker images

4.2. Docker container

Docker container — это запущенный экземпляр image. Если image — это рецепт или шаблон, то container — это уже работающий процесс.

Команды:

docker ps

Показывает только запущенные контейнеры.

docker ps -a

Показывает все контейнеры, включая остановленные.

4.3. Dockerfile

Dockerfile — это инструкция сборки image. В нём записано:

  • какой базовый image использовать;
  • какую рабочую папку создать;
  • какие файлы скопировать;
  • какие зависимости установить;
  • какую команду выполнить при запуске контейнера.

В этой работе Dockerfile строит image для Flask-приложения.

4.4. Docker Compose

Docker Compose нужен, когда приложение состоит из нескольких связанных сервисов. Например, Flask отдельно, PostgreSQL отдельно, pgAdmin отдельно.

Без Compose пришлось бы вручную писать несколько длинных команд docker run, создавать сеть, подключать volumes и передавать переменные окружения. С Compose всё описано в одном файле docker-compose.yml, а запуск выполняется одной командой:

docker compose up -d --build

4.5. Docker network

Docker Compose создаёт внутреннюю сеть. Внутри этой сети контейнеры могут обращаться друг к другу по имени сервиса.

В нашем проекте Flask подключается к PostgreSQL так:

DB_HOST=db

Почему db? Потому что в docker-compose.yml сервис PostgreSQL называется db.

Важно: внутри контейнера localhost означает сам этот контейнер. Если Flask-контейнер использует localhost, он будет искать PostgreSQL внутри себя, а PostgreSQL находится в другом контейнере. Поэтому правильно использовать db, а не localhost.

Дополнительная схема показывает главную сетевую идею Compose:

flowchart LR
    Web[web<br/>Flask container] -->|правильно:<br/>DB_HOST=db| DB[db<br/>PostgreSQL container]
    Pg[pgadmin<br/>pgAdmin container] -->|правильно:<br/>Host=db| DB
    Web -. неправильно .-> Localhost[localhost внутри web<br/>это сам web-контейнер]

    classDef ok fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#052e16;
    classDef warn fill:#fee2e2,stroke:#dc2626,stroke-width:2px,color:#450a0a;
    class Web,DB,Pg ok;
    class Localhost warn;
Loading

4.6. Docker volume

Volume — это постоянное хранилище данных. Контейнер можно удалить и создать заново, но данные PostgreSQL должны сохраниться.

В этой работе используется volume:

volumes:
  postgres_data:

Он подключается к PostgreSQL:

- postgres_data:/var/lib/postgresql/data

Визуально volume работает так:

flowchart TD
    A[postgres_db container] --> B["/var/lib/postgresql/data"]
    B --> C[(postgres_data Docker volume)]
    D[docker compose down] --> E[Контейнеры удалены<br>volume сохранён]
    F[docker compose down -v] --> G[Контейнеры удалены<br>volume удалён<br>данные потеряны]

    classDef data fill:#fef3c7,stroke:#d97706,stroke-width:2px,color:#451a03;
    classDef safe fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#052e16;
    classDef danger fill:#fee2e2,stroke:#dc2626,stroke-width:2px,color:#450a0a;
    class C data;
    class D,E safe;
    class F,G danger;
Loading

Команда:

docker volume ls

Показывает volumes.

Важно:

docker compose down

Останавливает и удаляет контейнеры, но не удаляет volume с данными.

docker compose down -v

Останавливает контейнеры и удаляет volume. Это удаляет данные PostgreSQL.


5. Docker container vs virtual machine

Контейнер и виртуальная машина решают похожую задачу изоляции, но делают это по-разному.

flowchart TB
    subgraph VMSTYLE[Virtual Machine]
        HW1[Hardware]
        HOSTOS1[Host OS]
        HYP[Hypervisor / VirtualBox]
        GOS1[Guest OS 1]
        APP1[App + Libraries]
        GOS2[Guest OS 2]
        APP2[App + Libraries]
        HW1 --> HOSTOS1 --> HYP
        HYP --> GOS1 --> APP1
        HYP --> GOS2 --> APP2
    end

    subgraph CONTSTYLE[Docker Container]
        HW2[Hardware]
        HOSTOS2[Host OS Linux kernel]
        DOCKER[Docker Engine]
        C1[Container 1<br/>App + Libraries]
        C2[Container 2<br/>App + Libraries]
        HW2 --> HOSTOS2 --> DOCKER
        DOCKER --> C1
        DOCKER --> C2
    end

    classDef vm fill:#eef2ff,stroke:#4f46e5,stroke-width:2px,color:#0f172a;
    classDef docker fill:#ecfeff,stroke:#0891b2,stroke-width:2px,color:#0f172a;
    class VMSTYLE,HW1,HOSTOS1,HYP,GOS1,GOS2,APP1,APP2 vm;
    class CONTSTYLE,HW2,HOSTOS2,DOCKER,C1,C2 docker;
Loading
Критерий Docker container Virtual machine
Уровень изоляции Изоляция процессов Полная гостевая операционная система
Kernel Использует kernel host-системы Имеет собственный guest OS kernel
Размер Обычно меньше Обычно больше
Запуск Обычно быстрее Обычно медленнее
Подходит для Упаковка и запуск приложений Запуск другой ОС или полной изолированной среды
Пример в этой работе Flask, PostgreSQL, pgAdmin Ubuntu Server внутри Oracle VirtualBox

Контейнеры не заменяют виртуальные машины полностью. В этой лабораторной работе они используются вместе: Ubuntu Server работает как виртуальная машина, а внутри неё Docker запускает контейнеры.

Такой подход удобен для обучения, потому что можно экспериментировать внутри VM и не загрязнять основную систему.


6. Docker Compose vs Kubernetes

Docker Compose и Kubernetes связаны с контейнерами, но предназначены для разных уровней сложности.

Вопрос Docker Compose Kubernetes
Главная цель Запуск нескольких контейнеров на одной машине Управление контейнерами в кластере
Где удобно использовать Локальная разработка, лабораторные работы, простые серверы Production-системы, масштабирование, отказоустойчивость
Основной файл docker-compose.yml Несколько YAML-файлов: Deployment, Service, ConfigMap, Secret и др.
Масштабирование Простое и ручное Более развитое и автоматизированное
Самовосстановление Ограниченное Встроенные механизмы rescheduling, health checks, rollout
Сложность Ниже Выше

Рекомендуемый порядок изучения:

  1. Docker basics.
  2. Dockerfile.
  3. Docker Compose.
  4. Docker Hub.
  5. Kubernetes.

Kubernetes легче понять после уверенного понимания image, container, port, volume, network и service name.

Визуально разница выглядит так:

flowchart LR
    subgraph ComposeSide[Docker Compose]
        C1[Одна машина]
        C2[docker-compose.yml]
        C3[web + db + pgadmin]
        C4[Локальная разработка<br/>и учебные проекты]
        C1 --> C2 --> C3 --> C4
    end

    subgraph KubernetesSide[Kubernetes]
        K1[Кластер машин]
        K2[Deployment / Service / ConfigMap / Secret]
        K3[Много экземпляров приложений]
        K4[Production, scaling,<br/>self-healing, rollout]
        K1 --> K2 --> K3 --> K4
    end

    C4 -. следующий уровень после уверенного Docker .-> K1

    classDef compose fill:#ecfeff,stroke:#0891b2,stroke-width:2px,color:#0f172a;
    classDef k8s fill:#eef2ff,stroke:#4f46e5,stroke-width:2px,color:#0f172a;
    class ComposeSide,C1,C2,C3,C4 compose;
    class KubernetesSide,K1,K2,K3,K4 k8s;
Loading

7. Docker Hub

Docker Hub — это registry, то есть сервис для хранения и распространения Docker images.

Простая аналогия:

  • GitHub хранит source code.
  • Docker Hub хранит Docker images.

Типичный workflow:

  1. Написать приложение.
  2. Создать Dockerfile.
  3. Собрать image.
  4. Протестировать container локально.
  5. Сделать tag image.
  6. Выполнить docker push в Docker Hub.
  7. На другой машине выполнить docker pull и запустить image.

Важно: Docker Hub хранит images, но не хранит ваши локальные контейнеры и не хранит данные вашего PostgreSQL volume.

sequenceDiagram
    participant Dev as Ubuntu VM
    participant Local as Local Docker image
    participant Hub as Docker Hub registry
    participant Other as Другая машина

    Dev->>Local: docker compose build web
    Dev->>Local: docker tag image username/repository:1.0
    Dev->>Hub: docker login
    Dev->>Hub: docker push username/repository:1.0
    Other->>Hub: docker pull username/repository:1.0
    Other->>Other: docker run или docker compose up
Loading

8. Итоговая структура проекта

Создайте такую структуру:

docker-flask-postgres-lab/
├── app.py
├── requirements.txt
├── Dockerfile
├── docker-compose.yml
├── .env.example
├── .gitignore
├── .dockerignore
└── README.md

Файл .env создаётся локально из .env.example и не публикуется в GitHub.

В этой публикационной версии все основные объяснения, шаги, команды и код находятся в README.md. Репозиторий остаётся компактным и удобным для чтения на GitHub.


9. Настройка сети в Oracle VirtualBox

Для лабораторной работы удобно использовать 2 сетевых адаптера.

Adapter Mode Назначение
Adapter 1 NAT Интернет внутри Ubuntu Server
Adapter 2 Host-Only Adapter Доступ к Ubuntu Server с основной машины

9.1. Создание Host-Only сети

В Oracle VirtualBox Manager откройте:

Tools → Network → Host-only Networks

Рекомендуемые параметры:

IPv4 Address: 192.168.56.1
IPv4 Network Mask: 255.255.255.0
DHCP Server: Enabled
Lower Address Bound: 192.168.56.101
Upper Address Bound: 192.168.56.254

9.2. Подключение адаптеров к Ubuntu VM

Выключите Ubuntu Server VM и откройте:

Ubuntu VM → Settings → Network

Настройте:

Adapter 1: NAT
Adapter 2: Host-only Adapter

9.3. Проверка IP-адресов в Ubuntu

В Ubuntu выполните:

ip -br addr

Пример результата:

enp0s3   UP   10.0.2.15/24
enp0s8   UP   192.168.56.101/24

Обычно:

  • 10.0.2.15 — NAT-интерфейс;
  • 192.168.56.101 — Host-Only интерфейс.

Запомните Host-Only IP. Далее он называется:

UBUNTU_HOST_ONLY_IP

9.4. Если Host-Only IP не появился

Проверьте интерфейсы:

ip -br link

Установите DHCP client, если он отсутствует:

sudo apt-get update
sudo apt-get install -y isc-dhcp-client

Поднимите интерфейс. Если ваш Host-Only интерфейс называется не enp0s8, замените имя:

sudo ip link set enp0s8 up
sudo dhclient enp0s8
ip -br addr

10. Установка Docker Engine и Docker Compose plugin на Ubuntu Server 24.04 LTS

Эти команды основаны на официальной инструкции Docker для Ubuntu.

10.1. Удалите старые или конфликтующие пакеты

for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
  sudo apt-get remove -y "$pkg" || true
done

10.2. Установите нужные системные пакеты

sudo apt-get update
sudo apt-get install -y ca-certificates curl

10.3. Добавьте официальный GPG key Docker

sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

10.4. Добавьте Docker repository

sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF

10.5. Установите Docker Engine и Compose plugin

sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

10.6. Проверьте установку

docker --version
docker compose version
sudo docker run hello-world
sudo systemctl status docker --no-pager

Если hello-world запустился, Docker работает.

10.7. Необязательно: запуск Docker без sudo

Для учебной VM можно добавить пользователя в группу docker:

sudo groupadd docker 2>/dev/null || true
sudo usermod -aG docker $USER
newgrp docker
docker run hello-world

Важное замечание по безопасности: пользователь в группе docker получает очень широкие права на машине. Для учебной VM это удобно, но на production-сервере такое решение нужно применять осторожно.


11. Создание папки проекта

Выполните:

cd ~
mkdir docker-flask-postgres-lab
cd docker-flask-postgres-lab

Создайте файлы:

touch app.py requirements.txt Dockerfile docker-compose.yml .env.example .gitignore .dockerignore README.md

Проверьте:

ls -la

12. Полный код всех файлов проекта

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

12.1. Файл app.py

Назначение: Flask-приложение. Оно подключается к PostgreSQL, создаёт таблицу visits, добавляет визиты и показывает служебные endpoints.

import os
import time
from datetime import datetime, timezone

import psycopg2
from flask import Flask, jsonify, request
from psycopg2.extras import RealDictCursor

app = Flask(__name__)
APP_VERSION = os.getenv("APP_VERSION", "1.0.0")


def get_db_connection():
    """Создаёт новое подключение к PostgreSQL, используя переменные окружения."""
    return psycopg2.connect(
        host=os.getenv("DB_HOST", "db"),
        port=os.getenv("DB_PORT", "5432"),
        database=os.getenv("DB_NAME", "labdb"),
        user=os.getenv("DB_USER", "labuser"),
        password=os.getenv("DB_PASSWORD", "labpassword"),
        connect_timeout=3,
    )


def wait_for_database(max_attempts=30, delay_seconds=2):
    """Ждёт, пока PostgreSQL станет доступен для подключения."""
    for attempt in range(1, max_attempts + 1):
        try:
            with get_db_connection() as connection:
                with connection.cursor() as cursor:
                    cursor.execute("SELECT 1;")
            print("Database is ready.", flush=True)
            return
        except Exception as error:
            print(
                f"Waiting for database... attempt {attempt}/{max_attempts}. Error: {error}",
                flush=True,
            )
            time.sleep(delay_seconds)
    raise RuntimeError("Database connection failed after waiting.")


def initialize_database():
    """Создаёт таблицу visits, если она ещё не существует."""
    with get_db_connection() as connection:
        with connection.cursor() as cursor:
            cursor.execute(
                """
                CREATE TABLE IF NOT EXISTS visits (
                    id SERIAL PRIMARY KEY,
                    client_ip TEXT,
                    user_agent TEXT,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                );
                """
            )
        connection.commit()


@app.get("/")
def home():
    return """
    <h1>Docker Flask PostgreSQL Lab</h1>
    <p>Flask-приложение работает внутри Docker-контейнера.</p>
    <p>PostgreSQL работает в отдельном контейнере, а контейнеры общаются через Docker Compose network.</p>
    <ul>
      <li><a href="/health">/health</a> — проверка Flask и PostgreSQL</li>
      <li><a href="/visits">/visits</a> — добавить визит и показать последние записи</li>
      <li><a href="/visits/count">/visits/count</a> — общее количество визитов</li>
      <li><a href="/info">/info</a> — техническая информация о запуске</li>
    </ul>
    """


@app.get("/health")
def health():
    try:
        with get_db_connection() as connection:
            with connection.cursor() as cursor:
                cursor.execute("SELECT 1;")
        database_status = "connected"
        status_code = 200
    except Exception as error:
        database_status = f"not connected: {error}"
        status_code = 503

    return (
        jsonify(
            {
                "status": "ok" if status_code == 200 else "error",
                "database": database_status,
                "app_version": APP_VERSION,
                "checked_at_utc": datetime.now(timezone.utc).isoformat(),
            }
        ),
        status_code,
    )


@app.get("/visits")
def visits():
    client_ip = request.headers.get("X-Forwarded-For", request.remote_addr)
    user_agent = request.headers.get("User-Agent", "unknown")

    with get_db_connection() as connection:
        with connection.cursor(cursor_factory=RealDictCursor) as cursor:
            cursor.execute(
                """
                INSERT INTO visits (client_ip, user_agent)
                VALUES (%s, %s)
                RETURNING id, created_at;
                """,
                (client_ip, user_agent),
            )
            new_visit = cursor.fetchone()

            cursor.execute(
                """
                SELECT id, client_ip, user_agent, created_at
                FROM visits
                ORDER BY id DESC
                LIMIT 10;
                """
            )
            latest_visits = cursor.fetchall()
        connection.commit()

    return jsonify(
        {
            "status": "success",
            "new_visit": dict(new_visit),
            "latest_visits": [dict(row) for row in latest_visits],
        }
    )


@app.get("/visits/count")
def visits_count():
    with get_db_connection() as connection:
        with connection.cursor() as cursor:
            cursor.execute("SELECT COUNT(*) FROM visits;")
            total = cursor.fetchone()[0]

    return jsonify({"total_visits": total})


@app.get("/info")
def info():
    return jsonify(
        {
            "app_version": APP_VERSION,
            "db_host_inside_compose_network": os.getenv("DB_HOST", "db"),
            "db_name": os.getenv("DB_NAME", "labdb"),
            "message": "В Docker Compose контейнеры обращаются друг к другу по имени сервиса, например db, а не localhost.",
        }
    )


if __name__ == "__main__":
    wait_for_database()
    initialize_database()
    app.run(host="0.0.0.0", port=8000)

Пояснение важных строк:

  • os.getenv(...) читает настройки из переменных окружения.
  • DB_HOST по умолчанию равен db, потому что это имя сервиса PostgreSQL в Docker Compose.
  • wait_for_database() ждёт готовности PostgreSQL, чтобы Flask не завершился слишком рано.
  • initialize_database() создаёт таблицу visits, если её ещё нет.
  • app.run(host="0.0.0.0", port=8000) разрешает доступ к Flask внутри контейнерной сети и через опубликованный порт.

12.2. Файл requirements.txt

Назначение: список Python-зависимостей.

flask==3.*
psycopg2-binary==2.9.*

Пояснение:

  • flask нужен для web-приложения.
  • psycopg2-binary нужен для подключения Python к PostgreSQL.

12.3. Файл Dockerfile

Назначение: инструкция для сборки image Flask-приложения.

FROM python:3.11-slim

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV PIP_NO_CACHE_DIR=1

WORKDIR /app

RUN useradd --create-home --shell /bin/bash appuser

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY app.py .
RUN chown -R appuser:appuser /app

USER appuser
EXPOSE 8000

CMD ["python", "app.py"]

Пояснение по шагам:

  • FROM python:3.11-slim берёт официальный Python image.
  • WORKDIR /app задаёт рабочую папку внутри container.
  • COPY requirements.txt . копирует файл зависимостей.
  • RUN pip install ... устанавливает зависимости.
  • COPY app.py . копирует приложение.
  • USER appuser запускает приложение не от root, что является более аккуратной практикой.
  • EXPOSE 8000 документирует порт приложения внутри container.
  • CMD ["python", "app.py"] запускает приложение.

12.4. Файл docker-compose.yml

Назначение: описание всех сервисов лабораторной работы.

name: docker-flask-postgres-lab

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    image: docker-flask-postgres-lab-web:1.0
    container_name: flask_web
    env_file:
      - .env
    environment:
      APP_VERSION: ${APP_VERSION:-1.0.0}
    ports:
      - "${WEB_PORT:-8000}:8000"
    depends_on:
      db:
        condition: service_healthy
    networks:
      - lab_network
    restart: unless-stopped

  db:
    image: postgres:16
    container_name: postgres_db
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    ports:
      - "${POSTGRES_HOST_PORT:-5432}:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 5s
      timeout: 5s
      retries: 10
    networks:
      - lab_network
    restart: unless-stopped

  pgadmin:
    image: dpage/pgadmin4:latest
    container_name: pgadmin_web
    environment:
      PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL}
      PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD}
    ports:
      - "${PGADMIN_HOST_PORT:-5050}:80"
    depends_on:
      db:
        condition: service_healthy
    networks:
      - lab_network
    restart: unless-stopped

volumes:
  postgres_data:

networks:
  lab_network:
    driver: bridge

Пояснение ключевых частей:

  • services содержит 3 сервиса: web, db, pgadmin.
  • web собирается из локального Dockerfile.
  • db использует готовый image postgres:16.
  • pgadmin использует готовый image dpage/pgadmin4:latest.
  • depends_on с condition: service_healthy помогает дождаться готовности PostgreSQL.
  • ports публикует порты контейнеров на Ubuntu VM.
  • volumes сохраняет данные PostgreSQL.
  • networks создаёт отдельную bridge-сеть для контейнеров.

12.5. Файл .env.example

Назначение: шаблон переменных окружения. Его можно хранить в GitHub.

# Flask application
APP_VERSION=1.0.0
WEB_PORT=8000

# PostgreSQL container settings
POSTGRES_DB=labdb
POSTGRES_USER=labuser
POSTGRES_PASSWORD=change_me_lab_password
POSTGRES_HOST_PORT=5432

# Flask-to-PostgreSQL connection settings inside the Docker Compose network
# Important: DB_HOST must be the Compose service name "db", not localhost.
DB_HOST=db
DB_PORT=5432
DB_NAME=labdb
DB_USER=labuser
DB_PASSWORD=change_me_lab_password

# pgAdmin web interface
PGADMIN_DEFAULT_EMAIL=[email protected]
PGADMIN_DEFAULT_PASSWORD=change_me_pgadmin_password
PGADMIN_HOST_PORT=5050

После копирования создаётся настоящий .env:

cp .env.example .env
nano .env

Важно: .env содержит пароли и локальные настройки, поэтому его нельзя публиковать в GitHub.

12.6. Файл .gitignore

Назначение: не отправлять временные и секретные файлы в Git.

.env
__pycache__/
*.py[cod]
.venv/
venv/
.env.*
!.env.example
.DS_Store
.vscode/
.idea/

12.7. Файл .dockerignore

Назначение: не отправлять лишние файлы в Docker build context.

.git
.gitignore
.env
__pycache__/
*.py[cod]
.venv/
venv/
README.md
docs/
images/
.DS_Store

13. Быстрое создание файлов через терминал

Если удобнее создать файлы прямо из терминала, можно использовать cat <<'EOF'.

Пример для requirements.txt:

cat > requirements.txt <<'EOF'
flask==3.*
psycopg2-binary==2.9.*
EOF

Пример для .env.example:

cat > .env.example <<'EOF'
# Flask application
APP_VERSION=1.0.0
WEB_PORT=8000

# PostgreSQL container settings
POSTGRES_DB=labdb
POSTGRES_USER=labuser
POSTGRES_PASSWORD=change_me_lab_password
POSTGRES_HOST_PORT=5432

# Flask-to-PostgreSQL connection settings inside the Docker Compose network
# Important: DB_HOST must be the Compose service name "db", not localhost.
DB_HOST=db
DB_PORT=5432
DB_NAME=labdb
DB_USER=labuser
DB_PASSWORD=change_me_lab_password

# pgAdmin web interface
[email protected]
PGADMIN_DEFAULT_PASSWORD=change_me_pgadmin_password
PGADMIN_HOST_PORT=5050
EOF

Для больших файлов, таких как app.py и docker-compose.yml, обычно удобнее использовать nano:

nano app.py
nano docker-compose.yml

Сохранение в nano:

Ctrl + O → Enter → Ctrl + X

14. Настройка .env

Создайте реальный файл окружения:

cp .env.example .env
nano .env

Минимальный корректный вариант:

APP_VERSION=1.0.0
WEB_PORT=8000
POSTGRES_DB=labdb
POSTGRES_USER=labuser
POSTGRES_PASSWORD=change_me_lab_password
POSTGRES_HOST_PORT=5432
DB_HOST=db
DB_PORT=5432
DB_NAME=labdb
DB_USER=labuser
DB_PASSWORD=change_me_lab_password
PGADMIN_DEFAULT_EMAIL=[email protected]
PGADMIN_DEFAULT_PASSWORD=change_me_pgadmin_password
PGADMIN_HOST_PORT=5050

Практическая подсказка: POSTGRES_PASSWORD и DB_PASSWORD должны совпадать, потому что первый пароль создаёт пользователя PostgreSQL, а второй используется Flask-приложением для подключения.


15. Предварительная проверка перед запуском

Перед запуском всегда проверяйте файлы.

15.1. Проверка структуры

ls -la

Должны быть видны:

app.py
requirements.txt
Dockerfile
docker-compose.yml
.env.example
.env
.gitignore
.dockerignore
README.md

15.2. Проверка Python syntax

Если Python установлен на Ubuntu:

python3 -m py_compile app.py

Если команда ничего не вывела, синтаксис корректный.

15.3. Проверка Docker Compose file

docker compose config

Эта команда полезна, потому что показывает итоговую конфигурацию после подстановки переменных из .env.

Если есть YAML-ошибка, Docker Compose сообщит строку и причину.


16. Сборка и запуск проекта

Запуск:

docker compose up -d --build

Пояснение:

  • docker compose запускает Compose plugin.
  • up создаёт и запускает сервисы.
  • -d запускает контейнеры в фоновом режиме.
  • --build пересобирает Flask image перед запуском.

Проверьте контейнеры:

docker compose ps
docker ps

Ожидаемый результат:

flask_web
postgres_db
pgadmin_web

Смотрите logs:

docker compose logs

Живой просмотр logs:

docker compose logs -f

Остановить просмотр logs:

Ctrl + C

16.1. Что происходит при docker compose up -d --build

sequenceDiagram
    participant User as Terminal
    participant Compose as Docker Compose
    participant DB as db / PostgreSQL
    participant Web as web / Flask
    participant Pg as pgAdmin

    User->>Compose: docker compose up -d --build
    Compose->>Compose: read docker-compose.yml and .env
    Compose->>Web: build Flask image from Dockerfile
    Compose->>DB: create postgres_db
    DB-->>Compose: healthcheck pg_isready = healthy
    Compose->>Web: start flask_web after db is healthy
    Web->>DB: connect using DB_HOST=db
    Web->>DB: create table visits if not exists
    Compose->>Pg: start pgadmin_web after db is healthy
    User->>Web: curl http://localhost:8000/health
    Web-->>User: JSON status ok
Loading

17. Проверка Flask из терминала Ubuntu

Выполните:

curl http://localhost:8000/
curl http://localhost:8000/health
curl http://localhost:8000/visits
curl http://localhost:8000/visits/count
curl http://localhost:8000/info

Ожидаемый смысл ответа /health:

{
  "status": "ok",
  "database": "connected"
}

Если /visits вызывается несколько раз, количество записей должно увеличиваться.

Проверьте это так:

curl http://localhost:8000/visits
curl http://localhost:8000/visits
curl http://localhost:8000/visits/count

17.1. Как работает endpoint /visits

sequenceDiagram
    participant Browser as Browser / curl
    participant Flask as Flask container web
    participant DB as PostgreSQL container db
    participant Volume as postgres_data volume

    Browser->>Flask: GET /visits
    Flask->>DB: INSERT INTO visits
    DB->>Volume: сохранить строку на disk volume
    DB-->>Flask: new id and created_at
    Flask->>DB: SELECT latest 10 visits
    DB-->>Flask: rows
    Flask-->>Browser: JSON response
Loading

18. Проверка из браузера основной машины

Сначала найдите Host-Only IP:

ip -br addr

Затем с основной машины откройте:

http://UBUNTU_HOST_ONLY_IP:8000
http://UBUNTU_HOST_ONLY_IP:8000/health
http://UBUNTU_HOST_ONLY_IP:8000/visits
http://UBUNTU_HOST_ONLY_IP:5050

Пример:

http://192.168.56.101:8000
http://192.168.56.101:5050

Если с Ubuntu curl localhost:8000 работает, а с основной машины браузер не открывает страницу, проверьте:

  1. Host-Only IP.
  2. VirtualBox Adapter 2.
  3. Firewall UFW.
  4. Публикацию ports в docker-compose.yml.

Если UFW включён:

sudo ufw status
sudo ufw allow 8000/tcp
sudo ufw allow 5050/tcp
sudo ufw reload

19. Проверка PostgreSQL из терминала

Войти в PostgreSQL CLI внутри контейнера:

docker exec -it postgres_db psql -U labuser -d labdb

Внутри psql выполните:

\dt
SELECT * FROM visits;
SELECT COUNT(*) FROM visits;
\q

Можно выполнить SQL одной командой без входа в интерактивный режим:

docker exec -it postgres_db psql -U labuser -d labdb -c "SELECT COUNT(*) FROM visits;"

Пояснение:

  • docker exec выполняет команду внутри уже работающего контейнера.
  • -it делает команду интерактивной.
  • postgres_db — имя контейнера.
  • psql — PostgreSQL command-line client.

20. Проверка PostgreSQL через pgAdmin

Откройте в браузере:

http://UBUNTU_HOST_ONLY_IP:5050

Войдите:

Email: [email protected]
Password: значение PGADMIN_DEFAULT_PASSWORD из .env

Добавьте server:

Name: Docker PostgreSQL Lab
Host name/address: db
Port: 5432
Maintenance database: labdb
Username: labuser
Password: значение DB_PASSWORD из .env

Важно: pgAdmin тоже работает в контейнере. Поэтому для подключения к PostgreSQL он использует db, а не localhost.


21. Ежедневные Docker-команды

Эти команды важно понимать и регулярно использовать.

21.1. Просмотр контейнеров

docker ps

Показывает работающие контейнеры.

docker ps -a

Показывает все контейнеры.

docker compose ps

Показывает контейнеры текущего Compose-проекта.

21.2. Просмотр images, volumes и networks

docker images
docker volume ls
docker network ls

21.3. Logs

Все logs проекта:

docker compose logs

Logs в реальном времени:

docker compose logs -f

Logs только Flask:

docker compose logs web

Logs только PostgreSQL:

docker compose logs db

21.4. Вход внутрь контейнера

Войти в Flask container:

docker exec -it flask_web sh

Посмотреть файлы внутри:

ls -la
pwd
exit

Войти в PostgreSQL CLI:

docker exec -it postgres_db psql -U labuser -d labdb

21.5. Остановка и удаление контейнеров

Остановить проект:

docker compose down

Остановить проект и удалить database volume:

docker compose down -v

Запустить снова:

docker compose up -d

21.6. Пересборка после изменения кода

Если изменили app.py:

docker compose build web
docker compose up -d

Или одной командой:

docker compose up -d --build

Пересборка без cache:

docker compose build --no-cache web

21.7. Очистка Docker

Посмотреть использование диска:

docker system df

Удалить неиспользуемые объекты:

docker system prune

Более агрессивная очистка, включая unused images:

docker system prune -a

Предупреждение: не используйте очистку без понимания, если на машине есть другие проекты.


22. Полезные команды Linux для этой лабораторной работы

Проверить IP:

ip -br addr

Проверить открытые ports:

sudo ss -tulpen

Проверить конкретный port:

sudo ss -tulpen | grep ':8000'
sudo ss -tulpen | grep ':5050'
sudo ss -tulpen | grep ':5432'

Проверить firewall:

sudo ufw status

Разрешить ports:

sudo ufw allow 8000/tcp
sudo ufw allow 5050/tcp

Редактировать файл:

nano docker-compose.yml

Показать последние команды:

history | tail -30

23. Как понимать поток работы

Полный поток такой:

Dockerfile → docker image → docker container

В этой лабораторной работе:

Dockerfile builds Flask image
Flask image runs as flask_web container
PostgreSQL image runs as postgres_db container
pgAdmin image runs as pgadmin_web container
Docker Compose connects them together

Логика подключения:

Browser or curl → Ubuntu VM port 8000 → Flask container port 8000
Flask container → Docker network → db:5432 → PostgreSQL container
pgAdmin browser → Ubuntu VM port 5050 → pgAdmin container → db:5432

Главный научно-технический смысл: контейнеризация отделяет приложение от конкретной ручной настройки операционной системы. Это повышает воспроизводимость, упрощает переносимость и помогает управлять зависимостями.


24. Упражнение по Docker Hub

Этот раздел необязательный, но очень полезный.

24.1. Login

docker login

Введите Docker Hub username и password/token.

24.2. Build image

docker compose build web

Проверьте image:

docker images

24.3. Tag image

Замените YOUR_DOCKERHUB_USERNAME на свой username:

docker tag docker-flask-postgres-lab-web:1.0 YOUR_DOCKERHUB_USERNAME/docker-flask-postgres-lab-web:1.0

24.4. Push image

docker push YOUR_DOCKERHUB_USERNAME/docker-flask-postgres-lab-web:1.0

24.5. Pull image на другой машине

docker pull YOUR_DOCKERHUB_USERNAME/docker-flask-postgres-lab-web:1.0

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


25. Типовые ошибки и исправления

Ошибка 1: Port already allocated

Пример проблемы: порт 8000, 5050 или 5432 уже занят.

Проверка:

sudo ss -tulpen | grep ':8000'
sudo ss -tulpen | grep ':5050'
sudo ss -tulpen | grep ':5432'

Исправление: изменить ports в .env:

WEB_PORT=8001
PGADMIN_HOST_PORT=5051
POSTGRES_HOST_PORT=5433

Перезапуск:

docker compose down
docker compose up -d --build

Ошибка 2: Flask cannot connect to PostgreSQL

Проверьте logs:

docker compose logs web
docker compose logs db

Проверьте .env:

DB_HOST=db
DB_PORT=5432
DB_NAME=labdb
DB_USER=labuser
DB_PASSWORD=change_me_lab_password

Частая ошибка: используется DB_HOST=localhost. Это неправильно внутри Compose network.

Ошибка 3: pgAdmin не подключается к database

В pgAdmin server connection используйте:

Host name/address: db
Port: 5432

Не используйте localhost, потому что pgAdmin работает в отдельном контейнере.

Ошибка 4: Docker требует sudo

Исправление:

sudo usermod -aG docker $USER
newgrp docker
docker run hello-world

Если не помогло, перезапустите Ubuntu VM.

Ошибка 5: Нужно начать с чистой database

docker compose down -v
docker compose up -d --build

Предупреждение: -v удаляет volume и все данные PostgreSQL.

Ошибка 6: Изменил код, но результат не поменялся

Пересоберите image:

docker compose up -d --build

Если браузер показывает старую страницу:

Ctrl + F5

Диагностику удобно вести по дереву:

flowchart TD
    A[Проблема] --> B{{Что именно не работает?}}
    B -->|docker command not found| C[Docker не установлен<br/>или shell не обновлён]
    C --> C1[docker --version<br/>newgrp docker<br/>logout/login]

    B -->|permission denied| D[Пользователь не в docker group]
    D --> D1[sudo usermod -aG docker $USER<br/>newgrp docker]

    B -->|port already allocated| E[Порт уже занят]
    E --> E1[ss -tulpn<br/>изменить WEB_PORT или PGADMIN_HOST_PORT в .env]

    B -->|database not connected| F[Ошибка DB_HOST<br/>или PostgreSQL ещё не готов]
    F --> F1[DB_HOST=db<br/>docker compose logs db<br/>docker compose ps]

    B -->|pgAdmin cannot connect| G[Неверный host в pgAdmin]
    G --> G1[Host name/address = db<br/>Username = labuser]

    B -->|data disappeared| H[Volume был удалён]
    H --> H1[docker volume ls<br/>не использовать down -v без необходимости]

    classDef problem fill:#fee2e2,stroke:#dc2626,stroke-width:2px,color:#450a0a;
    classDef decision fill:#fef3c7,stroke:#d97706,stroke-width:2px,color:#451a03;
    classDef fix fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#052e16;
    class A problem;
    class B decision;
    class C,D,E,F,G,H,C1,D1,E1,F1,G1,H1 fix;
Loading

26. Мини-чеклист диагностики

Если что-то не работает, идите сверху вниз:

docker compose config
docker compose ps
docker compose logs web
docker compose logs db
curl http://localhost:8000/health
sudo ss -tulpen | grep ':8000'
ip -br addr

Интерпретация:

  • docker compose config проверяет YAML и .env.
  • docker compose ps показывает состояние контейнеров.
  • logs web показывает ошибки Flask.
  • logs db показывает ошибки PostgreSQL.
  • curl /health проверяет приложение и подключение к базе данных.
  • ss проверяет, слушает ли Ubuntu нужный port.
  • ip -br addr помогает проверить Host-Only IP.

27. Контрольные вопросы

  1. Что такое Docker image?
  2. Что такое Docker container?
  3. Чем Dockerfile отличается от docker-compose.yml?
  4. Почему Flask использует DB_HOST=db, а не localhost?
  5. Что делает Docker volume?
  6. Чем отличается docker compose down от docker compose down -v?
  7. Почему Docker удобен для командной разработки?
  8. Чем Docker container отличается от virtual machine?
  9. Для чего нужен Docker Hub?
  10. Почему Kubernetes обычно изучают после Docker Compose?

28. Практические задания после основной части

Задание 1: Изменить версию приложения

В .env измените:

APP_VERSION=1.0.1

Перезапустите:

docker compose up -d
curl http://localhost:8000/info

Задание 2: Изменить внешний порт Flask

В .env измените:

WEB_PORT=8001

Перезапустите:

docker compose down
docker compose up -d
curl http://localhost:8001/health

Задание 3: Проверить сохранение данных

Добавьте visits:

curl http://localhost:8000/visits
curl http://localhost:8000/visits
curl http://localhost:8000/visits/count

Остановите и запустите проект:

docker compose down
docker compose up -d
curl http://localhost:8000/visits/count

Если count сохранился, volume работает.

Задание 4: Проверить удаление данных

docker compose down -v
docker compose up -d --build
curl http://localhost:8000/visits/count

Данные должны начаться заново.

Задание 5: Добавить новый endpoint

Добавьте в app.py:

@app.get("/hello/<name>")
def hello(name):
    return jsonify({"message": f"Hello, {name}"})

Пересоберите:

docker compose up -d --build
curl http://localhost:8000/hello/Ali

29. Что показать в конце работы

Подготовьте скриншоты или вывод терминала для:

  1. docker --version
  2. docker compose version
  3. docker compose config
  4. docker compose ps
  5. curl http://localhost:8000/health
  6. curl http://localhost:8000/visits
  7. curl http://localhost:8000/visits/count
  8. docker exec -it postgres_db psql -U labuser -d labdb -c "SELECT * FROM visits;"
  9. pgAdmin page, где видна таблица visits.
  10. Короткие ответы на контрольные вопросы 4, 5 и 6.

30. Краткая памятка команд

# Docker version
docker --version
docker compose version

# Start lab
docker compose up -d --build

# Status
docker compose ps
docker ps

# Logs
docker compose logs
docker compose logs -f
docker compose logs web
docker compose logs db

# Test app
curl http://localhost:8000/health
curl http://localhost:8000/visits
curl http://localhost:8000/visits/count

# Enter containers
docker exec -it flask_web sh
docker exec -it postgres_db psql -U labuser -d labdb

# Stop
docker compose down

# Stop and delete database data
docker compose down -v

# Rebuild
docker compose up -d --build
docker compose build --no-cache web

# Docker objects
docker images
docker volume ls
docker network ls
docker system df

# Cleanup unused objects
docker system prune

31. Проверка перед публикацией репозитория

Перед публикацией на GitHub проверьте, что в репозитории есть только безопасные и нужные файлы:

git status
ls -la

Должны публиковаться:

README.md
app.py
requirements.txt
Dockerfile
docker-compose.yml
.env.example
.gitignore
.dockerignore

Не должен публиковаться:

.env

Финальная техническая проверка перед commit:

python3 -m py_compile app.py
docker compose config
docker compose up -d --build
curl http://localhost:8000/health
curl http://localhost:8000/visits/count
docker compose down

Если все команды выполняются без ошибок, лабораторная работа готова к публикации.


32. Итоговая карта понимания

mindmap
  root((Docker Lab))
    Environment
      VirtualBox
      Ubuntu Server 24.04 LTS
      Docker Engine
      Docker Compose plugin
    Application
      Flask
      Python dependencies
      Dockerfile
      Image
      Container
    Database
      PostgreSQL
      Volume
      Persistent data
      pgAdmin
    Networking
      Compose service names
      DB_HOST=db
      Published ports
      Host-Only IP
    Daily operations
      docker compose ps
      docker compose logs
      docker exec
      docker compose down
      docker compose up -d --build
    Registry
      Docker Hub
      tag
      push
      pull
    Next step
      Kubernetes
      Cluster
      Scaling
      Self-healing
Loading

33. итог

Docker не является полной виртуальной машиной. Он запускает изолированные процессы на основе images и использует возможности операционной системы для изоляции. Виртуальная машина запускает полноценную гостевую операционную систему. Поэтому контейнеры обычно легче и быстрее, но виртуальные машины дают более полную изоляцию на уровне операционной системы.

Docker Compose не заменяет Kubernetes. Compose удобен для обучения, локальной разработки и простых multi-container приложений. Kubernetes используется там, где нужны кластеры, масштабирование, самовосстановление, rolling updates, service discovery и более сложное управление production-системами.

Docker Hub не запускает приложение сам по себе. Он хранит и распространяет images. Чтобы приложение работало, image нужно запустить на машине или в инфраструктуре, где есть Docker, Compose, Kubernetes или другой container runtime/workload manager.

После этой лабораторной работы важно понимать не только команды, но и архитектуру:

Host machine → VirtualBox VM → Ubuntu Server → Docker Engine → Containers → Application services

И внутреннюю связь сервисов:

Flask container → Docker network → PostgreSQL container
pgAdmin container → Docker network → PostgreSQL container
Browser/curl → published port → Flask or pgAdmin container

Это и есть практическая польза Docker: reproducibility, isolation, portability, clean deployment and easier debugging.


Flask Docker Visit PgAdmin Postgres db

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages