работа с контейнерами
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
.git
|
||||
.gitignore
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
.idea
|
||||
.vscode
|
||||
node_modules
|
||||
vendor
|
||||
public/build
|
||||
public/hot
|
||||
public/storage
|
||||
bootstrap/cache/*.php
|
||||
storage/*.key
|
||||
storage/backups
|
||||
storage/logs/*
|
||||
storage/framework/cache/data/*
|
||||
storage/framework/sessions/*
|
||||
storage/framework/views/*
|
||||
tests
|
||||
compose*.yaml
|
||||
README.md
|
||||
@@ -77,6 +77,23 @@ chmod +x scripts/deploy-ubuntu.sh
|
||||
./scripts/deploy-ubuntu.sh --skip-cache
|
||||
```
|
||||
|
||||
## Production без Sail
|
||||
|
||||
Для production используется отдельный стек `compose.prod.yaml`:
|
||||
|
||||
- `web` — непривилегированный nginx со статикой;
|
||||
- `app` — PHP-FPM с кодом и Composer-зависимостями внутри образа;
|
||||
- `mysql` — постоянная база на томе `sail-mysql`.
|
||||
|
||||
Node.js, Playwright, Xdebug, dev-зависимости Composer и bind-mount исходного кода в production-образы не входят.
|
||||
|
||||
```bash
|
||||
chmod +x scripts/deploy-production.sh
|
||||
./scripts/deploy-production.sh
|
||||
```
|
||||
|
||||
Скрипт сначала собирает и проверяет новый PHP-FPM, выполняет миграции и прогрев кэша, а затем переключает порт с legacy Sail-контейнера на production nginx. Если HTTP-проверка не проходит, legacy-контейнер запускается обратно.
|
||||
|
||||
## Как это связано с AzerothCore
|
||||
|
||||
По умолчанию Sail-контейнер подключается к auth-базе core-сервера так:
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/production/Dockerfile
|
||||
target: app
|
||||
args:
|
||||
APP_UID: '${WWWUSER:-1000}'
|
||||
APP_GID: '${WWWGROUP:-1000}'
|
||||
image: moonwell-web-app:production
|
||||
restart: unless-stopped
|
||||
init: true
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
APP_ENV: production
|
||||
APP_DEBUG: 'false'
|
||||
DB_HOST: mysql
|
||||
DB_PORT: 3306
|
||||
volumes:
|
||||
- './storage:/var/www/html/storage'
|
||||
tmpfs:
|
||||
- '/var/www/html/bootstrap/cache:uid=${WWWUSER:-1000},gid=${WWWGROUP:-1000},mode=0770'
|
||||
networks:
|
||||
- sail
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- 'SCRIPT_NAME=/healthz SCRIPT_FILENAME=/healthz REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000 2>/dev/null | grep -q pong'
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
|
||||
web:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/production/Dockerfile
|
||||
target: web
|
||||
args:
|
||||
APP_UID: '${WWWUSER:-1000}'
|
||||
APP_GID: '${WWWGROUP:-1000}'
|
||||
image: moonwell-web-nginx:production
|
||||
restart: unless-stopped
|
||||
init: true
|
||||
ports:
|
||||
- '127.0.0.1:${APP_PORT:-8080}:8080'
|
||||
volumes:
|
||||
- './storage/app/public:/var/www/html/public/storage:ro'
|
||||
networks:
|
||||
- sail
|
||||
depends_on:
|
||||
app:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ['CMD', 'wget', '--quiet', '--tries=1', '--spider', 'http://127.0.0.1:8080/healthz']
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /tmp
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
cap_drop:
|
||||
- ALL
|
||||
|
||||
mysql:
|
||||
image: mysql:8.4
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '${FORWARD_DB_PORT:-3307}:3306'
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
|
||||
MYSQL_ROOT_HOST: '%'
|
||||
MYSQL_DATABASE: '${DB_DATABASE}'
|
||||
MYSQL_USER: '${DB_USERNAME}'
|
||||
MYSQL_PASSWORD: '${DB_PASSWORD}'
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: 1
|
||||
MYSQL_EXTRA_OPTIONS: '${MYSQL_EXTRA_OPTIONS:-}'
|
||||
volumes:
|
||||
- 'sail-mysql:/var/lib/mysql'
|
||||
- './docker/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
|
||||
networks:
|
||||
- sail
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- mysqladmin
|
||||
- ping
|
||||
- '-p${DB_PASSWORD}'
|
||||
retries: 3
|
||||
timeout: 5s
|
||||
|
||||
networks:
|
||||
sail:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
sail-mysql:
|
||||
driver: local
|
||||
@@ -24,6 +24,12 @@ services:
|
||||
- sail
|
||||
depends_on:
|
||||
- mysql
|
||||
healthcheck:
|
||||
test: ['CMD', 'curl', '--fail', '--silent', 'http://127.0.0.1/healthz']
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
mysql:
|
||||
image: 'mysql:8.4'
|
||||
restart: unless-stopped
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
FROM php:8.3-fpm-bookworm AS php-base
|
||||
|
||||
ARG APP_UID=1000
|
||||
ARG APP_GID=1000
|
||||
|
||||
ENV APP_ENV=production \
|
||||
APP_DEBUG=false \
|
||||
COMPOSER_ALLOW_SUPERUSER=1
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
libfcgi-bin \
|
||||
libfreetype6-dev \
|
||||
libicu-dev \
|
||||
libjpeg62-turbo-dev \
|
||||
libpng-dev \
|
||||
libzip-dev \
|
||||
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||
&& docker-php-ext-install -j"$(nproc)" \
|
||||
bcmath \
|
||||
exif \
|
||||
gd \
|
||||
intl \
|
||||
pcntl \
|
||||
pdo_mysql \
|
||||
sockets \
|
||||
zip \
|
||||
&& apt-mark manual \
|
||||
libfcgi-bin \
|
||||
libfreetype6 \
|
||||
libicu72 \
|
||||
libjpeg62-turbo \
|
||||
libpng16-16 \
|
||||
libzip4 \
|
||||
&& apt-get purge -y --auto-remove \
|
||||
libfreetype6-dev \
|
||||
libicu-dev \
|
||||
libjpeg62-turbo-dev \
|
||||
libpng-dev \
|
||||
libzip-dev \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& groupadd --gid "$APP_GID" app \
|
||||
&& useradd --uid "$APP_UID" --gid "$APP_GID" --create-home --shell /usr/sbin/nologin app
|
||||
|
||||
COPY docker/production/php.ini /usr/local/etc/php/conf.d/99-production.ini
|
||||
COPY docker/production/php-fpm-pool.conf /usr/local/etc/php-fpm.d/zz-production.conf
|
||||
|
||||
FROM php-base AS vendor
|
||||
|
||||
COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer
|
||||
COPY . .
|
||||
|
||||
RUN composer install \
|
||||
--no-dev \
|
||||
--prefer-dist \
|
||||
--optimize-autoloader \
|
||||
--no-interaction \
|
||||
--no-progress \
|
||||
&& composer clear-cache
|
||||
|
||||
FROM node:24-bookworm-slim AS frontend
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci --no-audit --no-fund
|
||||
|
||||
COPY resources ./resources
|
||||
COPY public ./public
|
||||
COPY vite.config.* ./
|
||||
|
||||
ARG VITE_APP_NAME=Moonwell
|
||||
ENV VITE_APP_NAME="$VITE_APP_NAME"
|
||||
|
||||
RUN npm run build
|
||||
|
||||
FROM php-base AS app
|
||||
|
||||
COPY --from=vendor --chown=app:app /var/www/html /var/www/html
|
||||
COPY --from=frontend --chown=app:app /var/www/html/public/build /var/www/html/public/build
|
||||
|
||||
RUN mkdir -p \
|
||||
bootstrap/cache \
|
||||
storage/app/public \
|
||||
storage/framework/cache/data \
|
||||
storage/framework/sessions \
|
||||
storage/framework/views \
|
||||
storage/logs \
|
||||
&& chown -R app:app bootstrap/cache storage
|
||||
|
||||
EXPOSE 9000
|
||||
|
||||
CMD ["php-fpm", "--nodaemonize"]
|
||||
|
||||
FROM nginx:1.27-alpine AS web
|
||||
|
||||
ARG APP_UID=1000
|
||||
ARG APP_GID=1000
|
||||
|
||||
RUN addgroup -S -g "$APP_GID" app \
|
||||
&& adduser -S -D -H -u "$APP_UID" -G app app
|
||||
|
||||
COPY docker/production/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY --from=vendor --chown=app:app /var/www/html/public /var/www/html/public
|
||||
COPY --from=frontend --chown=app:app /var/www/html/public/build /var/www/html/public/build
|
||||
|
||||
USER app
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -0,0 +1,60 @@
|
||||
worker_processes auto;
|
||||
pid /tmp/nginx.pid;
|
||||
error_log /dev/stderr warn;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
access_log /dev/stdout;
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
keepalive_timeout 65;
|
||||
client_max_body_size 100m;
|
||||
|
||||
client_body_temp_path /tmp/client_temp;
|
||||
proxy_temp_path /tmp/proxy_temp;
|
||||
fastcgi_temp_path /tmp/fastcgi_temp;
|
||||
uwsgi_temp_path /tmp/uwsgi_temp;
|
||||
scgi_temp_path /tmp/scgi_temp;
|
||||
|
||||
server {
|
||||
listen 8080 default_server;
|
||||
server_name _;
|
||||
root /var/www/html/public;
|
||||
index index.php;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
location = /healthz {
|
||||
allow 127.0.0.1;
|
||||
deny all;
|
||||
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME /healthz;
|
||||
fastcgi_pass app:9000;
|
||||
}
|
||||
|
||||
location = /index.php {
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME /var/www/html/public/index.php;
|
||||
fastcgi_param HTTP_PROXY "";
|
||||
fastcgi_pass app:9000;
|
||||
fastcgi_read_timeout 60s;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
return 404;
|
||||
}
|
||||
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
[www]
|
||||
user = app
|
||||
group = app
|
||||
|
||||
listen = 0.0.0.0:9000
|
||||
|
||||
pm = dynamic
|
||||
pm.max_children = 8
|
||||
pm.start_servers = 2
|
||||
pm.min_spare_servers = 1
|
||||
pm.max_spare_servers = 4
|
||||
pm.max_requests = 500
|
||||
|
||||
request_terminate_timeout = 60s
|
||||
request_slowlog_timeout = 10s
|
||||
slowlog = /proc/self/fd/2
|
||||
|
||||
ping.path = /healthz
|
||||
ping.response = pong
|
||||
|
||||
clear_env = no
|
||||
catch_workers_output = yes
|
||||
decorate_workers_output = no
|
||||
@@ -0,0 +1,22 @@
|
||||
[PHP]
|
||||
expose_php = Off
|
||||
display_errors = Off
|
||||
display_startup_errors = Off
|
||||
log_errors = On
|
||||
memory_limit = 256M
|
||||
max_execution_time = 60
|
||||
post_max_size = 100M
|
||||
upload_max_filesize = 100M
|
||||
variables_order = EGPCS
|
||||
|
||||
[Date]
|
||||
date.timezone = UTC
|
||||
|
||||
[opcache]
|
||||
opcache.enable = 1
|
||||
opcache.enable_cli = 0
|
||||
opcache.memory_consumption = 128
|
||||
opcache.interned_strings_buffer = 16
|
||||
opcache.max_accelerated_files = 20000
|
||||
opcache.validate_timestamps = 0
|
||||
opcache.save_comments = 1
|
||||
@@ -56,6 +56,11 @@ RUN apt-get update && apt-get upgrade -y \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y nginx php8.3-fpm \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.3
|
||||
|
||||
RUN userdel -r ubuntu
|
||||
@@ -65,7 +70,10 @@ RUN git config --global --add safe.directory /var/www/html
|
||||
|
||||
COPY start-container /usr/local/bin/start-container
|
||||
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
COPY php-fpm-pool.conf /etc/php/8.3/fpm/pool.d/www.conf
|
||||
COPY php.ini /etc/php/8.3/cli/conf.d/99-sail.ini
|
||||
COPY php.ini /etc/php/8.3/fpm/conf.d/99-sail.ini
|
||||
RUN chmod +x /usr/local/bin/start-container
|
||||
|
||||
EXPOSE 80/tcp
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
user sail;
|
||||
worker_processes auto;
|
||||
pid /run/nginx.pid;
|
||||
error_log /dev/stderr warn;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
access_log /dev/stdout;
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
keepalive_timeout 65;
|
||||
client_max_body_size 100m;
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
server_name _;
|
||||
root /var/www/html/public;
|
||||
index index.php;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
location = /healthz {
|
||||
allow 127.0.0.1;
|
||||
deny all;
|
||||
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME /dev/null;
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param HTTP_PROXY "";
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_read_timeout 60s;
|
||||
}
|
||||
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
[www]
|
||||
user = sail
|
||||
group = sail
|
||||
|
||||
listen = 127.0.0.1:9000
|
||||
listen.owner = sail
|
||||
listen.group = sail
|
||||
|
||||
pm = dynamic
|
||||
pm.max_children = 8
|
||||
pm.start_servers = 2
|
||||
pm.min_spare_servers = 1
|
||||
pm.max_spare_servers = 4
|
||||
pm.max_requests = 500
|
||||
|
||||
request_terminate_timeout = 60s
|
||||
request_slowlog_timeout = 10s
|
||||
slowlog = /proc/self/fd/2
|
||||
|
||||
ping.path = /healthz
|
||||
ping.response = pong
|
||||
|
||||
clear_env = no
|
||||
catch_workers_output = yes
|
||||
decorate_workers_output = no
|
||||
@@ -4,10 +4,29 @@ user=root
|
||||
logfile=/var/log/supervisor/supervisord.log
|
||||
pidfile=/var/run/supervisord.pid
|
||||
|
||||
[program:php]
|
||||
command=%(ENV_SUPERVISOR_PHP_COMMAND)s
|
||||
user=%(ENV_SUPERVISOR_PHP_USER)s
|
||||
environment=LARAVEL_SAIL="1"
|
||||
[program:php-fpm]
|
||||
command=/usr/sbin/php-fpm8.3 --nodaemonize --fpm-config /etc/php/8.3/fpm/php-fpm.conf
|
||||
user=root
|
||||
priority=10
|
||||
autostart=true
|
||||
autorestart=true
|
||||
startsecs=2
|
||||
stopasgroup=true
|
||||
stopsignal=QUIT
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:nginx]
|
||||
command=/usr/sbin/nginx -g "daemon off;"
|
||||
user=root
|
||||
priority=20
|
||||
autostart=true
|
||||
autorestart=true
|
||||
startsecs=2
|
||||
stopasgroup=true
|
||||
stopsignal=QUIT
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
|
||||
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