работа с контейнерами
This commit is contained in:
Executable
+120
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -Eeuo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
|
||||
PROD_COMPOSE="${ROOT_DIR}/compose.prod.yaml"
|
||||
DEV_COMPOSE="${ROOT_DIR}/compose.yaml"
|
||||
ENV_FILE="${ROOT_DIR}/.env"
|
||||
LEGACY_WAS_RUNNING=0
|
||||
|
||||
log() {
|
||||
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
||||
}
|
||||
|
||||
fail() {
|
||||
printf '[error] %s\n' "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
env_value() {
|
||||
local key="$1"
|
||||
grep -E "^${key}=" "$ENV_FILE" | tail -n 1 | cut -d '=' -f 2- | sed -e 's/^"//' -e 's/"$//'
|
||||
}
|
||||
|
||||
prod() {
|
||||
docker compose -f "$PROD_COMPOSE" "$@"
|
||||
}
|
||||
|
||||
legacy() {
|
||||
docker compose -f "$DEV_COMPOSE" "$@"
|
||||
}
|
||||
|
||||
wait_for_health() {
|
||||
local service="$1"
|
||||
local container_id
|
||||
local status
|
||||
|
||||
container_id="$(prod ps -q "$service")"
|
||||
[[ -n "$container_id" ]] || fail "Контейнер ${service} не создан"
|
||||
|
||||
for _ in $(seq 1 45); do
|
||||
status="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container_id")"
|
||||
if [[ "$status" == healthy ]]; then
|
||||
return 0
|
||||
fi
|
||||
if [[ "$status" == exited || "$status" == dead ]]; then
|
||||
docker logs --tail 100 "$container_id" >&2 || true
|
||||
fail "Контейнер ${service} завершился со статусом ${status}"
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
docker logs --tail 100 "$container_id" >&2 || true
|
||||
fail "Контейнер ${service} не перешёл в healthy"
|
||||
}
|
||||
|
||||
rollback_legacy() {
|
||||
log "Production web не прошёл проверку, выполняю откат"
|
||||
prod stop web app >/dev/null 2>&1 || true
|
||||
if (( LEGACY_WAS_RUNNING )); then
|
||||
legacy start laravel.test >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
command -v docker >/dev/null 2>&1 || fail "Не найден Docker"
|
||||
docker compose version >/dev/null 2>&1 || fail "Не найден Docker Compose Plugin"
|
||||
[[ -f "$ENV_FILE" ]] || fail "Не найден ${ENV_FILE}"
|
||||
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
local app_uid app_gid app_port legacy_id
|
||||
app_uid="$(env_value WWWUSER)"
|
||||
app_gid="$(env_value WWWGROUP)"
|
||||
app_port="$(env_value APP_PORT)"
|
||||
app_uid="${app_uid:-1000}"
|
||||
app_gid="${app_gid:-1000}"
|
||||
app_port="${app_port:-8080}"
|
||||
|
||||
mkdir -p storage/app/public storage/framework/cache/data storage/framework/sessions storage/framework/views storage/logs
|
||||
if [[ "$(id -u)" -eq 0 ]]; then
|
||||
chown -R "${app_uid}:${app_gid}" storage
|
||||
fi
|
||||
chmod -R ug+rwX storage
|
||||
|
||||
log "Собираю production-образы"
|
||||
prod build app web
|
||||
|
||||
log "Запускаю новый PHP-FPM"
|
||||
prod up -d --no-deps app
|
||||
wait_for_health app
|
||||
|
||||
log "Выполняю миграции и прогреваю кэш"
|
||||
prod exec -T --user "${app_uid}:${app_gid}" app php artisan migrate --force
|
||||
prod exec -T --user "${app_uid}:${app_gid}" app php artisan optimize
|
||||
|
||||
legacy_id="$(legacy ps -q laravel.test 2>/dev/null || true)"
|
||||
if [[ -n "$legacy_id" ]] && [[ "$(docker inspect -f '{{.State.Running}}' "$legacy_id")" == true ]]; then
|
||||
LEGACY_WAS_RUNNING=1
|
||||
log "Останавливаю legacy Sail-контейнер"
|
||||
legacy stop laravel.test
|
||||
fi
|
||||
|
||||
log "Переключаю nginx на production web-контейнер"
|
||||
if ! prod up -d --no-deps web || ! wait_for_health web; then
|
||||
rollback_legacy
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! curl --fail --silent --max-time 15 "http://127.0.0.1:${app_port}/" >/dev/null; then
|
||||
rollback_legacy
|
||||
fail "HTTP-проверка production web завершилась ошибкой"
|
||||
fi
|
||||
|
||||
log "Production-деплой завершён: app и web healthy"
|
||||
prod ps app web
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user