168 lines
4.9 KiB
YAML
168 lines
4.9 KiB
YAML
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 |