diff --git a/.docker.env.example b/.docker.env.example index 59c33c5..2c321be 100644 --- a/.docker.env.example +++ b/.docker.env.example @@ -6,10 +6,9 @@ MYSQL_VERSION=9.7.1 POSTGRES_VERSION=18.4 ADMINER_VERSION=5.4.2 -# Имена контейнеров -MYSQL_CONTAINER=mysql -POSTGRES_CONTAINER=postgres -ADMINER_CONTAINER=adminer +# Публикация портов только на loopback по умолчанию. +# При необходимости можно явно указать другой адрес, например адрес VPN-интерфейса. +BIND_ADDRESS=127.0.0.1 # Порты хоста MYSQL_PORT=3306 diff --git a/.gitattributes b/.gitattributes index 7929293..b53897c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -16,3 +16,15 @@ *.conf text eol=lf *.ini text eol=lf *.make text eol=lf + +# Бинарные изображения и архивы +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.webp binary +*.ico binary +*.pdf binary +*.zip binary +*.gz binary +*.tgz binary diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..8e4c7cd --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +custom: + - "https://boosty.to/backendbezpafosa" + - "https://sponsr.ru/backendbezpafosa/" diff --git a/.github/workflows/sql-lab-check.yml b/.github/workflows/sql-lab-check.yml index 93f17ef..4184281 100644 --- a/.github/workflows/sql-lab-check.yml +++ b/.github/workflows/sql-lab-check.yml @@ -27,6 +27,9 @@ jobs: docker --version docker compose version + - name: Test managed storage path validation + run: make test-storage-paths + - name: Initialize environment run: make init @@ -39,6 +42,9 @@ jobs: - name: Check complete database stand run: make check + - name: Smoke-test trusted SQL imports + run: make test-sql-imports + - name: Confirm databases are running without Adminer run: | set -Eeuo pipefail @@ -54,6 +60,38 @@ jobs: - name: Start Adminer run: make up-ui + - name: Confirm all published ports bind to loopback + run: | + set -Eeuo pipefail + set -a + source .docker.env + set +a + + compose=(docker compose --env-file .docker.env -p "${COMPOSE_PROJECT_NAME}" --profile ui) + + assert_loopback_binding() { + local service="$1" + local container_port="$2" + local container_id + local host_ip + + container_id="$("${compose[@]}" ps --quiet "${service}")" + if [[ -z "${container_id}" ]]; then + echo "ERROR: Compose service ${service} has no container ID" >&2 + exit 1 + fi + + host_ip="$(docker inspect --format "{{(index (index .NetworkSettings.Ports \"${container_port}/tcp\") 0).HostIp}}" "${container_id}")" + if [[ "${host_ip}" != "127.0.0.1" ]]; then + echo "ERROR: ${service} (${container_id}) publishes ${container_port}/tcp on HostIp '${host_ip}', expected '127.0.0.1'" >&2 + exit 1 + fi + } + + assert_loopback_binding mysql 3306 + assert_loopback_binding postgres 5432 + assert_loopback_binding adminer 8080 + - name: Smoke-test Adminer login page run: | set -Eeuo pipefail diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..2a42bf8 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025-2026 Aleksandr Yurchenko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile index 26e27c4..d1d7d59 100644 --- a/Makefile +++ b/Makefile @@ -9,9 +9,9 @@ SHELL := bash .PHONY: help init check-env pull config up up-no-ui up-mysql up-mysql-ui \ up-postgres up-postgres-ui up-ui down-ui wait-mysql wait-postgres \ down status logs log in mysql mysql-user postgres postgres-user sh \ - samples-mysql samples-postgres mysql-grants mysql-import check check-mysql-access \ + samples-mysql samples-postgres mysql-grants mysql-import postgres-import check check-mysql-access \ check-postgres-access dump restore clean-mysql clean-postgres clean-all \ - reinit-mysql reinit-postgres reinit-all + reinit-mysql reinit-postgres reinit-all test-storage-paths test-sql-imports PROJECT_DIR := $(CURDIR) ENV_FILE_EXAMPLE := .docker.env.example @@ -20,7 +20,6 @@ HOST_UID := $(shell id -u) HOST_GID := $(shell id -g) REQUIRED_ENV_VARS := COMPOSE_PROJECT_NAME MYSQL_VERSION POSTGRES_VERSION ADMINER_VERSION \ - MYSQL_CONTAINER POSTGRES_CONTAINER ADMINER_CONTAINER \ MYSQL_PORT POSTGRES_PORT ADMINER_PORT \ MYSQL_DATA_DIR POSTGRES_DATA_DIR MYSQL_CONF_FILE \ MYSQL_INITDB_DIR POSTGRES_INITDB_DIR MYSQL_SAMPLES_DIR POSTGRES_SAMPLES_DIR \ @@ -33,9 +32,14 @@ COMPOSE_UI = $(COMPOSE) --profile ui MYSQL_SAMPLES_TMP_DIR := .tmp/mysql-samples SAKILA_URL := https://downloads.mysql.com/docs/sakila-db.zip +SAKILA_SHA256 := c2ecb3dec28d752241ccfca02974ba970de3c3fc5d98887fd3f9d5843f946672 POSTGRES_SAMPLES_TMP_DIR := .tmp/postgres-samples PAGILA_REF := 5ba5a57aeb159f75f02aca2432d3c262186d13d3 PAGILA_BASE_URL := https://raw.githubusercontent.com/devrimgunduz/pagila/$(PAGILA_REF) +PAGILA_LICENSE_URL := $(PAGILA_BASE_URL)/LICENSE.txt +PAGILA_LICENSE_BLOB := c6078c708c6f55b56e24f3687c591ca12df567ca +PAGILA_SCHEMA_BLOB := 23718a3adef90ced002e19ad4e1ac98d22aa5870 +PAGILA_DATA_BLOB := b7c016861fd0f84008645153c6a1d9e5a99b9cc6 CHINOOK_REF := 4a944a942426e1f3263fe539155fb7ef92b04b4a CHINOOK_BASE_URL := https://raw.githubusercontent.com/lerocha/chinook-database/$(CHINOOK_REF) CHINOOK_LICENSE_URL := $(CHINOOK_BASE_URL)/LICENSE.md @@ -73,6 +77,10 @@ help: @echo " make check проверить Compose и доступ DB_USER к обеим СУБД" @echo " make samples-mysql скачать optional samples Chinook и Sakila" @echo " make samples-postgres скачать optional samples Pagila и Chinook" + @echo " make test-storage-paths проверить защиту managed storage paths" + @echo " make test-sql-imports проверить trusted SQL imports в запущенных СУБД" + @echo " make mysql-import FILE=... DATABASE=... импортировать доверенный text SQL в MySQL" + @echo " make postgres-import FILE=... DATABASE=... импортировать доверенный text SQL в PostgreSQL" @echo " make clean-{mysql,postgres,all} CONFIRM=1" @echo " make reinit-{mysql,postgres,all} CONFIRM=1" @@ -98,10 +106,18 @@ check-env: $(ENV_FILE) echo "ERROR: обязательные MYSQL_DATABASE и POSTGRES_DATABASE должны называться demo" >&2; \ exit 1; \ fi; \ - if [[ "$$(realpath -m "$${MYSQL_DATA_DIR}")" == "$$(realpath -m "$${POSTGRES_DATA_DIR}")" ]]; then \ - echo "ERROR: MYSQL_DATA_DIR и POSTGRES_DATA_DIR должны быть разными каталогами" >&2; \ - exit 1; \ - fi + "$(PROJECT_DIR)/scripts/validate-storage-paths.sh" \ + --project-dir "$(PROJECT_DIR)" \ + --mysql-data "$${MYSQL_DATA_DIR}" \ + --postgres-data "$${POSTGRES_DATA_DIR}" \ + --mysql-samples "$${MYSQL_SAMPLES_DIR}" \ + --postgres-samples "$${POSTGRES_SAMPLES_DIR}" + +test-storage-paths: + @./scripts/test-storage-paths.sh + +test-sql-imports: + @./scripts/test-sql-imports.sh init: check-env @echo "Проверяем каталоги, конфигурацию и init-скрипты..." @@ -255,6 +271,7 @@ samples-mysql: check-env @command -v curl >/dev/null || { echo "ERROR: требуется curl" >&2; exit 1; } @command -v unzip >/dev/null || { echo "ERROR: требуется unzip" >&2; exit 1; } @command -v git >/dev/null || { echo "ERROR: требуется git для проверки Git blob SHA" >&2; exit 1; } + @command -v sha256sum >/dev/null || { echo "ERROR: требуется sha256sum" >&2; exit 1; } @set -Eeuo pipefail; $(LOAD_ENV) \ tmp_root="$(MYSQL_SAMPLES_TMP_DIR)"; \ download_dir="$${tmp_root}/download"; \ @@ -291,6 +308,7 @@ samples-mysql: check-env "$(CHINOOK_MYSQL_URL)" -o "$${download_dir}/Chinook_MySql.sql"; \ curl --fail --location --retry 3 --retry-all-errors --connect-timeout 15 --max-time 180 \ "$(SAKILA_URL)" -o "$${download_dir}/sakila-db.zip"; \ + echo "$(SAKILA_SHA256) $${download_dir}/sakila-db.zip" | sha256sum --check --status || { echo "ERROR: неожиданный SHA-256 sakila-db.zip" >&2; exit 1; }; \ test "$$(git hash-object --no-filters "$${download_dir}/LICENSE.md")" = "$(CHINOOK_LICENSE_BLOB)" || { echo "ERROR: неожиданный Git blob SHA LICENSE.md" >&2; exit 1; }; \ test "$$(git hash-object --no-filters "$${download_dir}/Chinook_MySql.sql")" = "$(CHINOOK_MYSQL_BLOB)" || { echo "ERROR: неожиданный Git blob SHA Chinook_MySql.sql" >&2; exit 1; }; \ test -s "$${download_dir}/LICENSE.md" || { echo "ERROR: LICENSE.md пуст" >&2; exit 1; }; \ @@ -326,6 +344,10 @@ samples-mysql: check-env sakila_data_source="$$(find "$${download_dir}/sakila" -type f -name sakila-data.sql -print -quit)"; \ test -n "$$sakila_schema_source" || { echo "ERROR: архив Sakila не содержит sakila-schema.sql" >&2; exit 1; }; \ test -n "$$sakila_data_source" || { echo "ERROR: архив Sakila не содержит sakila-data.sql" >&2; exit 1; }; \ + for sakila_source in "$$sakila_schema_source" "$$sakila_data_source"; do \ + grep -Fq 'Redistribution and use in source and binary forms' "$$sakila_source" || { echo "ERROR: в $${sakila_source} отсутствует ожидаемый New BSD notice" >&2; exit 1; }; \ + grep -Fq 'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS' "$$sakila_source" || { echo "ERROR: в $${sakila_source} отсутствует ожидаемый New BSD disclaimer" >&2; exit 1; }; \ + done; \ cp "$$sakila_schema_source" "$${ready_dir}/020_sakila_schema.sql"; \ cp "$$sakila_data_source" "$${ready_dir}/021_sakila_data.sql"; \ if [[ -f "$${target_dir}/.gitkeep" ]]; then cp "$${target_dir}/.gitkeep" "$${ready_dir}/.gitkeep"; else touch "$${ready_dir}/.gitkeep"; fi; \ @@ -377,10 +399,16 @@ samples-postgres: check-env "$(PAGILA_BASE_URL)/pagila-schema.sql" -o "$${download_dir}/pagila-schema.sql"; \ curl --fail --location --retry 3 --retry-all-errors --connect-timeout 15 --max-time 180 \ "$(PAGILA_BASE_URL)/pagila-data.sql" -o "$${download_dir}/pagila-data.sql"; \ + curl --fail --location --retry 3 --retry-all-errors --connect-timeout 15 --max-time 180 \ + "$(PAGILA_LICENSE_URL)" -o "$${download_dir}/LICENSE.pagila.txt"; \ curl --fail --location --retry 3 --retry-all-errors --connect-timeout 15 --max-time 180 \ "$(CHINOOK_LICENSE_URL)" -o "$${download_dir}/LICENSE.md"; \ curl --fail --location --retry 3 --retry-all-errors --connect-timeout 15 --max-time 180 \ "$(CHINOOK_POSTGRES_URL)" -o "$${download_dir}/Chinook_PostgreSql.sql"; \ + test "$$(git hash-object --no-filters "$${download_dir}/LICENSE.pagila.txt")" = "$(PAGILA_LICENSE_BLOB)" || { echo "ERROR: неожиданный Git blob SHA Pagila LICENSE.txt" >&2; exit 1; }; \ + test "$$(git hash-object --no-filters "$${download_dir}/pagila-schema.sql")" = "$(PAGILA_SCHEMA_BLOB)" || { echo "ERROR: неожиданный Git blob SHA pagila-schema.sql" >&2; exit 1; }; \ + test "$$(git hash-object --no-filters "$${download_dir}/pagila-data.sql")" = "$(PAGILA_DATA_BLOB)" || { echo "ERROR: неожиданный Git blob SHA pagila-data.sql" >&2; exit 1; }; \ + test -s "$${download_dir}/LICENSE.pagila.txt" || { echo "ERROR: Pagila LICENSE.txt пуст" >&2; exit 1; }; \ test -s "$${download_dir}/pagila-schema.sql" || { echo "ERROR: pagila-schema.sql пуст" >&2; exit 1; }; \ test -s "$${download_dir}/pagila-data.sql" || { echo "ERROR: pagila-data.sql пуст" >&2; exit 1; }; \ grep -Fq 'CREATE TABLE public.actor' "$${download_dir}/pagila-schema.sql" || { echo "ERROR: в schema нет таблицы actor" >&2; exit 1; }; \ @@ -406,8 +434,24 @@ samples-postgres: check-env test "$$(grep -Fxc "$${expected_line}" "$${chinook_source}" || true)" = 1 || { echo "ERROR: неожиданный формат database-level строки: $${expected_line}" >&2; exit 1; }; \ done; \ test "$$(awk 'BEGIN { in_comment = 0; count = 0 } { upper = toupper($$0) } /^[[:space:]]*\/\*/ { in_comment = 1 } !in_comment && (upper ~ /^[[:space:]]*(DROP|CREATE)[[:space:]]+DATABASE/ || upper ~ /^[[:space:]]*\\(C|CONNECT)([[:space:]]|$$)/) { count++ } /\*\// { in_comment = 0 } END { print count }' "$${chinook_source}")" = 3 || { echo "ERROR: Chinook PostgreSQL содержит неожиданные database-level statements" >&2; exit 1; }; \ - cp "$${download_dir}/pagila-schema.sql" "$${ready_dir}/010_pagila_schema.sql"; \ - cp "$${download_dir}/pagila-data.sql" "$${ready_dir}/020_pagila_data.sql"; \ + sed 's/\r$$//' "$${download_dir}/LICENSE.pagila.txt" > "$${download_dir}/LICENSE.pagila.normalized.txt"; \ + { \ + echo '-- Pagila license notice (upstream LICENSE.txt):'; \ + sed 's/^/-- /' "$${download_dir}/LICENSE.pagila.normalized.txt"; \ + echo; \ + cat "$${download_dir}/pagila-schema.sql"; \ + } > "$${ready_dir}/010_pagila_schema.sql"; \ + { \ + echo '-- Pagila license notice (upstream LICENSE.txt):'; \ + sed 's/^/-- /' "$${download_dir}/LICENSE.pagila.normalized.txt"; \ + echo; \ + cat "$${download_dir}/pagila-data.sql"; \ + } > "$${ready_dir}/020_pagila_data.sql"; \ + while IFS= read -r license_line || [[ -n "$${license_line}" ]]; do \ + for pagila_ready_file in "$${ready_dir}/010_pagila_schema.sql" "$${ready_dir}/020_pagila_data.sql"; do \ + grep -Fxq -- "-- $${license_line}" "$${pagila_ready_file}" || { echo "ERROR: Pagila notice перенесён не полностью в $${pagila_ready_file}" >&2; exit 1; }; \ + done; \ + done < "$${download_dir}/LICENSE.pagila.normalized.txt"; \ { \ echo '-- Chinook Database MIT license notice (upstream LICENSE.md):'; \ sed 's/^/-- /' "$${download_dir}/LICENSE.normalized.md"; \ @@ -438,14 +482,46 @@ samples-postgres: check-env mysql-grants: wait-mysql $(COMPOSE) exec -T mysql /docker-entrypoint-initdb.d/090_grant_training_access.sh -mysql-import: wait-mysql - @test -n "$(FILE)" || { echo "ERROR: укажите FILE=path/to/database.sql" >&2; exit 1; } - @test -f "$(FILE)" || { echo "ERROR: файл $(FILE) не найден" >&2; exit 1; } - @echo "Импортируем $(FILE) от имени root..." - $(COMPOSE) exec -T mysql sh -c 'MYSQL_PWD="$$MYSQL_ROOT_PASSWORD" mysql -uroot' < "$(FILE)" - @$(MAKE) --no-print-directory mysql-grants +mysql-import: + @set -Eeuo pipefail; \ + if [[ -z "$${FILE:-}" ]]; then echo "ERROR: укажите FILE=path/to/file.sql" >&2; exit 1; fi; \ + if [[ -z "$${DATABASE:-}" ]]; then echo "ERROR: укажите DATABASE=database_name" >&2; exit 1; fi; \ + if [[ ! -f "$${FILE}" || ! -r "$${FILE}" || ! -s "$${FILE}" ]]; then echo "ERROR: FILE должен быть существующим читаемым непустым обычным файлом" >&2; exit 1; fi; \ + if [[ ! "$${DATABASE}" =~ ^[a-z][a-z0-9_]{0,62}$$ ]]; then echo "ERROR: недопустимое имя MySQL database: $${DATABASE}" >&2; exit 1; fi; \ + case "$${DATABASE}" in mysql|information_schema|performance_schema|sys) echo "ERROR: импорт в системную MySQL database запрещён: $${DATABASE}" >&2; exit 1 ;; esac + @$(MAKE) --no-print-directory wait-mysql + @set -Eeuo pipefail; \ + $(LOAD_ENV) \ + if ! $(COMPOSE) exec -T -e IMPORT_DATABASE="$${DATABASE}" mysql sh -c 'MYSQL_PWD="$$DB_PASSWORD" exec mysql --host=127.0.0.1 --user="$$DB_USER" --batch --skip-column-names "$$IMPORT_DATABASE" --execute "SELECT 1;"' >/dev/null; then \ + echo "ERROR: DB_USER cannot connect to MySQL database $${DATABASE}; import was not started" >&2; exit 1; \ + fi; \ + echo "Импортируем $${FILE} в MySQL database $${DATABASE} от имени DB_USER..."; \ + $(COMPOSE) exec -T -e IMPORT_DATABASE="$${DATABASE}" mysql sh -c 'MYSQL_PWD="$$DB_PASSWORD" exec mysql --host=127.0.0.1 --user="$$DB_USER" --binary-mode=1 "$$IMPORT_DATABASE"' < "$${FILE}"; \ + if ! $(COMPOSE) exec -T -e IMPORT_DATABASE="$${DATABASE}" mysql sh -c 'MYSQL_PWD="$$DB_PASSWORD" exec mysql --host=127.0.0.1 --user="$$DB_USER" --batch --skip-column-names "$$IMPORT_DATABASE" --execute "SELECT 1;"' >/dev/null; then \ + echo "ERROR: DB_USER cannot reconnect to MySQL database $${DATABASE} after import" >&2; exit 1; \ + fi @$(MAKE) --no-print-directory check-mysql-access +postgres-import: + @set -Eeuo pipefail; \ + if [[ -z "$${FILE:-}" ]]; then echo "ERROR: укажите FILE=path/to/file.sql" >&2; exit 1; fi; \ + if [[ -z "$${DATABASE:-}" ]]; then echo "ERROR: укажите DATABASE=database_name" >&2; exit 1; fi; \ + if [[ ! -f "$${FILE}" || ! -r "$${FILE}" || ! -s "$${FILE}" ]]; then echo "ERROR: FILE должен быть существующим читаемым непустым обычным файлом" >&2; exit 1; fi; \ + if [[ ! "$${DATABASE}" =~ ^[a-z][a-z0-9_]{0,62}$$ ]]; then echo "ERROR: недопустимое имя PostgreSQL database: $${DATABASE}" >&2; exit 1; fi; \ + case "$${DATABASE}" in postgres|template0|template1) echo "ERROR: импорт в системную PostgreSQL database запрещён: $${DATABASE}" >&2; exit 1 ;; esac + @$(MAKE) --no-print-directory wait-postgres + @set -Eeuo pipefail; \ + $(LOAD_ENV) \ + if ! $(COMPOSE) exec -T -e IMPORT_DATABASE="$${DATABASE}" postgres sh -c 'PGPASSWORD="$$DB_PASSWORD" exec psql --host=127.0.0.1 --username="$$DB_USER" --dbname="$$IMPORT_DATABASE" --no-psqlrc --set=ON_ERROR_STOP=1 --command="SELECT 1;"' >/dev/null; then \ + echo "ERROR: DB_USER cannot connect to PostgreSQL database $${DATABASE}; import was not started" >&2; exit 1; \ + fi; \ + echo "Импортируем $${FILE} в PostgreSQL database $${DATABASE} от имени DB_USER..."; \ + $(COMPOSE) exec -T -e IMPORT_DATABASE="$${DATABASE}" postgres sh -c 'PGPASSWORD="$$DB_PASSWORD" exec psql --host=127.0.0.1 --username="$$DB_USER" --dbname="$$IMPORT_DATABASE" --no-psqlrc --set=ON_ERROR_STOP=1 --file=-' < "$${FILE}"; \ + if ! $(COMPOSE) exec -T -e IMPORT_DATABASE="$${DATABASE}" postgres sh -c 'PGPASSWORD="$$DB_PASSWORD" exec psql --host=127.0.0.1 --username="$$DB_USER" --dbname="$$IMPORT_DATABASE" --no-psqlrc --set=ON_ERROR_STOP=1 --command="SELECT 1;"' >/dev/null; then \ + echo "ERROR: DB_USER cannot reconnect to PostgreSQL database $${DATABASE} after import" >&2; exit 1; \ + fi + @$(MAKE) --no-print-directory check-postgres-access + check-mysql-access: wait-mysql $(COMPOSE) exec -T mysql /docker-entrypoint-initdb.d/099_check_training_access.sh @@ -474,10 +550,15 @@ clean-mysql: check-env @$(LOAD_ENV) \ project_dir_abs="$$(realpath -m "$(PROJECT_DIR)")"; \ data_dir_abs="$$(realpath -m "$${MYSQL_DATA_DIR}")"; \ - case "$${data_dir_abs}" in "$${project_dir_abs}"/*) ;; *) echo "ERROR: MYSQL_DATA_DIR должен находиться внутри проекта: $${data_dir_abs}" >&2; exit 1 ;; esac; \ - data_dir_rel="$$(realpath --relative-to="$${project_dir_abs}" "$${data_dir_abs}")"; \ + data_dir_rel="$${data_dir_abs#"$${project_dir_abs}"/}"; \ echo "🗑️ Удаление только данных MySQL: $${MYSQL_DATA_DIR}"; \ - $(COMPOSE_UI) down --remove-orphans; \ + container_id="$$( $(COMPOSE) ps --all --quiet mysql )"; \ + if [[ -n "$${container_id}" ]]; then \ + echo "⏹️ Остановка и удаление только MySQL..."; \ + $(COMPOSE) rm --stop --force mysql; \ + else \ + echo "Контейнер MySQL отсутствует; останавливать нечего."; \ + fi; \ docker run --rm --user 0:0 --entrypoint sh \ -e DATA_DIR_REL="$${data_dir_rel}" -e HOST_UID="$(HOST_UID)" -e HOST_GID="$(HOST_GID)" \ -v "$${project_dir_abs}:/workspace" "mysql:$${MYSQL_VERSION}" \ @@ -489,10 +570,15 @@ clean-postgres: check-env @$(LOAD_ENV) \ project_dir_abs="$$(realpath -m "$(PROJECT_DIR)")"; \ data_dir_abs="$$(realpath -m "$${POSTGRES_DATA_DIR}")"; \ - case "$${data_dir_abs}" in "$${project_dir_abs}"/*) ;; *) echo "ERROR: POSTGRES_DATA_DIR должен находиться внутри проекта: $${data_dir_abs}" >&2; exit 1 ;; esac; \ - data_dir_rel="$$(realpath --relative-to="$${project_dir_abs}" "$${data_dir_abs}")"; \ + data_dir_rel="$${data_dir_abs#"$${project_dir_abs}"/}"; \ echo "🗑️ Удаление только данных PostgreSQL: $${POSTGRES_DATA_DIR}"; \ - $(COMPOSE_UI) down --remove-orphans; \ + container_id="$$( $(COMPOSE) ps --all --quiet postgres )"; \ + if [[ -n "$${container_id}" ]]; then \ + echo "⏹️ Остановка и удаление только PostgreSQL..."; \ + $(COMPOSE) rm --stop --force postgres; \ + else \ + echo "Контейнер PostgreSQL отсутствует; останавливать нечего."; \ + fi; \ docker run --rm --user 0:0 --entrypoint sh \ -e DATA_DIR_REL="$${data_dir_rel}" -e HOST_UID="$(HOST_UID)" -e HOST_GID="$(HOST_GID)" \ -v "$${project_dir_abs}:/workspace" "postgres:$${POSTGRES_VERSION}" \ @@ -505,11 +591,8 @@ clean-all: check-env project_dir_abs="$$(realpath -m "$(PROJECT_DIR)")"; \ mysql_abs="$$(realpath -m "$${MYSQL_DATA_DIR}")"; \ postgres_abs="$$(realpath -m "$${POSTGRES_DATA_DIR}")"; \ - for data_dir_abs in "$$mysql_abs" "$$postgres_abs"; do \ - case "$$data_dir_abs" in "$${project_dir_abs}"/*) ;; *) echo "ERROR: data-каталоги должны находиться внутри проекта: $$data_dir_abs" >&2; exit 1 ;; esac; \ - done; \ - mysql_rel="$$(realpath --relative-to="$${project_dir_abs}" "$$mysql_abs")"; \ - postgres_rel="$$(realpath --relative-to="$${project_dir_abs}" "$$postgres_abs")"; \ + mysql_rel="$${mysql_abs#"$${project_dir_abs}"/}"; \ + postgres_rel="$${postgres_abs#"$${project_dir_abs}"/}"; \ echo "🗑️ Удаление данных MySQL и PostgreSQL..."; \ $(COMPOSE_UI) down --remove-orphans; \ docker run --rm --user 0:0 --entrypoint sh \ @@ -528,5 +611,5 @@ reinit-postgres: clean-postgres @$(MAKE) --no-print-directory check-postgres-access reinit-all: clean-all - @$(MAKE) --no-print-directory up-no-ui + @$(MAKE) --no-print-directory up @$(MAKE) --no-print-directory check diff --git a/README.md b/README.md index a4ada5a..bdb689b 100644 --- a/README.md +++ b/README.md @@ -1,551 +1,235 @@ -# SQL Lab (Docker) +

+ Docker SQL Lab — локальный стенд MySQL и PostgreSQL +

