From 52496c44a2c23674f64594c59c66867d9995752c Mon Sep 17 00:00:00 2001 From: mr-forust Date: Sun, 21 Jun 2026 22:22:31 +0200 Subject: [PATCH] chore: add ssh deploy workflow --- .gitea/workflows/deploy.yaml | 87 ++++++++++++++++++++++++++++++ .github/workflows/deploy.yaml | 87 ++++++++++++++++++++++++++++++ .github/workflows/prod_deploy.yaml | 41 -------------- 3 files changed, 174 insertions(+), 41 deletions(-) create mode 100644 .gitea/workflows/deploy.yaml create mode 100644 .github/workflows/deploy.yaml delete mode 100644 .github/workflows/prod_deploy.yaml diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml new file mode 100644 index 0000000..4407c33 --- /dev/null +++ b/.gitea/workflows/deploy.yaml @@ -0,0 +1,87 @@ +name: deploy + +on: + push: + branches: + - main + workflow_dispatch: + +concurrency: + group: deploy-main + cancel-in-progress: false + +jobs: + redeploy: + runs-on: [self-hosted, linux, arch, homelab, prod] + steps: + - name: Redeploy workstation + shell: bash + env: + DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} + DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }} + DEPLOY_USER: ${{ secrets.DEPLOY_USER }} + DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} + DEPLOY_KEY: ${{ secrets.DEPLOY_SSH_KEY }} + run: | + set -euo pipefail + + : "${DEPLOY_HOST:?missing DEPLOY_HOST}" + : "${DEPLOY_USER:?missing DEPLOY_USER}" + : "${DEPLOY_KEY:?missing DEPLOY_SSH_KEY}" + + deploy_port="${DEPLOY_PORT:-22}" + deploy_path="${DEPLOY_PATH:-/srv/homelab}" + + ssh_key="$RUNNER_TEMP/deploy_key" + mkdir -p "$RUNNER_TEMP" + printf '%s\n' "$DEPLOY_KEY" > "$ssh_key" + chmod 600 "$ssh_key" + + ssh_opts=( + -i "$ssh_key" + -p "$deploy_port" + -o BatchMode=yes + -o StrictHostKeyChecking=accept-new + ) + + ssh "${ssh_opts[@]}" "${DEPLOY_USER}@${DEPLOY_HOST}" "DEPLOY_PATH=$(printf '%q' \"$deploy_path\") bash -se" <<'EOF' + set -euo pipefail + + repo="${DEPLOY_PATH:-/srv/homelab}" + + if [ ! -d "$repo/.git" ]; then + echo "Repository not found at $repo" + exit 1 + fi + + git -C "$repo" fetch origin main + git -C "$repo" reset --hard origin/main + + echo "Redeploying docker compose stacks" + while IFS= read -r compose_file; do + [ -n "$compose_file" ] || continue + compose_dir=$(dirname "$compose_file") + echo " - $compose_dir" + docker compose -f "$compose_file" up -d --pull always --remove-orphans + done < <(find "$repo" -type f \( -name 'compose.yaml' -o -name 'compose.yml' \) | sort) + + echo "Applying Kubernetes manifests" + while IFS= read -r manifest; do + [ -n "$manifest" ] || continue + echo " - $manifest" + kubectl apply -f "$manifest" + done < <( + find "$repo" -type f \ + -path '*/k8s/*' \ + \( -name '*.yaml' -o -name '*.yml' \) \ + ! -name 'kustomization.yaml' \ + ! -name 'kustomization.yml' \ + ! -name '*.example.yaml' \ + ! -name '*.example.yml' \ + ! -name '*values.yaml' \ + ! -name '*values.yml' \ + ! -name 'patch-*.yaml' \ + ! -name 'patch-*.yml' \ + | sort + ) + EOF diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 0000000..4407c33 --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,87 @@ +name: deploy + +on: + push: + branches: + - main + workflow_dispatch: + +concurrency: + group: deploy-main + cancel-in-progress: false + +jobs: + redeploy: + runs-on: [self-hosted, linux, arch, homelab, prod] + steps: + - name: Redeploy workstation + shell: bash + env: + DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} + DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }} + DEPLOY_USER: ${{ secrets.DEPLOY_USER }} + DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} + DEPLOY_KEY: ${{ secrets.DEPLOY_SSH_KEY }} + run: | + set -euo pipefail + + : "${DEPLOY_HOST:?missing DEPLOY_HOST}" + : "${DEPLOY_USER:?missing DEPLOY_USER}" + : "${DEPLOY_KEY:?missing DEPLOY_SSH_KEY}" + + deploy_port="${DEPLOY_PORT:-22}" + deploy_path="${DEPLOY_PATH:-/srv/homelab}" + + ssh_key="$RUNNER_TEMP/deploy_key" + mkdir -p "$RUNNER_TEMP" + printf '%s\n' "$DEPLOY_KEY" > "$ssh_key" + chmod 600 "$ssh_key" + + ssh_opts=( + -i "$ssh_key" + -p "$deploy_port" + -o BatchMode=yes + -o StrictHostKeyChecking=accept-new + ) + + ssh "${ssh_opts[@]}" "${DEPLOY_USER}@${DEPLOY_HOST}" "DEPLOY_PATH=$(printf '%q' \"$deploy_path\") bash -se" <<'EOF' + set -euo pipefail + + repo="${DEPLOY_PATH:-/srv/homelab}" + + if [ ! -d "$repo/.git" ]; then + echo "Repository not found at $repo" + exit 1 + fi + + git -C "$repo" fetch origin main + git -C "$repo" reset --hard origin/main + + echo "Redeploying docker compose stacks" + while IFS= read -r compose_file; do + [ -n "$compose_file" ] || continue + compose_dir=$(dirname "$compose_file") + echo " - $compose_dir" + docker compose -f "$compose_file" up -d --pull always --remove-orphans + done < <(find "$repo" -type f \( -name 'compose.yaml' -o -name 'compose.yml' \) | sort) + + echo "Applying Kubernetes manifests" + while IFS= read -r manifest; do + [ -n "$manifest" ] || continue + echo " - $manifest" + kubectl apply -f "$manifest" + done < <( + find "$repo" -type f \ + -path '*/k8s/*' \ + \( -name '*.yaml' -o -name '*.yml' \) \ + ! -name 'kustomization.yaml' \ + ! -name 'kustomization.yml' \ + ! -name '*.example.yaml' \ + ! -name '*.example.yml' \ + ! -name '*values.yaml' \ + ! -name '*values.yml' \ + ! -name 'patch-*.yaml' \ + ! -name 'patch-*.yml' \ + | sort + ) + EOF diff --git a/.github/workflows/prod_deploy.yaml b/.github/workflows/prod_deploy.yaml deleted file mode 100644 index 0047066..0000000 --- a/.github/workflows/prod_deploy.yaml +++ /dev/null @@ -1,41 +0,0 @@ -## BINARY MODE, USE WITH THE GITHUB RUNNER BINARY INSTALLED ON THE SERVER - -name: Deploy to Server -run-name: Deploying onto server on ${{ github.ref }} -on: - push: - branches: - - main - - ci/actions -jobs: - deploy: - runs-on: [prod, self-hosted] - steps: - - name: Fetch and Diff Analysis - id: diff - run: | - cd ${{ secrets.PROD_DIR }} - git fetch origin main - CHANGES=$(git diff --name-only HEAD origin/main | cut -d/ -f1 | sort -u | tr '\n' ' ') - echo "dirs=$CHANGES" >> $GITHUB_OUTPUT - echo "Changed dirs: $CHANGES" - - - name: Sync Server Files - run: | - cd ${{ secrets.PROD_DIR }} - git reset --hard origin/main - echo "Server files synced with origin/main" - - - name: Deploy Services - run: | - cd ${{ secrets.PROD_DIR }} - for dir in ${{ steps.diff.outputs.dirs }}; do - if [ -d "$dir" ] && ([ -f "$dir/compose.yaml" ] || [ -f "$dir/docker-compose.yaml" ]); then - echo ">>> Deploying $dir" - cd "$dir" - DOCKER_BUILDKIT=1 BUILDKIT_PROGRESS=plain docker compose up -d --build --no-color - cd .. - else - echo ">>> Skipping $dir: no compose file found" - fi - done