This commit is contained in:
parent
f81021d2d0
commit
8cb0c58004
2 changed files with 47 additions and 58 deletions
|
|
@ -1,21 +1,13 @@
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
# Woodpecker CI/CD
|
||||||
# Woodpecker CI Pipeline
|
|
||||||
#
|
#
|
||||||
# Шаги:
|
# Required secrets:
|
||||||
# 1. docker-build — сборка и пуш образа (push в main)
|
# forgejo_host - registry host (example: git.example.com)
|
||||||
# 2. docker-build-tag — сборка и пуш образа с semver-тегом (git tag v*)
|
# forgejo_image - full image path (example: git.example.com/user/intradesk-monitor)
|
||||||
# 3. deploy — деплой на сервер (выполняется на агенте role=work_woodpecker)
|
# forgejo_username - registry username
|
||||||
#
|
# forgejo_token - registry token with package:write
|
||||||
# Секреты (Settings → Secrets репозитория):
|
|
||||||
# forgejo_host — хост реестра, например git.example.com
|
|
||||||
# forgejo_image — полный путь образа, например git.example.com/user/intradesk-monitor
|
|
||||||
# forgejo_username — логин (обычно = gitea.actor)
|
|
||||||
# forgejo_token — токен с правом package:write
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
# Build and push on main branch updates.
|
||||||
# ── 1а. Сборка при push в main ─────────────────────────────────────────────
|
|
||||||
- name: docker-build
|
- name: docker-build
|
||||||
image: woodpeckerci/plugin-docker-buildx
|
image: woodpeckerci/plugin-docker-buildx
|
||||||
settings:
|
settings:
|
||||||
|
|
@ -29,51 +21,45 @@ steps:
|
||||||
from_secret: forgejo_token
|
from_secret: forgejo_token
|
||||||
tags:
|
tags:
|
||||||
- latest
|
- latest
|
||||||
- "sha-${CI_COMMIT_SHA:0:8}"
|
- "sha-${CI_COMMIT_SHA}"
|
||||||
# Берём inline-кэш из latest; ARG GIT_COMMIT теперь в конце Dockerfile — кэш не сбивается
|
|
||||||
cache_from:
|
cache_from:
|
||||||
from_secret: forgejo_image
|
from_secret: forgejo_image
|
||||||
# mode=max кэширует все промежуточные слои (apk, npm install) в отдельный манифест
|
|
||||||
cache_to:
|
|
||||||
from_secret: forgejo_image_cache # значение: <registry>/<repo>:buildcache
|
|
||||||
rewrite_timestamp: false
|
rewrite_timestamp: false
|
||||||
build_args:
|
build_args:
|
||||||
- "GIT_COMMIT=${CI_COMMIT_SHA:0:8}"
|
- "GIT_COMMIT=${CI_COMMIT_SHA}"
|
||||||
- "BUILDKIT_INLINE_CACHE=1"
|
- "BUILDKIT_INLINE_CACHE=1"
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
|
|
||||||
# ── 1б. Сборка при git tag v* (semver) ────────────────────────────────────
|
# Build and push on Git tag (release) events.
|
||||||
- name: docker-build-tag
|
- name: docker-build-tag
|
||||||
image: woodpeckerci/plugin-docker-buildx
|
image: woodpeckerci/plugin-docker-buildx
|
||||||
settings:
|
settings:
|
||||||
registry:
|
registry:
|
||||||
from_secret: forgejo_host
|
from_secret: forgejo_host
|
||||||
repo:
|
repo:
|
||||||
from_secret: forgejo_image_2
|
from_secret: forgejo_image
|
||||||
username:
|
username:
|
||||||
from_secret: forgejo_username
|
from_secret: forgejo_username
|
||||||
password:
|
password:
|
||||||
from_secret: forgejo_token
|
from_secret: forgejo_token
|
||||||
tags:
|
tags:
|
||||||
- "${CI_COMMIT_TAG}" # v1.2.3
|
- "${CI_COMMIT_TAG}"
|
||||||
- latest
|
- latest
|
||||||
- "sha-${CI_COMMIT_SHA:0:8}" # всегда — нужно для отката
|
- "sha-${CI_COMMIT_SHA}"
|
||||||
cache_from:
|
cache_from:
|
||||||
from_secret: forgejo_image # значение: git.example.com/user/intradesk-monitor:latest
|
from_secret: forgejo_image
|
||||||
|
rewrite_timestamp: false
|
||||||
build_args:
|
build_args:
|
||||||
- "GIT_COMMIT=${CI_COMMIT_SHA:0:8}"
|
- "GIT_COMMIT=${CI_COMMIT_SHA}"
|
||||||
- "BUILDKIT_INLINE_CACHE=1"
|
- "BUILDKIT_INLINE_CACHE=1"
|
||||||
when:
|
when:
|
||||||
- event: tag
|
- event: tag
|
||||||
|
|
||||||
# ── 2. Деплой на продакшн-сервер ──────────────────────────────────────────
|
# Deploy for both push(main) and tag events.
|
||||||
# Выполняется на Woodpecker-агенте с меткой role=work_woodpecker.
|
|
||||||
# Требует: репозиторий помечен «trusted» в настройках Woodpecker-сервера
|
|
||||||
# (иначе монтирование volumes запрещено).
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
image: docker:cli
|
image: docker:27-cli
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- /opt/intra_monitor:/deploy
|
- /opt/intra_monitor:/deploy
|
||||||
|
|
@ -82,10 +68,8 @@ steps:
|
||||||
set -e
|
set -e
|
||||||
cd /deploy
|
cd /deploy
|
||||||
|
|
||||||
# Проверяем наличие .env на сервере
|
|
||||||
test -f .env || (echo "Missing /opt/intra_monitor/.env on deploy host" && exit 1)
|
test -f .env || (echo "Missing /opt/intra_monitor/.env on deploy host" && exit 1)
|
||||||
|
|
||||||
# Сохраняем ID текущего образа (для отката)
|
|
||||||
CONTAINER=$(docker compose ps -q intradesk-monitor 2>/dev/null | head -1)
|
CONTAINER=$(docker compose ps -q intradesk-monitor 2>/dev/null | head -1)
|
||||||
if [ -n "$CONTAINER" ]; then
|
if [ -n "$CONTAINER" ]; then
|
||||||
OLD_IMAGE=$(docker inspect --format='{{.Image}}' "$CONTAINER")
|
OLD_IMAGE=$(docker inspect --format='{{.Image}}' "$CONTAINER")
|
||||||
|
|
@ -93,16 +77,14 @@ steps:
|
||||||
echo "Snapshot for rollback: $OLD_IMAGE"
|
echo "Snapshot for rollback: $OLD_IMAGE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Удаляем legacy-контейнер со статичным именем, чтобы избежать name conflict
|
|
||||||
if docker ps -a --format '{{.Names}}' | grep -Eq '^intradesk-monitor$'; then
|
if docker ps -a --format '{{.Names}}' | grep -Eq '^intradesk-monitor$'; then
|
||||||
docker rm -f intradesk-monitor || true
|
docker rm -f intradesk-monitor || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Обновляем образ и перезапускаем
|
docker compose -p intradesk-monitor pull intradesk-monitor
|
||||||
docker compose -p intradesk-monitor pull
|
|
||||||
docker compose -p intradesk-monitor up -d --remove-orphans
|
docker compose -p intradesk-monitor up -d --remove-orphans
|
||||||
|
|
||||||
echo "Deployed: ${CI_COMMIT_SHA:0:8} (${CI_COMMIT_MESSAGE})"
|
echo "Deployed commit: ${CI_COMMIT_SHA} tag: ${CI_COMMIT_TAG}"
|
||||||
labels:
|
labels:
|
||||||
role: work_woodpecker
|
role: work_woodpecker
|
||||||
when:
|
when:
|
||||||
|
|
|
||||||
47
Dockerfile
47
Dockerfile
|
|
@ -1,35 +1,42 @@
|
||||||
FROM node:20-alpine
|
# syntax=docker/dockerfile:1.7
|
||||||
|
|
||||||
|
FROM node:20-alpine AS deps
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
# Build dependencies for native Node modules (better-sqlite3).
|
||||||
ENV LANG=C.UTF-8
|
|
||||||
ENV LC_ALL=C.UTF-8
|
|
||||||
|
|
||||||
# Зависимости для better-sqlite3 (нужна компиляция)
|
|
||||||
# Слой кэшируется пока не меняется базовый образ
|
|
||||||
RUN apk add --no-cache python3 make g++
|
RUN apk add --no-cache python3 make g++
|
||||||
|
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
RUN npm install --omit=dev --no-audit --no-fund \
|
# Use npm cache between builds; fallback to npm install when lock file is absent.
|
||||||
&& npm cache clean --force
|
RUN --mount=type=cache,target=/root/.npm \
|
||||||
|
if [ -f package-lock.json ]; then \
|
||||||
|
npm ci --omit=dev --no-audit --no-fund; \
|
||||||
|
else \
|
||||||
|
npm install --omit=dev --no-audit --no-fund; \
|
||||||
|
fi
|
||||||
|
|
||||||
# Код приложения — копируется после зависимостей
|
FROM node:20-alpine AS runtime
|
||||||
COPY server.js ./
|
WORKDIR /app
|
||||||
COPY refresh-service.js ./
|
|
||||||
COPY public/ ./public/
|
|
||||||
|
|
||||||
# Build-аргумент объявлен ПОСЛЕ тяжёлых слоёв — не сбивает кэш при каждом коммите
|
ENV NODE_ENV=production \
|
||||||
ARG GIT_COMMIT=unknown
|
LANG=C.UTF-8 \
|
||||||
ENV GIT_COMMIT=${GIT_COMMIT}
|
LC_ALL=C.UTF-8 \
|
||||||
|
PORT=3000 \
|
||||||
|
DB_PATH=/data/intradesk.db
|
||||||
|
|
||||||
|
# Runtime libs required by native modules.
|
||||||
|
RUN apk add --no-cache libstdc++
|
||||||
|
|
||||||
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
COPY server.js refresh-service.js ./
|
||||||
|
COPY public ./public
|
||||||
|
|
||||||
# Папка для базы данных
|
|
||||||
RUN mkdir -p /data
|
RUN mkdir -p /data
|
||||||
|
|
||||||
EXPOSE 3000
|
ARG GIT_COMMIT=unknown
|
||||||
|
LABEL org.opencontainers.image.revision=$GIT_COMMIT
|
||||||
|
|
||||||
ENV PORT=3000
|
EXPOSE 3000
|
||||||
ENV DB_PATH=/data/intradesk.db
|
|
||||||
|
|
||||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
||||||
CMD node -e "const http=require('http');const req=http.get('http://127.0.0.1:3000/healthz',res=>process.exit(res.statusCode===200?0:1));req.on('error',()=>process.exit(1));"
|
CMD node -e "const http=require('http');const req=http.get('http://127.0.0.1:3000/healthz',res=>process.exit(res.statusCode===200?0:1));req.on('error',()=>process.exit(1));"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue