first commit

This commit is contained in:
2026-03-11 22:04:36 +04:00
commit bae063a4fa
69 changed files with 12411 additions and 0 deletions
+209
View File
@@ -0,0 +1,209 @@
#!/usr/bin/env bash
set -Eeuo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
ENV_FILE="${ENV_FILE:-${ROOT_DIR}/.env}"
COMPOSE_FILE="${COMPOSE_FILE:-${ROOT_DIR}/compose.yaml}"
APP_SERVICE="${APP_SERVICE:-laravel.test}"
DB_SERVICE="${DB_SERVICE:-mysql}"
COMPOSER_IMAGE="${COMPOSER_IMAGE:-composer:2}"
BUILD_IMAGES=1
WARM_CACHE=1
usage() {
cat <<'EOF'
Использование:
./scripts/deploy-ubuntu.sh [--skip-build] [--skip-cache]
Что делает скрипт:
1. Создаёт .env из .env.example, если файла ещё нет
2. Подготавливает storage/bootstrap cache директории
3. Собирает docker-образ приложения
4. Устанавливает production-зависимости Composer внутри контейнера
5. Генерирует APP_KEY, если он пустой
6. Поднимает контейнеры
7. Ждёт готовности MySQL
8. Запускает миграции и прогревает Laravel-кэш
Требования:
- Ubuntu с установленными Docker Engine и Docker Compose Plugin
- настроенный .env с корректными значениями APP_URL и AZEROTHCORE_AUTH_DB_*
EOF
}
log() {
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
}
fail() {
printf '[error] %s\n' "$*" >&2
exit 1
}
require_command() {
command -v "$1" >/dev/null 2>&1 || fail "Не найдена команда: $1"
}
env_value() {
local key="$1"
[[ -f "$ENV_FILE" ]] || return 0
grep -E "^${key}=" "$ENV_FILE" | tail -n 1 | cut -d '=' -f 2- | sed -e 's/^"//' -e 's/"$//'
}
set_env_value() {
local key="$1"
local value="$2"
if grep -qE "^${key}=" "$ENV_FILE"; then
sed -i "s#^${key}=.*#${key}=${value}#" "$ENV_FILE"
else
printf '%s=%s\n' "$key" "$value" >> "$ENV_FILE"
fi
}
compose() {
docker compose -f "$COMPOSE_FILE" "$@"
}
composer_install() {
docker run --rm \
-u "${WWWUSER}:${WWWGROUP}" \
-v "${ROOT_DIR}:/app" \
-w /app \
"$COMPOSER_IMAGE" \
install --no-dev --prefer-dist --optimize-autoloader --no-interaction
}
app_exec() {
compose exec -T --user "${WWWUSER}:${WWWGROUP}" "$APP_SERVICE" "$@"
}
wait_for_mysql() {
local container_id
local status
local attempts=0
local max_attempts=60
container_id="$(compose ps -q "$DB_SERVICE")"
[[ -n "$container_id" ]] || fail "Не удалось определить контейнер MySQL"
while (( attempts < max_attempts )); do
status="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container_id" 2>/dev/null || true)"
if [[ "$status" == "healthy" || "$status" == "running" ]]; then
log "MySQL готов"
return 0
fi
attempts=$((attempts + 1))
sleep 2
done
fail "MySQL не перешёл в готовое состояние"
}
prepare_env() {
if [[ -f "$ENV_FILE" ]]; then
return 0
fi
[[ -f "${ROOT_DIR}/.env.example" ]] || fail "Не найден .env.example"
cp "${ROOT_DIR}/.env.example" "$ENV_FILE"
set_env_value "APP_ENV" "production"
set_env_value "APP_DEBUG" "false"
log "Создан ${ENV_FILE} из .env.example"
log "Проверь APP_URL и AZEROTHCORE_AUTH_DB_* перед публичным запуском"
}
prepare_directories() {
mkdir -p \
"${ROOT_DIR}/bootstrap/cache" \
"${ROOT_DIR}/storage/app" \
"${ROOT_DIR}/storage/framework/cache/data" \
"${ROOT_DIR}/storage/framework/sessions" \
"${ROOT_DIR}/storage/framework/testing" \
"${ROOT_DIR}/storage/framework/views" \
"${ROOT_DIR}/storage/logs"
chmod -R ug+rwx "${ROOT_DIR}/bootstrap/cache" "${ROOT_DIR}/storage"
}
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
--skip-build)
BUILD_IMAGES=0
;;
--skip-cache)
WARM_CACHE=0
;;
-h|--help)
usage
exit 0
;;
*)
fail "Неизвестный аргумент: $1"
;;
esac
shift
done
}
main() {
parse_args "$@"
require_command docker
docker compose version >/dev/null 2>&1 || fail "Не найден Docker Compose Plugin"
cd "$ROOT_DIR"
prepare_env
prepare_directories
WWWUSER="$(env_value WWWUSER)"
WWWGROUP="$(env_value WWWGROUP)"
WWWUSER="${WWWUSER:-1000}"
WWWGROUP="${WWWGROUP:-1000}"
log "Устанавливаю production-зависимости Composer"
composer_install
if (( BUILD_IMAGES )); then
log "Собираю образ приложения"
compose build "$APP_SERVICE"
fi
if [[ -z "$(env_value APP_KEY)" ]]; then
log "Генерирую APP_KEY"
compose run --rm --no-deps --user "${WWWUSER}:${WWWGROUP}" --entrypoint php "$APP_SERVICE" artisan key:generate --force
fi
log "Поднимаю контейнеры"
compose up -d
wait_for_mysql
log "Выполняю миграции"
app_exec php artisan migrate --force
if (( WARM_CACHE )); then
log "Обновляю Laravel-кэш"
app_exec php artisan optimize:clear
app_exec php artisan config:cache
app_exec php artisan route:cache
app_exec php artisan view:cache
fi
log "Деплой завершён"
log "Сайт доступен по адресу: $(env_value APP_URL)"
log "Проверка контейнеров: docker compose -f ${COMPOSE_FILE} ps"
}
main "$@"