Deploy IFT: optional observer-web/logrotate, bootstrap build on IFT server.
CI / test (push) Failing after 2m8s
CI / test (push) Failing after 2m8s
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -73,6 +73,28 @@ jobs:
|
|||||||
FILES="$(git diff --name-only "${HEAD}^" "${HEAD}" 2>/dev/null || git show --pretty="" --name-only "${HEAD}")"
|
FILES="$(git diff --name-only "${HEAD}^" "${HEAD}" 2>/dev/null || git show --pretty="" --name-only "${HEAD}")"
|
||||||
bash scripts/publish-ift-aux-images.sh "${REGISTRY}" "${TAG}" "${FILES}"
|
bash scripts/publish-ift-aux-images.sh "${REGISTRY}" "${TAG}" "${FILES}"
|
||||||
|
|
||||||
|
- name: Bootstrap optional aux images on IFT server
|
||||||
|
uses: appleboy/ssh-action@v0.1.5
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.IFT_SSH_HOST }}
|
||||||
|
username: ${{ secrets.IFT_SSH_USER }}
|
||||||
|
key: ${{ secrets.IFT_SSH_PRIVATE_KEY }}
|
||||||
|
script: |
|
||||||
|
export REGISTRY_USER='${{ secrets.REGISTRY_USER }}'
|
||||||
|
export REGISTRY_PASSWORD='${{ secrets.REGISTRY_PASSWORD }}'
|
||||||
|
echo "${REGISTRY_PASSWORD}" | docker login git.sabilin.com -u "${REGISTRY_USER}" --password-stdin
|
||||||
|
if [ "${{ github.event_name }}" = "workflow_run" ]; then
|
||||||
|
COMMIT="${{ github.event.workflow_run.head_sha }}"
|
||||||
|
else
|
||||||
|
COMMIT="${GITHUB_SHA}"
|
||||||
|
fi
|
||||||
|
WORKDIR="$(mktemp -d)"
|
||||||
|
git clone --depth 1 "https://${REGISTRY_USER}:${REGISTRY_PASSWORD}@git.sabilin.com/EventHub/EventHubBack.git" "${WORKDIR}/back"
|
||||||
|
git -C "${WORKDIR}/back" fetch --depth 1 origin "${COMMIT}"
|
||||||
|
git -C "${WORKDIR}/back" checkout "${COMMIT}"
|
||||||
|
BACK_DIR="${WORKDIR}/back" bash "${WORKDIR}/back/scripts/build-optional-aux-on-server.sh" "${REGISTRY}" "${{ steps.meta.outputs.tag }}" "${COMMIT}"
|
||||||
|
rm -rf "${WORKDIR}"
|
||||||
|
|
||||||
- name: Deploy core on IFT via SSH
|
- name: Deploy core on IFT via SSH
|
||||||
uses: appleboy/ssh-action@v0.1.5
|
uses: appleboy/ssh-action@v0.1.5
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
FROM erlang:28-alpine
|
FROM erlang:28-alpine
|
||||||
|
|
||||||
RUN apk add --no-cache \
|
RUN for i in 1 2 3 4 5; do \
|
||||||
elixir \
|
apk add --no-cache elixir nodejs npm git inotify-tools && break; \
|
||||||
nodejs \
|
echo "apk retry $i/5..."; sleep 15; \
|
||||||
npm \
|
done
|
||||||
git \
|
|
||||||
inotify-tools
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
RUN apk add --no-cache logrotate dcron tzdata
|
RUN for i in 1 2 3 4 5; do \
|
||||||
|
apk add --no-cache logrotate dcron tzdata && break; \
|
||||||
|
echo "apk retry $i/5..."; sleep 15; \
|
||||||
|
done
|
||||||
COPY logrotate.conf /etc/logrotate.conf
|
COPY logrotate.conf /etc/logrotate.conf
|
||||||
COPY entrypoint.sh /entrypoint.sh
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
RUN chmod +x /entrypoint.sh
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Сборка observer-web / logrotate на сервере IFT (fallback, если runner не тянет Alpine).
|
||||||
|
# Usage: BACK_DIR=/path/to/back build-optional-aux-on-server.sh <registry> <sha-tag> <commit-sha>
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REGISTRY="${1:?registry}"
|
||||||
|
TAG="${2:?sha-tag}"
|
||||||
|
COMMIT="${3:?commit-sha}"
|
||||||
|
|
||||||
|
git_with_auth() {
|
||||||
|
if [[ -n "${REGISTRY_USER:-}" && -n "${REGISTRY_PASSWORD:-}" ]]; then
|
||||||
|
local askpass
|
||||||
|
askpass="$(mktemp)"
|
||||||
|
cat > "${askpass}" <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
case "$1" in
|
||||||
|
*[Pp]assword*) printf '%s\n' "$REGISTRY_PASSWORD" ;;
|
||||||
|
*) printf '%s\n' "$REGISTRY_USER" ;;
|
||||||
|
esac
|
||||||
|
EOF
|
||||||
|
chmod +x "${askpass}"
|
||||||
|
GIT_TERMINAL_PROMPT=0 GIT_ASKPASS="${askpass}" \
|
||||||
|
REGISTRY_USER="${REGISTRY_USER}" REGISTRY_PASSWORD="${REGISTRY_PASSWORD}" \
|
||||||
|
"$@"
|
||||||
|
rm -f "${askpass}"
|
||||||
|
else
|
||||||
|
GIT_TERMINAL_PROMPT=0 "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
need_build() {
|
||||||
|
docker buildx imagetools inspect "${REGISTRY}/$1:${TAG}" >/dev/null 2>&1 && return 1
|
||||||
|
docker buildx imagetools inspect "${REGISTRY}/$1:ift" >/dev/null 2>&1 && return 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
build_one() {
|
||||||
|
local name="$1"
|
||||||
|
local context="$2"
|
||||||
|
local dockerfile="$3"
|
||||||
|
|
||||||
|
if ! need_build "${name}"; then
|
||||||
|
if docker buildx imagetools inspect "${REGISTRY}/${name}:${TAG}" >/dev/null 2>&1; then
|
||||||
|
echo "== ${name}: ${TAG} exists, skip"
|
||||||
|
else
|
||||||
|
echo "== ${name}: promote :ift -> ${TAG}"
|
||||||
|
docker buildx imagetools create -t "${REGISTRY}/${name}:${TAG}" "${REGISTRY}/${name}:ift"
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "== ${name}: build on IFT server"
|
||||||
|
bash scripts/retry-docker-build.sh 5 60 -- \
|
||||||
|
docker buildx build -f "${dockerfile}" --push \
|
||||||
|
-t "${REGISTRY}/${name}:${TAG}" \
|
||||||
|
-t "${REGISTRY}/${name}:ift" \
|
||||||
|
--provenance=false --sbom=false \
|
||||||
|
"${context}" || {
|
||||||
|
echo "WARN: ${name}: server build failed, deploy continues without it"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ -n "${BACK_DIR:-}" ]]; then
|
||||||
|
cd "${BACK_DIR}"
|
||||||
|
else
|
||||||
|
WORKDIR="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "${WORKDIR}"' EXIT
|
||||||
|
git_with_auth git clone --depth 1 "https://git.sabilin.com/EventHub/EventHubBack.git" "${WORKDIR}/back"
|
||||||
|
git_with_auth git -C "${WORKDIR}/back" fetch --depth 1 origin "${COMMIT}"
|
||||||
|
git -C "${WORKDIR}/back" checkout "${COMMIT}"
|
||||||
|
cd "${WORKDIR}/back"
|
||||||
|
fi
|
||||||
|
|
||||||
|
build_one observer-web . docker/ObserverWeb.Dockerfile
|
||||||
|
build_one logrotate docker/logrotate docker/logrotate/Dockerfile
|
||||||
@@ -12,9 +12,11 @@ rebuild_image() {
|
|||||||
local context="$2"
|
local context="$2"
|
||||||
local dockerfile="$3"
|
local dockerfile="$3"
|
||||||
local reason="$4"
|
local reason="$4"
|
||||||
|
local attempts="${5:-3}"
|
||||||
|
local wait="${6:-30}"
|
||||||
|
|
||||||
echo "== ${name}: rebuild (${reason})"
|
echo "== ${name}: rebuild (${reason})"
|
||||||
bash scripts/retry-docker-build.sh 3 30 -- \
|
bash scripts/retry-docker-build.sh "${attempts}" "${wait}" -- \
|
||||||
docker buildx build -f "${dockerfile}" --push \
|
docker buildx build -f "${dockerfile}" --push \
|
||||||
-t "${REGISTRY}/${name}:${TAG}" \
|
-t "${REGISTRY}/${name}:${TAG}" \
|
||||||
-t "${REGISTRY}/${name}:ift" \
|
-t "${REGISTRY}/${name}:ift" \
|
||||||
@@ -22,11 +24,25 @@ rebuild_image() {
|
|||||||
"${context}"
|
"${context}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try_rebuild() {
|
||||||
|
local optional="$1"
|
||||||
|
shift
|
||||||
|
if rebuild_image "$@"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [[ "${optional}" == "1" ]]; then
|
||||||
|
echo "WARN: $1: rebuild failed (optional), will try on IFT server or skip"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
publish_image() {
|
publish_image() {
|
||||||
local name="$1"
|
local name="$1"
|
||||||
local path_pattern="$2"
|
local path_pattern="$2"
|
||||||
local context="$3"
|
local context="$3"
|
||||||
local dockerfile="$4"
|
local dockerfile="$4"
|
||||||
|
local optional="${5:-0}"
|
||||||
|
|
||||||
if docker buildx imagetools inspect "${REGISTRY}/${name}:${TAG}" >/dev/null 2>&1; then
|
if docker buildx imagetools inspect "${REGISTRY}/${name}:${TAG}" >/dev/null 2>&1; then
|
||||||
echo "== ${name}: ${TAG} already in registry, skip"
|
echo "== ${name}: ${TAG} already in registry, skip"
|
||||||
@@ -34,13 +50,13 @@ publish_image() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if echo "${FILES}" | grep -qE "${path_pattern}"; then
|
if echo "${FILES}" | grep -qE "${path_pattern}"; then
|
||||||
rebuild_image "${name}" "${context}" "${dockerfile}" "matched: ${path_pattern}"
|
try_rebuild "${optional}" "${name}" "${context}" "${dockerfile}" "matched: ${path_pattern}"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "== ${name}: unchanged, promote :ift -> ${TAG}"
|
echo "== ${name}: unchanged, promote :ift -> ${TAG}"
|
||||||
if ! docker buildx imagetools inspect "${REGISTRY}/${name}:ift" >/dev/null 2>&1; then
|
if ! docker buildx imagetools inspect "${REGISTRY}/${name}:ift" >/dev/null 2>&1; then
|
||||||
rebuild_image "${name}" "${context}" "${dockerfile}" "bootstrap: :ift not found"
|
try_rebuild "${optional}" "${name}" "${context}" "${dockerfile}" "bootstrap: :ift not found"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
docker buildx imagetools create \
|
docker buildx imagetools create \
|
||||||
@@ -48,8 +64,8 @@ publish_image() {
|
|||||||
"${REGISTRY}/${name}:ift"
|
"${REGISTRY}/${name}:ift"
|
||||||
}
|
}
|
||||||
|
|
||||||
publish_image traefik-coraza '^docker/traefik/' docker/traefik docker/traefik/Dockerfile
|
publish_image traefik-coraza '^docker/traefik/' docker/traefik docker/traefik/Dockerfile 0
|
||||||
publish_image fallback '^docker/fallback/' docker/fallback docker/fallback/Dockerfile
|
publish_image fallback '^docker/fallback/' docker/fallback docker/fallback/Dockerfile 0
|
||||||
publish_image bot-emulator-users '^test/emulate_users/' . test/emulate_users/Dockerfile
|
publish_image bot-emulator-users '^test/emulate_users/' . test/emulate_users/Dockerfile 0
|
||||||
publish_image observer-web '^docker/ObserverWeb\.Dockerfile|^docker/observer_web/' . docker/ObserverWeb.Dockerfile
|
publish_image observer-web '^docker/ObserverWeb\.Dockerfile|^docker/observer_web/' . docker/ObserverWeb.Dockerfile 1
|
||||||
publish_image logrotate '^docker/logrotate/' docker/logrotate docker/logrotate/Dockerfile
|
publish_image logrotate '^docker/logrotate/' docker/logrotate docker/logrotate/Dockerfile 1
|
||||||
|
|||||||
Reference in New Issue
Block a user