-Локальный учебный SQL-стенд на Docker Compose с независимыми сервисами: +# Docker SQL Lab -- MySQL 9.7.1 LTS; -- PostgreSQL 18.4 — последняя стабильная major-ветка с пятилетним сроком - поддержки; -- один опциональный Adminer Docker Official Image 5.4.2 для обеих СУБД. +## Выберите язык -Upstream Adminer уже выпускает 5.4.4, но официальный Docker image пока -закреплён на 5.4.2. Поэтому стенд использует точный официальный тег 5.4.2 и не -собирает собственный образ только ради расхождения версий. +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| **Выбран** | [English](docs/langs/README_en.md) | [Español](docs/langs/README_es.md) | [中文](docs/langs/README_zh.md) | [Français](docs/langs/README_fr.md) | [Deutsch](docs/langs/README_de.md) | -В MySQL и PostgreSQL всегда создаётся небольшая база `demo`. Для MySQL -опционально доступны Sakila и Chinook, для PostgreSQL — Pagila и та же -Chinook. Это позволяет сравнивать запросы к одинаковой учебной модели в двух -СУБД. +Локальный Docker Compose-стенд для практики SQL и знакомства с MySQL и +PostgreSQL. Каждую СУБД можно запускать отдельно или обе вместе. Компактная +`demo` создаётся автоматически, а необязательные учебные базы Sakila, Pagila +и Chinook дают готовые данные для упражнений. Adminer подключается только при +необходимости. -## Быстрый старт - -Полный стенд с Adminer: - -```bash -make init -make up -``` - -Полный стенд без UI: - -```bash -make up-no-ui -``` - -Одиночные режимы: - -```bash -make up-mysql -make up-mysql-ui -make up-postgres -make up-postgres-ui -``` +## Скринкасты -Adminer можно добавить к уже работающим СУБД или остановить отдельно: +В записях используется PhpStorm. Вместо него подойдут DataGrip, DBeaver, +Adminer или другой клиент MySQL/PostgreSQL. -```bash -make up-ui -make down-ui -``` - -Команды одиночного запуска не останавливают уже работающие сервисы. Они лишь -не запускают другие сервисы автоматически. - -## Режимы запуска - -| Команда | MySQL | PostgreSQL | Adminer | +| Сценарий | Яндекс.Диск | Google Drive | Что показано | |---|---|---|---| -| `make up` | запускает | запускает | запускает | -| `make up-no-ui` | запускает или оставляет активным | запускает или оставляет активным | останавливает, если запущен | -| `make up-mysql` | запускает | не запускает автоматически | не запускает автоматически | -| `make up-mysql-ui` | запускает | не запускает автоматически | запускает | -| `make up-postgres` | не запускает автоматически | запускает | не запускает автоматически | -| `make up-postgres-ui` | не запускает автоматически | запускает | запускает | -| `make up-ui` | не меняет состояние | не меняет состояние | запускает | -| `make down-ui` | не меняет состояние | не меняет состояние | останавливает | +| Первый запуск с обязательной `demo`, затем добавление учебных баз | [Смотреть](https://disk.yandex.ru/i/Kj4TcMSBuIDVeA "docker-sql-lab-demo-then-training-databases.mp4") | [Смотреть](https://drive.google.com/file/d/1HzYWbMuBEobXlbGQYNfHYVAq95TLqEPf/view?usp=sharing "docker-sql-lab-demo-then-training-databases.mp4") | Запуск MySQL и PostgreSQL с обязательной `demo`; проверка; подготовка Sakila, Pagila и Chinook; подтверждённая переинициализация; повторная проверка и SQL-запросы. | +| Первый запуск с заранее подготовленными учебными базами | [Смотреть](https://disk.yandex.ru/i/nFgJZto8agbdWw "docker-sql-lab-training-databases-first-start.mp4") | [Смотреть](https://drive.google.com/file/d/1nKiGrJ4QINLCQcRk-k6vfTakpWsw-JS7/view?usp=sharing "docker-sql-lab-training-databases-first-start.mp4") | Подготовка Sakila, Pagila и Chinook до первого запуска; единая инициализация обязательной `demo` и учебных баз; проверка доступа и SQL-запросы. | -`make up-no-ui` не выполняет общий `docker compose down`: сначала он -останавливает только Adminer, затем запускает или оставляет запущенными обе -СУБД и ждёт их готовности. +## Стек -## Порты +- MySQL 9.7.1 LTS +- PostgreSQL 18.4 +- Adminer 5.4.2 Docker Official Image +- Docker Compose v2 +- GNU Make и Bash для команд проекта и сценариев инициализации -Порты задаются в `.docker.env`: +Закреплённые значения по умолчанию заданы в +[`.docker.env.example`](.docker.env.example); `make init` создаёт из него +локальный `.docker.env`. Сервисы описаны в +[`docker-compose.yml`](docker-compose.yml). -| Сервис | Переменная | Значение по умолчанию | -|---|---|---| -| MySQL | `MYSQL_PORT` | `3306` | -| PostgreSQL | `POSTGRES_PORT` | `5432` | -| Adminer | `ADMINER_PORT` | `8081` | - -При значениях по умолчанию Adminer открыт на -`http://127.0.0.1:8081`. - -## Credentials +
+⚠️ Важно: это учебное окружение -`.docker.env.example` содержит только локальные учебные значения: +Проект не является готовым шаблоном для промышленной эксплуатации. Для +внешнего использования нужны отдельные решения по учётным данным, публикации +сервисов в сети, хранению данных, резервному копированию и эксплуатации. -| Назначение | Пользователь | Пароль | -|---|---|---| -| Администратор MySQL | `MYSQL_ROOT_PASSWORD` задаёт пароль пользователя `root` | `MYSQL_ROOT_PASSWORD` | -| Администратор PostgreSQL | `POSTGRES_SUPERUSER` | `POSTGRES_SUPERUSER_PASSWORD` | -| Общий учебный пользователь | `DB_USER` | `DB_PASSWORD` | +
-Административная PostgreSQL-роль и `DB_USER` обязаны различаться. Реальный -`.docker.env` исключён из Git. +## Основные возможности -Значения из примера нельзя использовать в production, публичном окружении или -на доступном извне сервере. +- MySQL и PostgreSQL работают независимо или одновременно. +- Обязательная `demo` в каждой СУБД содержит одинаковые начальные записи. +- Необязательные Sakila и Chinook доступны для MySQL, Pagila и Chinook — для + PostgreSQL. +- Adminer — отдельный дополнительный веб-интерфейс для обеих СУБД. +- Каталоги данных, инициализации и учебных баз разделены по СУБД и подключены + в контейнеры с хоста. +- Проверки конфигурации и доступа, импорт доверенных SQL-файлов и команды + очистки и переинициализации, удаляющие данные, + собраны в [`Makefile`](Makefile). -## Один Adminer для двух СУБД +## Требования -Adminer находится в общей Compose-сети с MySQL и PostgreSQL, не зависит от их -состояния и включается профилем `ui`. Это лёгкий optional UI с дизайном -`nette`; без профиля он не запускается и не расходует ресурсы. +1. Docker Engine или Docker Desktop с Docker Compose v2. +2. GNU Make, Bash и базовые утилиты командной строки Unix, используемые + сценариями. -Plugin `adminer/plugins-enabled/001-login-servers.php` заменяет свободный ввод -движка и сервера выпадающим списком из двух допустимых подключений: +Рекомендуемая среда: Linux; macOS с Docker Desktop; Windows с Docker Desktop +и WSL2. Выполняйте команды из корня репозитория. Ветка проекта по умолчанию — +`master`. -```text -MySQL (mysql) -PostgreSQL (postgres) -``` - -Невалидный default server `db` в форме отсутствует. Пользователь выбирает -одно подключение, затем вводит общий `DB_USER`/`DB_PASSWORD` и базу. - -Страница входа содержит локальную подсказку: выбрать MySQL или PostgreSQL, -использовать значения `DB_USER`/`DB_PASSWORD` из `.docker.env` и базу `demo`. -После отдельной подготовки samples доступны также Sakila и Chinook для MySQL, -Pagila и Chinook для PostgreSQL. - -Вход в MySQL: - -```text -Server: MySQL (mysql) -Username: значение DB_USER -Password: значение DB_PASSWORD -Database: demo, sakila, chinook или пустое поле -``` - -Вход в PostgreSQL: - -```text -Server: PostgreSQL (postgres) -Username: значение DB_USER -Password: значение DB_PASSWORD -Database: demo, pagila или chinook, если optional sample установлен -``` - -Имена `mysql` и `postgres` применяются только внутри Docker-сети. - -## Внешние клиенты - -Полноценные IDE-клиенты — PhpStorm, DataGrip, DBeaver — и CLI на хосте -подключаются к `127.0.0.1` и опубликованному порту, а не к имени -Compose-сервиса. - -MySQL: - -```text -Host: 127.0.0.1 -Port: значение MYSQL_PORT -User: значение DB_USER -Password: значение DB_PASSWORD -Database: demo, sakila или chinook, если optional sample установлен -``` - -PostgreSQL: - -```text -Host: 127.0.0.1 -Port: значение POSTGRES_PORT -User: значение DB_USER -Password: значение DB_PASSWORD -Database: demo, pagila или chinook, если optional sample установлен -``` - -CLI внутри контейнеров не требует размещать пароль в shell history: +## Быстрый старт ```bash -make mysql -make mysql-user -make postgres -make postgres-user +make init +make up ``` -## Учебные базы - -MySQL: - -- `demo` — обязательная база с таблицей `demo.demo_users`; -- `sakila` — опциональная официальная учебная база; -- `chinook` — опциональная база с музыкальным каталогом и продажами. - -PostgreSQL: - -- `demo` — обязательная база с таблицей `public.demo_users`; -- `pagila` — опциональный PostgreSQL-порт Sakila с фильмами, актёрами, - клиентами и прокатом; -- `chinook` — та же модель музыкального каталога и продаж, что в MySQL. - -Обе таблицы `demo_users` имеют одинаковую смысловую структуру: - -| Поле | Назначение | -|---|---| -| `id` | автоматически создаваемый integer primary key | -| `name` | `varchar(100) NOT NULL` | -| `email` | `varchar(150) NOT NULL UNIQUE` | -| `created_at` | обязательный timestamp с `CURRENT_TIMESTAMP` по умолчанию | +`make init` создаёт локальный `.docker.env` из отслеживаемого +[`.docker.env.example`](.docker.env.example), проверяет контролируемые пути +хранения и создаёт рабочие каталоги. При первом запуске официальные точки +входа инициализируют обе СУБД. Даже без необязательных учебных баз вы получите +рабочие MySQL и PostgreSQL с обязательной `demo` и начальными записями. -MySQL использует `TIMESTAMP`, PostgreSQL — `timestamptz`. В обе базы -идемпотентно добавляются одинаковые обязательные строки: - -| Name | Email | Created at | -|---|---|---| -| Alice | `alice@example.com` | `2025-01-10 09:00:00+03` | -| Bob | `bob@example.com` | `2025-01-11 10:15:00+03` | -| Carol | `carol@example.com` | `2025-01-12 11:30:00+03` | -| Dave | `dave@example.com` | `2025-01-13 12:45:00+03` | -| Eve | `eve@example.com` | `2025-01-14 14:00:00+03` | - -Дополнительные пользовательские строки разрешены и не считаются ошибкой при -проверках. - -Обычные `make init`, `make up`, `make up-no-ui`, `make up-mysql` и -`make up-postgres` не скачивают и не подготавливают optional samples. Обе СУБД -полностью работоспособны только с обязательной `demo`. +`make up` запускает MySQL, PostgreSQL и Adminer; `make up-no-ui` — обе СУБД +без Adminer. С настройками по умолчанию Adminer доступен по адресу +`http://127.0.0.1:8081`. -## Optional samples MySQL +Подробно о запуске, подключениях и учётных данных: +[Начало работы](docs/langs/ru/getting-started.md). -Скачать Chinook и официальный архив Sakila и подготовить локальные SQL-файлы: +### Нужны готовые учебные данные? -```bash -make samples-mysql -``` +Учебные базы не обязательны: `demo` создаётся всегда; для MySQL доступны +Sakila и Chinook, для PostgreSQL — Pagila и Chinook. -Для нового пустого каталога данных: - -```bash -make samples-mysql -make up-mysql -``` - -Для уже инициализированного MySQL: +**Первый запуск, каталоги данных пусты** ```bash +make init make samples-mysql -make reinit-mysql CONFIRM=1 -``` - -MySQL выполняет init-файлы только при первом запуске с пустым -`MYSQL_DATA_DIR`. Загрузка samples не изменяет данные и не перезапускает -контейнеры автоматически. - -`make samples-mysql` больше не скачивает World. Файлы сохраняются -детерминированно: - -```text -samples/mysql/ -├── .gitkeep -├── 010_chinook.sql -├── 020_sakila_schema.sql -└── 021_sakila_data.sql -``` - -Эти загруженные SQL-файлы считаются локально сгенерированными и исключены из -Git. `initdb/mysql/050_load_optional_samples.sh` пропускает отсутствующие -samples, безопасно пропускает уже полную `chinook` и прекращает init с ошибкой -при неполной/неожиданной `chinook` или неполной паре schema/data Sakila. - -## Optional samples PostgreSQL: Pagila и Chinook - -Подготовить Pagila и Chinook отдельной явной командой: - -```bash make samples-postgres +make up ``` -Для существующей локальной установки `.docker.env` не перезаписывается -автоматически: добавьте в него вручную -`POSTGRES_SAMPLES_DIR=./samples/postgres`. - -Для нового пустого каталога данных: - -```bash -make samples-postgres -make up-postgres -``` - -Для уже инициализированного PostgreSQL требуется явное пересоздание только его -data-каталога: - -```bash -make samples-postgres -make reinit-postgres CONFIRM=1 -``` - -`make samples-postgres` только скачивает и проверяет SQL обеих баз: команда не -запускает контейнеры, не удаляет данные и не выполняет reinit. Официальный -PostgreSQL entrypoint читает `/docker-entrypoint-initdb.d` лишь при -инициализации пустого `POSTGRES_DATA_DIR`, поэтому добавление файлов не меняет -существующую базу. - -Используется upstream -[`devrimgunduz/pagila`](https://github.com/devrimgunduz/pagila), закреплённый -на immutable commit -[`5ba5a57aeb159f75f02aca2432d3c262186d13d3`](https://github.com/devrimgunduz/pagila/commit/5ba5a57aeb159f75f02aca2432d3c262186d13d3). -Загружаются только `pagila-schema.sql` и COPY-вариант `pagila-data.sql`; -альтернативный insert-файл не используется. Pagila распространяется по -PostgreSQL License. - -Проверенная ревизия Pagila использует схему `public`, стандартные -PL/pgSQL-функции и `COPY FROM stdin`; дополнительных extensions, пакетов или -собственного Docker image не требуется. Подготовленные файлы сохраняются -детерминированно: - -```text -samples/postgres/ -├── 010_pagila_schema.sql -├── 020_pagila_data.sql -└── 030_chinook.sql -``` +Учебные базы подготавливаются до первой инициализации; официальные точки входа +загрузят их вместе с `demo`. -Все файлы локальные и исключены из Git. Отсутствие пары Pagila безопасно -пропускается, а наличие только одного файла останавливает чистую инициализацию -с ошибкой. Chinook обрабатывается независимо: она также optional. Повторный -загрузчик отдельно пропускает уже полные Pagila и Chinook с ожидаемым -владельцем, но не удаляет и не исправляет автоматически неполную базу или -неверное владение. Для этого требуется явный -`make reinit-postgres CONFIRM=1`. Штатные команды очистки data-каталогов не -удаляют `samples/postgres`. - -## Источник и безопасная подготовка Chinook - -Оба варианта Chinook берутся только из официального upstream -[`lerocha/chinook-database`](https://github.com/lerocha/chinook-database) на -immutable commit -[`4a944a942426e1f3263fe539155fb7ef92b04b4a`](https://github.com/lerocha/chinook-database/commit/4a944a942426e1f3263fe539155fb7ef92b04b4a), -соответствующем release `v1.4.5`. Chinook распространяется по MIT license; -полный copyright и permission notice из закреплённого `LICENSE.md` добавляется -SQL-комментариями в каждую подготовленную локальную копию. - -Upstream SQL нельзя выполнять напрямую: он содержит `DROP DATABASE`, -`CREATE DATABASE` и выбор базы. Команды подготовки проверяют Git blob SHA, -версию, целевую СУБД, ключевые таблицы и точный формат трёх setup-строк, затем -удаляют только эти известные строки. Готовый SQL повторно проверяется на -отсутствие database-level setup и публикуется атомарно вместе с остальными -sample-файлами. Он загружается только в заранее выбранную базу `chinook`. - -Chinook выбрана вместо MySQL World, потому что upstream явно указывает MIT -license и предоставляет одинаковые MySQL/PostgreSQL datasets. Существующая -база `world` автоматически не удаляется. Чтобы убрать старую `world` и -получить `chinook` в уже инициализированном MySQL, сначала подготовьте samples, -затем осознанно выполните `make reinit-mysql CONFIRM=1`; эта команда удалит -данные только MySQL. - -## Инициализация и порядок файлов - -```text -initdb/ -├── mysql/ -│ ├── 001_demo.sql -│ ├── 030_training_database.sql.example -│ ├── 050_load_optional_samples.sh -│ ├── 090_grant_training_access.sh -│ └── 099_check_training_access.sh -└── postgres/ - ├── 001_create_training_role.sh - ├── 010_initialize_demo.sh - ├── 030_training_database.sh.example - ├── 050_load_optional_samples.sh - └── 099_check_training_access.sh -``` +> **Внимание:** переинициализация удаляет данные выбранной СУБД. Резервная +> копия нужна, только если требуется сохранить собственные данные; для +> одноразового учебного стенда без ценных изменений она не обязательна. -Файлы `.example` служат шаблонами и не выполняются entrypoint автоматически. -MySQL-шаблон показывает добавление новой базы перед grants. PostgreSQL-шаблон -безопасно передаёт значения через psql variables, назначает `DB_USER` -владельцем новой базы и создаёт начальную таблицу от его имени. +
+📦 Стенд уже запускался: добавить или повторно использовать учебные базы -Оба официальных entrypoint обрабатывают init-каталог только для пустого -data-каталога. Изменение init-файлов не обновляет существующую базу. +**Уже инициализировано без учебных баз.** Обычный `make up` не применит новые +файлы инициализации или учебных баз. Сначала сохраните важные данные, затем +выполните нужный вариант: -## Конфигурация СУБД +- MySQL: `make samples-mysql`, затем `make reinit-mysql CONFIRM=1`. +- PostgreSQL: `make samples-postgres`, затем `make reinit-postgres CONFIRM=1`. +- Обе СУБД: `make samples-mysql`, `make samples-postgres`, затем `make reinit-all CONFIRM=1`. -```text -conf/ -├── mysql/ -│ └── my.cnf -└── postgres/ - └── postgresql.conf.example -``` +> **Внимание:** `reinit-*` удаляет данные выбранной СУБД и выполняется только с точным `CONFIRM=1`. -`conf/mysql/my.cnf` подключается к MySQL и фиксирует `utf8mb4`, collation -`utf8mb4_0900_ai_ci`, строгий SQL mode с `ONLY_FULL_GROUP_BY`, часовой пояс -`+03:00` и отключение DNS lookup клиентов. Performance-настройки оставлены -только понятными закомментированными примерами: универсальных значений для -лимитов памяти, соединений и slow query log нет. - -`conf/postgres/postgresql.conf.example` полностью закомментирован и -автоматически к Compose не подключается. Он показывает, как ресурсы и тип -нагрузки влияют на `shared_buffers`, `work_mem`, `maintenance_work_mem` и -временную диагностику медленных запросов. Активного PostgreSQL performance -tuning и отдельного logging collector нет: сервер продолжает писать в штатные -Docker logs. - -## Права учебного пользователя - -В MySQL `090_grant_training_access.sh` создаёт или обновляет `DB_USER` и -выдаёт ему `ALL PRIVILEGES` отдельно на каждую фактически существующую -несистемную базу. Глобальные административные права на `*.*` не выдаются. - -В PostgreSQL роль `DB_USER` получает `LOGIN`, владеет обязательной базой -`demo` и схемой `public`, но остаётся без `SUPERUSER`, `CREATEDB`, -`CREATEROLE`, `REPLICATION` и `BYPASSRLS`. Таблица `demo_users` создаётся от -имени этой роли. Если подготовлена Pagila, база создаётся с владельцем -`DB_USER`, а schema и data загружаются от его имени. Закреплённый upstream dump -содержит `OWNER TO postgres`; загрузчик безопасно заменяет эти фиксированные -owner-выражения на quoted psql-переменную `DB_USER`, не меняя локальные -SQL-файлы и не повышая права роли. PostgreSQL Chinook также создаётся с -владельцем `DB_USER`; этой роли принадлежат схема `public`, таблицы и все -созданные в ней последовательности, представления, функции и пользовательские -типы. Пароли не хардкодятся и берутся только из environment контейнеров. - -## Проверки - -Проверка каждой СУБД отдельно: +**Учебные базы уже установлены.** Используйте обычный `make up` или выбранную +цель `make up-*`: повторная загрузка и переинициализация не нужны, базы +сохраняются в каталогах хоста, подключённых в контейнеры. -```bash -make check-mysql-access -make check-postgres-access -``` +
-MySQL-проверка требует `demo.demo_users`, все пять обязательных email, -проверяет temporary read/write и пробный откатываемый `INSERT` в `demo_users`. -Она также проверяет доступ ко всем существующим пользовательским базам и -`sakila.actor` только при наличии sample. Для optional Chinook отдельно -проверяются таблицы с точным регистром `Artist`, `Album`, `Track`, `Customer`, -`Invoice`, данные, join и откатываемая запись. - -PostgreSQL-проверка подключается как `DB_USER` по TCP к работающему серверу, -проверяет владение базой и `demo_users`, все пять обязательных email, создаёт -временную таблицу, записывает и читает строку, выполняет откатываемый `INSERT` -в `demo_users` и подтверждает отсутствие всех административных атрибутов роли. -Наличие Pagila и Chinook определяется независимо по фактическим базам, а не по -sample-файлам. Для каждой установленной базы дополнительно проверяются -владелец, ожидаемые таблицы и владельцы объектов, данные, читающий join, -временный объект и откатываемый `INSERT` без остаточных данных. Поэтому -поддерживаются все варианты: только `demo`, `demo + pagila`, -`demo + chinook`, `demo + pagila + chinook`. - -Для полного стенда: +Подробнее: [Базы и учебные данные](docs/langs/ru/databases.md). -```bash -make check -``` +## Режимы запуска -Команда проверяет Compose-конфигурацию и фактический доступ `DB_USER` к обеим -СУБД. +| Команда | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | Запускает | Запускает | Запускает | +| `make up-no-ui` | Запускает | Запускает | Останавливает | +| `make up-mysql` | Запускает | Не запускает | Не запускает | +| `make up-postgres` | Не запускает | Запускает | Не запускает | -## Troubleshooting optional Chinook +Команды одной СУБД не останавливают уже работающую другую; Adminer управляется +отдельно. Полный набор целей описан в [`Makefile`](Makefile). -Если загрузчик сообщает, что `chinook` уже существует, но неполна или имеет -неожиданного владельца, он намеренно ничего не удаляет и не пытается исправить -базу поверх существующих объектов. Проверьте, что sample подготовлен текущей -командой `make samples-mysql` или `make samples-postgres`, сохраните нужные -данные, затем при необходимости явно выполните reinit соответствующей СУБД с -`CONFIRM=1`. Reinit удаляет data-каталог выбранной СУБД; обычные `make up*` -этого не делают. +## Подключения и доступные базы -Если подготовленный `010_chinook.sql` или `030_chinook.sql` отклонён до -загрузки, не запускайте raw upstream SQL вручную. Повторите подготовку и -проверьте сеть; несовпадение Git blob SHA или формата setup-строк считается -ошибкой безопасности. +Внутри Compose-сети Adminer использует серверы `mysql` и `postgres`. Клиенты на +хосте используют `127.0.0.1` и настроенные `MYSQL_PORT` или `POSTGRES_PORT`. +Для обычной работы укажите `DB_USER` и `DB_PASSWORD`. -## Остановка и очистка данных +| СУБД | Доступна всегда | После инициализации необязательных учебных баз | +|---|---|---| +| MySQL | `demo` | `sakila`, `chinook` | +| PostgreSQL | `demo` | `pagila`, `chinook` | -Остановить все сервисы без удаления bind-mounted данных: +Имена необязательных баз действительны только после их фактической инициализации. +Подробности: [запуск и подключения](docs/langs/ru/getting-started.md) · +[базы и учебные данные](docs/langs/ru/databases.md). -```bash -make down -``` +## Кратко об учётных данных -Удаление данных всегда требует явного `CONFIRM=1`: +| Назначение | Пользователь | Пароль | +|---|---|---| +| Общий учебный пользователь | `DB_USER` | `DB_PASSWORD` | +| Администратор MySQL | `root` | `MYSQL_ROOT_PASSWORD` | +| Суперпользователь PostgreSQL | `POSTGRES_SUPERUSER` | `POSTGRES_SUPERUSER_PASSWORD` | -```bash -make clean-mysql CONFIRM=1 -make clean-postgres CONFIRM=1 -make clean-all CONFIRM=1 -``` +`POSTGRES_SUPERUSER` и `DB_USER` должны быть разными ролями. Для упражнений +используйте учебного пользователя и замените примерные пароли до публикации +сервисов. -Первые две команды удаляют только каталог соответствующей СУБД. `clean-all` -удаляет только `data/mysql` и `data/postgres`. `.docker.env`, конфигурация, -init-файлы, optional samples и backup сохраняются. Перед удалением проверяется, -что data-каталог находится внутри проекта; пустой каталог возвращается -текущему UID/GID. +## Базы и ключевые проверки -Чистая инициализация с последующей проверкой: +Обе `demo` содержат эквивалентную таблицу `demo_users` с пятью строками. +Статические проверки не требуют запущенных СУБД: ```bash -make reinit-mysql CONFIRM=1 -make reinit-postgres CONFIRM=1 -make reinit-all CONFIRM=1 +make check-env +make config +make test-storage-paths ``` -Одиночные команды запускают только выбранную СУБД без Adminer. `reinit-all` -запускает обе СУБД без Adminer и выполняет общую проверку. - -## Основные команды - -| Команда | Назначение | -|---|---| -| `make init` | Создать `.docker.env`, data/init/samples-каталоги и проверить скрипты | -| `make pull` | Скачать три образа | -| `make config` | Проверить итоговую Compose-конфигурацию | -| `make samples-mysql` | Подготовить optional Chinook и Sakila без запуска контейнеров | -| `make samples-postgres` | Подготовить optional Pagila и Chinook без запуска контейнеров | -| `make status` | Показать MySQL, PostgreSQL и профильный Adminer | -| `make logs` | Смотреть общие логи | -| `make log postgres` | Смотреть лог выбранного сервиса (`SERVICE=postgres` также поддерживается) | -| `make in postgres` | Открыть shell выбранного контейнера (`SERVICE=postgres` также поддерживается) | -| `make wait-mysql` | Дождаться MySQL | -| `make wait-postgres` | Дождаться PostgreSQL | -| `make mysql-grants` | Повторно применить MySQL grants | -| `make mysql-import FILE=...` | Импортировать MySQL dump, применить grants и проверить доступ | -| `make dump` / `make restore` | Создать / восстановить backup MySQL `demo` | - -## Структура данных и Git - -Данные СУБД разделены: - -```text -data/ -├── mysql/ -└── postgres/ -``` +После запуска `make check` проверяет `demo` и доступ `DB_USER`, а +`make test-sql-imports` — публичные цели импорта доверенных SQL-файлов. Порядок +и ограничения: [Проверки и эксплуатация](docs/langs/ru/operations.md). -Контейнеры могут присвоить файлам числовые UID/GID своих системных -пользователей. Не редактируйте содержимое data-каталогов вручную. +## Безопасность и жизненный цикл -Для официального образа PostgreSQL 18 host-каталог `data/postgres` подключён к -`/var/lib/postgresql`; фактический versioned data directory образ создаёт -внутри этого bind mount. +- `BIND_ADDRESS=127.0.0.1` публикует сервисы только на интерфейсе обратной петли + (loopback). +- `BIND_ADDRESS=0.0.0.0` открывает их на всех интерфейсах: заранее настройте + межсетевой экран, надёжные учётные данные и доверенную сеть. +- Официальные точки входа выполняют инициализацию только для пустого каталога + данных. +- `make mysql-import` и `make postgres-import` принимают только доверенный SQL. + Это не изолированная среда (`sandbox`): возможна частичная запись без полного + автоматического отката. Перед важным импортом проверьте SQL-файл и сделайте + подходящую резервную копию. +- Встроенные `make dump` и `make restore` покрывают только MySQL `demo`; + встроенной цели резервного копирования для PostgreSQL нет. +- Все цели `clean-*` и `reinit-*` удаляют данные и требуют точного + `CONFIRM=1`. -В Git не должны попадать: +Безопасные последовательности: +[Проверки и эксплуатация](docs/langs/ru/operations.md). +При ошибках сначала соберите диагностику: +[Диагностика](docs/langs/ru/troubleshooting.md). -```text -.docker.env -.env -data/ -backup/ -.tmp/ -samples/mysql/*.sql -samples/postgres/*.sql -``` +## Лицензии учебных данных -Обязательные init-скрипты и оба шаблона `.example` остаются отслеживаемыми. +Необязательные учебные наборы данных сохраняют лицензии и уведомления об +авторских правах и лицензиях исходных проектов. Происхождение, закреплённые +ревизии, сведения о целостности и тексты лицензий приведены в +[`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md). --- -Автор: **Александр Юрченко** - -Лицензия: MIT +

+ + YA + +
+ yaleksandr89.github.io +

diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md new file mode 100644 index 0000000..9b20573 --- /dev/null +++ b/THIRD_PARTY_NOTICES.md @@ -0,0 +1,119 @@ +# Third-Party Notices + +SQL Lab itself is licensed under the MIT License in [`LICENSE.md`](LICENSE.md). + +The optional sample databases described below are third-party works with their +own license terms. Their SQL files are downloaded locally by explicit +`make samples-*` commands and are excluded from Git. They are not relicensed +under the SQL Lab license. + +## Chinook Database + +- Upstream: `lerocha/chinook-database` +- Pinned revision: + `4a944a942426e1f3263fe539155fb7ef92b04b4a` +- Files used: + - `ChinookDatabase/DataSources/Chinook_MySql.sql` + - `ChinookDatabase/DataSources/Chinook_PostgreSql.sql` + - `LICENSE.md` +- Integrity: + - license Git blob: + `7487a9edc2d42e50d7a38ab1fbdba33ac63230f7` + - MySQL SQL Git blob: + `cdbd482f1be7fde54644480ec7c794ff2764b109` + - PostgreSQL SQL Git blob: + `d93a20d08239ac6bdd8a56601e148f5d4d048593` + +The complete upstream license notice is inserted into each locally prepared +Chinook SQL file. + +### Chinook license notice + +Chinook Database + +Copyright (c) 2008-2024 Luis Rocha + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +## Pagila + +- Upstream: `devrimgunduz/pagila` +- Pinned revision: + `5ba5a57aeb159f75f02aca2432d3c262186d13d3` +- Files used: + - `pagila-schema.sql` + - `pagila-data.sql` + - `LICENSE.txt` +- Integrity: + - license Git blob: + `c6078c708c6f55b56e24f3687c591ca12df567ca` + - schema Git blob: + `23718a3adef90ced002e19ad4e1ac98d22aa5870` + - data Git blob: + `b7c016861fd0f84008645153c6a1d9e5a99b9cc6` + +The pinned upstream README describes Pagila as being available under the +PostgreSQL License, while the pinned `LICENSE.txt` contains the permission text +reproduced below. SQL Lab preserves that exact upstream text without assigning +a different SPDX identifier. The complete notice is inserted into both locally +prepared Pagila SQL files. + +### Pagila license notice + +Copyright (c) Devrim Gündüz + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +## Sakila Sample Database + +- Official archive: + `https://downloads.mysql.com/docs/sakila-db.zip` +- Verified archive SHA-256: + `c2ecb3dec28d752241ccfca02974ba970de3c3fc5d98887fd3f9d5843f946672` +- Files used: + - `sakila-schema.sql` + - `sakila-data.sql` +- Official license reference: + `https://dev.mysql.com/doc/sakila/en/sakila-license.html` + +MySQL states that `sakila-schema.sql` and `sakila-data.sql` are licensed under +the New BSD license. Other materials in the distribution are not covered by +that open license. + +SQL Lab extracts only those two SQL files. It does not publish the Sakila +documentation or `sakila.mwb`. Before extraction, the archive SHA-256 is +verified. Both SQL files must contain the expected New BSD notice and +disclaimer, and they are copied without modifying their embedded copyright and +license text. diff --git a/docker-compose.yml b/docker-compose.yml index 76ab6bf..909ca3b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,6 @@ services: mysql: image: mysql:${MYSQL_VERSION} - container_name: ${MYSQL_CONTAINER} restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} @@ -10,10 +9,10 @@ services: DB_PASSWORD: ${DB_PASSWORD} TZ: Europe/Moscow ports: - - "${MYSQL_PORT}:3306" + - "${BIND_ADDRESS:-127.0.0.1}:${MYSQL_PORT}:3306" volumes: - "${MYSQL_DATA_DIR}:/var/lib/mysql" - - "${MYSQL_CONF_FILE}:/etc/mysql/conf.d/z-stepik.cnf:ro" + - "${MYSQL_CONF_FILE}:/etc/mysql/conf.d/sql-lab.cnf:ro" - "${MYSQL_INITDB_DIR}:/docker-entrypoint-initdb.d:ro" - "${MYSQL_SAMPLES_DIR}:/opt/mysql-samples:ro" healthcheck: @@ -24,7 +23,6 @@ services: postgres: image: postgres:${POSTGRES_VERSION} - container_name: ${POSTGRES_CONTAINER} restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_SUPERUSER} @@ -34,7 +32,7 @@ services: DB_PASSWORD: ${DB_PASSWORD} TZ: Europe/Moscow ports: - - "${POSTGRES_PORT}:5432" + - "${BIND_ADDRESS:-127.0.0.1}:${POSTGRES_PORT}:5432" volumes: - "${POSTGRES_DATA_DIR}:/var/lib/postgresql" - "${POSTGRES_INITDB_DIR}:/docker-entrypoint-initdb.d:ro" @@ -47,7 +45,6 @@ services: adminer: image: adminer:${ADMINER_VERSION} - container_name: ${ADMINER_CONTAINER} restart: unless-stopped profiles: - ui @@ -55,7 +52,7 @@ services: ADMINER_DESIGN: nette TZ: Europe/Moscow ports: - - "${ADMINER_PORT}:8080" + - "${BIND_ADDRESS:-127.0.0.1}:${ADMINER_PORT}:8080" volumes: - "./adminer/plugins-enabled/001-login-servers.php:/var/www/html/plugins-enabled/001-login-servers.php:ro" - "./adminer/plugins-enabled/002-login-help.php:/var/www/html/plugins-enabled/002-login-help.php:ro" diff --git a/docs/assets/docker-sql-lab-cover.png b/docs/assets/docker-sql-lab-cover.png new file mode 100644 index 0000000..190165f Binary files /dev/null and b/docs/assets/docker-sql-lab-cover.png differ diff --git a/docs/assets/ya-logo-dark-50px.png b/docs/assets/ya-logo-dark-50px.png new file mode 100644 index 0000000..e0c821f Binary files /dev/null and b/docs/assets/ya-logo-dark-50px.png differ diff --git a/docs/langs/README_de.md b/docs/langs/README_de.md new file mode 100644 index 0000000..8c7696c --- /dev/null +++ b/docs/langs/README_de.md @@ -0,0 +1,218 @@ +

+ Docker SQL Lab — lokale MySQL- und PostgreSQL-Umgebung +

+ +# Docker SQL Lab + +## Sprache auswählen + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../../README.md) | [English](README_en.md) | [Español](README_es.md) | [中文](README_zh.md) | [Français](README_fr.md) | **Ausgewählt** | + +Eine lokale Docker-Compose-Umgebung zum Üben von SQL sowie zum Kennenlernen +und Vergleichen von MySQL und PostgreSQL. Beide DBMS lassen sich einzeln oder +gemeinsam starten. Die kompakte `demo`-Datenbank entsteht automatisch; +optionale Sakila-, Pagila- und Chinook-Datensätze liefern sofort abfragbare +Übungsdaten. Adminer wird nur bei Bedarf aktiviert. + +## Bildschirmaufzeichnungen + +Die Aufzeichnungen verwenden PhpStorm; DataGrip, DBeaver, Adminer oder ein +anderer MySQL-/PostgreSQL-Client eignen sich ebenfalls. Sie wurden auf Russisch aufgenommen. + +| Szenario | Yandex Disk | Google Drive | Gezeigt wird | +|---|---|---|---| +| Erster Start mit obligatorischem `demo`, danach Übungsdatenbanken hinzufügen | [Ansehen](https://disk.yandex.ru/i/Kj4TcMSBuIDVeA "docker-sql-lab-demo-then-training-databases.mp4") | [Ansehen](https://drive.google.com/file/d/1HzYWbMuBEobXlbGQYNfHYVAq95TLqEPf/view?usp=sharing "docker-sql-lab-demo-then-training-databases.mp4") | Startet MySQL und PostgreSQL mit obligatorischem `demo`; prüft; bereitet Sakila, Pagila und Chinook vor; bestätigt die Neuinitialisierung; prüft erneut und führt SQL-Abfragen aus. | +| Erster Start mit vorab vorbereiteten Übungsdatenbanken | [Ansehen](https://disk.yandex.ru/i/nFgJZto8agbdWw "docker-sql-lab-training-databases-first-start.mp4") | [Ansehen](https://drive.google.com/file/d/1nKiGrJ4QINLCQcRk-k6vfTakpWsw-JS7/view?usp=sharing "docker-sql-lab-training-databases-first-start.mp4") | Bereitet Sakila, Pagila und Chinook vor dem ersten Start vor; initialisiert obligatorisches `demo` und Übungsdatenbanken zusammen; prüft Zugriff und führt SQL-Abfragen aus. | + +## Stack und festgelegte Versionen + +- MySQL 9.7.1 LTS +- PostgreSQL 18.4 +- Adminer 5.4.2 Docker Official Image +- Docker Compose v2 +- GNU Make und Bash für Projektbefehle und Initialisierungsskripte + +Die festgelegten Standardwerte stehen in +[`.docker.env.example`](../../.docker.env.example); `make init` erstellt daraus +die lokale `.docker.env`. Die Services stehen in +[`docker-compose.yml`](../../docker-compose.yml). + +
+⚠️ Wichtig: Dies ist eine Lernumgebung + +Das Projekt ist kein produktionsfertiges Template. Für externe Nutzung sind +eigene Entscheidungen zu Zugangsdaten, Netzwerkfreigabe, Storage, Backups und +Betrieb nötig. + +
+ +## Hauptfunktionen + +- MySQL und PostgreSQL laufen einzeln oder gemeinsam. +- Jedes DBMS hat eine obligatorische `demo` mit denselben Seed-Datensätzen. +- Optional: Sakila und Chinook für MySQL, Pagila und Chinook für PostgreSQL. +- Adminer ist eine unabhängige optionale Oberfläche für beide DBMS. +- Daten-, Init- und Sample-Verzeichnisse sind je DBMS getrennt eingebunden. +- Prüfungen, vertrauenswürdige SQL-Imports und destructive Aktionen bündelt das + [`Makefile`](../../Makefile). + +## Voraussetzungen + +1. Docker Engine oder Docker Desktop mit Docker Compose v2. +2. GNU Make, Bash und die von den Skripten verwendeten Unix-CLI-Basiswerkzeuge. + +Empfohlen: Linux; macOS mit Docker Desktop; Windows mit Docker Desktop und +WSL2. Befehle werden im Repository-Stamm ausgeführt. Der Standardbranch ist +`master`. + +## Schnellstart + +```bash +make init +make up +``` + +`make init` erzeugt die lokale `.docker.env` aus +[`.docker.env.example`](../../.docker.env.example), prüft verwaltete Pfade und +legt Arbeitsverzeichnisse an. Beim ersten Containerstart initialisieren die +offiziellen Entrypoints beide DBMS. Auch ohne optionale Samples erhalten Sie +MySQL und PostgreSQL mit `demo` und Seed-Datensätzen. + +`make up` startet MySQL, PostgreSQL und Adminer; `make up-no-ui` startet beide +DBMS ohne Adminer. Standardmäßig ist Adminer unter +`http://127.0.0.1:8081` erreichbar. + +Startmodi, Verbindungen und Zugangsdaten: +[Erste Schritte](de/getting-started.md). + +### Fertige Übungsdaten gewünscht? + +Samples sind optional: `demo` wird immer erstellt; Sakila und Chinook sind für MySQL verfügbar, Pagila und Chinook für PostgreSQL. + +**Erster Start mit leeren Datenverzeichnissen** + +```bash +make init +make samples-mysql +make samples-postgres +make up +``` + +Bereiten Sie Samples vor der ersten Initialisierung vor; die Entrypoints laden sie zusammen mit `demo`. + +> **Warnung:** Die Neuinitialisierung löscht die Daten des gewählten DBMS. +> Sichern Sie nur eigene Daten, die erhalten bleiben sollen; ein einmaliges Lab ohne wertvolle Änderungen braucht kein Backup. + +
+📦 Das Lab lief bereits: Samples hinzufügen oder erneut verwenden + +**Ohne Samples initialisiert.** `make up` wendet neue Init-/Sample-Dateien nicht an. Wenn wichtige Daten erhalten bleiben sollen, sichern Sie sie und wählen dann die passende Variante: + +- MySQL: `make samples-mysql`, danach `make reinit-mysql CONFIRM=1`. +- PostgreSQL: `make samples-postgres`, danach `make reinit-postgres CONFIRM=1`. +- Beide DBMS: `make samples-mysql`, `make samples-postgres`, danach `make reinit-all CONFIRM=1`. + +> **Warnung:** `reinit-*` löscht die gewählten Daten und läuft nur mit dem exakten `CONFIRM=1`. + +**Samples bereits installiert.** Nutzen Sie `make up` oder das gewünschte `make up-*`: Erneuter download und reinit entfallen; die Datenbanken bleiben im bind-mounted storage erhalten. + +
+ +Details: [Datenbanken und Samples](de/databases.md). + +## Startmodi + +| Befehl | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | Startet | Startet | Startet | +| `make up-no-ui` | Startet | Startet | Stoppt | +| `make up-mysql` | Startet | Startet nicht | Startet nicht | +| `make up-postgres` | Startet nicht | Startet | Startet nicht | + +Ein Einzel-DBMS-Befehl stoppt das andere nicht; Adminer wird separat verwaltet. +Alle Targets stehen im [`Makefile`](../../Makefile). + +## Verbindungen und verfügbare Datenbanken + +Im Compose-Netz nutzt Adminer `mysql` und `postgres`. Host-Clients nutzen +`127.0.0.1` und `MYSQL_PORT` oder `POSTGRES_PORT`. Für Übungen dienen +`DB_USER` und `DB_PASSWORD`. + +| DBMS | Immer verfügbar | Nach optionaler Sample-Initialisierung | +|---|---|---| +| MySQL | `demo` | `sakila`, `chinook` | +| PostgreSQL | `demo` | `pagila`, `chinook` | + +Optionale Datenbanken existieren erst nach der tatsächlichen Initialisierung. +Details: [Start und Verbindungen](de/getting-started.md) · +[Datenbanken und Samples](de/databases.md). + +## Zugangsdaten im Überblick + +| Zweck | Benutzer | Passwort | +|---|---|---| +| Gemeinsamer Lernbenutzer | `DB_USER` | `DB_PASSWORD` | +| MySQL-Administrator | `root` | `MYSQL_ROOT_PASSWORD` | +| PostgreSQL-Superuser | `POSTGRES_SUPERUSER` | `POSTGRES_SUPERUSER_PASSWORD` | + +`POSTGRES_SUPERUSER` und `DB_USER` müssen verschieden sein. Verwenden Sie für +Übungen den Lernbenutzer und ersetzen Sie Beispielpasswörter vor Freigaben. + +## Datenbanken und wichtige Prüfungen + +Beide `demo`-Datenbanken enthalten eine äquivalente Tabelle `demo_users` mit +fünf Zeilen. Diese Prüfungen brauchen keine laufenden DBMS: + +```bash +make check-env +make config +make test-storage-paths +``` + +Nach dem Start prüft `make check` die `demo` und den Zugriff von `DB_USER`; +`make test-sql-imports` testet die öffentlichen Trusted-Import-Targets. +Reihenfolge und Grenzen: +[Prüfungen und Betrieb](de/operations.md). + +## Sicherheit und Lebenszyklus + +- `BIND_ADDRESS=127.0.0.1` veröffentlicht nur auf Loopback. +- `BIND_ADDRESS=0.0.0.0` öffnet alle Interfaces; richten Sie vorher Firewall, + starke Zugangsdaten und ein vertrauenswürdiges Netz ein. +- Offizielle Entrypoints führen Init nur bei leeren Daten aus. +- `make mysql-import` und `make postgres-import` akzeptieren nur + vertrauenswürdiges SQL. Sie sind keine Sandbox: partielle Ausführung ohne + vollständigen automatischen Rollback ist möglich. + Prüfen Sie vor einem wichtigen Import die SQL-Datei und erstellen Sie ein geeignetes Backup. +- `make dump` und `make restore` sichern nur MySQL `demo`; ein eingebautes + PostgreSQL-Backup-Target fehlt. +- Alle `clean-*`- und `reinit-*`-Befehle sind destructive und verlangen exakt + `CONFIRM=1`. + +Sichere Abläufe: [Prüfungen und Betrieb](de/operations.md). Bei Fehlern zuerst +Diagnosedaten sammeln: +[Diagnose und Fehlerbehebung](de/troubleshooting.md). + +## Lizenzen der Übungsdaten + +Optionale Datensätze behalten Lizenzen und Hinweise ihrer Upstream-Projekte. +Herkunft, festgelegte Revisionen, Integrität und Lizenztexte stehen in +[`THIRD_PARTY_NOTICES.md`](../../THIRD_PARTY_NOTICES.md). + +

+ + YA + +
+ yaleksandr89.github.io +

diff --git a/docs/langs/README_en.md b/docs/langs/README_en.md new file mode 100644 index 0000000..df88aaa --- /dev/null +++ b/docs/langs/README_en.md @@ -0,0 +1,220 @@ +

+ Docker SQL Lab +

+ +# Docker SQL Lab + +## Choose a language + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../../README.md) | **Selected** | [Español](README_es.md) | [中文](README_zh.md) | [Français](README_fr.md) | [Deutsch](README_de.md) | + +A local Docker Compose lab for practicing SQL and exploring and comparing +MySQL and PostgreSQL. Run either DBMS independently or both together. A compact +`demo` database is created automatically, while optional Sakila, Pagila, and +Chinook datasets provide ready-to-query training data. Enable Adminer only +when you need it. + +## Screencasts + +The recordings use PhpStorm. DataGrip, DBeaver, Adminer, or another +MySQL/PostgreSQL client will work instead. The screencasts are recorded in Russian. + +| Scenario | Yandex Disk | Google Drive | What it shows | +|---|---|---|---| +| First start with required `demo`, then add training databases | [Watch](https://disk.yandex.ru/i/Kj4TcMSBuIDVeA "docker-sql-lab-demo-then-training-databases.mp4") | [Watch](https://drive.google.com/file/d/1HzYWbMuBEobXlbGQYNfHYVAq95TLqEPf/view?usp=sharing "docker-sql-lab-demo-then-training-databases.mp4") | Start MySQL and PostgreSQL with required `demo`; check them; prepare Sakila, Pagila, and Chinook; confirm reinitialization; check again and run SQL queries. | +| First start with training databases prepared in advance | [Watch](https://disk.yandex.ru/i/nFgJZto8agbdWw "docker-sql-lab-training-databases-first-start.mp4") | [Watch](https://drive.google.com/file/d/1nKiGrJ4QINLCQcRk-k6vfTakpWsw-JS7/view?usp=sharing "docker-sql-lab-training-databases-first-start.mp4") | Prepare Sakila, Pagila, and Chinook before the first start; initialize required `demo` and the training databases together; check access and run SQL queries. | + +## Stack + +- MySQL 9.7.1 LTS +- PostgreSQL 18.4 +- Adminer 5.4.2 Docker Official Image +- Docker Compose v2 +- GNU Make and Bash for project commands and initialization scripts + +Pinned defaults are defined in +[`.docker.env.example`](../../.docker.env.example); `make init` creates the +local `.docker.env` from it. Services are defined in +[`docker-compose.yml`](../../docker-compose.yml). + +
+⚠️ Important: this is a training environment + +This project is not a production-ready template. External use requires +separate decisions about credentials, network exposure, storage, backups, and +operations. + +
+ +## Features + +- MySQL and PostgreSQL run independently or together. +- A required `demo` database in each DBMS contains equivalent seed rows. +- Optional Sakila and Chinook are available for MySQL; Pagila and Chinook for + PostgreSQL. +- Adminer is a separate optional UI shared by both DBMSs. +- Each DBMS has separate bind-mounted data, init, and sample directories. +- Configuration and access checks, trusted SQL imports, and destructive + commands are collected in the [`Makefile`](../../Makefile). + +## Requirements + +1. Docker Engine or Docker Desktop with Docker Compose v2. +2. GNU Make, Bash, and the basic Unix CLI utilities used by the scripts. + +Recommended environments: Linux; macOS with Docker Desktop; Windows with +Docker Desktop and WSL2. Run commands from the repository root. The project's +default branch is `master`. + +## Quick start + +```bash +make init +make up +``` + +`make init` creates the local `.docker.env` from the tracked +[`.docker.env.example`](../../.docker.env.example), validates managed paths, +and creates working directories. On the first container start, the official +entrypoints initialize both DBMSs. Even without optional samples, you get +working MySQL and PostgreSQL instances with the required `demo` database and +seed rows. + +`make up` starts MySQL, PostgreSQL, and Adminer; `make up-no-ui` starts both +DBMSs without Adminer. With the defaults, Adminer is available at +`http://127.0.0.1:8081`. + +For startup modes, connections, and credentials, see +[Getting started](en/getting-started.md). + +### Want ready-made training data? + +Optional samples are not required: `demo` is always created; MySQL supports Sakila and Chinook, while PostgreSQL supports Pagila and Chinook. + +**First start with empty data directories** + +```bash +make init +make samples-mysql +make samples-postgres +make up +``` + +Prepare samples before the first initialization; the official entrypoints load them alongside `demo`. + +> **Warning:** reinitialization deletes the selected DBMS data. Back up only +> custom data you need to keep; a one-off lab with no valuable changes needs no backup. + +
+📦 The lab has run before: add or reuse samples + +**Initialized without samples.** A regular `make up` does not apply new init/sample files. If you need to preserve important data, back it up, then use the appropriate option: + +- MySQL: `make samples-mysql`, then `make reinit-mysql CONFIRM=1`. +- PostgreSQL: `make samples-postgres`, then `make reinit-postgres CONFIRM=1`. +- Both DBMSs: `make samples-mysql`, `make samples-postgres`, then `make reinit-all CONFIRM=1`. + +> **Warning:** `reinit-*` deletes the selected DBMS data and runs only with the exact `CONFIRM=1`. + +**Samples already installed.** Use the regular `make up` or a selected `make up-*`: no repeated download or reinitialization is needed, and databases persist in bind-mounted storage. + +
+ +Details: [Databases and samples](en/databases.md). + +## Startup modes + +| Command | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | Starts | Starts | Starts | +| `make up-no-ui` | Starts | Starts | Stops | +| `make up-mysql` | Starts | Does not start | Does not start | +| `make up-postgres` | Does not start | Starts | Does not start | + +A single-DBMS command does not stop the other running DBMS; Adminer is managed +separately. The complete target list is in the [`Makefile`](../../Makefile). + +## Connections and available databases + +Inside the Compose network, Adminer uses `mysql` and `postgres`. Host clients +use `127.0.0.1` with the configured `MYSQL_PORT` or `POSTGRES_PORT`. Sign in +for routine work with `DB_USER` and `DB_PASSWORD`. + +| DBMS | Always available | After optional sample initialization | +|---|---|---| +| MySQL | `demo` | `sakila`, `chinook` | +| PostgreSQL | `demo` | `pagila`, `chinook` | + +Optional database names are valid only after actual initialization. Details: +[startup and connections](en/getting-started.md) · +[databases and samples](en/databases.md). + +## Credentials at a glance + +| Purpose | User | Password | +|---|---|---| +| Shared training user | `DB_USER` | `DB_PASSWORD` | +| MySQL administrator | `root` | `MYSQL_ROOT_PASSWORD` | +| PostgreSQL superuser | `POSTGRES_SUPERUSER` | `POSTGRES_SUPERUSER_PASSWORD` | + +`POSTGRES_SUPERUSER` and `DB_USER` must be different roles. Use the training +user for exercises, and replace example passwords before publishing services. + +## Databases and key checks + +Both `demo` databases contain an equivalent `demo_users` table with five rows. +These static checks do not require running DBMSs: + +```bash +make check-env +make config +make test-storage-paths +``` + +After startup, `make check` verifies `demo` and `DB_USER` access; +`make test-sql-imports` exercises the public trusted import targets. For the +safe order and limitations, see +[Validation and operations](en/operations.md). + +## Safety and lifecycle + +- `BIND_ADDRESS=127.0.0.1` publishes services only on loopback. +- `BIND_ADDRESS=0.0.0.0` exposes them on every interface; configure the + firewall, strong credentials, and network trust first. +- Official entrypoints run init only for an empty data directory. +- `make mysql-import` and `make postgres-import` accept trusted SQL only. + This is not a sandbox: partial execution is possible without a guaranteed + full automatic rollback. + Review the SQL file and create a suitable backup before an important import. +- Built-in `make dump` and `make restore` cover only MySQL `demo`; there is no + built-in PostgreSQL backup target. +- Every `clean-*` and `reinit-*` command is destructive and requires the exact + `CONFIRM=1`. + +Safe sequences: [Validation and operations](en/operations.md). For failures, +collect evidence first: [Troubleshooting](en/troubleshooting.md). + +## Training data licenses + +Optional sample datasets retain the licenses and notices of their upstream +projects. Provenance, pinned revisions, integrity information, and license +texts are in +[`THIRD_PARTY_NOTICES.md`](../../THIRD_PARTY_NOTICES.md). + +

+ + YA + +
+ yaleksandr89.github.io +

diff --git a/docs/langs/README_es.md b/docs/langs/README_es.md new file mode 100644 index 0000000..c660f48 --- /dev/null +++ b/docs/langs/README_es.md @@ -0,0 +1,214 @@ +

+ Docker SQL Lab — entorno local de MySQL y PostgreSQL +

+ +# Docker SQL Lab + +## Elija un idioma + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../../README.md) | [English](README_en.md) | **Seleccionado** | [中文](README_zh.md) | [Français](README_fr.md) | [Deutsch](README_de.md) | + +Un laboratorio local con Docker Compose para practicar SQL y conocer y comparar +MySQL y PostgreSQL. Puede iniciar cada SGBD por separado o ambos a la vez. +La base compacta `demo` se crea automáticamente; los datasets opcionales +Sakila, Pagila y Chinook ofrecen datos listos para consultar. Active Adminer +solo cuando lo necesite. + +## Videotutoriales + +Las grabaciones usan PhpStorm; también sirven DataGrip, DBeaver, Adminer u otro +cliente MySQL/PostgreSQL. Los screencasts están grabados en ruso. + +| Escenario | Yandex Disk | Google Drive | Qué muestra | +|---|---|---|---| +| Primer inicio con `demo` obligatoria y posterior adición de bases didácticas | [Ver](https://disk.yandex.ru/i/Kj4TcMSBuIDVeA "docker-sql-lab-demo-then-training-databases.mp4") | [Ver](https://drive.google.com/file/d/1HzYWbMuBEobXlbGQYNfHYVAq95TLqEPf/view?usp=sharing "docker-sql-lab-demo-then-training-databases.mp4") | Inicia MySQL y PostgreSQL con `demo` obligatoria; comprueba; prepara Sakila, Pagila y Chinook; confirma la reinicialización; vuelve a comprobar y ejecuta consultas SQL. | +| Primer inicio con las bases didácticas preparadas de antemano | [Ver](https://disk.yandex.ru/i/nFgJZto8agbdWw "docker-sql-lab-training-databases-first-start.mp4") | [Ver](https://drive.google.com/file/d/1nKiGrJ4QINLCQcRk-k6vfTakpWsw-JS7/view?usp=sharing "docker-sql-lab-training-databases-first-start.mp4") | Prepara Sakila, Pagila y Chinook antes del primer inicio; inicializa juntas `demo` obligatoria y las bases didácticas; comprueba el acceso y ejecuta consultas SQL. | + +## Stack + +- MySQL 9.7.1 LTS +- PostgreSQL 18.4 +- Adminer 5.4.2 Docker Official Image +- Docker Compose v2 +- GNU Make y Bash para los comandos y scripts de inicialización + +Los valores predeterminados fijados se definen en +[`.docker.env.example`](../../.docker.env.example); `make init` crea desde él +el `.docker.env` local. Los servicios se definen en +[`docker-compose.yml`](../../docker-compose.yml). + +
+⚠️ Importante: este es un entorno didáctico + +El proyecto no es una plantilla lista para producción. El uso externo exige +decisiones propias sobre credenciales, exposición de red, almacenamiento, +backups y operación. + +
+ +## Funciones principales + +- MySQL y PostgreSQL funcionan por separado o juntos. +- Cada SGBD incluye una base `demo` obligatoria con los mismos seed rows. +- MySQL admite Sakila y Chinook opcionales; PostgreSQL, Pagila y Chinook. +- Adminer es una interfaz opcional e independiente para ambos SGBD. +- Cada SGBD tiene directorios bind-mounted separados para datos, init y samples. +- Las comprobaciones, imports SQL de confianza y acciones destructivas se + centralizan en el [`Makefile`](../../Makefile). + +## Requisitos + +1. Docker Engine o Docker Desktop con Docker Compose v2. +2. GNU Make, Bash y las utilidades Unix CLI básicas usadas por los scripts. + +Entornos recomendados: Linux; macOS con Docker Desktop; Windows con Docker +Desktop y WSL2. Ejecute los comandos desde la raíz del repositorio. La rama +predeterminada del proyecto es `master`. + +## Inicio rápido + +```bash +make init +make up +``` + +`make init` crea el `.docker.env` local desde +[`.docker.env.example`](../../.docker.env.example), valida las rutas gestionadas +y crea los directorios de trabajo. En el primer arranque, los entrypoints +oficiales inicializan ambos SGBD. Sin samples opcionales seguirá teniendo MySQL +y PostgreSQL operativos con `demo` y sus seed rows. + +`make up` inicia MySQL, PostgreSQL y Adminer; `make up-no-ui` inicia ambos SGBD +sin Adminer. Por defecto, Adminer está en `http://127.0.0.1:8081`. + +Modos, conexiones y credenciales: +[Primeros pasos](es/getting-started.md). + +### ¿Necesita datos didácticos preparados? + +Los samples son opcionales: `demo` se crea siempre; MySQL ofrece Sakila y Chinook, y PostgreSQL, Pagila y Chinook. + +**Primer arranque con directorios de datos vacíos** + +```bash +make init +make samples-mysql +make samples-postgres +make up +``` + +Prepare los samples antes de la primera inicialización; los entrypoints los cargarán junto con `demo`. + +> **Advertencia:** la reinicialización elimina los datos del SGBD elegido. Haga +> backup solo de los datos propios que quiera conservar; un laboratorio puntual sin cambios valiosos no lo necesita. + +
+📦 El laboratorio ya se inició: añadir o reutilizar samples + +**Inicializado sin samples.** `make up` no aplica nuevos archivos init/sample. Si necesita conservar datos importantes, haga backup y use la opción adecuada: + +- MySQL: `make samples-mysql` y después `make reinit-mysql CONFIRM=1`. +- PostgreSQL: `make samples-postgres` y después `make reinit-postgres CONFIRM=1`. +- Ambos SGBD: `make samples-mysql`, `make samples-postgres` y después `make reinit-all CONFIRM=1`. + +> **Advertencia:** `reinit-*` elimina los datos seleccionados y solo se ejecuta con `CONFIRM=1` exacto. + +**Samples ya instalados.** Use `make up` o el `make up-*` elegido: no repita download ni reinit; las bases persisten en el almacenamiento bind-mounted. + +
+ +Detalles: [Bases y samples](es/databases.md). + +## Modos de inicio + +| Comando | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | Inicia | Inicia | Inicia | +| `make up-no-ui` | Inicia | Inicia | Detiene | +| `make up-mysql` | Inicia | No inicia | No inicia | +| `make up-postgres` | No inicia | Inicia | No inicia | + +Un comando de un solo SGBD no detiene al otro; Adminer se gestiona aparte. La +lista completa está en el [`Makefile`](../../Makefile). + +## Conexiones y bases disponibles + +Dentro de Compose, Adminer usa `mysql` y `postgres`. Los clientes del host usan +`127.0.0.1` y `MYSQL_PORT` o `POSTGRES_PORT`. Para el trabajo habitual, use +`DB_USER` y `DB_PASSWORD`. + +| SGBD | Siempre disponible | Tras inicializar samples opcionales | +|---|---|---| +| MySQL | `demo` | `sakila`, `chinook` | +| PostgreSQL | `demo` | `pagila`, `chinook` | + +Las bases opcionales solo existen tras su inicialización real. Detalles: +[inicio y conexiones](es/getting-started.md) · +[bases y samples](es/databases.md). + +## Credenciales resumidas + +| Finalidad | Usuario | Contraseña | +|---|---|---| +| Usuario didáctico común | `DB_USER` | `DB_PASSWORD` | +| Administrador MySQL | `root` | `MYSQL_ROOT_PASSWORD` | +| Superusuario PostgreSQL | `POSTGRES_SUPERUSER` | `POSTGRES_SUPERUSER_PASSWORD` | + +`POSTGRES_SUPERUSER` y `DB_USER` deben ser roles distintos. Use el usuario +didáctico para ejercicios y cambie las contraseñas de ejemplo antes de publicar. + +## Bases y comprobaciones clave + +Ambas `demo` contienen una tabla `demo_users` equivalente con cinco filas. +Estas comprobaciones no requieren SGBD en ejecución: + +```bash +make check-env +make config +make test-storage-paths +``` + +Tras el arranque, `make check` valida `demo` y el acceso de `DB_USER`; +`make test-sql-imports` prueba los imports públicos de confianza. Orden y +límites: [Comprobaciones y operaciones](es/operations.md). + +## Seguridad y ciclo de vida + +- `BIND_ADDRESS=127.0.0.1` publica solo en loopback. +- `BIND_ADDRESS=0.0.0.0` expone todos los interfaces; configure antes firewall, + credenciales robustas y una red de confianza. +- Los entrypoints oficiales ejecutan init solo con datos vacíos. +- `make mysql-import` y `make postgres-import` aceptan únicamente SQL de + confianza. No son un sandbox: puede haber ejecución parcial sin rollback + automático completo. + Antes de un import importante, revise el archivo SQL y cree un backup adecuado. +- `make dump` y `make restore` cubren solo `demo` de MySQL; no hay target de + backup integrado para PostgreSQL. +- Cada comando `clean-*` y `reinit-*` es destructivo y exige `CONFIRM=1` exacto. + +Secuencias seguras: [Comprobaciones y operaciones](es/operations.md). +Ante fallos, reúna primero diagnósticos: [Diagnóstico](es/troubleshooting.md). + +## Licencias de los datos didácticos + +Los datasets opcionales conservan las licencias y avisos de sus proyectos +upstream. Procedencia, revisiones fijadas, integridad y textos están en +[`THIRD_PARTY_NOTICES.md`](../../THIRD_PARTY_NOTICES.md). + +

+ + YA + +
+ yaleksandr89.github.io +

diff --git a/docs/langs/README_fr.md b/docs/langs/README_fr.md new file mode 100644 index 0000000..d653abe --- /dev/null +++ b/docs/langs/README_fr.md @@ -0,0 +1,215 @@ +

+ Docker SQL Lab — environnement local MySQL et PostgreSQL +

+ +# Docker SQL Lab + +## Choisissez une langue + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../../README.md) | [English](README_en.md) | [Español](README_es.md) | [中文](README_zh.md) | **Sélectionné** | [Deutsch](README_de.md) | + +Un environnement Docker Compose local pour pratiquer SQL, découvrir et +comparer MySQL et PostgreSQL. Lancez chaque SGBD séparément ou les deux +ensemble. La petite base `demo` est créée automatiquement ; les datasets +optionnels Sakila, Pagila et Chinook offrent des données prêtes à interroger. +Activez Adminer uniquement au besoin. + +## Vidéos de démonstration + +Les enregistrements utilisent PhpStorm ; DataGrip, DBeaver, Adminer ou un autre +client MySQL/PostgreSQL conviennent aussi. Les screencasts sont enregistrés en russe. + +| Scénario | Yandex Disk | Google Drive | Contenu | +|---|---|---|---| +| Premier démarrage avec `demo` obligatoire, puis ajout des bases d’entraînement | [Voir](https://disk.yandex.ru/i/Kj4TcMSBuIDVeA "docker-sql-lab-demo-then-training-databases.mp4") | [Voir](https://drive.google.com/file/d/1HzYWbMuBEobXlbGQYNfHYVAq95TLqEPf/view?usp=sharing "docker-sql-lab-demo-then-training-databases.mp4") | Démarre MySQL et PostgreSQL avec `demo` obligatoire ; vérifie ; prépare Sakila, Pagila et Chinook ; confirme la réinitialisation ; vérifie de nouveau et exécute des requêtes SQL. | +| Premier démarrage avec les bases d’entraînement préparées à l’avance | [Voir](https://disk.yandex.ru/i/nFgJZto8agbdWw "docker-sql-lab-training-databases-first-start.mp4") | [Voir](https://drive.google.com/file/d/1nKiGrJ4QINLCQcRk-k6vfTakpWsw-JS7/view?usp=sharing "docker-sql-lab-training-databases-first-start.mp4") | Prépare Sakila, Pagila et Chinook avant le premier démarrage ; initialise ensemble `demo` obligatoire et les bases d’entraînement ; vérifie l’accès et exécute des requêtes SQL. | + +## Stack et versions épinglées + +- MySQL 9.7.1 LTS +- PostgreSQL 18.4 +- Adminer 5.4.2 Docker Official Image +- Docker Compose v2 +- GNU Make et Bash pour les commandes et scripts d'initialisation + +Les valeurs par défaut épinglées sont définies dans +[`.docker.env.example`](../../.docker.env.example) ; `make init` crée à partir +de ce fichier le `.docker.env` local. Les services sont définis dans +[`docker-compose.yml`](../../docker-compose.yml). + +
+⚠️ Important : environnement de formation + +Ce projet n'est pas un template prêt pour la production. Un usage externe +nécessite des choix dédiés pour les identifiants, l'exposition réseau, le +stockage, les sauvegardes et l'exploitation. + +
+ +## Fonctionnalités principales + +- MySQL et PostgreSQL fonctionnent séparément ou ensemble. +- Chaque SGBD possède une base `demo` obligatoire avec les mêmes seed rows. +- MySQL propose Sakila et Chinook en option ; PostgreSQL, Pagila et Chinook. +- Adminer est une interface optionnelle et indépendante pour les deux SGBD. +- Données, init et samples ont des bind mounts distincts pour chaque SGBD. +- Contrôles, imports SQL de confiance et actions destructives sont regroupés + dans le [`Makefile`](../../Makefile). + +## Prérequis + +1. Docker Engine ou Docker Desktop avec Docker Compose v2. +2. GNU Make, Bash et les utilitaires Unix CLI de base utilisés par les scripts. + +Environnements conseillés : Linux ; macOS avec Docker Desktop ; Windows avec +Docker Desktop et WSL2. Exécutez les commandes depuis la racine du dépôt. La +branche par défaut du projet est `master`. + +## Démarrage rapide + +```bash +make init +make up +``` + +`make init` crée le `.docker.env` local depuis +[`.docker.env.example`](../../.docker.env.example), valide les chemins gérés et +crée les répertoires de travail. Au premier démarrage, les entrypoints officiels +initialisent les deux SGBD. Sans samples optionnels, MySQL et PostgreSQL restent +opérationnels avec `demo` et ses seed rows. + +`make up` lance MySQL, PostgreSQL et Adminer ; `make up-no-ui` lance les deux +SGBD sans Adminer. Par défaut, Adminer répond sur `http://127.0.0.1:8081`. + +Modes, connexions et identifiants : +[Prise en main](fr/getting-started.md). + +### Besoin de données d'entraînement prêtes à l'emploi ? + +Les samples sont optionnels : `demo` est toujours créée ; Sakila et Chinook sont proposés pour MySQL, Pagila et Chinook pour PostgreSQL. + +**Premier démarrage avec data vide** + +```bash +make init +make samples-mysql +make samples-postgres +make up +``` + +Préparez les samples avant la première initialisation ; les entrypoints les chargeront avec `demo`. + +> **Attention :** la réinitialisation supprime les données du SGBD choisi. Ne +> sauvegardez que les données personnelles à conserver ; un lab ponctuel sans changement précieux n’exige pas de sauvegarde. + +
+📦 Le laboratoire a déjà démarré : ajouter ou réutiliser les samples + +**Déjà initialisé sans samples.** `make up` n'applique pas les nouveaux fichiers init/sample. Si vous devez conserver des données importantes, sauvegardez-les, puis choisissez l'option adaptée : + +- MySQL : `make samples-mysql`, puis `make reinit-mysql CONFIRM=1`. +- PostgreSQL : `make samples-postgres`, puis `make reinit-postgres CONFIRM=1`. +- Les deux SGBD : `make samples-mysql`, `make samples-postgres`, puis `make reinit-all CONFIRM=1`. + +> **Attention :** `reinit-*` supprime les données sélectionnées et exige exactement `CONFIRM=1`. + +**Samples déjà installés.** Utilisez `make up` ou le `make up-*` choisi : aucun nouveau download ni reinit ; les bases persistent dans le stockage bind-mounted. + +
+ +Détails : [Bases et samples](fr/databases.md). + +## Modes de démarrage + +| Commande | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | Lance | Lance | Lance | +| `make up-no-ui` | Lance | Lance | Arrête | +| `make up-mysql` | Lance | Ne lance pas | Ne lance pas | +| `make up-postgres` | Ne lance pas | Lance | Ne lance pas | + +Une commande mono-SGBD n'arrête pas l'autre ; Adminer se gère séparément. La +liste complète figure dans le [`Makefile`](../../Makefile). + +## Connexions et bases disponibles + +Dans le réseau Compose, Adminer utilise `mysql` et `postgres`. Les clients de +l'hôte utilisent `127.0.0.1` et `MYSQL_PORT` ou `POSTGRES_PORT`. Pour les +exercices, utilisez `DB_USER` et `DB_PASSWORD`. + +| SGBD | Toujours disponible | Après initialisation des samples | +|---|---|---| +| MySQL | `demo` | `sakila`, `chinook` | +| PostgreSQL | `demo` | `pagila`, `chinook` | + +Les bases optionnelles n'existent qu'après leur initialisation effective. +Détails : [démarrage et connexions](fr/getting-started.md) · +[bases et samples](fr/databases.md). + +## Identifiants en bref + +| Usage | Utilisateur | Mot de passe | +|---|---|---| +| Utilisateur de formation commun | `DB_USER` | `DB_PASSWORD` | +| Administrateur MySQL | `root` | `MYSQL_ROOT_PASSWORD` | +| Superuser PostgreSQL | `POSTGRES_SUPERUSER` | `POSTGRES_SUPERUSER_PASSWORD` | + +`POSTGRES_SUPERUSER` et `DB_USER` doivent être distincts. Utilisez le compte de +formation et remplacez les mots de passe d'exemple avant toute publication. + +## Bases et contrôles essentiels + +Les deux `demo` contiennent une table `demo_users` équivalente de cinq lignes. +Ces contrôles ne nécessitent aucun SGBD lancé : + +```bash +make check-env +make config +make test-storage-paths +``` + +Après démarrage, `make check` vérifie `demo` et l'accès de `DB_USER` ; +`make test-sql-imports` teste les imports publics de confiance. Ordre et +limites : [Contrôles et opérations](fr/operations.md). + +## Sécurité et cycle de vie + +- `BIND_ADDRESS=127.0.0.1` publie uniquement sur loopback. +- `BIND_ADDRESS=0.0.0.0` expose toutes les interfaces ; configurez d'abord + firewall, identifiants robustes et réseau de confiance. +- Les entrypoints officiels exécutent init uniquement sur des données vides. +- `make mysql-import` et `make postgres-import` n'acceptent que du SQL de + confiance. Ce n'est pas un sandbox : une exécution partielle sans rollback + automatique complet reste possible. + Avant un import important, vérifiez le fichier SQL et créez un backup adapté. +- `make dump` et `make restore` couvrent seulement `demo` MySQL ; aucun target + de backup PostgreSQL n'est intégré. +- Tout `clean-*` et `reinit-*` est destructif et exige exactement `CONFIRM=1`. + +Séquences sûres : [Contrôles et opérations](fr/operations.md). En cas d'échec, +collectez d'abord le diagnostic : +[Diagnostic et dépannage](fr/troubleshooting.md). + +## Licences des données d'entraînement + +Les datasets optionnels conservent les licences et notices de leurs projets +upstream. Provenance, révisions épinglées, intégrité et textes figurent dans +[`THIRD_PARTY_NOTICES.md`](../../THIRD_PARTY_NOTICES.md). + +

