fix1
This commit is contained in:
parent
464d53c70b
commit
299f69abd5
8 changed files with 118 additions and 116 deletions
|
|
@ -7,6 +7,9 @@ ADMIN_SECRET=мой_секрет_для_создания_юзеров
|
||||||
# Порт публикации контейнера на хосте для docker compose
|
# Порт публикации контейнера на хосте для docker compose
|
||||||
APP_PORT=3000
|
APP_PORT=3000
|
||||||
|
|
||||||
|
# Имя production-образа для docker compose deploy
|
||||||
|
IMAGE_NAME=registry.example.com/team/intradesk-monitor
|
||||||
|
|
||||||
# Порт сервера (по умолчанию 3000)
|
# Порт сервера (по умолчанию 3000)
|
||||||
PORT=3000
|
PORT=3000
|
||||||
|
|
||||||
|
|
|
||||||
101
.woodpecker.yml
101
.woodpecker.yml
|
|
@ -1,22 +1,87 @@
|
||||||
# If you use multiple agents, uncomment labels below and set the same labels on the target agent.
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
# labels:
|
# Woodpecker CI Pipeline
|
||||||
# deploy-host: intradesk-monitor
|
#
|
||||||
|
# Шаги:
|
||||||
|
# 1. docker-build — сборка и push образа при push в main
|
||||||
|
# 2. docker-build-tag — сборка и push образа при git tag
|
||||||
|
# 3. deploy — деплой на сервер на агенте role=work_woodpecker
|
||||||
|
#
|
||||||
|
# Секреты (Settings -> Secrets):
|
||||||
|
# forgejo_host — хост registry
|
||||||
|
# forgejo_image — полный путь образа
|
||||||
|
# forgejo_username — пользователь registry
|
||||||
|
# forgejo_token — токен для push
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: deploy
|
- name: docker-build
|
||||||
image: docker:27-cli
|
image: woodpeckerci/plugin-docker-buildx
|
||||||
volumes:
|
settings:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
registry:
|
||||||
- /opt/intradesk-monitor:/opt/intradesk-monitor
|
from_secret: forgejo_host
|
||||||
commands:
|
repo:
|
||||||
- mkdir -p /opt/intradesk-monitor/deploy /opt/intradesk-monitor/data
|
from_secret: forgejo_image
|
||||||
- cp docker-compose.deploy.yml /opt/intradesk-monitor/docker-compose.deploy.yml
|
username:
|
||||||
- cp deploy.sh /opt/intradesk-monitor/deploy.sh
|
from_secret: forgejo_username
|
||||||
- cp deploy/remote-deploy.sh /opt/intradesk-monitor/deploy/remote-deploy.sh
|
password:
|
||||||
- chmod +x /opt/intradesk-monitor/deploy.sh /opt/intradesk-monitor/deploy/remote-deploy.sh
|
from_secret: forgejo_token
|
||||||
- test -f /opt/intradesk-monitor/.env || (echo "Missing /opt/intradesk-monitor/.env on deploy host" && exit 1)
|
tags:
|
||||||
- docker build -t intradesk-monitor:$CI_COMMIT_SHA -t intradesk-monitor:latest .
|
- latest
|
||||||
- APP_DIR=/opt/intradesk-monitor IMAGE_REPO=intradesk-monitor IMAGE_TAG=$CI_COMMIT_SHA /opt/intradesk-monitor/deploy/remote-deploy.sh
|
- "sha-${CI_COMMIT_SHA:0:8}"
|
||||||
|
build_args:
|
||||||
|
- "BUILDKIT_INLINE_CACHE=1"
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: ${CI_REPO_DEFAULT_BRANCH}
|
branch: main
|
||||||
|
|
||||||
|
- name: docker-build-tag
|
||||||
|
image: woodpeckerci/plugin-docker-buildx
|
||||||
|
settings:
|
||||||
|
registry:
|
||||||
|
from_secret: forgejo_host
|
||||||
|
repo:
|
||||||
|
from_secret: forgejo_image
|
||||||
|
username:
|
||||||
|
from_secret: forgejo_username
|
||||||
|
password:
|
||||||
|
from_secret: forgejo_token
|
||||||
|
tags:
|
||||||
|
- "${CI_COMMIT_TAG}"
|
||||||
|
- latest
|
||||||
|
- "sha-${CI_COMMIT_SHA:0:8}"
|
||||||
|
build_args:
|
||||||
|
- "BUILDKIT_INLINE_CACHE=1"
|
||||||
|
when:
|
||||||
|
- event: tag
|
||||||
|
|
||||||
|
- name: deploy
|
||||||
|
image: docker:cli
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- /opt/intradesk-monitor:/deploy
|
||||||
|
commands:
|
||||||
|
- |
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cp docker-compose.deploy.yml /deploy/docker-compose.yml
|
||||||
|
test -f /deploy/.env || (echo "Missing /opt/intradesk-monitor/.env on deploy host" && exit 1)
|
||||||
|
|
||||||
|
cd /deploy
|
||||||
|
|
||||||
|
CONTAINER=$(docker compose ps -q intradesk-monitor 2>/dev/null | head -1)
|
||||||
|
if [ -n "$CONTAINER" ]; then
|
||||||
|
OLD_IMAGE=$(docker inspect --format='{{.Image}}' "$CONTAINER")
|
||||||
|
printf '%s' "$OLD_IMAGE" > .previous_image
|
||||||
|
echo "Snapshot for rollback: $OLD_IMAGE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker compose pull
|
||||||
|
docker compose up -d --remove-orphans
|
||||||
|
|
||||||
|
echo "Deployed: ${CI_COMMIT_SHA:0:8} (${CI_COMMIT_MESSAGE})"
|
||||||
|
labels:
|
||||||
|
role: work_woodpecker
|
||||||
|
when:
|
||||||
|
- event: push
|
||||||
|
branch: main
|
||||||
|
- event: tag
|
||||||
|
|
|
||||||
74
README.md
74
README.md
|
|
@ -1,10 +1,12 @@
|
||||||
# Монитор заявок - CleverParking
|
# Монитор заявок - CleverParking
|
||||||
|
|
||||||
Node/Express приложение со встроенным фронтендом и SQLite. Проект подготовлен для:
|
Node/Express приложение со встроенным фронтендом и SQLite.
|
||||||
|
|
||||||
- локального запуска через Docker Compose;
|
Проект теперь настроен по той же схеме, что и другой рабочий сервис на этом сервере:
|
||||||
- автоматической сборки Docker-образа в Woodpecker;
|
|
||||||
- deploy прямо на хост, где установлен Woodpecker agent.
|
- образ собирается в Woodpecker и публикуется в registry;
|
||||||
|
- deploy выполняется на агенте с label `role=work_woodpecker`;
|
||||||
|
- на сервере запускается `docker compose pull && docker compose up -d`.
|
||||||
|
|
||||||
## Локальный запуск
|
## Локальный запуск
|
||||||
|
|
||||||
|
|
@ -13,69 +15,47 @@ cp .env.example .env
|
||||||
docker compose up -d --build
|
docker compose up -d --build
|
||||||
```
|
```
|
||||||
|
|
||||||
Приложение будет доступно на `http://localhost:3000`, а база SQLite сохранится в папке `./data`.
|
Локальный compose собирает образ из текущего каталога и хранит SQLite в `./data`.
|
||||||
|
|
||||||
## Что добавлено для production
|
## Production deploy
|
||||||
|
|
||||||
- `Dockerfile` с production `NODE_ENV` и `HEALTHCHECK`;
|
На сервере должен существовать каталог `/opt/intradesk-monitor` с файлом `.env`.
|
||||||
- `/healthz` endpoint для проверки контейнера;
|
|
||||||
- fail-fast проверка `JWT_SECRET` и `ADMIN_SECRET` в production;
|
|
||||||
- `docker-compose.deploy.yml` для запуска заранее собранного локального образа;
|
|
||||||
- `.woodpecker.yml` для сборки и deploy на хосте агента;
|
|
||||||
- `deploy/remote-deploy.sh` и `deploy.sh` для повторного запуска того же сценария уже на сервере.
|
|
||||||
|
|
||||||
## Как теперь работает deploy
|
Минимальный пример `/opt/intradesk-monitor/.env`:
|
||||||
|
|
||||||
1. Woodpecker забирает код из Git.
|
|
||||||
2. На push в default branch step `deploy` запускается на агенте, который стоит на целевой машине.
|
|
||||||
3. Step собирает локальный образ `intradesk-monitor:$CI_COMMIT_SHA` и тег `latest`.
|
|
||||||
4. В `/opt/intradesk-monitor` копируются deploy-файлы из репозитория.
|
|
||||||
5. Затем выполняется `docker compose up -d` уже с локально собранным образом.
|
|
||||||
|
|
||||||
Registry и SSH для такого сценария не нужны.
|
|
||||||
|
|
||||||
## Что нужно на машине с агентом
|
|
||||||
|
|
||||||
- установленный Docker с `docker compose`;
|
|
||||||
- Woodpecker agent на этой же машине;
|
|
||||||
- каталог `/opt/intradesk-monitor`;
|
|
||||||
- файл `/opt/intradesk-monitor/.env`;
|
|
||||||
- доверенный (`trusted`) репозиторий в Woodpecker, потому что pipeline использует bind-mount хостовых путей и Docker socket.
|
|
||||||
|
|
||||||
Пример `/opt/intradesk-monitor/.env`:
|
|
||||||
|
|
||||||
```dotenv
|
```dotenv
|
||||||
JWT_SECRET=long_random_secret
|
JWT_SECRET=long_random_secret
|
||||||
ADMIN_SECRET=another_long_secret
|
ADMIN_SECRET=another_long_secret
|
||||||
APP_PORT=3000
|
APP_PORT=3000
|
||||||
|
IMAGE_NAME=git.example.com/user/intradesk-monitor
|
||||||
```
|
```
|
||||||
|
|
||||||
`PORT` и `DB_PATH` в production задаются через compose автоматически.
|
Во время deploy pipeline копирует [docker-compose.deploy.yml](c:/Users/Professional/Documents/VSCode/intra_git/intradesk-monitor/docker-compose.deploy.yml) в `/opt/intradesk-monitor/docker-compose.yml`, затем выполняет стандартный `docker compose pull` и `docker compose up -d`.
|
||||||
|
|
||||||
## Настройка агента
|
## Секреты Woodpecker
|
||||||
|
|
||||||
Текущий `.woodpecker.yml` ожидает, что на хосте доступны:
|
Нужны секреты репозитория:
|
||||||
|
|
||||||
- `/var/run/docker.sock`
|
- `forgejo_host`
|
||||||
- `/opt/intradesk-monitor`
|
- `forgejo_image`
|
||||||
|
- `forgejo_username`
|
||||||
|
- `forgejo_token`
|
||||||
|
|
||||||
Если у тебя несколько агентов, добавь на нужный агент собственный label и раскомментируй блок `labels` в `.woodpecker.yml`, чтобы deploy уходил строго на нужную машину.
|
`forgejo_image` должен совпадать с `IMAGE_NAME` в серверном `.env`.
|
||||||
|
|
||||||
## Первый деплой
|
## Что делает pipeline
|
||||||
|
|
||||||
1. Создать каталог `/opt/intradesk-monitor`.
|
[.woodpecker.yml](c:/Users/Professional/Documents/VSCode/intra_git/intradesk-monitor/.woodpecker.yml) содержит три шага:
|
||||||
2. Положить в него `.env`.
|
|
||||||
3. Убедиться, что агент Woodpecker может работать с Docker на хосте.
|
|
||||||
4. Пометить репозиторий как `trusted` в Woodpecker.
|
|
||||||
5. Запушить изменения в default branch.
|
|
||||||
|
|
||||||
После этого Woodpecker сам соберёт образ на целевой машине и перезапустит контейнер.
|
- `docker-build` — сборка и push `latest` и `sha-<shortsha>` при push в `main`;
|
||||||
|
- `docker-build-tag` — сборка и push git tag, `latest` и `sha-<shortsha>` при событии tag;
|
||||||
|
- `deploy` — deploy на прод-сервере через Docker socket на агенте `role=work_woodpecker`.
|
||||||
|
|
||||||
## Полезные команды на сервере
|
## Полезные команды на сервере
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /opt/intradesk-monitor
|
cd /opt/intradesk-monitor
|
||||||
docker ps --filter name=intradesk-monitor
|
docker compose ps
|
||||||
docker logs -f intradesk-monitor
|
docker compose logs -f
|
||||||
./deploy.sh
|
cat .previous_image
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
#!/usr/bin/env sh
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
|
||||||
|
|
||||||
export APP_DIR="${APP_DIR:-$SCRIPT_DIR}"
|
|
||||||
|
|
||||||
exec "$SCRIPT_DIR/deploy/remote-deploy.sh"
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
#!/usr/bin/env sh
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
APP_DIR=${APP_DIR:-/opt/intradesk-monitor}
|
|
||||||
COMPOSE_FILE=${COMPOSE_FILE:-docker-compose.deploy.yml}
|
|
||||||
|
|
||||||
cd "$APP_DIR"
|
|
||||||
mkdir -p data deploy
|
|
||||||
|
|
||||||
if [ ! -f .env ]; then
|
|
||||||
echo ".env is missing in $APP_DIR. Create it from .env.example before the first deploy." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "${IMAGE_REPO:-}" ] && [ -n "${IMAGE_TAG:-}" ]; then
|
|
||||||
cat > .env.runtime <<EOF
|
|
||||||
IMAGE_REPO=${IMAGE_REPO}
|
|
||||||
IMAGE_TAG=${IMAGE_TAG}
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f .env.runtime ]; then
|
|
||||||
echo ".env.runtime is missing. Provide IMAGE_REPO and IMAGE_TAG for the deploy." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
set -a
|
|
||||||
. ./.env.runtime
|
|
||||||
set +a
|
|
||||||
|
|
||||||
if [ "${PULL_IMAGE:-0}" = "1" ]; then
|
|
||||||
docker compose -f "$COMPOSE_FILE" pull
|
|
||||||
fi
|
|
||||||
|
|
||||||
docker compose -f "$COMPOSE_FILE" up -d --remove-orphans
|
|
||||||
docker image prune -f >/dev/null 2>&1 || true
|
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
services:
|
services:
|
||||||
intradesk-monitor:
|
intradesk-monitor:
|
||||||
image: ${IMAGE_REPO}:${IMAGE_TAG}
|
image: ${IMAGE_NAME}:latest
|
||||||
container_name: intradesk-monitor
|
container_name: intradesk-monitor
|
||||||
restart: unless-stopped
|
restart: always
|
||||||
|
env_file: .env
|
||||||
ports:
|
ports:
|
||||||
- "${APP_PORT:-3000}:3000"
|
- "${APP_PORT:-3000}:3000"
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/data
|
- ./data:/data
|
||||||
environment:
|
environment:
|
||||||
NODE_ENV: production
|
NODE_ENV: production
|
||||||
JWT_SECRET: ${JWT_SECRET}
|
|
||||||
ADMIN_SECRET: ${ADMIN_SECRET}
|
|
||||||
PORT: 3000
|
PORT: 3000
|
||||||
DB_PATH: /data/intradesk.db
|
DB_PATH: /data/intradesk.db
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,13 @@ services:
|
||||||
container_name: intradesk-monitor
|
container_name: intradesk-monitor
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
restart: unless-stopped
|
restart: always
|
||||||
|
env_file: .env
|
||||||
ports:
|
ports:
|
||||||
- "${APP_PORT:-3000}:3000"
|
- "${APP_PORT:-3000}:3000"
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/data
|
- ./data:/data
|
||||||
environment:
|
environment:
|
||||||
NODE_ENV: production
|
NODE_ENV: production
|
||||||
JWT_SECRET: ${JWT_SECRET}
|
|
||||||
ADMIN_SECRET: ${ADMIN_SECRET}
|
|
||||||
PORT: 3000
|
PORT: 3000
|
||||||
DB_PATH: /data/intradesk.db
|
DB_PATH: /data/intradesk.db
|
||||||
|
|
|
||||||
BIN
intradesk-monitor.zip
Normal file
BIN
intradesk-monitor.zip
Normal file
Binary file not shown.
Loading…
Add table
Reference in a new issue