Initial commit
This commit is contained in:
168
build/workflows/deploy.yml
Normal file
168
build/workflows/deploy.yml
Normal file
@@ -0,0 +1,168 @@
|
||||
name: Deploy (yggdrasil)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: [ mainhost ]
|
||||
env:
|
||||
SSH_HOST: ${{ secrets.SSH_HOST }}
|
||||
SSH_USER: ${{ secrets.SSH_USER }}
|
||||
SSH_KEY_PATH: /home/gitea-runner/.ssh/id_ed25519
|
||||
|
||||
SSH_OPTS: >-
|
||||
-F /dev/null
|
||||
-o IdentitiesOnly=yes
|
||||
-o IdentityAgent=none
|
||||
-o PreferredAuthentications=publickey
|
||||
-o PubkeyAuthentication=yes
|
||||
-o PasswordAuthentication=no
|
||||
-o NumberOfPasswordPrompts=0
|
||||
-o BatchMode=yes
|
||||
-o ServerAliveInterval=15
|
||||
-o ServerAliveCountMax=3
|
||||
-o ConnectTimeout=20
|
||||
-o StrictHostKeyChecking=no
|
||||
|
||||
APP_ROOT: /var/www/yggdrasil
|
||||
KEEP_N: "5"
|
||||
SHARED_DIRS: "uploads:cache"
|
||||
HEALTH_URL: "https://yggdrasil.corpintech.net/"
|
||||
SERVICE_NAME: "apache2"
|
||||
|
||||
steps:
|
||||
- name: Checkout (pure git, private repo)
|
||||
env:
|
||||
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
export GIT_TERMINAL_PROMPT=0
|
||||
|
||||
git init -b main
|
||||
git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
|
||||
|
||||
git -c http.extraHeader="Authorization: token ${GIT_TOKEN}" \
|
||||
fetch --no-tags --depth=1 origin "${GITHUB_SHA}"
|
||||
|
||||
git checkout -q "${GITHUB_SHA}"
|
||||
|
||||
- name: SSH smoke test
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ssh $SSH_OPTS -i "$SSH_KEY_PATH" "${SSH_USER}@${SSH_HOST}" true
|
||||
|
||||
- name: Deploy atomically
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
REL="$(date -u +%Y%m%d-%H%M%SZ)-${GITHUB_SHA}"
|
||||
TAR_LOCAL="release/${REL}.tar.gz"
|
||||
|
||||
mkdir -p release
|
||||
|
||||
IFS=':' read -r -a SHARED_DIR_ARR <<< "${SHARED_DIRS}"
|
||||
|
||||
EXCLUDES=(--exclude-vcs --exclude='./node_modules' --exclude='./release')
|
||||
for d in "${SHARED_DIR_ARR[@]}"; do
|
||||
EXCLUDES+=( "--exclude=./${d}" )
|
||||
done
|
||||
|
||||
tar -czf "${TAR_LOCAL}" "${EXCLUDES[@]}" .
|
||||
|
||||
ssh $SSH_OPTS -i "$SSH_KEY_PATH" "${SSH_USER}@${SSH_HOST}" \
|
||||
"set -e;
|
||||
install -d -m 2755 '${APP_ROOT}' '${APP_ROOT}/releases' '${APP_ROOT}/shared' '${APP_ROOT}/logs';"
|
||||
|
||||
for d in "${SHARED_DIR_ARR[@]}"; do
|
||||
ssh $SSH_OPTS -i "$SSH_KEY_PATH" "${SSH_USER}@${SSH_HOST}" \
|
||||
"install -d -m 2755 '${APP_ROOT}/shared/${d}'"
|
||||
done
|
||||
|
||||
scp -O $SSH_OPTS -i "$SSH_KEY_PATH" "${TAR_LOCAL}" "${SSH_USER}@${SSH_HOST}:/tmp/${REL}.tar.gz"
|
||||
|
||||
ssh $SSH_OPTS -i "$SSH_KEY_PATH" "${SSH_USER}@${SSH_HOST}" bash -s -- \
|
||||
"${APP_ROOT}" \
|
||||
"${REL}" \
|
||||
"${KEEP_N}" \
|
||||
"${SHARED_DIRS}" \
|
||||
"${HEALTH_URL}" \
|
||||
"${SERVICE_NAME}" \
|
||||
"${GITHUB_SHA}" <<'REMOTE'
|
||||
set -euo pipefail
|
||||
|
||||
APP_ROOT="$1"
|
||||
REL="$2"
|
||||
KEEP_N="$3"
|
||||
SHARED_DIRS="$4"
|
||||
HEALTH_URL="$5"
|
||||
SERVICE_NAME="$6"
|
||||
GITSHA="$7"
|
||||
|
||||
IFS=':' read -r -a SHARED_DIR_ARR <<< "${SHARED_DIRS}"
|
||||
|
||||
RELEASES="${APP_ROOT}/releases"
|
||||
SHARED="${APP_ROOT}/shared"
|
||||
CUR="${APP_ROOT}/current"
|
||||
NEW="${RELEASES}/${REL}"
|
||||
TAR="/tmp/${REL}.tar.gz"
|
||||
|
||||
echo "--> Extracting ${REL}"
|
||||
mkdir -p "${NEW}"
|
||||
tar -xzf "${TAR}" -C "${NEW}"
|
||||
rm -f "${TAR}"
|
||||
|
||||
echo "--> Linking shared dirs"
|
||||
for d in "${SHARED_DIR_ARR[@]}"; do
|
||||
echo " ${d}"
|
||||
rm -rf "${NEW:?}/${d}"
|
||||
ln -s "${SHARED}/${d}" "${NEW}/${d}"
|
||||
done
|
||||
|
||||
if [ -f "${SHARED}/.env" ]; then
|
||||
ln -sf "${SHARED}/.env" "${NEW}/.env"
|
||||
fi
|
||||
|
||||
printf "sha=%s\nbuilt_at=%s\n" "${GITSHA}" "$(date -u +%FT%TZ)" > "${NEW}/RELEASE"
|
||||
|
||||
PREV="$(readlink -f "${CUR}" 2>/dev/null || true)"
|
||||
|
||||
echo "--> Swapping symlink"
|
||||
ln -sfn "${NEW}" "${CUR}"
|
||||
|
||||
echo "--> Restarting Apache"
|
||||
sudo /usr/bin/systemctl restart "${SERVICE_NAME}"
|
||||
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
echo "--> Health check ${HEALTH_URL}"
|
||||
if ! curl -fsS --max-time 10 "${HEALTH_URL}" >/dev/null; then
|
||||
echo "Health check failed, rolling back..."
|
||||
if [ -n "${PREV}" ] && [ -e "${PREV}" ]; then
|
||||
ln -sfn "${PREV}" "${CUR}"
|
||||
sudo /usr/bin/systemctl restart "${SERVICE_NAME}"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "--> Cleaning old releases"
|
||||
CUR_REAL="$(readlink -f "${CUR}" 2>/dev/null || true)"
|
||||
cd "${RELEASES}"
|
||||
|
||||
i=0
|
||||
for name in $(ls -1t); do
|
||||
path="${RELEASES}/${name}"
|
||||
|
||||
if [ "${path}" = "${CUR_REAL}" ] || [ "${path}" = "${PREV}" ] || [ "${path}" = "${NEW}" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
i=$((i+1))
|
||||
if [ "${i}" -gt "${KEEP_N}" ]; then
|
||||
rm -rf -- "${path}"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "--> Deploy complete"
|
||||
REMOTE
|
||||
Reference in New Issue
Block a user