+ + YA + +
+ yaleksandr89.github.io +

diff --git a/docs/langs/README_zh.md b/docs/langs/README_zh.md new file mode 100644 index 0000000..2fecfa5 --- /dev/null +++ b/docs/langs/README_zh.md @@ -0,0 +1,211 @@ +

+ Docker SQL Lab — 本地 MySQL 与 PostgreSQL 实验环境 +

+ +# Docker SQL Lab + +## 选择语言 + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../../README.md) | [English](README_en.md) | [Español](README_es.md) | **已选择** | [Français](README_fr.md) | [Deutsch](README_de.md) | + +用于练习 SQL、了解并比较 MySQL 与 PostgreSQL 的本地 Docker Compose +实验环境。两种数据库既可单独启动,也可同时运行。精简的 `demo` +数据库会自动创建;可选的 Sakila、Pagila 和 Chinook 数据集提供开箱即用 +的查询练习数据。仅在需要时启用 Adminer。 + +## 录屏演示 + +录屏使用 PhpStorm;也可使用 DataGrip、DBeaver、Adminer 或其他 +MySQL/PostgreSQL 客户端。录屏以俄语录制。 + +| 场景 | Yandex Disk | Google Drive | 演示内容 | +|---|---|---|---| +| 首次启动必需的 `demo`,随后添加练习数据库 | [观看](https://disk.yandex.ru/i/Kj4TcMSBuIDVeA "docker-sql-lab-demo-then-training-databases.mp4") | [观看](https://drive.google.com/file/d/1HzYWbMuBEobXlbGQYNfHYVAq95TLqEPf/view?usp=sharing "docker-sql-lab-demo-then-training-databases.mp4") | 使用必需的 `demo` 启动 MySQL 和 PostgreSQL;检查;准备 Sakila、Pagila 和 Chinook;确认重新初始化;再次检查并执行 SQL 查询。 | +| 首次启动前已准备好练习数据库 | [观看](https://disk.yandex.ru/i/nFgJZto8agbdWw "docker-sql-lab-training-databases-first-start.mp4") | [观看](https://drive.google.com/file/d/1nKiGrJ4QINLCQcRk-k6vfTakpWsw-JS7/view?usp=sharing "docker-sql-lab-training-databases-first-start.mp4") | 在首次启动前准备 Sakila、Pagila 和 Chinook;一起初始化必需的 `demo` 和练习数据库;检查访问并执行 SQL 查询。 | + +## 技术栈与固定版本 + +- MySQL 9.7.1 LTS +- PostgreSQL 18.4 +- Adminer 5.4.2 Docker Official Image +- Docker Compose v2 +- GNU Make 与 Bash,用于项目命令和初始化脚本 + +固定的默认值定义在 +[`.docker.env.example`](../../.docker.env.example);`make init` 会据此创建 +本地 `.docker.env`。服务定义在 +[`docker-compose.yml`](../../docker-compose.yml)。 + +
+⚠️ 重要:这是学习环境 + +本项目不是可直接用于 production 的模板。对外使用前,必须另行设计 +credentials、网络暴露、存储、备份与运维方案。 + +
+ +## 主要功能 + +- MySQL 与 PostgreSQL 可单独运行,也可同时运行。 +- 每种数据库都有必需的 `demo`,并包含相同的 seed rows。 +- MySQL 可选 Sakila 和 Chinook;PostgreSQL 可选 Pagila 和 Chinook。 +- Adminer 是供两种数据库共用、独立启用的可选界面。 +- 两种数据库分别使用 bind-mounted data、init 与 sample 目录。 +- 配置与访问检查、可信 SQL 导入和 destructive 操作集中在 + [`Makefile`](../../Makefile)。 + +## 要求 + +1. Docker Engine 或带有 Docker Compose v2 的 Docker Desktop。 +2. GNU Make、Bash 以及脚本使用的基础 Unix CLI 工具。 + +推荐环境:Linux;装有 Docker Desktop 的 macOS;Docker Desktop + +WSL2 的 Windows。所有命令都从仓库根目录执行。项目默认分支为 +`master`。 + +## 快速开始 + +```bash +make init +make up +``` + +`make init` 从受版本控制的 +[`.docker.env.example`](../../.docker.env.example) 创建本地 `.docker.env`, +检查 managed paths 并创建工作目录。首次启动容器时,官方 entrypoints +会初始化两种数据库。即使不安装可选 samples,MySQL 与 PostgreSQL +仍可正常使用,并都包含必需的 `demo` 与 seed rows。 + +`make up` 启动 MySQL、PostgreSQL 和 Adminer;`make up-no-ui` 只启动两种 +数据库。默认可通过 `http://127.0.0.1:8081` 访问 Adminer。 + +启动模式、连接与凭据详见:[入门](zh/getting-started.md)。 + +### 需要现成的练习数据吗? + +Samples 并非必需:`demo` 始终创建;MySQL 支持 Sakila 和 Chinook,PostgreSQL 支持 Pagila 和 Chinook。 + +**首次启动,data 目录为空** + +```bash +make init +make samples-mysql +make samples-postgres +make up +``` + +请在首次初始化前准备 samples;官方 entrypoints 会将它们与 `demo` 一起载入。 + +> **警告:** 重新初始化会删除所选数据库的数据。只有需要保留自己的数据时 +> 才需备份;没有重要改动的一次性学习环境不要求备份。 + +
+📦 环境已启动过:添加或继续使用 samples + +**已在没有 samples 时初始化。** 普通的 `make up` 不会应用新增的 init/sample 文件。若需保留重要数据,请先备份,再选择对应方式: + +- MySQL:`make samples-mysql`,然后 `make reinit-mysql CONFIRM=1`。 +- PostgreSQL:`make samples-postgres`,然后 `make reinit-postgres CONFIRM=1`。 +- 两种数据库:`make samples-mysql`、`make samples-postgres`,然后 `make reinit-all CONFIRM=1`。 + +> **警告:** `reinit-*` 会删除所选数据库的数据,且只有准确提供 `CONFIRM=1` 才会执行。 + +**Samples 已安装。** 直接使用 `make up` 或所选的 `make up-*`:无需重复 download 或 reinit,数据库会保留在 bind-mounted storage 中。 + +
+ +详见:[数据库与 samples](zh/databases.md)。 + +## 启动模式 + +| 命令 | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | 启动 | 启动 | 启动 | +| `make up-no-ui` | 启动 | 启动 | 停止 | +| `make up-mysql` | 启动 | 不启动 | 不启动 | +| `make up-postgres` | 不启动 | 启动 | 不启动 | + +单数据库命令不会停止另一个已运行的数据库;Adminer 单独管理。完整 +targets 列表见 [`Makefile`](../../Makefile)。 + +## 连接与可用数据库 + +在 Compose 网络内,Adminer 使用 `mysql` 和 `postgres`。宿主机客户端 +使用 `127.0.0.1` 以及配置的 `MYSQL_PORT` 或 `POSTGRES_PORT`。日常练习 +使用 `DB_USER` 和 `DB_PASSWORD`。 + +| 数据库 | 始终可用 | 可选 samples 初始化后 | +|---|---|---| +| MySQL | `demo` | `sakila`、`chinook` | +| PostgreSQL | `demo` | `pagila`、`chinook` | + +可选数据库只有在实际初始化后才存在。详见: +[启动与连接](zh/getting-started.md) · +[数据库与 samples](zh/databases.md)。 + +## 凭据概览 + +| 用途 | 用户 | 密码 | +|---|---|---| +| 共用学习用户 | `DB_USER` | `DB_PASSWORD` | +| MySQL 管理员 | `root` | `MYSQL_ROOT_PASSWORD` | +| PostgreSQL superuser | `POSTGRES_SUPERUSER` | `POSTGRES_SUPERUSER_PASSWORD` | + +`POSTGRES_SUPERUSER` 与 `DB_USER` 必须是不同角色。练习时使用学习用户; +对外发布服务前请替换示例密码。 + +## 数据库与关键检查 + +两种 `demo` 都包含等价的 `demo_users` 表和五行数据。以下静态检查 +无需启动数据库: + +```bash +make check-env +make config +make test-storage-paths +``` + +启动后,`make check` 检查 `demo` 与 `DB_USER` 访问; +`make test-sql-imports` 测试公开的可信导入 targets。顺序与限制详见: +[检查与运维](zh/operations.md)。 + +## 安全与生命周期 + +- `BIND_ADDRESS=127.0.0.1` 仅在 loopback 上发布服务。 +- `BIND_ADDRESS=0.0.0.0` 会暴露所有网络接口;请先配置 firewall、 + 强凭据与可信网络。 +- 官方 entrypoints 仅在 data 为空时执行 init。 +- `make mysql-import` 与 `make postgres-import` 只接受可信 SQL。它们不是 + sandbox:可能部分执行,且不保证完整自动 rollback。 + 重要导入前,请检查 SQL 文件并创建合适的 backup。 +- 内置 `make dump` 与 `make restore` 只覆盖 MySQL `demo`;没有内置 + PostgreSQL backup target。 +- 所有 `clean-*` 与 `reinit-*` 都是 destructive 操作,并且必须准确提供 + `CONFIRM=1`。 + +安全操作顺序:[检查与运维](zh/operations.md)。出现问题时先收集诊断: +[诊断与故障排除](zh/troubleshooting.md)。 + +## 练习数据许可证 + +可选数据集保留各 upstream 项目的许可证与 notices。来源、固定 +revision、完整性信息与许可证文本见 +[`THIRD_PARTY_NOTICES.md`](../../THIRD_PARTY_NOTICES.md)。 + +

+ + YA + +
+ yaleksandr89.github.io +

diff --git a/docs/langs/de/databases.md b/docs/langs/de/databases.md new file mode 100644 index 0000000..9f57b60 --- /dev/null +++ b/docs/langs/de/databases.md @@ -0,0 +1,125 @@ +# Datenbanken und Samples + +[← Zurück zur README](../README_de.md) + +## Sprache + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/databases.md) | [English](../en/databases.md) | [Español](../es/databases.md) | [中文](../zh/databases.md) | [Français](../fr/databases.md) | **Ausgewählt** | + +## Abschnitt + +| Erste Schritte | Datenbanken und Samples | Prüfungen und Betrieb | Diagnose und Fehlerbehebung | +| --- | --- | --- | --- | +| [Erste Schritte](getting-started.md) | **Ausgewählt** | [Prüfungen und Betrieb](operations.md) | [Diagnose und Fehlerbehebung](troubleshooting.md) | + + +## Obligatorische `demo`-Datenbanken + +Beide DBMS initialisieren `demo`: + +- MySQL: `demo.demo_users` +- PostgreSQL: `demo.public.demo_users` + +Die Tabellen besitzen entsprechende Felder `id`, `name`, `email` und +`created_at` sowie Alice, Bob, Carol, Dave und Eve. Zusätzliche Zeilen sind +zulässig. `make check-env` verlangt `MYSQL_DATABASE=demo` und +`POSTGRES_DATABASE=demo`. + + +## Optionale Samples + +| DBMS | Optionale Datenbanken | Vorbereitung | +|---|---|---| +| MySQL | `chinook`, `sakila` | `make samples-mysql` | +| PostgreSQL | `pagila`, `chinook` | `make samples-postgres` | + + +## Samples vorbereiten + +Die Vorbereitung benötigt `curl` und `git`; MySQL-Samples erfordern zusätzlich `unzip` und `sha256sum`. + +Die Vorbereitung lädt festgelegte upstream-Dateien herunter und prüft sie, +startet aber keine Container und importiert nichts in bereits initialisierte +Datenbanken. Temporäre Downloads bleiben lokal, werden nicht committed und +liegen unter `MYSQL_SAMPLES_DIR` beziehungsweise `POSTGRES_SAMPLES_DIR`. +Herkunft, Integritätswerte und Lizenzen stehen in +[`THIRD_PARTY_NOTICES.md`](../../../THIRD_PARTY_NOTICES.md). + +Wann die Vorbereitung erfolgen muss und wie ein vorhandenes DBMS neu +initialisiert wird, steht unter +[Initialisierung und Lebenszyklus](#section-initialization). + +Ein vollständig fehlendes Sample wird übersprungen und verhindert `demo` +nicht. Unvollständige Samples oder unerwartete Datenbanken werden ohne +automatische Reparatur oder Löschung abgelehnt. + + +## Speicherstruktur + +```text +data/ +├── mysql/ +└── postgres/ + +initdb/ +├── mysql/ +└── postgres/ +``` + +| DBMS | Data | Init | Optionale Samples | +|---|---|---|---| +| MySQL | `MYSQL_DATA_DIR` (`./data/mysql`) | `MYSQL_INITDB_DIR` (`./initdb/mysql`) | `MYSQL_SAMPLES_DIR` (`./samples/mysql`) | +| PostgreSQL | `POSTGRES_DATA_DIR` (`./data/postgres`) | `POSTGRES_INITDB_DIR` (`./initdb/postgres`) | `POSTGRES_SAMPLES_DIR` (`./samples/postgres`) | + +Data- und Sample-Pfade sind über `.docker.env` konfigurierbar und werden als +managed paths validiert. Die Regeln für init-Verzeichnisse stehen unter +[Initialisierung und Lebenszyklus](#section-initialization). Bearbeiten Sie +Dateien in `data/` nicht manuell; sie können numerischen Container-UID/GID +gehören. + + +## Initialisierung und Lebenszyklus + +> **Wichtig:** Offizielle MySQL- und PostgreSQL-Entrypoints führen init-Dateien +> nur bei leerem data directory aus. Nach der Initialisierung hinzugefügte +> Dateien ändern keine bestehende Datenbank. `make down` erhält die Daten; eine +> bestätigte Neuinitialisierung löscht dagegen die aktuellen Daten des gewählten +> DBMS und erstellt die Datenbanken aus den aktuellen Init-Skripten neu. Ein +> Backup ist nur nötig, wenn eigene Daten erhalten bleiben sollen; ein einmaliges +> Lab ohne wertvolle Änderungen braucht keines. + +Bereiten Sie Samples für die erste Initialisierung vor dem ersten Start vor: + +```bash +make samples-mysql +make up-mysql + +make samples-postgres +make up-postgres +``` + +Sichern Sie bei einem initialisierten DBMS eigene Daten bei Bedarf und verwenden +Sie dann nur die passende bestätigte Neuinitialisierung: + +```bash +make samples-mysql +make reinit-mysql CONFIRM=1 + +make samples-postgres +make reinit-postgres CONFIRM=1 +``` + + +## Lernzugriff und Ownership + +MySQL erstellt `DB_USER` und gewährt Zugriff auf alle beim init +gefundenen Nicht-Systemdatenbanken. PostgreSQL erstellt einen getrennten +`DB_USER` ohne superuser/createdb/createrole und macht ihn zum Eigentümer von +`demo`, dem `public`-Schema und geladenen Sample-Objekten. Administrative +credentials bleiben getrennt: `MYSQL_ROOT_PASSWORD`, `POSTGRES_SUPERUSER` +und `POSTGRES_SUPERUSER_PASSWORD`. Bearbeiten Sie container-owned Dateien in +`data/` nicht manuell. + +[Zurück zur README](../README_de.md) diff --git a/docs/langs/de/getting-started.md b/docs/langs/de/getting-started.md new file mode 100644 index 0000000..1adbbf0 --- /dev/null +++ b/docs/langs/de/getting-started.md @@ -0,0 +1,167 @@ +# Erste Schritte + +[← Zurück zur README](../README_de.md) + +## Sprache + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/getting-started.md) | [English](../en/getting-started.md) | [Español](../es/getting-started.md) | [中文](../zh/getting-started.md) | [Français](../fr/getting-started.md) | **Ausgewählt** | + +## Abschnitt + +| Erste Schritte | Datenbanken und Samples | Prüfungen und Betrieb | Diagnose und Fehlerbehebung | +| --- | --- | --- | --- | +| **Ausgewählt** | [Datenbanken und Samples](databases.md) | [Prüfungen und Betrieb](operations.md) | [Diagnose und Fehlerbehebung](troubleshooting.md) | + + +## Voraussetzungen + +- Docker Engine oder Docker Desktop mit Docker Compose v2. +- GNU Make, Bash und grundlegende Unix-Kommandozeilenwerkzeuge. +- Empfohlene Umgebungen: Linux; macOS mit Docker Desktop; oder Windows mit + Docker Desktop und WSL2. + +Führen Sie Befehle im Repository-Stamm aus. Der Standardbranch des Projekts ist +`master`. + + +## Schnellstart + +`make init` erstellt eine lokale `.docker.env` aus +[`.docker.env.example`](../../../.docker.env.example), prüft die verwalteten +Speicherpfade und legt die Arbeitsverzeichnisse an. Starten Sie danach das +vollständige Lab: + +```bash +make init +make up +``` + +`make up` startet MySQL, PostgreSQL und Adminer. Mit der Standardkonfiguration +ist Adminer unter `http://127.0.0.1:8081` erreichbar. + +Mit `make up-no-ui` starten Sie beide DBMS ohne Adminer. Die obligatorische +`demo`-Datenbank wird bei der ersten Initialisierung immer erstellt; +Beispieldatensätze sind optional. Um sie bei der ersten Initialisierung zu +laden, bereiten Sie sie vor dem ersten `make up` vor. Bei bereits +initialisierten Datenverzeichnissen erstellen Sie ein Backup vor einer +bestätigten Neuinitialisierung nur, wenn eigene Daten erhalten bleiben sollen. Das genaue Verfahren steht +unter [Initialisierung und Lebenszyklus](databases.md#section-initialization). + +```bash +make status +make logs +make down +``` + +`make down` entfernt Container und Netzwerk, behält aber bind-mounted Daten. + + +## Startmodi + +| Befehl | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | Startet | Startet | Startet | +| `make up-no-ui` | Startet | Startet | Stoppt | +| `make up-mysql` | Startet | Startet nicht | Startet nicht | +| `make up-postgres` | Startet nicht | Startet | Startet nicht | + +Einzel-DBMS-Befehle stoppen das andere laufende DBMS nicht; Adminer wird separat verwaltet. + +
+📋 Vollständige Tabelle der Startmodi + +| Befehl | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | Startet | Startet | Startet | +| `make up-no-ui` | Startet oder lässt laufen | Startet oder lässt laufen | Stoppt, falls aktiv | +| `make up-mysql` | Startet | Startet nicht automatisch | Startet nicht automatisch | +| `make up-mysql-ui` | Startet | Startet nicht automatisch | Startet | +| `make up-postgres` | Startet nicht automatisch | Startet | Startet nicht automatisch | +| `make up-postgres-ui` | Startet nicht automatisch | Startet | Startet | +| `make up-ui` | Ändert nichts | Ändert nichts | Startet | +| `make down-ui` | Ändert nichts | Ändert nichts | Stoppt | + +Einzel-DBMS-Befehle stoppen ein bereits laufendes anderes DBMS nicht. Adminer +lässt sich separat starten und stoppen und ist nicht nur an MySQL gebunden. + +
+ + +## Verbindungen + +### Adminer + +Im Compose-Netzwerk bietet Adminer zwei vordefinierte Server an: + +```text +MySQL (mysql) +PostgreSQL (postgres) +``` + +Wählen Sie einen Server und melden Sie sich mit `DB_USER`, `DB_PASSWORD` und +einer Datenbank wie `demo` an. `mysql` und `postgres` sind interne +Compose-Dienstnamen, keine Hostnamen für Desktop-Clients. + +### Clients auf dem Host + +| DBMS | Standardhost | Portvariable | Benutzer | Standarddatenbank | +|---|---|---|---|---| +| MySQL | `127.0.0.1` | `MYSQL_PORT` | `DB_USER` | `demo` | +| PostgreSQL | `127.0.0.1` | `POSTGRES_PORT` | `DB_USER` | `demo` | + +DataGrip, DBeaver, PhpStorm und Host-CLI-Werkzeuge nutzen veröffentlichte +Adresse und Port. Nach einer Änderung von `BIND_ADDRESS` verwenden Sie bei +Bedarf die erreichbare Adresse dieser Schnittstelle. + +### CLI in den Containern + +Passwörter werden über die Containerumgebung übergeben und nicht in die +Shell-History geschrieben: + +```bash +make mysql # MySQL-Administrator, Datenbank demo +make mysql-user # DB_USER, Datenbank demo +make postgres # PostgreSQL-Superuser, Datenbank demo +make postgres-user # DB_USER, Datenbank demo +``` + + +## Zugangsdaten + +`.docker.env` wird aus [`.docker.env.example`](../../../.docker.env.example) erstellt und von Git ignoriert. +Bewahren Sie Passwörter dort auf; codieren Sie sie nicht in versioniertem +Compose, SQL oder Client-Konfigurationen. + +| Zweck | Benutzer | Passwort | +|---|---|---| +| Gemeinsamer Lernbenutzer | `DB_USER` | `DB_PASSWORD` | +| MySQL-Administrator | `root` | `MYSQL_ROOT_PASSWORD` | +| PostgreSQL-Administrator/Superuser | `POSTGRES_SUPERUSER` | `POSTGRES_SUPERUSER_PASSWORD` | + +`POSTGRES_SUPERUSER` und `DB_USER` müssen verschiedene Rollen sein. Verwenden +Sie den Lernbenutzer für normale Übungen. Ersetzen Sie Beispielpasswörter, +bevor Dienste geteilt oder außerhalb des lokalen Rechners veröffentlicht werden. + + +## Ports und `BIND_ADDRESS` + +| Dienst | Portvariable | Beispielwert | +|---|---|---| +| MySQL | `MYSQL_PORT` | `3306` | +| PostgreSQL | `POSTGRES_PORT` | `5432` | +| Adminer | `ADMINER_PORT` | `8081` | + +Standardmäßig werden alle drei Dienste nur an loopback gebunden: + +```env +BIND_ADDRESS=127.0.0.1 +``` + +`127.0.0.1` ist der lokale Standard. `BIND_ADDRESS=0.0.0.0` veröffentlicht die +Ports auf allen Netzwerkschnittstellen. Für LAN oder VPN ist die Adresse einer +bestimmten Schnittstelle vorzuziehen. Ändern Sie die Bindung bewusst und +beachten Sie Firewall, Passwortstärke und Vertrauenswürdigkeit des Netzes. + +[Zurück zur README](../README_de.md) diff --git a/docs/langs/de/operations.md b/docs/langs/de/operations.md new file mode 100644 index 0000000..6591a69 --- /dev/null +++ b/docs/langs/de/operations.md @@ -0,0 +1,163 @@ +# Prüfungen und Betrieb + +[← Zurück zur README](../README_de.md) + +## Sprache + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/operations.md) | [English](../en/operations.md) | [Español](../es/operations.md) | [中文](../zh/operations.md) | [Français](../fr/operations.md) | **Ausgewählt** | + +## Abschnitt + +| Erste Schritte | Datenbanken und Samples | Prüfungen und Betrieb | Diagnose und Fehlerbehebung | +| --- | --- | --- | --- | +| [Erste Schritte](getting-started.md) | [Datenbanken und Samples](databases.md) | **Ausgewählt** | [Diagnose und Fehlerbehebung](troubleshooting.md) | + + +## Öffentliche Make targets + +Öffentliche Targets und ihre Implementierung stehen im [`Makefile`](../../../Makefile). + +Wichtige Targets sind `make init`, `make up`, `make down`, `make check`, +`make test-storage-paths`, `make test-sql-imports`, `make mysql-import` +und `make postgres-import`. Vertrauenswürdiges SQL ist keine isolierte Umgebung (`sandbox`), kann +partiell ausgeführt werden und erhält keine Garantie für automatic rollback; +erstellen Sie vor wichtigen Imports ein Backup. Integrierte backup targets +decken nur MySQL `demo` ab, nicht PostgreSQL. `clean-*` und `reinit-*` +sind destruktiv und erfordern exakt `CONFIRM=1`. + +
+📋 Vollständige Referenz der öffentlichen Make targets + +`make help` zeigt die kompakte Liste. + +| Befehl | Zweck | +|---|---| +| `make init` | `.docker.env` erstellen, managed paths prüfen, Verzeichnisse anlegen | +| `make check-env` | Env-Werte, Rollen, Datenbanknamen und Pfade prüfen | +| `make pull` | Die drei festgelegten Images laden | +| `make config` | Erweiterte Compose-Konfiguration validieren | +| `make up`, `make up-no-ui` | Beide DBMS mit oder ohne Adminer starten | +| `make up-mysql`, `make up-mysql-ui` | MySQL, optional mit Adminer, starten | +| `make up-postgres`, `make up-postgres-ui` | PostgreSQL, optional mit Adminer, starten | +| `make up-ui`, `make down-ui` | Nur Adminer starten oder stoppen | +| `make down` | Lab stoppen, ohne bind-mounted Daten zu löschen | +| `make status`, `make logs` | Status anzeigen oder alle Logs verfolgen | +| `make log SERVICE=postgres` | Einen Dienst verfolgen; auch `make log postgres` | +| `make in SERVICE=postgres` | Dienst-Shell öffnen; auch `make in postgres` | +| `make mysql`, `make mysql-user` | MySQL als Admin oder `DB_USER` öffnen | +| `make postgres`, `make postgres-user` | PostgreSQL als Superuser oder `DB_USER` öffnen | +| `make samples-mysql`, `make samples-postgres` | Geprüfte Samples vorbereiten | +| `make check-mysql-access`, `make check-postgres-access` | Ein laufendes DBMS prüfen | +| `make check` | Compose und `DB_USER`-Zugriff auf beide DBMS prüfen | +| `make test-storage-paths` | Managed paths ohne Docker runtime testen | +| `make test-sql-imports` | Smoke-Test beider öffentlicher SQL-Imports | +| `make mysql-import FILE=... DATABASE=...` | Plain SQL als `DB_USER` in MySQL importieren | +| `make postgres-import FILE=... DATABASE=...` | Plain SQL als `DB_USER` in PostgreSQL importieren | +| `make dump`, `make restore` | MySQL-`demo` sichern oder wiederherstellen | +| `make clean-{mysql,postgres,all} CONFIRM=1` | Ausgewählte data directories löschen | +| `make reinit-{mysql,postgres,all} CONFIRM=1` | Datenbanken löschen, neu erstellen und prüfen | + +
+ + +## Prüfungen + +### Statische und lokale Prüfungen + +```bash +make check-env +make config +make test-storage-paths +``` + +`make check-env` erstellt bei Bedarf `.docker.env` und validiert Werte und +Pfade. `make config` prüft das erweiterte Compose-Modell. +`make test-storage-paths` benötigt keine Docker runtime und testet Pfade +außerhalb des Projekts, symlink-Komponenten, überlappende oder verschachtelte +Pfade sowie reserved directories. + +### Runtime-Prüfungen + +```bash +make up-no-ui +make check +make test-sql-imports +make down +``` + +`make check` prüft `demo` und den tatsächlichen `DB_USER`-Zugriff in beiden +DBMS sowie installierte Samples. `make test-sql-imports` benötigt beide +laufenden DBMS, ruft `mysql-import` und `postgres-import` auf, erstellt +eindeutig benannte temporäre Tabellen in `demo`, prüft marker rows als +`DB_USER` und löscht nur diese Tabellen. Dies ist ein Smoke-Test des trusted +import workflow, keine isolierte Umgebung (`sandbox`) und kein Sicherheitsnachweis für fremdes SQL. + + +## Sicherheit der storage paths + +`make check-env` führt +[`scripts/validate-storage-paths.sh`](../../../scripts/validate-storage-paths.sh) +aus. Data +paths müssen strikt unter `data/`, sample paths unter `samples/` liegen; +Symlinks sowie gleiche, verschachtelte, überlappende oder reservierte Pfade +werden abgelehnt. `make test-storage-paths` testet dies ohne Docker runtime. + + +## Import vertrauenswürdiger SQL-Dateien + +```bash +make mysql-import FILE=path/to/file.sql DATABASE=demo +make postgres-import FILE=path/to/file.sql DATABASE=demo +``` + +Für beide targets gilt: + +- `FILE` und `DATABASE` sind erforderlich. +- Die lokale plain-SQL-Datei muss existieren, lesbar und nicht leer sein. +- Die Datenbank muss existieren; Systemdatenbanken sind verboten. +- Der Import läuft als `DB_USER`, erstellt keine Datenbank und vergibt keine grants. +- `DATABASE` wählt die erste Verbindung, erzeugt aber keine isolierte Umgebung (`sandbox`). +- Qualified names, Client-/Session-Befehle und tatsächliche grants können + andere erreichbare Objekte betreffen. +- Partielle Ausführung ist möglich; automatischer Rollback wird nicht zugesagt. +- Erstellen Sie vor wichtigen Imports ein Backup. +- gzip, Archive und PostgreSQL-custom-format backups werden nicht verarbeitet. + + +## Backup + +Die eingebauten Targets decken nur die konfigurierte MySQL-Datenbank `demo` ab: + +```bash +make dump +make restore +``` + +`make dump` schreibt `backup/demo.sql`; `make restore` liest die Datei und +wendet die MySQL-Lern-grants erneut an. Verwenden Sie für PostgreSQL ein eigenes +Backup-Verfahren. + + +## Bereinigung und Neuinitialisierung + +> **Warnung:** Alle `clean-*`- und `reinit-*`-Targets sind destruktiv und +> verlangen die exakte Bestätigung `CONFIRM=1`. + +```bash +make clean-mysql CONFIRM=1 +make clean-postgres CONFIRM=1 +make clean-all CONFIRM=1 + +make reinit-mysql CONFIRM=1 +make reinit-postgres CONFIRM=1 +make reinit-all CONFIRM=1 +``` + +Einzelne Targets löschen nur das gewählte DBMS-data directory; `all` löscht +beide. Konfiguration, init, Samples und Backups bleiben erhalten. Reinit +startet und prüft anschließend die gewählten DBMS; `reinit-all` startet MySQL, +PostgreSQL und Adminer und führt anschließend die gemeinsame Zugriffsprüfung aus. + +[Zurück zur README](../README_de.md) diff --git a/docs/langs/de/troubleshooting.md b/docs/langs/de/troubleshooting.md new file mode 100644 index 0000000..cf5a78d --- /dev/null +++ b/docs/langs/de/troubleshooting.md @@ -0,0 +1,63 @@ +# Diagnose und Fehlerbehebung + +[← Zurück zur README](../README_de.md) + +## Sprache + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/troubleshooting.md) | [English](../en/troubleshooting.md) | [Español](../es/troubleshooting.md) | [中文](../zh/troubleshooting.md) | [Français](../fr/troubleshooting.md) | **Ausgewählt** | + +## Abschnitt + +| Erste Schritte | Datenbanken und Samples | Prüfungen und Betrieb | Diagnose und Fehlerbehebung | +| --- | --- | --- | --- | +| [Erste Schritte](getting-started.md) | [Datenbanken und Samples](databases.md) | [Prüfungen und Betrieb](operations.md) | **Ausgewählt** | + +Sammeln Sie zuerst Diagnosedaten und korrigieren Sie dann die konkrete +Ursache. Falls eine Neuinitialisierung nötig bleibt, sichern Sie eigene Daten +nur, wenn sie erhalten bleiben sollen, und verwenden `reinit-... CONFIRM=1` nur als bewussten letzten Schritt. + +Verbindliche Details zu Lebenszyklus und Betrieb: [Datenbanken](databases.md#section-initialization) · [Betrieb](operations.md#section-clean-reinitialize). + + +## Konfiguration oder Pfadvalidierung schlägt fehl + +Führen Sie `make check-env` aus. Data paths müssen strikt unter `data/` und +Samples unter `samples/` liegen; symlinks, Überschneidungen und reservierte +Verzeichnisse sind unzulässig. Korrigieren Sie `.docker.env` und führen Sie +`make config` aus. + + +## Ein Dienst wird nicht bereit + +```bash +make status +make log SERVICE=mysql +make log SERVICE=postgres +``` + +Prüfen Sie Docker, Port, `.docker.env` und Logs, bevor Sie Daten ändern. + + +## Init-Änderungen oder Samples erscheinen nicht + +Bei bereits initialisierten Daten ist das erwartet. Prüfen Sie Pfade und +Vorbereitung; wenn wichtige Daten erhalten bleiben sollen, sichern Sie sie und +verwenden `reinit-... CONFIRM=1` nur als bewussten letzten Schritt. + + +## Sample ist unvollständig oder hat einen unerwarteten Besitzer + +Der Loader überschreibt oder repariert unerwartete Datenbanken nicht. Führen +Sie `make samples-mysql` oder `make samples-postgres` erneut aus und prüfen Sie +den Fehler; sichern Sie Daten vor einer Neuinitialisierung. + + +## Ein Client kann keine Verbindung herstellen + +Host-Clients verwenden veröffentlichte Adresse und `MYSQL_PORT` oder +`POSTGRES_PORT`; Adminer verwendet `mysql` oder `postgres` im Compose-Netz. +Prüfen Sie `BIND_ADDRESS`, Firewall, Datenbankauswahl und `DB_USER`-Zugangsdaten. + +[Zurück zur README](../README_de.md) diff --git a/docs/langs/en/databases.md b/docs/langs/en/databases.md new file mode 100644 index 0000000..ac59ecd --- /dev/null +++ b/docs/langs/en/databases.md @@ -0,0 +1,133 @@ +# Databases and samples + +[← Back to README](../README_en.md) + +## Language + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/databases.md) | **Selected** | [Español](../es/databases.md) | [中文](../zh/databases.md) | [Français](../fr/databases.md) | [Deutsch](../de/databases.md) | + +## Section + +| Getting started | Databases and samples | Validation and operations | Troubleshooting | +| --- | --- | --- | --- | +| [Getting started](getting-started.md) | **Selected** | [Validation and operations](operations.md) | [Troubleshooting](troubleshooting.md) | + + +## Required `demo` databases + +Both DBMSs initialize a required database named `demo`: + +- MySQL: `demo.demo_users` +- PostgreSQL: `demo.public.demo_users` + +The tables have equivalent `id`, `name`, `email`, and `created_at` fields and +contain the same five required example users: Alice, Bob, Carol, Dave, and Eve. +The access checks allow additional user-created rows. + +The default database names are enforced by `make check-env` through +`MYSQL_DATABASE=demo` and `POSTGRES_DATABASE=demo`. + + +## Optional samples + +| DBMS | Optional databases | Preparation command | +|---|---|---| +| MySQL | `chinook`, `sakila` | `make samples-mysql` | +| PostgreSQL | `pagila`, `chinook` | `make samples-postgres` | + + +## Sample preparation + +Preparation requires `curl` and `git`; MySQL samples additionally require `unzip` and `sha256sum`. + +The preparation commands download and verify pinned upstream files but do not +start containers or import into an initialized database. Downloads are local, +are excluded from Git, and are stored under `MYSQL_SAMPLES_DIR` or +`POSTGRES_SAMPLES_DIR`. Their provenance, integrity pins, and license terms are +documented in +[`THIRD_PARTY_NOTICES.md`](../../../THIRD_PARTY_NOTICES.md). + +See [Initialization lifecycle](#section-initialization) for when preparation +must occur and how an initialized DBMS can be reinitialized. + +A completely absent optional sample is skipped and does not prevent the +required `demo` database from being created. A partial sample set or an +unexpected existing sample database is rejected instead of being repaired or +deleted automatically. + + +## Storage layout + +The default bind-mounted storage is separated by DBMS: + +```text +data/ +├── mysql/ +└── postgres/ + +initdb/ +├── mysql/ +└── postgres/ +``` + +The related `.docker.env` settings are separate as well: + +| DBMS | Data | Init | Optional samples | +|---|---|---|---| +| MySQL | `MYSQL_DATA_DIR` (`./data/mysql`) | `MYSQL_INITDB_DIR` (`./initdb/mysql`) | `MYSQL_SAMPLES_DIR` (`./samples/mysql`) | +| PostgreSQL | `POSTGRES_DATA_DIR` (`./data/postgres`) | `POSTGRES_INITDB_DIR` (`./initdb/postgres`) | `POSTGRES_SAMPLES_DIR` (`./samples/postgres`) | + +Data and sample locations can be changed through `.docker.env`, subject to +managed storage-path validation. See +[Initialization lifecycle](#section-initialization) for the rules governing +the init directories. + +Do not edit database files inside `data/` manually. Container-owned files may +use numeric UID/GID values that differ from the host user. + + +## Initialization lifecycle + +> **Important:** Official MySQL and PostgreSQL entrypoints run init files only +> for an empty data directory. Adding files after initialization does not +> change an existing database. `make down` preserves data, while confirmed +> reinitialization deletes the selected DBMS's current data and recreates its +> databases from the current init scripts. Back up custom data only when you +> need to preserve it; a one-off lab with no valuable changes needs no backup. + +For first initialization with sample datasets, prepare them before the first +start: + +```bash +make samples-mysql +make up-mysql + +make samples-postgres +make up-postgres +``` + +For an initialized DBMS, preserve custom data if needed and then use only its +matching confirmed reinitialization: + +```bash +make samples-mysql +make reinit-mysql CONFIRM=1 + +make samples-postgres +make reinit-postgres CONFIRM=1 +``` + + +## Training access and ownership + +MySQL creates `DB_USER` and grants it access to every non-system +database found during init. PostgreSQL creates a separate, non-superuser +`DB_USER` without createdb/createrole privileges and makes it owner of +`demo`, the `public` schema, and loaded sample objects. Administrative +credentials remain separate: `MYSQL_ROOT_PASSWORD`, `POSTGRES_SUPERUSER`, +and `POSTGRES_SUPERUSER_PASSWORD`. Do not edit container-owned files in +`data/` manually. + +[Back to README](../README_en.md) diff --git a/docs/langs/en/getting-started.md b/docs/langs/en/getting-started.md new file mode 100644 index 0000000..9e4d6ae --- /dev/null +++ b/docs/langs/en/getting-started.md @@ -0,0 +1,176 @@ +# Getting started + +[← Back to README](../README_en.md) + +## Language + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/getting-started.md) | **Selected** | [Español](../es/getting-started.md) | [中文](../zh/getting-started.md) | [Français](../fr/getting-started.md) | [Deutsch](../de/getting-started.md) | + +## Section + +| Getting started | Databases and samples | Validation and operations | Troubleshooting | +| --- | --- | --- | --- | +| **Selected** | [Databases and samples](databases.md) | [Validation and operations](operations.md) | [Troubleshooting](troubleshooting.md) | + + +## Requirements + +- Docker Engine or Docker Desktop with Docker Compose v2. +- GNU Make, Bash, and basic Unix CLI utilities. +- Recommended environments: Linux; macOS with Docker Desktop; or Windows with + Docker Desktop and WSL2. + +Run project commands from the repository root. The default project branch is +`master`. + + +## Quick start + +`make init` creates a local `.docker.env` from +[`.docker.env.example`](../../../.docker.env.example), validates the managed +storage paths, and creates the working directories. Then start the full lab: + +```bash +make init +make up +``` + +`make up` starts MySQL, PostgreSQL, and Adminer. With the default configuration, +open Adminer at `http://127.0.0.1:8081`. + +Use `make up-no-ui` to start both DBMSs without Adminer. The required `demo` +database is always created during first initialization; sample datasets are +optional. To include them in the first initialization, prepare them before the +first `make up`. For initialized data directories, create a backup before +confirmed reinitialization only when you need to preserve custom data. See +[Initialization lifecycle](databases.md#section-initialization) for the exact +procedure. + +Useful follow-up commands: + +```bash +make status +make logs +make down +``` + +`make down` removes the containers and network but preserves the bind-mounted +database data. + + +## Startup modes + +| Command | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | Starts | Starts | Starts | +| `make up-no-ui` | Starts | Starts | Stops | +| `make up-mysql` | Starts | Does not start | Does not start | +| `make up-postgres` | Does not start | Starts | Does not start | + +Single-DBMS commands do not stop the other running database; Adminer is managed separately. + +
+📋 Full startup-mode table + +| Command | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | Starts | Starts | Starts | +| `make up-no-ui` | Starts or keeps running | Starts or keeps running | Stops if running | +| `make up-mysql` | Starts | Does not start automatically | Does not start automatically | +| `make up-mysql-ui` | Starts | Does not start automatically | Starts | +| `make up-postgres` | Does not start automatically | Starts | Does not start automatically | +| `make up-postgres-ui` | Does not start automatically | Starts | Starts | +| `make up-ui` | Does not change | Does not change | Starts | +| `make down-ui` | Does not change | Does not change | Stops | + +The single-service commands do not stop another database that is already +running. Adminer can be started and stopped separately and is not tied to +MySQL alone. + +
+ + +## Connections + +### Adminer + +Adminer provides two predefined server choices inside the Compose network: + +```text +MySQL (mysql) +PostgreSQL (postgres) +``` + +Select a server, then sign in with `DB_USER`, `DB_PASSWORD`, and a database +name such as `demo`. The service names `mysql` and `postgres` work inside the +Compose network; they are not host names for desktop clients. + +### Host clients + +DataGrip, DBeaver, PhpStorm, and host CLI tools connect through the published +address and port: + +| DBMS | Host with default settings | Port variable | User | Default database | +|---|---|---|---|---| +| MySQL | `127.0.0.1` | `MYSQL_PORT` | `DB_USER` | `demo` | +| PostgreSQL | `127.0.0.1` | `POSTGRES_PORT` | `DB_USER` | `demo` | + +If you change `BIND_ADDRESS`, use that reachable interface address instead of +`127.0.0.1` where appropriate. + +### Container CLI + +The Make targets pass passwords through the container environment instead of +placing them in shell history: + +```bash +make mysql # MySQL administrator, demo database +make mysql-user # DB_USER, demo database +make postgres # PostgreSQL superuser, demo database +make postgres-user # DB_USER, demo database +``` + + +## Credentials + +Copying [`.docker.env.example`](../../../.docker.env.example) creates `.docker.env`; the latter is ignored by +Git. Keep passwords there and do not hardcode them in Compose, SQL, or client +configuration committed to the repository. + +| Purpose | User setting | Password setting | +|---|---|---| +| Shared training user for both DBMSs | `DB_USER` | `DB_PASSWORD` | +| MySQL administrator | `root` | `MYSQL_ROOT_PASSWORD` | +| PostgreSQL administrator/superuser | `POSTGRES_SUPERUSER` | `POSTGRES_SUPERUSER_PASSWORD` | + +`POSTGRES_SUPERUSER` and `DB_USER` must be different roles. Use the shared +training user for normal exercises; do not use root or superuser credentials +for routine work. Replace the example passwords before sharing access or +publishing any service beyond the local machine. + + +## Ports and `BIND_ADDRESS` + +The host-side ports are configured in `.docker.env`: + +| Service | Port variable | Example default | +|---|---|---| +| MySQL | `MYSQL_PORT` | `3306` | +| PostgreSQL | `POSTGRES_PORT` | `5432` | +| Adminer | `ADMINER_PORT` | `8081` | + +All three services publish only on loopback by default: + +```env +BIND_ADDRESS=127.0.0.1 +``` + +This is the safe default for a local lab. Setting `BIND_ADDRESS=0.0.0.0` +publishes the configured ports on every network interface. For VPN or LAN +access, prefer the address of the specific interface. Change the binding only +deliberately, after considering firewall rules, password strength, and trust +in every connected network. + +[Back to README](../README_en.md) diff --git a/docs/langs/en/operations.md b/docs/langs/en/operations.md new file mode 100644 index 0000000..a23fa09 --- /dev/null +++ b/docs/langs/en/operations.md @@ -0,0 +1,184 @@ +# Validation and operations + +[← Back to README](../README_en.md) + +## Language + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/operations.md) | **Selected** | [Español](../es/operations.md) | [中文](../zh/operations.md) | [Français](../fr/operations.md) | [Deutsch](../de/operations.md) | + +## Section + +| Getting started | Databases and samples | Validation and operations | Troubleshooting | +| --- | --- | --- | --- | +| [Getting started](getting-started.md) | [Databases and samples](databases.md) | **Selected** | [Troubleshooting](troubleshooting.md) | + + +## Make targets + +Public targets and their implementation are in the [`Makefile`](../../../Makefile). + +Key targets include `make init`, `make up`, `make down`, `make check`, +`make test-storage-paths`, `make test-sql-imports`, `make mysql-import`, +and `make postgres-import`. Trusted SQL is not a sandbox, may execute +partially, and has no guaranteed automatic rollback; create a backup before an +important import. Built-in backup targets cover MySQL `demo` only, not +PostgreSQL. `clean-*` and `reinit-*` are destructive and require exact +`CONFIRM=1`. + +
+📋 Complete public Make target reference + +Run `make help` for the concise command list. + +| Command | Purpose | +|---|---| +| `make init` | Create `.docker.env`, validate managed paths, and create required working directories | +| `make check-env` | Check required environment values, role separation, database names, and managed paths | +| `make pull` | Pull the three pinned container images | +| `make config` | Validate the expanded Compose configuration | +| `make up`, `make up-no-ui` | Start both DBMSs with or without Adminer | +| `make up-mysql`, `make up-mysql-ui` | Start MySQL, optionally with Adminer | +| `make up-postgres`, `make up-postgres-ui` | Start PostgreSQL, optionally with Adminer | +| `make up-ui`, `make down-ui` | Start or stop only Adminer | +| `make down` | Stop the lab without deleting bind-mounted data | +| `make status` | Show service status | +| `make logs` | Follow logs for all services | +| `make log SERVICE=postgres` | Follow one service log; `make log postgres` is also supported | +| `make in SERVICE=postgres` | Open a service shell; `make in postgres` is also supported | +| `make mysql`, `make mysql-user` | Open MySQL as administrator or `DB_USER` | +| `make postgres`, `make postgres-user` | Open PostgreSQL as superuser or `DB_USER` | +| `make samples-mysql`, `make samples-postgres` | Prepare verified optional samples | +| `make check-mysql-access`, `make check-postgres-access` | Verify training-user access to one running DBMS | +| `make check` | Validate Compose and check `DB_USER` access to both running DBMSs | +| `make test-storage-paths` | Test managed storage-path protection without Docker runtime | +| `make test-sql-imports` | Smoke-test both public trusted SQL import targets | +| `make mysql-import FILE=... DATABASE=...` | Import trusted plain SQL into an existing MySQL database as `DB_USER` | +| `make postgres-import FILE=... DATABASE=...` | Import trusted plain SQL into an existing PostgreSQL database as `DB_USER` | +| `make dump`, `make restore` | Dump or restore the configured MySQL `demo` database | +| `make clean-{mysql,postgres,all} CONFIRM=1` | Delete selected managed data directories | +| `make reinit-{mysql,postgres,all} CONFIRM=1` | Delete, recreate, and check selected databases | + +
+ + +## Validation + +### Static and local checks + +```bash +make check-env +make config +make test-storage-paths +``` + +`make check-env` creates `.docker.env` from the example if it is absent, then +validates required settings and managed paths. `make config` validates the +expanded Compose model. + +`make test-storage-paths` does not require the Docker runtime. It exercises the +guards for paths outside the project, symbolic-link components, overlapping or +nested managed paths, and reserved directories. The same validator protects +the configured MySQL/PostgreSQL data and sample locations during normal setup. + +### Runtime checks + +Start both databases without Adminer, check training access, exercise imports, +and stop the services: + +```bash +make up-no-ui +make check +make test-sql-imports +make down +``` + +`make check` verifies the required `demo` data and actual `DB_USER` access in +both DBMSs. It also checks supported optional samples when they are installed. + +`make test-sql-imports` requires both DBMSs to be running. It invokes the +public `mysql-import` and `postgres-import` targets, creates uniquely named +temporary smoke tables in `demo`, verifies marker rows as `DB_USER`, and +removes only those tables. It tests the trusted SQL import workflow; it does +not prove that untrusted SQL is safe or sandboxed. + + +## Storage-path safety + +`make check-env` runs +[`scripts/validate-storage-paths.sh`](../../../scripts/validate-storage-paths.sh). +Data paths +must be strict descendants of `data/`, and sample paths of `samples/`. +Symlink components, equal, nested, overlapping, and reserved paths are +rejected. `make test-storage-paths` exercises these rules without Docker +runtime. + + +## Trusted SQL imports + +Import only trusted local plain SQL files: + +```bash +make mysql-import FILE=path/to/file.sql DATABASE=demo +make postgres-import FILE=path/to/file.sql DATABASE=demo +``` + +For both targets: + +- `FILE` and `DATABASE` are required. +- The file must be a readable, non-empty regular file. +- The database name must start with a lowercase ASCII letter and contain only + lowercase ASCII letters, digits, or `_`; system databases are rejected. +- The database must already exist and accept a connection from `DB_USER`. +- Import runs as `DB_USER`, never as MySQL root or PostgreSQL superuser. +- The target neither creates a database nor grants access. +- Archives, gzip streams, and PostgreSQL custom-format backups are not + supported by these targets. + +`DATABASE` selects the initial connection database; it does not create a +sandbox. Qualified names, session or client commands, and the actual grants of +`DB_USER` may permit access to other objects. SQL may modify or delete anything +that role can access. + +An import may complete partially. Neither target promises an automatic full +rollback after an error. Review the file and create an appropriate backup +before an important import. + + +## Backup + +The built-in backup targets cover only the configured MySQL `demo` database: + +```bash +make dump +make restore +``` + +`make dump` writes `backup/demo.sql` with the default configuration. +`make restore` reads that file and reapplies MySQL training grants. Use a +separate PostgreSQL backup procedure when PostgreSQL data must be preserved. + + +## Clean and reinitialize + +> **Warning:** Every `clean-*` and `reinit-*` command below is destructive and +> requires the exact opt-in `CONFIRM=1`. + +```bash +make clean-mysql CONFIRM=1 +make clean-postgres CONFIRM=1 +make clean-all CONFIRM=1 + +make reinit-mysql CONFIRM=1 +make reinit-postgres CONFIRM=1 +make reinit-all CONFIRM=1 +``` + +The single-DBMS commands delete only that DBMS data directory. The `all` +variants delete both database data directories. Configuration, init files, +optional sample downloads, and backups are preserved. Reinitialization then +starts and checks the selected DBMSs; `reinit-all` starts MySQL, PostgreSQL, +and Adminer, then performs the shared access check. + +[Back to README](../README_en.md) diff --git a/docs/langs/en/troubleshooting.md b/docs/langs/en/troubleshooting.md new file mode 100644 index 0000000..3769cf9 --- /dev/null +++ b/docs/langs/en/troubleshooting.md @@ -0,0 +1,72 @@ +# Troubleshooting + +[← Back to README](../README_en.md) + +## Language + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/troubleshooting.md) | **Selected** | [Español](../es/troubleshooting.md) | [中文](../zh/troubleshooting.md) | [Français](../fr/troubleshooting.md) | [Deutsch](../de/troubleshooting.md) | + +## Section + +| Getting started | Databases and samples | Validation and operations | Troubleshooting | +| --- | --- | --- | --- | +| [Getting started](getting-started.md) | [Databases and samples](databases.md) | [Validation and operations](operations.md) | **Selected** | + +Collect diagnostics first, then correct the specific cause. If a +reinitialization is still required, back up custom data only when you need to +keep it and use confirmed `reinit-... CONFIRM=1` only as a deliberate last resort. + +Canonical lifecycle and operational details: [databases](databases.md#section-initialization) · [operations](operations.md#section-clean-reinitialize). + + +## Configuration or storage-path validation fails + +Run `make check-env` and read the rejected variable and path in the error. +Managed data paths must be strictly inside the project `data/` tree; sample +paths must be inside `samples/`. They cannot contain symbolic-link components, +overlap one another, or use reserved project directories. Correct +`.docker.env`, then rerun `make check-env` and `make config`. + + +## A service does not become ready + +Check the service state and logs before changing data: + +```bash +make status +make log SERVICE=mysql +make log SERVICE=postgres +``` + +Confirm that Docker is running, the configured host port is available, and +`.docker.env` contains all required values. Fix the specific configuration or +port conflict and start the service again. + + +## Init changes or optional samples do not appear + +This is expected when the data directory is already initialized. Verify the +configured data and sample paths and confirm that the preparation command +succeeded. If existing data matters, back it up. Use the matching +`reinit-... CONFIRM=1` command only as a deliberate last step; it deletes that +DBMS's data. + + +## An optional sample is incomplete or has unexpected ownership + +The loader intentionally refuses to overwrite or repair an unexpected +database. Re-run the appropriate `make samples-mysql` or +`make samples-postgres` preparation command and inspect the error. Preserve any +needed data before considering a confirmed reinitialization. + + +## A client cannot connect + +Host clients use the published host address and `MYSQL_PORT` or +`POSTGRES_PORT`, not the Compose service name. Adminer uses `mysql` or +`postgres` inside the Compose network. Confirm `BIND_ADDRESS`, firewall rules, +the selected database, and the non-administrative `DB_USER` credentials. + +[Back to README](../README_en.md) diff --git a/docs/langs/es/databases.md b/docs/langs/es/databases.md new file mode 100644 index 0000000..54216ae --- /dev/null +++ b/docs/langs/es/databases.md @@ -0,0 +1,119 @@ +# Bases y samples + +[← Volver al README](../README_es.md) + +## Idioma + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/databases.md) | [English](../en/databases.md) | **Seleccionado** | [中文](../zh/databases.md) | [Français](../fr/databases.md) | [Deutsch](../de/databases.md) | + +## Sección + +| Primeros pasos | Bases y samples | Comprobaciones y operaciones | Diagnóstico | +| --- | --- | --- | --- | +| [Primeros pasos](getting-started.md) | **Seleccionado** | [Comprobaciones y operaciones](operations.md) | [Diagnóstico](troubleshooting.md) | + + +## Bases `demo` obligatorias + +Ambos SGBD inicializan `demo`: + +- MySQL: `demo.demo_users` +- PostgreSQL: `demo.public.demo_users` + +Las tablas tienen campos equivalentes `id`, `name`, `email` y `created_at`, y +los mismos cinco usuarios: Alice, Bob, Carol, Dave y Eve. Las comprobaciones +admiten filas adicionales. `make check-env` exige `MYSQL_DATABASE=demo` y +`POSTGRES_DATABASE=demo`. + + +## Samples opcionales + +| SGBD | Bases opcionales | Preparación | +|---|---|---| +| MySQL | `chinook`, `sakila` | `make samples-mysql` | +| PostgreSQL | `pagila`, `chinook` | `make samples-postgres` | + + +## Preparación de samples + +La preparación requiere `curl` y `git`; los samples MySQL también necesitan `unzip` y `sha256sum`. + +La preparación descarga y verifica archivos upstream fijados, pero no inicia +contenedores ni importa en una base ya inicializada. Las descargas temporales +son locales, no se versionan y quedan bajo `MYSQL_SAMPLES_DIR` o +`POSTGRES_SAMPLES_DIR`. Procedencia, hashes y licencias están en +[`THIRD_PARTY_NOTICES.md`](../../../THIRD_PARTY_NOTICES.md). + +Consulte [Inicialización y ciclo de vida](#section-initialization) para saber +cuándo preparar los samples y cómo reinicializar un SGBD existente. + +Un sample ausente se omite y no impide crear `demo`. Un conjunto parcial o una +base inesperada se rechazan sin reparación ni borrado automático. + + +## Estructura de almacenamiento + +```text +data/ +├── mysql/ +└── postgres/ + +initdb/ +├── mysql/ +└── postgres/ +``` + +| SGBD | Data | Init | Samples opcionales | +|---|---|---|---| +| MySQL | `MYSQL_DATA_DIR` (`./data/mysql`) | `MYSQL_INITDB_DIR` (`./initdb/mysql`) | `MYSQL_SAMPLES_DIR` (`./samples/mysql`) | +| PostgreSQL | `POSTGRES_DATA_DIR` (`./data/postgres`) | `POSTGRES_INITDB_DIR` (`./initdb/postgres`) | `POSTGRES_SAMPLES_DIR` (`./samples/postgres`) | + +Las rutas data y samples son configurables en `.docker.env` y están sujetas a +validación. Las reglas de los directorios init se describen en +[Inicialización y ciclo de vida](#section-initialization). No edite manualmente +los archivos de `data/`; pueden pertenecer a UID/GID numéricos del contenedor. + + +## Inicialización y ciclo de vida + +> **Importante:** Los entrypoints oficiales de MySQL y PostgreSQL ejecutan init +> solo si el data directory está vacío. Añadir archivos tras la inicialización +> no cambia una base existente. `make down` conserva los datos, mientras que +> una reinicialización confirmada elimina los datos actuales del SGBD elegido y +> recrea las bases con los scripts init actuales. Haga backup solo si debe +> conservar datos propios; un laboratorio puntual sin cambios valiosos no lo necesita. + +Para una primera inicialización con samples, prepárelos antes del primer inicio: + +```bash +make samples-mysql +make up-mysql + +make samples-postgres +make up-postgres +``` + +Para un SGBD inicializado, conserve los datos propios si hace falta y use +únicamente su reinicialización confirmada correspondiente: + +```bash +make samples-mysql +make reinit-mysql CONFIRM=1 + +make samples-postgres +make reinit-postgres CONFIRM=1 +``` + + +## Acceso didáctico y ownership + +MySQL crea `DB_USER` y le concede acceso a todas las bases no +sistémicas encontradas durante init. PostgreSQL crea un `DB_USER` separado, +sin superuser/createdb/createrole, y lo hace propietario de `demo`, de +`public` y de los objetos sample. Las credenciales administrativas siguen +separadas: `MYSQL_ROOT_PASSWORD`, `POSTGRES_SUPERUSER` y +`POSTGRES_SUPERUSER_PASSWORD`. No edite manualmente archivos de `data/`. + +[Volver al README](../README_es.md) diff --git a/docs/langs/es/getting-started.md b/docs/langs/es/getting-started.md new file mode 100644 index 0000000..d02e557 --- /dev/null +++ b/docs/langs/es/getting-started.md @@ -0,0 +1,166 @@ +# Primeros pasos + +[← Volver al README](../README_es.md) + +## Idioma + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/getting-started.md) | [English](../en/getting-started.md) | **Seleccionado** | [中文](../zh/getting-started.md) | [Français](../fr/getting-started.md) | [Deutsch](../de/getting-started.md) | + +## Sección + +| Primeros pasos | Bases y samples | Comprobaciones y operaciones | Diagnóstico | +| --- | --- | --- | --- | +| **Seleccionado** | [Bases y samples](databases.md) | [Comprobaciones y operaciones](operations.md) | [Diagnóstico](troubleshooting.md) | + + +## Requisitos + +- Docker Engine o Docker Desktop con Docker Compose v2. +- GNU Make, Bash y utilidades básicas de línea de comandos Unix. +- Entornos recomendados: Linux; macOS con Docker Desktop; o Windows con + Docker Desktop y WSL2. + +Ejecute los comandos desde la raíz del repositorio. La rama predeterminada del +proyecto es `master`. + + +## Inicio rápido + +`make init` crea un `.docker.env` local desde +[`.docker.env.example`](../../../.docker.env.example), valida las rutas de +almacenamiento gestionadas y crea los directorios de trabajo. Después, inicie +el laboratorio completo: + +```bash +make init +make up +``` + +`make up` inicia MySQL, PostgreSQL y Adminer. Con la configuración por defecto, +Adminer está en `http://127.0.0.1:8081`. + +Use `make up-no-ui` para iniciar ambos SGBD sin Adminer. La base obligatoria +`demo` siempre se crea durante la primera inicialización; los datasets de +ejemplo son opcionales. Para incluirlos en la primera inicialización, +prepárelos antes del primer `make up`. Si necesita conservar datos propios de +directorios ya inicializados, cree un backup antes de la reinicialización +confirmada. Consulte el procedimiento exacto en +[Inicialización y ciclo de vida](databases.md#section-initialization). + +```bash +make status +make logs +make down +``` + +`make down` elimina los contenedores y la red, pero conserva los datos +bind-mounted. + + +## Modos de inicio + +| Comando | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | Inicia | Inicia | Inicia | +| `make up-no-ui` | Inicia | Inicia | Detiene | +| `make up-mysql` | Inicia | No inicia | No inicia | +| `make up-postgres` | No inicia | Inicia | No inicia | + +Los comandos de un SGBD no detienen el otro ya activo; Adminer se gestiona aparte. + +
+📋 Tabla completa de modos de inicio + +| Comando | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | Inicia | Inicia | Inicia | +| `make up-no-ui` | Inicia o mantiene activo | Inicia o mantiene activo | Detiene si estaba activo | +| `make up-mysql` | Inicia | No inicia automáticamente | No inicia automáticamente | +| `make up-mysql-ui` | Inicia | No inicia automáticamente | Inicia | +| `make up-postgres` | No inicia automáticamente | Inicia | No inicia automáticamente | +| `make up-postgres-ui` | No inicia automáticamente | Inicia | Inicia | +| `make up-ui` | No cambia | No cambia | Inicia | +| `make down-ui` | No cambia | No cambia | Detiene | + +Los comandos de un solo SGBD no detienen el otro si ya está activo. Adminer se +puede iniciar y detener por separado y no está ligado únicamente a MySQL. + +
+ + +## Conexiones + +### Adminer + +Dentro de la red de Compose, Adminer ofrece dos servidores predefinidos: + +```text +MySQL (mysql) +PostgreSQL (postgres) +``` + +Seleccione uno e introduzca `DB_USER`, `DB_PASSWORD` y una base como `demo`. +`mysql` y `postgres` son nombres internos de servicio, no hosts para clientes +de escritorio. + +### Clientes en el host + +| SGBD | Host predeterminado | Variable de puerto | Usuario | Base predeterminada | +|---|---|---|---|---| +| MySQL | `127.0.0.1` | `MYSQL_PORT` | `DB_USER` | `demo` | +| PostgreSQL | `127.0.0.1` | `POSTGRES_PORT` | `DB_USER` | `demo` | + +DataGrip, DBeaver, PhpStorm y los CLI del host usan la dirección y el puerto +publicados. Si cambia `BIND_ADDRESS`, use la dirección accesible de esa interfaz. + +### CLI dentro de los contenedores + +Las contraseñas pasan por el entorno del contenedor y no quedan en el historial: + +```bash +make mysql # administrador MySQL, base demo +make mysql-user # DB_USER, base demo +make postgres # superusuario PostgreSQL, base demo +make postgres-user # DB_USER, base demo +``` + + +## Credenciales + +`.docker.env` se crea a partir de [`.docker.env.example`](../../../.docker.env.example) y está ignorado por +Git. Guarde allí las contraseñas; no las codifique en Compose, SQL ni en +configuración de cliente versionada. + +| Finalidad | Usuario | Contraseña | +|---|---|---| +| Usuario didáctico común | `DB_USER` | `DB_PASSWORD` | +| Administrador MySQL | `root` | `MYSQL_ROOT_PASSWORD` | +| Administrador/superusuario PostgreSQL | `POSTGRES_SUPERUSER` | `POSTGRES_SUPERUSER_PASSWORD` | + +`POSTGRES_SUPERUSER` y `DB_USER` deben ser roles distintos. Use `DB_USER` para +los ejercicios habituales. Cambie las contraseñas de ejemplo antes de +compartir o publicar cualquier servicio. + + +## Puertos y `BIND_ADDRESS` + +| Servicio | Variable | Valor de ejemplo | +|---|---|---| +| MySQL | `MYSQL_PORT` | `3306` | +| PostgreSQL | `POSTGRES_PORT` | `5432` | +| Adminer | `ADMINER_PORT` | `8081` | + +Por defecto, los tres servicios solo se publican en loopback: + +```env +BIND_ADDRESS=127.0.0.1 +``` + +`127.0.0.1` es el valor local predeterminado. `BIND_ADDRESS=0.0.0.0` publica +los puertos en todas las interfaces. Para LAN o VPN, prefiera la dirección de +una interfaz concreta. Cambie este valor conscientemente y revise firewall, +fortaleza de contraseñas y confianza en la red. + +[Volver al README](../README_es.md) diff --git a/docs/langs/es/operations.md b/docs/langs/es/operations.md new file mode 100644 index 0000000..6d1f74a --- /dev/null +++ b/docs/langs/es/operations.md @@ -0,0 +1,162 @@ +# Comprobaciones y operaciones + +[← Volver al README](../README_es.md) + +## Idioma + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/operations.md) | [English](../en/operations.md) | **Seleccionado** | [中文](../zh/operations.md) | [Français](../fr/operations.md) | [Deutsch](../de/operations.md) | + +## Sección + +| Primeros pasos | Bases y samples | Comprobaciones y operaciones | Diagnóstico | +| --- | --- | --- | --- | +| [Primeros pasos](getting-started.md) | [Bases y samples](databases.md) | **Seleccionado** | [Diagnóstico](troubleshooting.md) | + + +## Targets públicos de Make + +Los targets públicos y su implementación están en el [`Makefile`](../../../Makefile). + +Targets clave: `make init`, `make up`, `make down`, `make check`, +`make test-storage-paths`, `make test-sql-imports`, `make mysql-import` y +`make postgres-import`. El SQL de confianza no es un sandbox, puede +ejecutarse parcialmente y no ofrece rollback automático completo; haga backup +antes de un import importante. Los backups integrados solo cubren MySQL +`demo`, no PostgreSQL. `clean-*` y `reinit-*` son destructivos y exigen +`CONFIRM=1` exacto. + +
+📋 Referencia completa de targets públicos de Make + +`make help` muestra la lista resumida. + +| Comando | Función | +|---|---| +| `make init` | Crear `.docker.env`, validar rutas y crear directorios | +| `make check-env` | Validar variables, roles, bases y managed paths | +| `make pull` | Descargar las tres imágenes fijadas | +| `make config` | Validar la configuración Compose expandida | +| `make up`, `make up-no-ui` | Iniciar ambos SGBD con o sin Adminer | +| `make up-mysql`, `make up-mysql-ui` | Iniciar MySQL, opcionalmente con Adminer | +| `make up-postgres`, `make up-postgres-ui` | Iniciar PostgreSQL, opcionalmente con Adminer | +| `make up-ui`, `make down-ui` | Iniciar o detener solo Adminer | +| `make down` | Detener sin borrar los datos bind-mounted | +| `make status`, `make logs` | Mostrar estado o seguir todos los logs | +| `make log SERVICE=postgres` | Seguir un servicio; también `make log postgres` | +| `make in SERVICE=postgres` | Abrir un shell; también `make in postgres` | +| `make mysql`, `make mysql-user` | Abrir MySQL como admin o `DB_USER` | +| `make postgres`, `make postgres-user` | Abrir PostgreSQL como superusuario o `DB_USER` | +| `make samples-mysql`, `make samples-postgres` | Preparar samples verificados | +| `make check-mysql-access`, `make check-postgres-access` | Comprobar un SGBD activo | +| `make check` | Validar Compose y acceso de `DB_USER` a ambos SGBD | +| `make test-storage-paths` | Probar la protección de managed paths sin Docker runtime | +| `make test-sql-imports` | Smoke-test de los dos imports SQL públicos | +| `make mysql-import FILE=... DATABASE=...` | Importar plain SQL en MySQL como `DB_USER` | +| `make postgres-import FILE=... DATABASE=...` | Importar plain SQL en PostgreSQL como `DB_USER` | +| `make dump`, `make restore` | Exportar o restaurar `demo` de MySQL | +| `make clean-{mysql,postgres,all} CONFIRM=1` | Borrar data directories seleccionados | +| `make reinit-{mysql,postgres,all} CONFIRM=1` | Borrar, recrear y comprobar bases | + +
+ + +## Comprobaciones + +### Estáticas y locales + +```bash +make check-env +make config +make test-storage-paths +``` + +`make check-env` crea `.docker.env` si falta y valida valores y rutas. +`make config` valida el modelo Compose expandido. `make test-storage-paths` no +requiere Docker runtime: prueba rutas fuera del proyecto, componentes symlink, +rutas solapadas o anidadas y directorios reservados. + +### Runtime + +```bash +make up-no-ui +make check +make test-sql-imports +make down +``` + +`make check` verifica `demo` y el acceso real de `DB_USER` en ambos SGBD, +además de samples instalados. `make test-sql-imports` requiere ambos SGBD, +invoca `mysql-import` y `postgres-import`, crea tablas temporales con nombres +únicos en `demo`, comprueba marker rows como `DB_USER` y elimina solo esas +tablas. Es un smoke-test del flujo de trusted imports; no es un sandbox ni una +prueba de seguridad para SQL no confiable. + + +## Seguridad de storage paths + +`make check-env` ejecuta +[`scripts/validate-storage-paths.sh`](../../../scripts/validate-storage-paths.sh). +Los data +paths deben estar estrictamente bajo `data/` y los sample paths bajo +`samples/`; se rechazan symlinks, rutas iguales, anidadas, solapadas o +reservadas. `make test-storage-paths` prueba estas reglas sin Docker runtime. + + +## Importación de SQL de confianza + +```bash +make mysql-import FILE=path/to/file.sql DATABASE=demo +make postgres-import FILE=path/to/file.sql DATABASE=demo +``` + +Para ambos targets: + +- `FILE` y `DATABASE` son obligatorios. +- El archivo debe existir, ser legible, no estar vacío y ser plain SQL local. +- La base debe existir; las bases de sistema están prohibidas. +- El import se ejecuta como `DB_USER`; no crea la base ni concede grants. +- `DATABASE` elige la conexión inicial, pero no crea un sandbox. +- Nombres cualificados, comandos client/session y los grants reales pueden + afectar otros objetos accesibles. +- Puede producirse una ejecución parcial; no se promete rollback automático. +- Haga backup antes de una importación importante. +- gzip, archivos y backups PostgreSQL custom-format no están soportados. + + +## Backup + +Los targets integrados cubren solo la base MySQL `demo` configurada: + +```bash +make dump +make restore +``` + +`make dump` escribe `backup/demo.sql`; `make restore` lo lee y reaplica los +grants didácticos de MySQL. Use otro procedimiento para PostgreSQL. + + +## Limpieza y reinicialización + +> **Advertencia:** todos los targets `clean-*` y `reinit-*` son destructivos y +> exigen la confirmación exacta `CONFIRM=1`. + +```bash +make clean-mysql CONFIRM=1 +make clean-postgres CONFIRM=1 +make clean-all CONFIRM=1 + +make reinit-mysql CONFIRM=1 +make reinit-postgres CONFIRM=1 +make reinit-all CONFIRM=1 +``` + +Los targets individuales borran solo los datos del SGBD elegido; los de tipo +`all` borran ambos. Conservan configuración, init, samples y backups. La +reinicialización vuelve a iniciar y comprobar los SGBD seleccionados; +`reinit-all` inicia MySQL, PostgreSQL y Adminer, y después realiza la +comprobación común de acceso. + +[Volver al README](../README_es.md) diff --git a/docs/langs/es/troubleshooting.md b/docs/langs/es/troubleshooting.md new file mode 100644 index 0000000..cc88be9 --- /dev/null +++ b/docs/langs/es/troubleshooting.md @@ -0,0 +1,62 @@ +# Diagnóstico + +[← Volver al README](../README_es.md) + +## Idioma + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/troubleshooting.md) | [English](../en/troubleshooting.md) | **Seleccionado** | [中文](../zh/troubleshooting.md) | [Français](../fr/troubleshooting.md) | [Deutsch](../de/troubleshooting.md) | + +## Sección + +| Primeros pasos | Bases y samples | Comprobaciones y operaciones | Diagnóstico | +| --- | --- | --- | --- | +| [Primeros pasos](getting-started.md) | [Bases y samples](databases.md) | [Comprobaciones y operaciones](operations.md) | **Seleccionado** | + +Primero reúna diagnósticos y después corrija la causa concreta. Si aún +hace falta reinicializar, haga backup solo de los datos propios que necesite +conservar y use `reinit-... CONFIRM=1` solo como última medida deliberada. + +Detalles canónicos del ciclo de vida y las operaciones: [bases](databases.md#section-initialization) · [operaciones](operations.md#section-clean-reinitialize). + + +## Falla la configuración o la validación de rutas + +Ejecute `make check-env`. Los data paths deben estar estrictamente bajo +`data/` y los samples bajo `samples/`; no pueden contener symlinks, solaparse +ni usar directorios reservados. Corrija `.docker.env` y ejecute `make config`. + + +## Un servicio no está listo + +```bash +make status +make log SERVICE=mysql +make log SERVICE=postgres +``` + +Compruebe Docker, el puerto, `.docker.env` y los logs antes de tocar datos. + + +## No aparecen cambios de init o samples + +Es normal si data ya estaba inicializado. Revise las rutas y la preparación; +si necesita conservar datos importantes, haga backup y use +`reinit-... CONFIRM=1` solo como último paso deliberado. + + +## Un sample está incompleto o tiene propietario inesperado + +El loader no sobrescribe ni repara bases inesperadas. Repita +`make samples-mysql` o `make samples-postgres`, inspeccione el error y preserve +los datos antes de reinicializar. + + +## Un cliente no conecta + +Los clientes del host usan la dirección publicada y `MYSQL_PORT` o +`POSTGRES_PORT`; Adminer usa `mysql` o `postgres` dentro de Compose. Revise +`BIND_ADDRESS`, firewall, base seleccionada y credenciales `DB_USER`. + +[Volver al README](../README_es.md) diff --git a/docs/langs/fr/databases.md b/docs/langs/fr/databases.md new file mode 100644 index 0000000..7f80f06 --- /dev/null +++ b/docs/langs/fr/databases.md @@ -0,0 +1,124 @@ +# Bases et samples + +[← Retour au README](../README_fr.md) + +## Langue + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/databases.md) | [English](../en/databases.md) | [Español](../es/databases.md) | [中文](../zh/databases.md) | **Sélectionné** | [Deutsch](../de/databases.md) | + +## Section + +| Prise en main | Bases et samples | Contrôles et opérations | Diagnostic et dépannage | +| --- | --- | --- | --- | +| [Prise en main](getting-started.md) | **Sélectionné** | [Contrôles et opérations](operations.md) | [Diagnostic et dépannage](troubleshooting.md) | + + +## Bases `demo` obligatoires + +Les deux SGBD initialisent `demo` : + +- MySQL : `demo.demo_users` +- PostgreSQL : `demo.public.demo_users` + +Les tables ont les champs équivalents `id`, `name`, `email` et `created_at`, +avec Alice, Bob, Carol, Dave et Eve. Les contrôles acceptent des lignes +supplémentaires. `make check-env` impose `MYSQL_DATABASE=demo` et +`POSTGRES_DATABASE=demo`. + + +## Samples optionnels + +| SGBD | Bases optionnelles | Préparation | +|---|---|---| +| MySQL | `chinook`, `sakila` | `make samples-mysql` | +| PostgreSQL | `pagila`, `chinook` | `make samples-postgres` | + + +## Préparation des samples + +La préparation demande `curl` et `git` ; les samples MySQL exigent aussi `unzip` et `sha256sum`. + +La préparation télécharge et vérifie des fichiers upstream épinglés, sans +démarrer les conteneurs ni importer dans une base déjà initialisée. Les +téléchargements temporaires restent locaux, ne sont pas commités et sont +placés sous `MYSQL_SAMPLES_DIR` ou `POSTGRES_SAMPLES_DIR`. Provenance, +intégrité et licences figurent dans +[`THIRD_PARTY_NOTICES.md`](../../../THIRD_PARTY_NOTICES.md). + +Consultez [Initialisation et cycle de vie](#section-initialization) pour le +moment de la préparation et la réinitialisation d’un SGBD existant. + +Un sample totalement absent est ignoré et n’empêche pas la création de `demo`. +Un ensemble incomplet ou une base inattendue est refusé, sans réparation ni +suppression automatique. + + +## Organisation du stockage + +```text +data/ +├── mysql/ +└── postgres/ + +initdb/ +├── mysql/ +└── postgres/ +``` + +| SGBD | Data | Init | Samples optionnels | +|---|---|---|---| +| MySQL | `MYSQL_DATA_DIR` (`./data/mysql`) | `MYSQL_INITDB_DIR` (`./initdb/mysql`) | `MYSQL_SAMPLES_DIR` (`./samples/mysql`) | +| PostgreSQL | `POSTGRES_DATA_DIR` (`./data/postgres`) | `POSTGRES_INITDB_DIR` (`./initdb/postgres`) | `POSTGRES_SAMPLES_DIR` (`./samples/postgres`) | + +Les chemins data et samples se configurent dans `.docker.env` sous contrôle +des managed paths. Les règles des répertoires init sont décrites dans +[Initialisation et cycle de vie](#section-initialization). Ne modifiez pas +manuellement les fichiers de `data/` : ils peuvent appartenir à des UID/GID +numériques du conteneur. + + +## Initialisation et cycle de vie + +> **Important :** Les entrypoints officiels MySQL et PostgreSQL n’exécutent +> init que si le data directory est vide. Ajouter des fichiers après +> l’initialisation ne modifie pas une base existante. `make down` conserve les +> données, tandis qu’une réinitialisation confirmée supprime les données +> actuelles du SGBD choisi et recrée les bases depuis les scripts init actuels. +> Sauvegardez uniquement les données personnelles à conserver ; un lab ponctuel sans changement précieux ne l’exige pas. + +Pour une première initialisation avec samples, préparez-les avant le premier +démarrage : + +```bash +make samples-mysql +make up-mysql + +make samples-postgres +make up-postgres +``` + +Pour un SGBD déjà initialisé, conservez les données personnelles si nécessaire, +puis utilisez uniquement sa réinitialisation confirmée correspondante : + +```bash +make samples-mysql +make reinit-mysql CONFIRM=1 + +make samples-postgres +make reinit-postgres CONFIRM=1 +``` + + +## Accès pédagogique et ownership + +MySQL crée `DB_USER` et lui accorde l’accès à toutes les bases non +système trouvées pendant init. PostgreSQL crée un `DB_USER` distinct, sans +superuser/createdb/createrole, et le rend propriétaire de `demo`, du schéma +`public` et des objets sample. Les credentials administratifs restent +séparés : `MYSQL_ROOT_PASSWORD`, `POSTGRES_SUPERUSER` et +`POSTGRES_SUPERUSER_PASSWORD`. Ne modifiez pas manuellement les fichiers de +`data/` appartenant aux conteneurs. + +[Retour au README](../README_fr.md) diff --git a/docs/langs/fr/getting-started.md b/docs/langs/fr/getting-started.md new file mode 100644 index 0000000..b3b5c10 --- /dev/null +++ b/docs/langs/fr/getting-started.md @@ -0,0 +1,167 @@ +# Prise en main + +[← Retour au README](../README_fr.md) + +## Langue + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/getting-started.md) | [English](../en/getting-started.md) | [Español](../es/getting-started.md) | [中文](../zh/getting-started.md) | **Sélectionné** | [Deutsch](../de/getting-started.md) | + +## Section + +| Prise en main | Bases et samples | Contrôles et opérations | Diagnostic et dépannage | +| --- | --- | --- | --- | +| **Sélectionné** | [Bases et samples](databases.md) | [Contrôles et opérations](operations.md) | [Diagnostic et dépannage](troubleshooting.md) | + + +## Prérequis + +- Docker Engine ou Docker Desktop avec Docker Compose v2. +- GNU Make, Bash et les utilitaires Unix de base en ligne de commande. +- Environnements recommandés : Linux ; macOS avec Docker Desktop ; ou Windows + avec Docker Desktop et WSL2. + +Exécutez les commandes depuis la racine du dépôt. La branche par défaut du +projet est `master`. + + +## Démarrage rapide + +`make init` crée un `.docker.env` local depuis +[`.docker.env.example`](../../../.docker.env.example), valide les chemins de +stockage gérés et crée les répertoires de travail. Démarrez ensuite le +laboratoire complet : + +```bash +make init +make up +``` + +`make up` démarre MySQL, PostgreSQL et Adminer. Avec la configuration par +défaut, Adminer est disponible sur `http://127.0.0.1:8081`. + +Utilisez `make up-no-ui` pour démarrer les deux SGBD sans Adminer. La base +obligatoire `demo` est toujours créée à la première initialisation ; les jeux +de données d’exemple sont optionnels. Pour les inclure à la première +initialisation, préparez-les avant le premier `make up`. Si les répertoires de +données sont déjà initialisés, sauvegardez-les avant une réinitialisation +confirmée uniquement si vous devez conserver des données personnelles. Consultez la procédure exacte dans +[Initialisation et cycle de vie](databases.md#section-initialization). + +```bash +make status +make logs +make down +``` + +`make down` supprime les conteneurs et le réseau, mais conserve les données +bind-mounted. + + +## Modes de démarrage + +| Commande | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | Démarre | Démarre | Démarre | +| `make up-no-ui` | Démarre | Démarre | Arrête | +| `make up-mysql` | Démarre | Ne démarre pas | Ne démarre pas | +| `make up-postgres` | Ne démarre pas | Démarre | Ne démarre pas | + +Les commandes d’un SGBD n’arrêtent pas l’autre déjà actif ; Adminer se gère séparément. + +
+📋 Tableau complet des modes de démarrage + +| Commande | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | Démarre | Démarre | Démarre | +| `make up-no-ui` | Démarre ou laisse actif | Démarre ou laisse actif | Arrête s’il est actif | +| `make up-mysql` | Démarre | Ne démarre pas automatiquement | Ne démarre pas automatiquement | +| `make up-mysql-ui` | Démarre | Ne démarre pas automatiquement | Démarre | +| `make up-postgres` | Ne démarre pas automatiquement | Démarre | Ne démarre pas automatiquement | +| `make up-postgres-ui` | Ne démarre pas automatiquement | Démarre | Démarre | +| `make up-ui` | Ne change rien | Ne change rien | Démarre | +| `make down-ui` | Ne change rien | Ne change rien | Arrête | + +Les commandes dédiées à un SGBD n’arrêtent pas l’autre s’il fonctionne déjà. +Adminer se démarre et s’arrête séparément et n’est pas lié uniquement à MySQL. + +
+ + +## Connexions + +### Adminer + +Dans le réseau Compose, Adminer propose deux serveurs prédéfinis : + +```text +MySQL (mysql) +PostgreSQL (postgres) +``` + +Choisissez un serveur, puis saisissez `DB_USER`, `DB_PASSWORD` et une base telle +que `demo`. `mysql` et `postgres` sont des noms internes au réseau Compose, pas +des noms d’hôte pour les clients desktop. + +### Clients sur l’hôte + +| SGBD | Hôte par défaut | Variable de port | Utilisateur | Base par défaut | +|---|---|---|---|---| +| MySQL | `127.0.0.1` | `MYSQL_PORT` | `DB_USER` | `demo` | +| PostgreSQL | `127.0.0.1` | `POSTGRES_PORT` | `DB_USER` | `demo` | + +DataGrip, DBeaver, PhpStorm et les CLI de l’hôte utilisent l’adresse et le port +publiés. Si `BIND_ADDRESS` change, utilisez l’adresse joignable de l’interface. + +### CLI dans les conteneurs + +Les mots de passe passent par l’environnement du conteneur et non par +l’historique du shell : + +```bash +make mysql # administrateur MySQL, base demo +make mysql-user # DB_USER, base demo +make postgres # superutilisateur PostgreSQL, base demo +make postgres-user # DB_USER, base demo +``` + + +## Identifiants + +`.docker.env` est créé depuis [`.docker.env.example`](../../../.docker.env.example) et ignoré par Git. Gardez +les mots de passe dans ce fichier ; ne les codez pas en dur dans Compose, SQL +ou une configuration client versionnée. + +| Usage | Utilisateur | Mot de passe | +|---|---|---| +| Utilisateur pédagogique commun | `DB_USER` | `DB_PASSWORD` | +| Administrateur MySQL | `root` | `MYSQL_ROOT_PASSWORD` | +| Administrateur/superutilisateur PostgreSQL | `POSTGRES_SUPERUSER` | `POSTGRES_SUPERUSER_PASSWORD` | + +`POSTGRES_SUPERUSER` et `DB_USER` doivent être deux rôles différents. Utilisez +le compte pédagogique pour les exercices courants. Remplacez les mots de passe +d’exemple avant tout partage ou toute publication de service. + + +## Ports et `BIND_ADDRESS` + +| Service | Variable | Valeur d’exemple | +|---|---|---| +| MySQL | `MYSQL_PORT` | `3306` | +| PostgreSQL | `POSTGRES_PORT` | `5432` | +| Adminer | `ADMINER_PORT` | `8081` | + +Par défaut, les trois services ne sont publiés que sur loopback : + +```env +BIND_ADDRESS=127.0.0.1 +``` + +`127.0.0.1` est la valeur locale par défaut. `BIND_ADDRESS=0.0.0.0` publie les +ports sur toutes les interfaces. Pour un LAN ou VPN, préférez l’adresse d’une +interface précise. Ce changement doit être volontaire et tenir compte du +firewall, de la robustesse des mots de passe et de la confiance accordée au réseau. + +[Retour au README](../README_fr.md) diff --git a/docs/langs/fr/operations.md b/docs/langs/fr/operations.md new file mode 100644 index 0000000..1c7bc49 --- /dev/null +++ b/docs/langs/fr/operations.md @@ -0,0 +1,162 @@ +# Contrôles et opérations + +[← Retour au README](../README_fr.md) + +## Langue + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/operations.md) | [English](../en/operations.md) | [Español](../es/operations.md) | [中文](../zh/operations.md) | **Sélectionné** | [Deutsch](../de/operations.md) | + +## Section + +| Prise en main | Bases et samples | Contrôles et opérations | Diagnostic et dépannage | +| --- | --- | --- | --- | +| [Prise en main](getting-started.md) | [Bases et samples](databases.md) | **Sélectionné** | [Diagnostic et dépannage](troubleshooting.md) | + + +## Targets Make publics + +Les targets publics et leur implémentation figurent dans le [`Makefile`](../../../Makefile). + +Targets essentiels : `make init`, `make up`, `make down`, `make check`, +`make test-storage-paths`, `make test-sql-imports`, `make mysql-import` et +`make postgres-import`. Le SQL de confiance n’est pas un sandbox, peut être +exécuté partiellement et n’offre aucun rollback automatique garanti ; faites +un backup avant tout import important. Les backups intégrés couvrent seulement +MySQL `demo`, pas PostgreSQL. `clean-*` et `reinit-*` sont destructifs et +exigent `CONFIRM=1` exact. + +
+📋 Référence complète des targets Make publics + +`make help` affiche la liste concise. + +| Commande | Rôle | +|---|---| +| `make init` | Créer `.docker.env`, valider les chemins et créer les répertoires | +| `make check-env` | Vérifier env, rôles, noms de bases et managed paths | +| `make pull` | Télécharger les trois images épinglées | +| `make config` | Valider la configuration Compose développée | +| `make up`, `make up-no-ui` | Démarrer les deux SGBD avec ou sans Adminer | +| `make up-mysql`, `make up-mysql-ui` | Démarrer MySQL, avec Adminer en option | +| `make up-postgres`, `make up-postgres-ui` | Démarrer PostgreSQL, avec Adminer en option | +| `make up-ui`, `make down-ui` | Démarrer ou arrêter seulement Adminer | +| `make down` | Arrêter sans supprimer les données bind-mounted | +| `make status`, `make logs` | Afficher l’état ou suivre tous les logs | +| `make log SERVICE=postgres` | Suivre un service ; `make log postgres` fonctionne aussi | +| `make in SERVICE=postgres` | Ouvrir un shell ; `make in postgres` fonctionne aussi | +| `make mysql`, `make mysql-user` | Ouvrir MySQL comme admin ou `DB_USER` | +| `make postgres`, `make postgres-user` | Ouvrir PostgreSQL comme superutilisateur ou `DB_USER` | +| `make samples-mysql`, `make samples-postgres` | Préparer les samples vérifiés | +| `make check-mysql-access`, `make check-postgres-access` | Contrôler un SGBD actif | +| `make check` | Valider Compose et l’accès `DB_USER` aux deux SGBD | +| `make test-storage-paths` | Tester les managed paths sans Docker runtime | +| `make test-sql-imports` | Smoke-test des deux imports SQL publics | +| `make mysql-import FILE=... DATABASE=...` | Importer du plain SQL dans MySQL comme `DB_USER` | +| `make postgres-import FILE=... DATABASE=...` | Importer du plain SQL dans PostgreSQL comme `DB_USER` | +| `make dump`, `make restore` | Sauvegarder ou restaurer `demo` dans MySQL | +| `make clean-{mysql,postgres,all} CONFIRM=1` | Supprimer les data directories choisis | +| `make reinit-{mysql,postgres,all} CONFIRM=1` | Supprimer, recréer et contrôler les bases | + +
+ + +## Contrôles + +### Contrôles statiques et locaux + +```bash +make check-env +make config +make test-storage-paths +``` + +`make check-env` crée `.docker.env` s’il manque, puis valide valeurs et chemins. +`make config` valide le modèle Compose développé. `make test-storage-paths` ne +demande pas de Docker runtime : il teste les sorties du projet, composants +symlink, chemins qui se chevauchent ou s’imbriquent et répertoires réservés. + +### Contrôles runtime + +```bash +make up-no-ui +make check +make test-sql-imports +make down +``` + +`make check` valide `demo` et l’accès réel de `DB_USER` aux deux SGBD, ainsi que +les samples installés. `make test-sql-imports` exige que les deux SGBD soient +actifs ; il appelle `mysql-import` et `postgres-import`, crée des tables +temporaires aux noms uniques dans `demo`, vérifie les marker rows comme +`DB_USER` puis ne supprime que ces tables. C’est un smoke-test du flux trusted +import, ni un sandbox ni une preuve de sécurité pour du SQL non fiable. + + +## Sécurité des storage paths + +`make check-env` exécute +[`scripts/validate-storage-paths.sh`](../../../scripts/validate-storage-paths.sh). +Les data +paths doivent rester strictement sous `data/`, les sample paths sous +`samples/` ; symlinks, chemins égaux, imbriqués, chevauchants ou réservés +sont refusés. `make test-storage-paths` teste ces règles sans Docker runtime. + + +## Imports SQL de confiance + +```bash +make mysql-import FILE=path/to/file.sql DATABASE=demo +make postgres-import FILE=path/to/file.sql DATABASE=demo +``` + +Pour les deux targets : + +- `FILE` et `DATABASE` sont obligatoires. +- Le fichier local plain SQL doit exister, être lisible et non vide. +- La base doit déjà exister ; les bases système sont interdites. +- L’import s’exécute comme `DB_USER`, sans créer de base ni accorder de grants. +- `DATABASE` choisit la connexion initiale, mais ne crée pas de sandbox. +- Les qualified names, commandes client/session et grants effectifs peuvent + atteindre d’autres objets accessibles. +- Une exécution partielle est possible ; aucun rollback automatique n’est promis. +- Effectuez une sauvegarde avant un import important. +- gzip, archives et backups PostgreSQL custom-format ne sont pas pris en charge. + + +## Sauvegarde + +Les targets intégrés couvrent uniquement la base MySQL `demo` configurée : + +```bash +make dump +make restore +``` + +`make dump` écrit `backup/demo.sql` ; `make restore` le lit et réapplique les +grants pédagogiques MySQL. Utilisez une procédure distincte pour PostgreSQL. + + +## Nettoyage et réinitialisation + +> **Attention :** tous les targets `clean-*` et `reinit-*` sont destructifs et +> exigent la confirmation exacte `CONFIRM=1`. + +```bash +make clean-mysql CONFIRM=1 +make clean-postgres CONFIRM=1 +make clean-all CONFIRM=1 + +make reinit-mysql CONFIRM=1 +make reinit-postgres CONFIRM=1 +make reinit-all CONFIRM=1 +``` + +Les commandes unitaires ne suppriment que les données du SGBD choisi ; `all` +supprime celles des deux. Configuration, init, samples et backups restent en +place. La réinitialisation redémarre et contrôle les SGBD choisis ; +`reinit-all` démarre MySQL, PostgreSQL et Adminer, puis effectue le contrôle +d’accès commun. + +[Retour au README](../README_fr.md) diff --git a/docs/langs/fr/troubleshooting.md b/docs/langs/fr/troubleshooting.md new file mode 100644 index 0000000..b503448 --- /dev/null +++ b/docs/langs/fr/troubleshooting.md @@ -0,0 +1,62 @@ +# Diagnostic et dépannage + +[← Retour au README](../README_fr.md) + +## Langue + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/troubleshooting.md) | [English](../en/troubleshooting.md) | [Español](../es/troubleshooting.md) | [中文](../zh/troubleshooting.md) | **Sélectionné** | [Deutsch](../de/troubleshooting.md) | + +## Section + +| Prise en main | Bases et samples | Contrôles et opérations | Diagnostic et dépannage | +| --- | --- | --- | --- | +| [Prise en main](getting-started.md) | [Bases et samples](databases.md) | [Contrôles et opérations](operations.md) | **Sélectionné** | + +Collectez d’abord le diagnostic, puis corrigez la cause précise. Si une +réinitialisation reste nécessaire, sauvegardez seulement les données +personnelles à conserver et n’utilisez `reinit-... CONFIRM=1` qu’en dernier recours volontaire. + +Détails canoniques du cycle de vie et des opérations : [bases](databases.md#section-initialization) · [opérations](operations.md#section-clean-reinitialize). + + +## Échec de configuration ou de validation des chemins + +Lancez `make check-env`. Les data paths doivent rester strictement sous +`data/` et les samples sous `samples/` ; aucun symlink, chevauchement ou +répertoire réservé n’est admis. Corrigez `.docker.env` puis lancez `make config`. + + +## Un service n’est pas prêt + +```bash +make status +make log SERVICE=mysql +make log SERVICE=postgres +``` + +Vérifiez Docker, le port, `.docker.env` et les logs avant de toucher aux données. + + +## Les changements init ou les samples n’apparaissent pas + +C’est normal si data est déjà initialisé. Vérifiez chemins et préparation ; si +des données importantes doivent être conservées, sauvegardez-les et n’utilisez +`reinit-... CONFIRM=1` qu’en dernier recours volontaire. + + +## Sample incomplet ou propriétaire inattendu + +Le loader ne remplace ni ne répare une base inattendue. Relancez +`make samples-mysql` ou `make samples-postgres` et inspectez l’erreur ; +préservez les données avant toute réinitialisation. + + +## Un client ne se connecte pas + +Les clients hôtes utilisent l’adresse publiée et `MYSQL_PORT` ou +`POSTGRES_PORT` ; Adminer utilise `mysql` ou `postgres` dans Compose. Vérifiez +`BIND_ADDRESS`, firewall, base sélectionnée et identifiants `DB_USER`. + +[Retour au README](../README_fr.md) diff --git a/docs/langs/ru/databases.md b/docs/langs/ru/databases.md new file mode 100644 index 0000000..9dc5c3c --- /dev/null +++ b/docs/langs/ru/databases.md @@ -0,0 +1,134 @@ +# Базы и учебные данные + +[← Вернуться к README](../../../README.md) + +## Язык + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| **Выбран** | [English](../en/databases.md) | [Español](../es/databases.md) | [中文](../zh/databases.md) | [Français](../fr/databases.md) | [Deutsch](../de/databases.md) | + +## Раздел + +| Начало работы | Базы и учебные данные | Проверки и эксплуатация | Диагностика | +| --- | --- | --- | --- | +| [Начало работы](getting-started.md) | **Выбран** | [Проверки и эксплуатация](operations.md) | [Диагностика](troubleshooting.md) | + + +## Обязательные базы `demo` + +Обе СУБД инициализируют обязательную базу с именем `demo`: + +- MySQL: `demo.demo_users` +- PostgreSQL: `demo.public.demo_users` + +Таблицы содержат эквивалентные поля `id`, `name`, `email`, `created_at` и +одинаковые пять обязательных пользователей: Alice, Bob, Carol, Dave и Eve. +Проверки допускают дополнительные строки, созданные пользователем. + +Имена баз по умолчанию задаются как `MYSQL_DATABASE=demo` и +`POSTGRES_DATABASE=demo`; `make check-env` требует именно эти значения. + + +## Необязательные учебные базы + +| СУБД | Необязательные базы | Команда подготовки | +|---|---|---| +| MySQL | `chinook`, `sakila` | `make samples-mysql` | +| PostgreSQL | `pagila`, `chinook` | `make samples-postgres` | + + +## Подготовка учебных баз + +Для подготовки нужны `curl` и `git`; учебные базы MySQL дополнительно требуют +`unzip` и `sha256sum`. + +Команды подготовки загружают и проверяют закреплённые файлы исходных проектов, но не +запускают контейнеры и не импортируют данные в уже инициализированную СУБД. +Загрузки остаются локальными, исключаются из Git и сохраняются в +`MYSQL_SAMPLES_DIR` или `POSTGRES_SAMPLES_DIR`. Происхождение, контрольные +значения целостности и лицензии описаны в +[`THIRD_PARTY_NOTICES.md`](../../../THIRD_PARTY_NOTICES.md). + +Порядок подготовки относительно первого запуска и повторной инициализации +описан в разделе [«Инициализация и жизненный цикл»](#section-initialization). + +Полностью отсутствующая необязательная учебная база пропускается и не мешает +создать обязательную `demo`. Частичный набор файлов учебных баз или неожиданно +существующая учебная база отклоняются без автоматического исправления или +удаления. + + +## Структура хранения + +Каталоги хоста для хранения данных по умолчанию разделены по СУБД: + +```text +data/ +├── mysql/ +└── postgres/ + +initdb/ +├── mysql/ +└── postgres/ +``` + +Связанные настройки `.docker.env` также разделены: + +| СУБД | Данные | Инициализация | Необязательные учебные базы | +|---|---|---|---| +| MySQL | `MYSQL_DATA_DIR` (`./data/mysql`) | `MYSQL_INITDB_DIR` (`./initdb/mysql`) | `MYSQL_SAMPLES_DIR` (`./samples/mysql`) | +| PostgreSQL | `POSTGRES_DATA_DIR` (`./data/postgres`) | `POSTGRES_INITDB_DIR` (`./initdb/postgres`) | `POSTGRES_SAMPLES_DIR` (`./samples/postgres`) | + +Пути данных и учебных баз можно изменить через `.docker.env` с учётом проверки +контролируемых путей хранения. Правила применения каталогов инициализации +описаны в разделе [«Инициализация и жизненный цикл»](#section-initialization). + +Не редактируйте файлы СУБД внутри `data/` вручную. Файлы, принадлежащие +контейнерам, могут иметь числовые UID/GID, отличающиеся от пользователя хоста. + + +## Инициализация и жизненный цикл + +> **Важно:** Официальные точки входа MySQL и PostgreSQL выполняют файлы +> инициализации только при пустом каталоге данных. Добавление файлов после +> инициализации не изменяет существующую базу. `make down` сохраняет данные, +> а подтверждённая переинициализация удаляет текущие данные выбранной СУБД и +> создаёт базы заново из актуальных init-скриптов. Резервная копия нужна, если +> требуется сохранить собственные данные; для одноразового учебного стенда без +> ценных изменений она не обязательна. + +Для первой инициализации с учебными базами подготовьте их до первого запуска: + +```bash +make samples-mysql +make up-mysql + +make samples-postgres +make up-postgres +``` + +Для уже инициализированной СУБД при необходимости сначала сохраните +собственные данные, затем используйте только соответствующую подтверждённую +переинициализацию: + +```bash +make samples-mysql +make reinit-mysql CONFIRM=1 + +make samples-postgres +make reinit-postgres CONFIRM=1 +``` + + +## Доступ учебного пользователя и владение объектами + +MySQL создаёт `DB_USER` и выдаёт ему права на все пользовательские +базы, обнаруженные во время инициализации. PostgreSQL создаёт отдельную роль +`DB_USER` без прав `superuser`, `createdb` и `createrole` и назначает её владельцем +`demo`, схемы `public` и загруженных объектов учебных баз. Административные +учётные данные остаются отдельными: `MYSQL_ROOT_PASSWORD`, +`POSTGRES_SUPERUSER` и `POSTGRES_SUPERUSER_PASSWORD`. Не редактируйте +файлы в `data/`, принадлежащие контейнерам, вручную. + +[Вернуться к README](../../../README.md) diff --git a/docs/langs/ru/getting-started.md b/docs/langs/ru/getting-started.md new file mode 100644 index 0000000..2fee3a8 --- /dev/null +++ b/docs/langs/ru/getting-started.md @@ -0,0 +1,177 @@ +# Начало работы + +[← Вернуться к README](../../../README.md) + +## Язык + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| **Выбран** | [English](../en/getting-started.md) | [Español](../es/getting-started.md) | [中文](../zh/getting-started.md) | [Français](../fr/getting-started.md) | [Deutsch](../de/getting-started.md) | + +## Раздел + +| Начало работы | Базы и учебные данные | Проверки и эксплуатация | Диагностика | +| --- | --- | --- | --- | +| **Выбран** | [Базы и учебные данные](databases.md) | [Проверки и эксплуатация](operations.md) | [Диагностика](troubleshooting.md) | + + +## Требования + +- Docker Engine или Docker Desktop с Docker Compose v2. +- GNU Make, Bash и базовые утилиты командной строки Unix. +- Рекомендуемая среда: Linux; macOS с Docker Desktop; Windows с Docker Desktop + и WSL2. + +Выполняйте команды из корня репозитория. Ветка проекта по умолчанию — `master`. + + +## Быстрый старт + +`make init` создаёт локальный `.docker.env` из +[`.docker.env.example`](../../../.docker.env.example), проверяет контролируемые +пути хранения и создаёт рабочие каталоги. Затем запустите полный стенд: + +```bash +make init +make up +``` + +`make up` запускает MySQL, PostgreSQL и Adminer. С конфигурацией по умолчанию +Adminer доступен по адресу `http://127.0.0.1:8081`. + +Чтобы запустить обе СУБД без Adminer, используйте `make up-no-ui`. При первой +инициализации всегда создаётся обязательная база `demo`; учебные базы +необязательны. Если они нужны при первой инициализации, подготовьте их до +первого `make up`. Если нужно сохранить собственные данные из уже +инициализированных каталогов, перед подтверждённой переинициализацией создайте +резервную копию. Точный порядок действий приведён в разделе +[«Инициализация и жизненный цикл»](databases.md#section-initialization). + +Полезные следующие команды: + +```bash +make status +make logs +make down +``` + +`make down` удаляет контейнеры и сеть, но сохраняет данные СУБД в каталогах +хоста, подключённых в контейнеры. + + +## Режимы запуска + +| Команда | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | Запускает | Запускает | Запускает | +| `make up-no-ui` | Запускает | Запускает | Останавливает | +| `make up-mysql` | Запускает | Не запускает | Не запускает | +| `make up-postgres` | Не запускает | Запускает | Не запускает | + +Команды одной СУБД не останавливают уже работающую другую; Adminer управляется отдельно. + +
+📋 Полная таблица режимов запуска + +| Команда | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | Запускает | Запускает | Запускает | +| `make up-no-ui` | Запускает или оставляет активным | Запускает или оставляет активным | Останавливает, если запущен | +| `make up-mysql` | Запускает | Не запускает автоматически | Не запускает автоматически | +| `make up-mysql-ui` | Запускает | Не запускает автоматически | Запускает | +| `make up-postgres` | Не запускает автоматически | Запускает | Не запускает автоматически | +| `make up-postgres-ui` | Не запускает автоматически | Запускает | Запускает | +| `make up-ui` | Не меняет состояние | Не меняет состояние | Запускает | +| `make down-ui` | Не меняет состояние | Не меняет состояние | Останавливает | + +Команды одиночного запуска не останавливают другую уже работающую СУБД. +Adminer можно запускать и останавливать отдельно; он не привязан только к +MySQL. + +
+ + +## Подключения + +### Adminer + +Внутри Compose-сети Adminer предлагает два заранее заданных сервера: + +```text +MySQL (mysql) +PostgreSQL (postgres) +``` + +Выберите сервер, затем укажите `DB_USER`, `DB_PASSWORD` и имя базы, например +`demo`. Имена сервисов `mysql` и `postgres` работают внутри Compose-сети; для +клиентов на компьютере пользователя это не адреса серверов. + +### Клиенты на хосте + +DataGrip, DBeaver, PhpStorm и клиенты командной строки на компьютере +пользователя подключаются через опубликованный адрес и порт: + +| СУБД | Хост по умолчанию | Переменная порта | Пользователь | База по умолчанию | +|---|---|---|---|---| +| MySQL | `127.0.0.1` | `MYSQL_PORT` | `DB_USER` | `demo` | +| PostgreSQL | `127.0.0.1` | `POSTGRES_PORT` | `DB_USER` | `demo` | + +Если вы изменили `BIND_ADDRESS`, при необходимости используйте вместо +`127.0.0.1` доступный адрес этого интерфейса. + +### CLI в контейнерах + +Цели Make передают пароли через окружение контейнера и не помещают их в +историю командной оболочки: + +```bash +make mysql # администратор MySQL, база demo +make mysql-user # DB_USER, база demo +make postgres # суперпользователь PostgreSQL, база demo +make postgres-user # DB_USER, база demo +``` + + +## Учётные данные + +При копировании [`.docker.env.example`](../../../.docker.env.example) создаётся `.docker.env`; этот файл +исключён из Git. Храните пароли в нём и не записывайте их напрямую в Compose, +SQL или отслеживаемую конфигурацию клиентов. + +| Назначение | Настройка пользователя | Настройка пароля | +|---|---|---| +| Общий учебный пользователь двух СУБД | `DB_USER` | `DB_PASSWORD` | +| Администратор MySQL | `root` | `MYSQL_ROOT_PASSWORD` | +| Администратор/суперпользователь PostgreSQL | `POSTGRES_SUPERUSER` | `POSTGRES_SUPERUSER_PASSWORD` | + +`POSTGRES_SUPERUSER` и `DB_USER` должны быть разными ролями. Для обычных +упражнений используйте общего учебного пользователя, а не `root` или +суперпользователя. +Замените пароли из примера до предоставления общего доступа или публикации +любого сервиса за пределами локального компьютера. + + +## Порты и `BIND_ADDRESS` + +Порты хоста настраиваются в `.docker.env`: + +| Сервис | Переменная порта | Значение примера | +|---|---|---| +| MySQL | `MYSQL_PORT` | `3306` | +| PostgreSQL | `POSTGRES_PORT` | `5432` | +| Adminer | `ADMINER_PORT` | `8081` | + +По умолчанию все три сервиса публикуются только на интерфейсе обратной петли +(loopback): + +```env +BIND_ADDRESS=127.0.0.1 +``` + +Это безопасное значение по умолчанию для локального стенда. Значение +`BIND_ADDRESS=0.0.0.0` публикует настроенные порты на всех сетевых интерфейсах. +Для доступа через VPN или LAN предпочтительнее адрес конкретного интерфейса. +Меняйте привязку осознанно, учитывая правила межсетевого экрана, надёжность паролей и +доверие ко всем подключённым сетям. + +[Вернуться к README](../../../README.md) diff --git a/docs/langs/ru/operations.md b/docs/langs/ru/operations.md new file mode 100644 index 0000000..eca1501 --- /dev/null +++ b/docs/langs/ru/operations.md @@ -0,0 +1,188 @@ +# Проверки и эксплуатация + +[← Вернуться к README](../../../README.md) + +## Язык + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| **Выбран** | [English](../en/operations.md) | [Español](../es/operations.md) | [中文](../zh/operations.md) | [Français](../fr/operations.md) | [Deutsch](../de/operations.md) | + +## Раздел + +| Начало работы | Базы и учебные данные | Проверки и эксплуатация | Диагностика | +| --- | --- | --- | --- | +| [Начало работы](getting-started.md) | [Базы и учебные данные](databases.md) | **Выбран** | [Диагностика](troubleshooting.md) | + + +## Команды `Makefile` + +Публичные цели и их фактическая реализация находятся в +[`Makefile`](../../../Makefile). + +Ключевые цели: `make init`, `make up`, `make down`, `make check`, +`make test-storage-paths`, `make test-sql-imports`, `make mysql-import` и +`make postgres-import`. Импорт доверенного SQL не является изолированной +средой (`sandbox`), может выполниться частично и не гарантирует автоматический +откат; перед важным импортом нужна резервная копия. Встроенные цели резервного +копирования покрывают только MySQL `demo`, но не PostgreSQL. Цели `clean-*` и +`reinit-*` удаляют данные и требуют точного `CONFIRM=1`. + +
+📋 Полный справочник публичных целей Make + +Краткий список команд выводит `make help`. + +| Команда | Назначение | +|---|---| +| `make init` | Создать `.docker.env`, проверить контролируемые пути хранения и создать рабочие каталоги | +| `make check-env` | Проверить обязательные значения окружения, разделение ролей, имена баз и контролируемые пути хранения | +| `make pull` | Загрузить три закреплённых образа контейнеров | +| `make config` | Проверить развёрнутую Compose-конфигурацию | +| `make up`, `make up-no-ui` | Запустить обе СУБД с Adminer или без него | +| `make up-mysql`, `make up-mysql-ui` | Запустить MySQL, при необходимости с Adminer | +| `make up-postgres`, `make up-postgres-ui` | Запустить PostgreSQL, при необходимости с Adminer | +| `make up-ui`, `make down-ui` | Запустить или остановить только Adminer | +| `make down` | Остановить стенд без удаления данных в каталогах хоста, подключённых в контейнеры | +| `make status` | Показать состояние сервисов | +| `make logs` | Следить за логами всех сервисов | +| `make log SERVICE=postgres` | Следить за логом одного сервиса; также работает `make log postgres` | +| `make in SERVICE=postgres` | Открыть командную оболочку сервиса; также работает `make in postgres` | +| `make mysql`, `make mysql-user` | Открыть MySQL как администратор или `DB_USER` | +| `make postgres`, `make postgres-user` | Открыть PostgreSQL как суперпользователь или `DB_USER` | +| `make samples-mysql`, `make samples-postgres` | Подготовить проверенные необязательные учебные базы | +| `make check-mysql-access`, `make check-postgres-access` | Проверить доступ учебного пользователя к одной запущенной СУБД | +| `make check` | Проверить Compose и доступ `DB_USER` к двум запущенным СУБД | +| `make test-storage-paths` | Проверить защиту контролируемых путей хранения без запуска Docker | +| `make test-sql-imports` | Быстро проверить две публичные цели импорта доверенных SQL-файлов | +| `make mysql-import FILE=... DATABASE=...` | Импортировать доверенный файл в формате `plain SQL` в существующую базу MySQL от `DB_USER` | +| `make postgres-import FILE=... DATABASE=...` | Импортировать доверенный файл в формате `plain SQL` в существующую базу PostgreSQL от `DB_USER` | +| `make dump`, `make restore` | Создать или восстановить dump настроенной MySQL-базы `demo` | +| `make clean-{mysql,postgres,all} CONFIRM=1` | Удалить выбранные контролируемые каталоги данных | +| `make reinit-{mysql,postgres,all} CONFIRM=1` | Удалить, пересоздать и проверить выбранные базы | + +
+ + +## Проверки + +### Статические и локальные проверки + +```bash +make check-env +make config +make test-storage-paths +``` + +`make check-env` создаёт `.docker.env` из примера, если файла ещё нет, затем +проверяет обязательные настройки и контролируемые пути хранения. `make config` проверяет +развёрнутую Compose-модель. + +Для `make test-storage-paths` запуск Docker не требуется. Тест проверяет защиту +от путей за пределами проекта, компонентов символических ссылок, +пересекающихся или вложенных контролируемых путей и зарезервированных +каталогов. Та же проверка защищает настроенные каталоги данных и учебных баз +MySQL/PostgreSQL при обычной инициализации. + +### Проверки после запуска + +Запустите обе СУБД без Adminer, проверьте учебный доступ и импорт, затем +остановите сервисы: + +```bash +make up-no-ui +make check +make test-sql-imports +make down +``` + +`make check` проверяет обязательные данные `demo` и фактический доступ +`DB_USER` в обеих СУБД. Если установлены поддерживаемые учебные базы, они +также проверяются. + +Для `make test-sql-imports` обе СУБД должны быть запущены. Тест вызывает +публичные цели `mysql-import` и `postgres-import`, создаёт уникальные временные +проверочные таблицы в `demo`, проверяет контрольные записи от имени `DB_USER` и +удаляет только эти таблицы. Это проверка процесса импорта доверенного SQL, а не +доказательство безопасности или изолированная среда для недоверенного SQL. + + +## Безопасность путей хранения + +`make check-env` запускает +[`scripts/validate-storage-paths.sh`](../../../scripts/validate-storage-paths.sh). +Пути данных должны быть строго внутри `data/`, пути учебных баз — внутри +`samples/`; компоненты символических ссылок, совпадающие, вложенные, пересекающиеся и +зарезервированные пути отклоняются. `make test-storage-paths` проверяет эти +ограничения без запуска Docker. + + +## Импорт доверенных SQL-файлов + +Импортируйте только доверенные локальные файлы в формате `plain SQL`: + +```bash +make mysql-import FILE=path/to/file.sql DATABASE=demo +make postgres-import FILE=path/to/file.sql DATABASE=demo +``` + +Для обеих целей: + +- `FILE` и `DATABASE` обязательны. +- Файл должен быть существующим, читаемым и непустым обычным файлом. +- Имя базы должно начинаться со строчной ASCII-буквы и содержать только + строчные ASCII-буквы, цифры или `_`; системные базы запрещены. +- База должна существовать и принимать подключение от `DB_USER`. +- Импорт выполняется от `DB_USER`, а не от `root` MySQL или суперпользователя + PostgreSQL. +- Цель не создаёт базу и не выдаёт права. +- Цели не обрабатывают архивы, потоки `gzip` и резервные копии PostgreSQL в + формате `custom format`. + +`DATABASE` выбирает начальную базу подключения, но не создаёт изолированную +среду. Полные имена объектов, команды сеанса или клиента и фактические права +роли `DB_USER` могут разрешить доступ к другим объектам. SQL способен +изменить или удалить всё, к чему у этой роли есть доступ. + +Импорт может выполниться частично. Ни одна цель не обещает автоматический +полный откат после ошибки. Перед важным импортом изучите файл и создайте +подходящую резервную копию. + + +## Резервное копирование + +Встроенные цели резервного копирования работают только с настроенной базой +MySQL `demo`: + +```bash +make dump +make restore +``` + +С конфигурацией по умолчанию `make dump` записывает `backup/demo.sql`. +`make restore` читает этот файл и повторно применяет учебные права MySQL. Для +сохранения PostgreSQL используйте отдельную процедуру резервного копирования. + + +## Очистка и переинициализация + +> **Внимание:** все перечисленные ниже команды `clean-*` и `reinit-*` удаляют +> данные и требуют точного подтверждения `CONFIRM=1`. + +```bash +make clean-mysql CONFIRM=1 +make clean-postgres CONFIRM=1 +make clean-all CONFIRM=1 + +make reinit-mysql CONFIRM=1 +make reinit-postgres CONFIRM=1 +make reinit-all CONFIRM=1 +``` + +Одиночные команды удаляют только каталог данных выбранной СУБД. Варианты +`all` удаляют каталоги данных обеих СУБД. Конфигурация, файлы инициализации, +загруженные учебные базы и резервные копии сохраняются. Затем +переинициализация запускает и проверяет выбранные СУБД; `reinit-all` запускает +MySQL, PostgreSQL и Adminer, затем выполняет общую проверку доступа. + +[Вернуться к README](../../../README.md) diff --git a/docs/langs/ru/troubleshooting.md b/docs/langs/ru/troubleshooting.md new file mode 100644 index 0000000..9c744cc --- /dev/null +++ b/docs/langs/ru/troubleshooting.md @@ -0,0 +1,75 @@ +# Диагностика + +[← Вернуться к README](../../../README.md) + +## Язык + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| **Выбран** | [English](../en/troubleshooting.md) | [Español](../es/troubleshooting.md) | [中文](../zh/troubleshooting.md) | [Français](../fr/troubleshooting.md) | [Deutsch](../de/troubleshooting.md) | + +## Раздел + +| Начало работы | Базы и учебные данные | Проверки и эксплуатация | Диагностика | +| --- | --- | --- | --- | +| [Начало работы](getting-started.md) | [Базы и учебные данные](databases.md) | [Проверки и эксплуатация](operations.md) | **Выбран** | + +Сначала соберите диагностику, затем исправьте конкретную причину. Если +изменение всё же требует переинициализации, сохраните собственные данные, если +их нужно оставить, и только после этого используйте подтверждённый +`reinit-... CONFIRM=1` как осознанную последнюю меру. + +Канонические описания жизненного цикла и операций: [базы](databases.md#section-initialization) · [операции](operations.md#section-clean-reinitialize). + + +## Ошибка конфигурации или проверки путей хранения + +Выполните `make check-env` и найдите в ошибке отклонённую переменную и путь. +Контролируемые пути данных должны находиться строго внутри каталога проекта +`data/`, а пути учебных баз — внутри `samples/`. Они не могут содержать +компоненты символических ссылок, +пересекаться между собой или использовать зарезервированные каталоги проекта. +Исправьте `.docker.env`, затем повторите `make check-env` и `make config`. + + +## Сервис не переходит в состояние готовности + +До изменения данных проверьте состояние и логи: + +```bash +make status +make log SERVICE=mysql +make log SERVICE=postgres +``` + +Убедитесь, что Docker запущен, настроенный порт компьютера свободен, а +`.docker.env` содержит обязательные значения. Исправьте конкретную настройку +или конфликт порта и снова запустите сервис. + + +## Изменения инициализации или учебных баз не появились + +Для уже инициализированного каталога данных это ожидаемое поведение. Проверьте +настроенные пути данных и учебных баз и успешность команды подготовки. Если +существующие данные важны, сохраните их. Используйте соответствующую команду +`reinit-... CONFIRM=1` только как осознанную последнюю меру: она удаляет данные +этой СУБД. + + +## Учебная база неполна или имеет неожиданного владельца + +Загрузчик намеренно не перезаписывает и не исправляет неожиданную базу. Повторите +подходящую подготовку `make samples-mysql` или `make samples-postgres` и +изучите ошибку. Сохраните нужные данные, прежде чем рассматривать +переинициализацию с подтверждением. + + +## Клиент не подключается + +Клиенты на компьютере пользователя используют опубликованный адрес и +`MYSQL_PORT` или +`POSTGRES_PORT`, а не имя Compose-сервиса. Adminer использует `mysql` или +`postgres` внутри Compose-сети. Проверьте `BIND_ADDRESS`, межсетевой экран, +выбранную базу и учётные данные непривилегированного пользователя `DB_USER`. + +[Вернуться к README](../../../README.md) diff --git a/docs/langs/zh/databases.md b/docs/langs/zh/databases.md new file mode 100644 index 0000000..d892c48 --- /dev/null +++ b/docs/langs/zh/databases.md @@ -0,0 +1,114 @@ +# 数据库与 samples + +[← 返回 README](../README_zh.md) + +## 语言 + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/databases.md) | [English](../en/databases.md) | [Español](../es/databases.md) | **已选择** | [Français](../fr/databases.md) | [Deutsch](../de/databases.md) | + +## 章节 + +| 入门 | 数据库与 samples | 检查与运维 | 诊断与故障排除 | +| --- | --- | --- | --- | +| [入门](getting-started.md) | **已选择** | [检查与运维](operations.md) | [诊断与故障排除](troubleshooting.md) | + + +## 必需的 `demo` 数据库 + +两种数据库都会初始化 `demo`: + +- MySQL:`demo.demo_users` +- PostgreSQL:`demo.public.demo_users` + +表包含等价字段 `id`、`name`、`email` 和 `created_at`,以及相同的五名 +用户 Alice、Bob、Carol、Dave 和 Eve;检查允许用户添加额外行。 +`make check-env` 要求 `MYSQL_DATABASE=demo` 与 `POSTGRES_DATABASE=demo`。 + + +## 可选 samples + +| 数据库 | 可选数据库 | 准备命令 | +|---|---|---| +| MySQL | `chinook`、`sakila` | `make samples-mysql` | +| PostgreSQL | `pagila`、`chinook` | `make samples-postgres` | + + +## 准备 samples + +准备过程需要 `curl` 和 `git`;MySQL samples 还需要 `unzip` 与 `sha256sum`。 + +准备命令会下载并校验固定的 upstream 文件,但不会启动容器,也不会向 +已初始化数据库导入数据。临时下载仅保存在本地,不提交到 Git,最终位于 +`MYSQL_SAMPLES_DIR` 或 `POSTGRES_SAMPLES_DIR`。来源、完整性固定值和许可 +见 [`THIRD_PARTY_NOTICES.md`](../../../THIRD_PARTY_NOTICES.md)。 + +准备时机以及重新初始化现有数据库的方法见 +[初始化生命周期](#section-initialization)。 + +完全缺失的 sample 会被跳过,不影响创建 `demo`。不完整的 sample 集合或 +意外存在的 sample 数据库会被拒绝,不会自动修复或删除。 + + +## 存储目录结构 + +```text +data/ +├── mysql/ +└── postgres/ + +initdb/ +├── mysql/ +└── postgres/ +``` + +| 数据库 | Data | Init | 可选 samples | +|---|---|---|---| +| MySQL | `MYSQL_DATA_DIR` (`./data/mysql`) | `MYSQL_INITDB_DIR` (`./initdb/mysql`) | `MYSQL_SAMPLES_DIR` (`./samples/mysql`) | +| PostgreSQL | `POSTGRES_DATA_DIR` (`./data/postgres`) | `POSTGRES_INITDB_DIR` (`./initdb/postgres`) | `POSTGRES_SAMPLES_DIR` (`./samples/postgres`) | + +data 与 sample 路径可在 `.docker.env` 中修改,但必须通过 managed path +验证。init 目录的应用规则见[初始化生命周期](#section-initialization)。 +不要手工编辑 `data/` 中的数据库文件,它们可能属于容器使用的数字 UID/GID。 + + +## 初始化生命周期 + +> **重要:** MySQL 与 PostgreSQL 官方 entrypoints 仅对空 data 目录执行 +> init 文件。初始化后添加文件不会改变已有数据库。`make down` 会保留 +> 数据,而确认后的重新初始化会删除所选数据库当前的数据,并根据最新 init +> 脚本重新创建数据库。只有需要保留自己的数据时才需备份;没有重要改动的 +> 一次性学习环境不要求备份。 + +如需在首次初始化时包含 samples,请在第一次启动前准备: + +```bash +make samples-mysql +make up-mysql + +make samples-postgres +make up-postgres +``` + +对于已经初始化的数据库,如有需要请先保留自己的数据,然后只执行对应的确认重新初始化: + +```bash +make samples-mysql +make reinit-mysql CONFIRM=1 + +make samples-postgres +make reinit-postgres CONFIRM=1 +``` + + +## 学习用户访问与 ownership + +MySQL 在 init 时创建 `DB_USER`,并授予它所有非系统数据库的 +访问权。PostgreSQL 创建独立的非 superuser `DB_USER`,不授予 +createdb/createrole,并让它拥有 `demo`、`public` schema 和已加载 +sample 对象。管理员 credentials 保持独立:`MYSQL_ROOT_PASSWORD`、 +`POSTGRES_SUPERUSER` 与 `POSTGRES_SUPERUSER_PASSWORD`。不要手工编辑 +`data/` 中由容器拥有的文件。 + +[返回 README](../README_zh.md) diff --git a/docs/langs/zh/getting-started.md b/docs/langs/zh/getting-started.md new file mode 100644 index 0000000..83db386 --- /dev/null +++ b/docs/langs/zh/getting-started.md @@ -0,0 +1,157 @@ +# 入门 + +[← 返回 README](../README_zh.md) + +## 语言 + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/getting-started.md) | [English](../en/getting-started.md) | [Español](../es/getting-started.md) | **已选择** | [Français](../fr/getting-started.md) | [Deutsch](../de/getting-started.md) | + +## 章节 + +| 入门 | 数据库与 samples | 检查与运维 | 诊断与故障排除 | +| --- | --- | --- | --- | +| **已选择** | [数据库与 samples](databases.md) | [检查与运维](operations.md) | [诊断与故障排除](troubleshooting.md) | + + +## 要求 + +- Docker Engine 或 Docker Desktop,并使用 Docker Compose v2。 +- GNU Make、Bash 和基本 Unix 命令行工具。 +- 推荐环境:Linux;使用 Docker Desktop 的 macOS;或使用 Docker Desktop + 与 WSL2 的 Windows。 + +请在仓库根目录执行命令。项目默认分支为 `master`。 + + +## 快速开始 + +`make init` 会根据 [`.docker.env.example`](../../../.docker.env.example) +创建本地 `.docker.env`,验证受控存储路径并创建工作目录。然后启动完整环境: + +```bash +make init +make up +``` + +`make up` 会启动 MySQL、PostgreSQL 和 Adminer。默认配置下,Adminer +地址为 `http://127.0.0.1:8081`。 + +使用 `make up-no-ui` 可启动两种数据库而不启动 Adminer。首次初始化时 +始终创建必需的 `demo` 数据库;示例数据集是可选的。如需在首次初始化时 +加载它们,请在第一次 `make up` 前完成准备。对于已经初始化的数据目录, +仅在需要保留自己的数据时才在确认重新初始化前备份。准确步骤见 +[初始化生命周期](databases.md#section-initialization)。 + +```bash +make status +make logs +make down +``` + +`make down` 删除容器和网络,但保留 bind-mounted 数据。 + + +## 启动模式 + +| 命令 | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | 启动 | 启动 | 启动 | +| `make up-no-ui` | 启动 | 启动 | 停止 | +| `make up-mysql` | 启动 | 不启动 | 不启动 | +| `make up-postgres` | 不启动 | 启动 | 不启动 | + +单数据库命令不会停止另一种已运行的数据库;Adminer 可单独管理。 + +
+📋 完整启动模式表 + +| 命令 | MySQL | PostgreSQL | Adminer | +|---|---|---|---| +| `make up` | 启动 | 启动 | 启动 | +| `make up-no-ui` | 启动或保持运行 | 启动或保持运行 | 若运行则停止 | +| `make up-mysql` | 启动 | 不自动启动 | 不自动启动 | +| `make up-mysql-ui` | 启动 | 不自动启动 | 启动 | +| `make up-postgres` | 不自动启动 | 启动 | 不自动启动 | +| `make up-postgres-ui` | 不自动启动 | 启动 | 启动 | +| `make up-ui` | 不改变 | 不改变 | 启动 | +| `make down-ui` | 不改变 | 不改变 | 停止 | + +单数据库命令不会停止已经运行的另一种数据库。Adminer 可以单独启停, +并非只服务于 MySQL。 + +
+ + +## 连接 + +### Adminer + +在 Compose 网络内,Adminer 提供两个预设服务器: + +```text +MySQL (mysql) +PostgreSQL (postgres) +``` + +选择服务器后,使用 `DB_USER`、`DB_PASSWORD` 和数据库名(如 `demo`) +登录。`mysql` 与 `postgres` 是 Compose 内部服务名,不是桌面客户端的 +主机名。 + +### 主机客户端 + +| 数据库 | 默认主机 | 端口变量 | 用户 | 默认数据库 | +|---|---|---|---|---| +| MySQL | `127.0.0.1` | `MYSQL_PORT` | `DB_USER` | `demo` | +| PostgreSQL | `127.0.0.1` | `POSTGRES_PORT` | `DB_USER` | `demo` | + +DataGrip、DBeaver、PhpStorm 和主机 CLI 使用发布的地址与端口。如果修改 +`BIND_ADDRESS`,请按需改用对应接口可达的地址。 + +### 容器内 CLI + +Make targets 通过容器环境传递密码,不会把密码写入 shell history: + +```bash +make mysql # MySQL 管理员,demo 数据库 +make mysql-user # DB_USER,demo 数据库 +make postgres # PostgreSQL 超级用户,demo 数据库 +make postgres-user # DB_USER,demo 数据库 +``` + + +## 凭据 + +`.docker.env` 从 [`.docker.env.example`](../../../.docker.env.example) 创建,并被 Git 忽略。密码应保存在 +该文件中,不要硬编码进受版本控制的 Compose、SQL 或客户端配置。 + +| 用途 | 用户设置 | 密码设置 | +|---|---|---| +| 两种数据库共用的学习用户 | `DB_USER` | `DB_PASSWORD` | +| MySQL 管理员 | `root` | `MYSQL_ROOT_PASSWORD` | +| PostgreSQL 管理员/超级用户 | `POSTGRES_SUPERUSER` | `POSTGRES_SUPERUSER_PASSWORD` | + +`POSTGRES_SUPERUSER` 与 `DB_USER` 必须是不同角色。日常练习应使用学习 +用户。对外共享或发布服务前,请替换示例密码。 + + +## 端口与 `BIND_ADDRESS` + +| 服务 | 端口变量 | 示例默认值 | +|---|---|---| +| MySQL | `MYSQL_PORT` | `3306` | +| PostgreSQL | `POSTGRES_PORT` | `5432` | +| Adminer | `ADMINER_PORT` | `8081` | + +默认情况下,三个服务只绑定 loopback: + +```env +BIND_ADDRESS=127.0.0.1 +``` + +`127.0.0.1` 是本地默认值。`BIND_ADDRESS=0.0.0.0` 会在所有网络接口上 +发布端口。LAN 或 VPN 访问应优先使用具体接口的地址。修改时必须明确 +评估 firewall、密码强度和网络可信度。 + +[返回 README](../README_zh.md) diff --git a/docs/langs/zh/operations.md b/docs/langs/zh/operations.md new file mode 100644 index 0000000..b4438df --- /dev/null +++ b/docs/langs/zh/operations.md @@ -0,0 +1,158 @@ +# 检查与运维 + +[← 返回 README](../README_zh.md) + +## 语言 + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/operations.md) | [English](../en/operations.md) | [Español](../es/operations.md) | **已选择** | [Français](../fr/operations.md) | [Deutsch](../de/operations.md) | + +## 章节 + +| 入门 | 数据库与 samples | 检查与运维 | 诊断与故障排除 | +| --- | --- | --- | --- | +| [入门](getting-started.md) | [数据库与 samples](databases.md) | **已选择** | [诊断与故障排除](troubleshooting.md) | + + +## 公共 Make targets + +公共 targets 及其实现位于 [`Makefile`](../../../Makefile)。 + +关键 targets 包括 `make init`、`make up`、`make down`、 +`make check`、`make test-storage-paths`、`make test-sql-imports`、 +`make mysql-import` 和 `make postgres-import`。Trusted SQL 不是 +sandbox,可能 partial execution,且不保证 automatic rollback;重要导入 +前先做 backup。内置 backup targets 仅覆盖 MySQL `demo`,不覆盖 +PostgreSQL。`clean-*` 与 `reinit-*` 是 destructive 操作,并要求精确 +`CONFIRM=1`。 + +
+📋 完整公共 Make targets 参考 + +`make help` 显示简要命令列表。 + +| 命令 | 用途 | +|---|---| +| `make init` | 创建 `.docker.env`、验证 managed paths、创建目录 | +| `make check-env` | 检查 env、角色分离、数据库名与 managed paths | +| `make pull` | 拉取三个固定版本的镜像 | +| `make config` | 验证展开后的 Compose 配置 | +| `make up`、`make up-no-ui` | 启动两个数据库,启用或不启用 Adminer | +| `make up-mysql`、`make up-mysql-ui` | 启动 MySQL,可选 Adminer | +| `make up-postgres`、`make up-postgres-ui` | 启动 PostgreSQL,可选 Adminer | +| `make up-ui`、`make down-ui` | 仅启动或停止 Adminer | +| `make down` | 停止环境但不删除 bind-mounted 数据 | +| `make status`、`make logs` | 查看状态或跟踪所有日志 | +| `make log SERVICE=postgres` | 跟踪单个服务;也支持 `make log postgres` | +| `make in SERVICE=postgres` | 打开服务 shell;也支持 `make in postgres` | +| `make mysql`、`make mysql-user` | 以管理员或 `DB_USER` 打开 MySQL | +| `make postgres`、`make postgres-user` | 以超级用户或 `DB_USER` 打开 PostgreSQL | +| `make samples-mysql`、`make samples-postgres` | 准备已校验的 samples | +| `make check-mysql-access`、`make check-postgres-access` | 检查一个运行中的数据库 | +| `make check` | 验证 Compose 及 `DB_USER` 对两种数据库的访问 | +| `make test-storage-paths` | 无需 Docker runtime 测试 managed path 保护 | +| `make test-sql-imports` | smoke-test 两个公共 SQL import targets | +| `make mysql-import FILE=... DATABASE=...` | 以 `DB_USER` 向 MySQL 导入 plain SQL | +| `make postgres-import FILE=... DATABASE=...` | 以 `DB_USER` 向 PostgreSQL 导入 plain SQL | +| `make dump`、`make restore` | 备份或恢复 MySQL `demo` | +| `make clean-{mysql,postgres,all} CONFIRM=1` | 删除选定的 data 目录 | +| `make reinit-{mysql,postgres,all} CONFIRM=1` | 删除、重建并检查数据库 | + +
+ + +## 检查 + +### 静态与本地检查 + +```bash +make check-env +make config +make test-storage-paths +``` + +`make check-env` 在缺失时创建 `.docker.env`,然后验证配置与 managed +paths。`make config` 验证展开后的 Compose 模型。`make test-storage-paths` +不需要 Docker runtime;它测试项目外路径、symlink 组件、路径重叠/嵌套 +以及 reserved directories。 + +### Runtime 检查 + +```bash +make up-no-ui +make check +make test-sql-imports +make down +``` + +`make check` 验证必需的 `demo` 数据和 `DB_USER` 的实际访问,也检查已安装 +的可选 samples。`make test-sql-imports` 要求两种数据库都已启动;它调用 +公共 `mysql-import` 与 `postgres-import`,在 `demo` 中创建唯一命名的临时 +表,以 `DB_USER` 验证 marker rows,并且只删除这些表。这是 trusted import +工作流的 smoke-test,不是 sandbox,也不能证明不可信 SQL 的安全性。 + + +## Storage path 安全 + +`make check-env` 会运行 +[`scripts/validate-storage-paths.sh`](../../../scripts/validate-storage-paths.sh)。Data +paths 必须严格位于 `data/` 内,sample paths 必须严格位于 +`samples/` 内;symlink、相同、嵌套、重叠和 reserved paths 都会被拒绝。 +`make test-storage-paths` 无需 Docker runtime 即可测试这些规则。 + + +## Trusted SQL 导入 + +```bash +make mysql-import FILE=path/to/file.sql DATABASE=demo +make postgres-import FILE=path/to/file.sql DATABASE=demo +``` + +两个 targets 都遵循以下规则: + +- `FILE` 与 `DATABASE` 必填。 +- 文件必须是存在、可读、非空的本地 plain SQL。 +- 数据库必须已存在;禁止系统数据库。 +- import 以 `DB_USER` 执行,不创建数据库,也不授予 grants。 +- `DATABASE` 只选择初始连接,不创建 sandbox。 +- qualified names、client/session commands 及真实 grants 可能影响其他 + 可访问对象。 +- 可能发生 partial execution;不承诺自动 rollback。 +- 重要导入前必须备份。 +- 不处理 gzip、archives 或 PostgreSQL custom-format backups。 + + +## 备份 + +内置 targets 只覆盖配置的 MySQL `demo` 数据库: + +```bash +make dump +make restore +``` + +`make dump` 写入 `backup/demo.sql`;`make restore` 读取该文件并重新应用 +MySQL 学习 grants。PostgreSQL 数据应使用独立备份流程。 + + +## 清理与重新初始化 + +> **警告:** 所有 `clean-*` 和 `reinit-*` 命令都是破坏性的,并且要求 +> 精确确认 `CONFIRM=1`。 + +```bash +make clean-mysql CONFIRM=1 +make clean-postgres CONFIRM=1 +make clean-all CONFIRM=1 + +make reinit-mysql CONFIRM=1 +make reinit-postgres CONFIRM=1 +make reinit-all CONFIRM=1 +``` + +单数据库命令只删除对应 data 目录;`all` 会删除两种数据库的数据。配置、 +init、samples 和 backups 会保留。reinit 随后启动并检查所选数据库; +`reinit-all` 会启动 MySQL、PostgreSQL 和 Adminer,然后执行共享访问检查。 + +[返回 README](../README_zh.md) diff --git a/docs/langs/zh/troubleshooting.md b/docs/langs/zh/troubleshooting.md new file mode 100644 index 0000000..c26f901 --- /dev/null +++ b/docs/langs/zh/troubleshooting.md @@ -0,0 +1,59 @@ +# 诊断与故障排除 + +[← 返回 README](../README_zh.md) + +## 语言 + +| Русский | English | Español | 中文 | Français | Deutsch | +| --- | --- | --- | --- | --- | --- | +| [Русский](../ru/troubleshooting.md) | [English](../en/troubleshooting.md) | [Español](../es/troubleshooting.md) | **已选择** | [Français](../fr/troubleshooting.md) | [Deutsch](../de/troubleshooting.md) | + +## 章节 + +| 入门 | 数据库与 samples | 检查与运维 | 诊断与故障排除 | +| --- | --- | --- | --- | +| [入门](getting-started.md) | [数据库与 samples](databases.md) | [检查与运维](operations.md) | **已选择** | + +先收集诊断信息,再针对原因修正。若仍需重新初始化,仅在需要保留自己的 +数据时才备份,并仅将确认后的 `reinit-... CONFIRM=1` 作为有意的最后手段。 + +生命周期与运维的规范说明:[数据库](databases.md#section-initialization) · [运维](operations.md#section-clean-reinitialize)。 + + +## 配置或 storage path 验证失败 + +运行 `make check-env`。data paths 必须严格位于 `data/` 内,samples 必须 +位于 `samples/` 内;不得包含 symlink、互相重叠或使用 reserved +directories。修正 `.docker.env` 后运行 `make config`。 + + +## 服务未就绪 + +```bash +make status +make log SERVICE=mysql +make log SERVICE=postgres +``` + +在修改数据前,检查 Docker、端口、`.docker.env` 与日志。 + + +## init 修改或 samples 未出现 + +如果 data 已初始化,这是预期行为。检查路径与准备命令;若需保留重要数据, +请备份,并仅在明确需要时最后使用 `reinit-... CONFIRM=1`。 + + +## sample 不完整或所有者异常 + +loader 不会覆盖或修复意外数据库。重新运行 `make samples-mysql` 或 +`make samples-postgres` 并检查错误;重新初始化前先保留所需数据。 + + +## 客户端无法连接 + +主机客户端使用发布地址及 `MYSQL_PORT` 或 `POSTGRES_PORT`;Adminer 在 +Compose 网络中使用 `mysql` 或 `postgres`。检查 `BIND_ADDRESS`、 +firewall、数据库选择和非管理员 `DB_USER` 凭据。 + +[返回 README](../README_zh.md) diff --git a/initdb/mysql/030_training_database.sql.example b/initdb/mysql/030_training_database.sql.example index 29b8f2f..398c496 100644 --- a/initdb/mysql/030_training_database.sql.example +++ b/initdb/mysql/030_training_database.sql.example @@ -22,51 +22,50 @@ -- При чистой инициализации порядок будет таким: -- -- 001_demo.sql --- 050_load_optional_samples.sh -- 030_shop.sql +-- 050_load_optional_samples.sh -- 090_grant_training_access.sh -- 099_check_training_access.sh -- --- Grant-скрипт обнаружит новую базу shop автоматически. +-- Grant-скрипт обнаружит новую пользовательскую базу shop и выдаст +-- учебному пользователю доступ к ней во время чистой инициализации. -- -- ============================================================================ -- Вариант 2. Добавить базу в уже работающий MySQL без удаления данных -- ============================================================================ -- --- Подготовьте файл: +-- Административно создайте новую базу отдельно, затем примените grants: -- --- cp initdb/mysql/030_training_database.sql.example initdb/mysql/030_shop.sql +-- make mysql-grants -- --- Отредактируйте его и выполните: +-- Подготовьте доверенный plain SQL-файл со схемой и данными для уже созданной +-- базы shop. В нём не должно быть CREATE DATABASE и USE. -- --- make mysql-import FILE=initdb/mysql/030_shop.sql +-- Выполните импорт: -- --- Команда: +-- make mysql-import FILE=/path/to/shop.sql DATABASE=shop -- --- 1. импортирует SQL от имени root; --- 2. повторно выдаст DB_USER права на все учебные базы; --- 3. проверит доступ учебного пользователя. +-- mysql-import требует FILE и DATABASE, выполняет импорт от имени DB_USER, +-- не создаёт базу и не выдаёт grants, а после импорта запускает проверку +-- доступа учебного пользователя. -- -- ============================================================================ -- Вариант 3. Добавить сторонний SQL dump -- ============================================================================ -- --- Если dump уже содержит: +-- Сторонний dump нужно привести к форме schema/data-only без database-level +-- directives (CREATE DATABASE и USE), а административное создание или +-- восстановление базы выполнить отдельно от mysql-import. -- --- CREATE DATABASE ... --- USE ... +-- mysql-import предназначен для доверенного plain SQL внутри уже +-- существующей базы; он не является sandbox для недоверенного SQL. -- --- его можно импортировать напрямую: +-- Например, если dump содержит: -- --- make mysql-import FILE=/path/to/database.sql --- --- Если dump содержит только CREATE TABLE / INSERT, добавьте в начало: --- --- CREATE DATABASE IF NOT EXISTS `shop` --- CHARACTER SET utf8mb4 --- COLLATE utf8mb4_0900_ai_ci; +-- CREATE DATABASE ... +-- USE ... -- --- USE `shop`; +-- удалите эти директивы перед импортом. -- -- ============================================================================ -- Вариант 4. Разделить схему и данные на несколько файлов @@ -78,7 +77,8 @@ -- initdb/mysql/031_shop_data.sql -- -- Главное требование: оба файла должны выполняться раньше --- 090_grant_training_access.sh. +-- 050_load_optional_samples.sh, 090_grant_training_access.sh и +-- 099_check_training_access.sh. -- -- ============================================================================ -- Пример содержимого учебной базы diff --git a/scripts/test-sql-imports.sh b/scripts/test-sql-imports.sh new file mode 100755 index 0000000..e016eb4 --- /dev/null +++ b/scripts/test-sql-imports.sh @@ -0,0 +1,151 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +project_dir="$(cd -- "${script_dir}/.." && pwd)" +cd -- "${project_dir}" + +fail() { + printf 'ERROR: %s\n' "$*" >&2 + exit 1 +} + +[[ -f .docker.env ]] || fail '.docker.env is required; run make init first' + +set -a +source .docker.env +set +a + +for variable_name in COMPOSE_PROJECT_NAME DB_USER DB_PASSWORD; do + [[ -n "${!variable_name:-}" ]] || fail "${variable_name} is required in .docker.env" +done + +compose=(docker compose --env-file .docker.env -p "${COMPOSE_PROJECT_NAME}") +temp_dir="$(mktemp -d)" +mysql_table='' +postgres_table='' +mysql_cleanup_needed=false +postgres_cleanup_needed=false + +assert_safe_identifier() { + local identifier="$1" + + [[ "${identifier}" =~ ^[a-z][a-z0-9_]{0,62}$ ]] || \ + fail "generated unsafe SQL identifier: ${identifier}" +} + +mysql_query() { + local query="$1" + + "${compose[@]}" exec -T \ + -e IMPORT_DATABASE=demo \ + -e IMPORT_QUERY="${query}" \ + mysql sh -c 'MYSQL_PWD="$DB_PASSWORD" exec mysql --host=127.0.0.1 --user="$DB_USER" --batch --skip-column-names "$IMPORT_DATABASE" --execute "$IMPORT_QUERY"' +} + +postgres_query() { + local query="$1" + + "${compose[@]}" exec -T \ + -e IMPORT_DATABASE=demo \ + -e IMPORT_QUERY="${query}" \ + postgres sh -c 'PGPASSWORD="$DB_PASSWORD" exec psql --host=127.0.0.1 --username="$DB_USER" --dbname="$IMPORT_DATABASE" --no-psqlrc --set=ON_ERROR_STOP=1 --tuples-only --no-align --command="$IMPORT_QUERY"' +} + +drop_smoke_tables() { + local cleanup_failed=0 + + if [[ "${mysql_cleanup_needed}" == true ]]; then + if mysql_query "DROP TABLE IF EXISTS \`${mysql_table}\`;" >/dev/null; then + mysql_cleanup_needed=false + else + printf 'ERROR: failed to remove MySQL smoke table\n' >&2 + cleanup_failed=1 + fi + fi + if [[ "${postgres_cleanup_needed}" == true ]]; then + if postgres_query "DROP TABLE IF EXISTS public.${postgres_table};" >/dev/null; then + postgres_cleanup_needed=false + else + printf 'ERROR: failed to remove PostgreSQL smoke table\n' >&2 + cleanup_failed=1 + fi + fi + + return "${cleanup_failed}" +} + +cleanup() { + local exit_status=$? + local cleanup_failed=0 + local final_status + + trap - EXIT + set +e + + if ! drop_smoke_tables; then + cleanup_failed=1 + fi + if ! rm -rf -- "${temp_dir}"; then + printf 'ERROR: failed to remove smoke-test temporary directory\n' >&2 + cleanup_failed=1 + fi + if ((cleanup_failed)); then + printf 'ERROR: trusted SQL import smoke-test cleanup failed\n' >&2 + fi + + final_status="${exit_status}" + if ((exit_status == 0 && cleanup_failed)); then + final_status=1 + fi + + exit "${final_status}" +} +trap cleanup EXIT + +make --no-print-directory wait-mysql +make --no-print-directory wait-postgres + +suffix="$(date +%s)_$$_${RANDOM}" +mysql_table="sql_import_smoke_mysql_${suffix}" +postgres_table="sql_import_smoke_postgres_${suffix}" +mysql_marker="mysql_import_marker_${suffix}" +postgres_marker="postgres_import_marker_${suffix}" + +assert_safe_identifier "${mysql_table}" +assert_safe_identifier "${postgres_table}" + +[[ "$(mysql_query "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = '${mysql_table}';")" == 0 ]] || \ + fail "MySQL smoke table already exists: ${mysql_table}" +[[ "$(postgres_query "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_name = '${postgres_table}';")" == 0 ]] || \ + fail "PostgreSQL smoke table already exists: ${postgres_table}" + +mysql_sql="${temp_dir}/mysql-import.sql" +postgres_sql="${temp_dir}/postgres-import.sql" + +printf 'CREATE TABLE `%s` (marker VARCHAR(255) NOT NULL);\nINSERT INTO `%s` (marker) VALUES (\047%s\047);\n' \ + "${mysql_table}" "${mysql_table}" "${mysql_marker}" > "${mysql_sql}" +printf 'CREATE TABLE public.%s (marker TEXT NOT NULL);\nINSERT INTO public.%s (marker) VALUES (\047%s\047);\n' \ + "${postgres_table}" "${postgres_table}" "${postgres_marker}" > "${postgres_sql}" + +mysql_cleanup_needed=true +make mysql-import FILE="${mysql_sql}" DATABASE=demo +[[ "$(mysql_query "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = '${mysql_table}';")" == 1 ]] || \ + fail "MySQL smoke table was not created: ${mysql_table}" +[[ "$(mysql_query "SELECT marker FROM \`${mysql_table}\`;")" == "${mysql_marker}" ]] || \ + fail 'MySQL smoke marker did not match' + +postgres_cleanup_needed=true +make postgres-import FILE="${postgres_sql}" DATABASE=demo +[[ "$(postgres_query "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_name = '${postgres_table}';")" == 1 ]] || \ + fail "PostgreSQL smoke table was not created: ${postgres_table}" +[[ "$(postgres_query "SELECT marker FROM public.${postgres_table};")" == "${postgres_marker}" ]] || \ + fail 'PostgreSQL smoke marker did not match' + +drop_smoke_tables +[[ "$(mysql_query "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = '${mysql_table}';")" == 0 ]] || \ + fail "MySQL smoke table still exists: ${mysql_table}" +[[ "$(postgres_query "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_name = '${postgres_table}';")" == 0 ]] || \ + fail "PostgreSQL smoke table still exists: ${postgres_table}" + +printf 'PASS: trusted SQL import smoke tests completed\n' diff --git a/scripts/test-storage-paths.sh b/scripts/test-storage-paths.sh new file mode 100755 index 0000000..cea5300 --- /dev/null +++ b/scripts/test-storage-paths.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +validator="$script_dir/validate-storage-paths.sh" +temp_dir="$(mktemp -d)" +project_dir="$temp_dir/project" +outside_dir="$temp_dir/outside" +failures=0 + +cleanup() { + rm -rf -- "$temp_dir" +} +trap cleanup EXIT + +mkdir -p \ + "$project_dir/data/mysql" \ + "$project_dir/data/postgres" \ + "$project_dir/samples/mysql" \ + "$project_dir/samples/postgres" \ + "$outside_dir" + +run_validator() { + local mysql_data="${1-$project_dir/data/mysql}" + local postgres_data="${2-$project_dir/data/postgres}" + local mysql_samples="${3-$project_dir/samples/mysql}" + local postgres_samples="${4-$project_dir/samples/postgres}" + + "$validator" \ + --project-dir "$project_dir" \ + --mysql-data "$mysql_data" \ + --postgres-data "$postgres_data" \ + --mysql-samples "$mysql_samples" \ + --postgres-samples "$postgres_samples" +} + +expect_accept() { + local case_name="$1" + shift + + if ! run_validator "$@" >/dev/null 2>&1; then + printf 'FAIL: positive case %q was rejected\n' "$case_name" >&2 + failures=$((failures + 1)) + fi +} + +expect_reject() { + local case_name="$1" + shift + + if run_validator "$@" >/dev/null 2>&1; then + printf 'FAIL: negative case %q was accepted\n' "$case_name" >&2 + failures=$((failures + 1)) + fi +} + +expect_accept 'default managed paths' +expect_accept 'relative data and sample paths' \ + 'data/mysql' \ + 'data/postgres' \ + 'samples/mysql' \ + 'samples/postgres' +expect_accept 'other names strictly inside their roots' \ + "$project_dir/data/mysql-v2" \ + "$project_dir/data/postgres-v2" \ + "$project_dir/samples/mysql-extra" \ + "$project_dir/samples/postgres-extra" + +fresh_clone_project_dir="$temp_dir/fresh-clone" +mkdir -p "$fresh_clone_project_dir" +if ! "$validator" \ + --project-dir "$fresh_clone_project_dir" \ + --mysql-data 'data/mysql' \ + --postgres-data 'data/postgres' \ + --mysql-samples 'samples/mysql' \ + --postgres-samples 'samples/postgres' \ + >/dev/null 2>&1; then + printf 'FAIL: positive case %q was rejected\n' 'fresh clone without managed directories' >&2 + failures=$((failures + 1)) +fi +if [[ -e "$fresh_clone_project_dir/data" || -e "$fresh_clone_project_dir/samples" ]]; then + printf 'FAIL: validator created managed directories in %q\n' "$fresh_clone_project_dir" >&2 + failures=$((failures + 1)) +fi + +docs_project_dir="$temp_dir/docs/projects/sql-lab" +mkdir -p \ + "$docs_project_dir/data/mysql" \ + "$docs_project_dir/data/postgres" \ + "$docs_project_dir/samples/mysql" \ + "$docs_project_dir/samples/postgres" +if ! "$validator" \ + --project-dir "$docs_project_dir" \ + --mysql-data "$docs_project_dir/data/mysql" \ + --postgres-data "$docs_project_dir/data/postgres" \ + --mysql-samples "$docs_project_dir/samples/mysql" \ + --postgres-samples "$docs_project_dir/samples/postgres" \ + >/dev/null 2>&1; then + printf 'FAIL: positive case %q was rejected\n' 'project under docs/projects/sql-lab' >&2 + failures=$((failures + 1)) +fi + +expect_reject '.git' "$project_dir/.git" +expect_reject '.github' "$project_dir/data/mysql" "$project_dir/data/postgres" "$project_dir/.github" +expect_reject 'project root' "$project_dir" +expect_reject 'data root' "$project_dir/data" +expect_reject 'samples root' "$project_dir/data/mysql" "$project_dir/data/postgres" "$project_dir/samples" +expect_reject 'outside directory' "$outside_dir" +expect_reject 'relative outside directory' '../outside' +expect_reject 'empty path' '' +expect_reject 'filesystem root' '/' + +for reserved_component in .git .github initdb conf adminer backup .tmp docs scripts; do + expect_reject "reserved component $reserved_component" \ + "$project_dir/data/$reserved_component/mysql" +done + +ln -s "$project_dir/data/mysql" "$project_dir/data/mysql-link" +expect_reject 'symlink managed path' "$project_dir/data/mysql-link" + +ln -s "$outside_dir" "$project_dir/data/escape" +expect_reject 'symlink component outside project' "$project_dir/data/escape/nested" + +expect_reject 'same data paths' "$project_dir/data/mysql" "$project_dir/data/mysql" +expect_reject 'nested data paths' "$project_dir/data/mysql" "$project_dir/data/mysql/nested" +expect_reject 'same sample paths' \ + "$project_dir/data/mysql" \ + "$project_dir/data/postgres" \ + "$project_dir/samples/mysql" \ + "$project_dir/samples/mysql" +expect_reject 'nested sample paths' \ + "$project_dir/data/mysql" \ + "$project_dir/data/postgres" \ + "$project_dir/samples/mysql" \ + "$project_dir/samples/mysql/nested" +expect_reject 'sample inside data' \ + "$project_dir/data/mysql" \ + "$project_dir/data/postgres" \ + "$project_dir/data/mysql/sample" +expect_reject 'data inside sample' \ + "$project_dir/samples/mysql/data" \ + "$project_dir/data/postgres" + +if ((failures > 0)); then + printf 'FAIL: %d storage-path test case(s) failed\n' "$failures" >&2 + exit 1 +fi + +printf 'PASS: storage-path validator tests completed\n' diff --git a/scripts/validate-storage-paths.sh b/scripts/validate-storage-paths.sh new file mode 100755 index 0000000..260706a --- /dev/null +++ b/scripts/validate-storage-paths.sh @@ -0,0 +1,173 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +usage() { + cat >&2 <<'USAGE' +Usage: validate-storage-paths.sh \ + --project-dir PATH \ + --mysql-data PATH \ + --postgres-data PATH \ + --mysql-samples PATH \ + --postgres-samples PATH +USAGE +} + +reject() { + local variable_name="$1" + local rejected_path="$2" + local reason="$3" + + printf 'ERROR: %s: rejected path %q (%s)\n' \ + "$variable_name" "$rejected_path" "$reason" >&2 + exit 1 +} + +require_value() { + local variable_name="$1" + local value="$2" + + [[ -n "$value" ]] || reject "$variable_name" "$value" 'path must not be empty' +} + +is_strict_descendant() { + local parent="$1" + local child="$2" + + [[ "$child" == "$parent/"* ]] +} + +contains_reserved_component() { + local managed_path="$1" + local component + local -a components + local -a reserved_components=(.git .github initdb conf adminer backup .tmp docs scripts) + + IFS='/' read -r -a components <<< "$managed_path" + for component in "${components[@]}"; do + case "$component" in + ''|.|..|data|samples) ;; + *) + local reserved + for reserved in "${reserved_components[@]}"; do + [[ "$component" == "$reserved" ]] && return 0 + done + ;; + esac + done + + return 1 +} + +has_symlink_component() { + local path="$1" + local component + local current=/ + local -a components + + IFS='/' read -r -a components <<< "$path" + for component in "${components[@]}"; do + case "$component" in + ''|.) continue ;; + ..) current="$current/.." ;; + *) current="$current/$component" ;; + esac + + [[ -L "$current" ]] && return 0 + done + + return 1 +} + +project_dir='' +mysql_data='' +postgres_data='' +mysql_samples='' +postgres_samples='' + +while (($#)); do + case "$1" in + --project-dir|--mysql-data|--postgres-data|--mysql-samples|--postgres-samples) + (($# >= 2)) || { usage; exit 2; } + case "$1" in + --project-dir) project_dir="$2" ;; + --mysql-data) mysql_data="$2" ;; + --postgres-data) postgres_data="$2" ;; + --mysql-samples) mysql_samples="$2" ;; + --postgres-samples) postgres_samples="$2" ;; + esac + shift 2 + ;; + --help|-h) + usage + exit 0 + ;; + *) + printf 'ERROR: unknown argument: %s\n' "$1" >&2 + usage + exit 2 + ;; + esac +done + +require_value PROJECT_DIR "$project_dir" +require_value MYSQL_DATA_DIR "$mysql_data" +require_value POSTGRES_DATA_DIR "$postgres_data" +require_value MYSQL_SAMPLES_DIR "$mysql_samples" +require_value POSTGRES_SAMPLES_DIR "$postgres_samples" + +project_dir_abs="$(realpath -m -- "$project_dir")" +[[ -d "$project_dir_abs" ]] || reject PROJECT_DIR "$project_dir" 'project directory does not exist' + +data_root="$project_dir_abs/data" +samples_root="$project_dir_abs/samples" + +variable_names=(MYSQL_DATA_DIR POSTGRES_DATA_DIR MYSQL_SAMPLES_DIR POSTGRES_SAMPLES_DIR) +raw_paths=("$mysql_data" "$postgres_data" "$mysql_samples" "$postgres_samples") +allowed_roots=("$data_root" "$data_root" "$samples_root" "$samples_root") +resolved_paths=() + +for index in "${!variable_names[@]}"; do + variable_name="${variable_names[$index]}" + raw_path="${raw_paths[$index]}" + allowed_root="${allowed_roots[$index]}" + + if [[ "$raw_path" == /* ]]; then + path_to_inspect="$raw_path" + else + path_to_inspect="$project_dir_abs/$raw_path" + fi + + if has_symlink_component "$path_to_inspect"; then + reject "$variable_name" "$raw_path" 'managed path contains a symbolic-link component' + fi + + resolved_path="$(realpath -m -- "$path_to_inspect")" + if ! is_strict_descendant "$allowed_root" "$resolved_path"; then + reject "$variable_name" "$raw_path" "must be strictly inside $allowed_root" + fi + + managed_path="${resolved_path#"$project_dir_abs"/}" + if contains_reserved_component "$managed_path"; then + reject "$variable_name" "$raw_path" 'managed path contains a reserved component' + fi + + resolved_paths[$index]="$resolved_path" +done + +for ((left = 0; left < ${#resolved_paths[@]}; left++)); do + for ((right = left + 1; right < ${#resolved_paths[@]}; right++)); do + left_path="${resolved_paths[$left]}" + right_path="${resolved_paths[$right]}" + + if [[ "$left_path" == "$right_path" ]]; then + reject "${variable_names[$left]}" "${raw_paths[$left]}" \ + "must not match ${variable_names[$right]}" + fi + + if is_strict_descendant "$left_path" "$right_path" || \ + is_strict_descendant "$right_path" "$left_path"; then + reject "${variable_names[$left]}" "${raw_paths[$left]}" \ + "must not be nested with ${variable_names[$right]}" + fi + done +done