Skip to content

Commit f6592e3

Browse files
committed
Add deploy-mirror workflow
1 parent f9dd03a commit f6592e3

1 file changed

Lines changed: 148 additions & 0 deletions

File tree

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
name: Deploy Mirror
2+
3+
run-name: "Deploy mirror: ${{ github.sha }}"
4+
5+
concurrency:
6+
group: deploy-mirror
7+
cancel-in-progress: true
8+
9+
on:
10+
workflow_dispatch:
11+
12+
env:
13+
REGISTRY: ghcr.io
14+
IMAGE_NAME: ${{ github.repository }}
15+
16+
permissions:
17+
contents: read
18+
packages: write
19+
20+
jobs:
21+
deploy:
22+
name: Deploy Mirror
23+
runs-on: ubuntu-latest
24+
25+
steps:
26+
- name: Checkout
27+
uses: actions/checkout@v4
28+
29+
- name: Set up Docker Buildx
30+
uses: docker/setup-buildx-action@v3
31+
32+
- name: Log in to GHCR
33+
uses: docker/login-action@v3
34+
with:
35+
registry: ${{ env.REGISTRY }}
36+
username: ${{ github.actor }}
37+
password: ${{ secrets.GITHUB_TOKEN }}
38+
39+
- name: Extract metadata
40+
id: meta
41+
uses: docker/metadata-action@v5
42+
with:
43+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
44+
45+
- name: Set up Node.js
46+
uses: actions/setup-node@v4
47+
with:
48+
node-version: 22
49+
50+
- name: Install and typecheck
51+
run: |
52+
npm ci
53+
npx astro sync
54+
npm run typecheck
55+
56+
- name: Build and push
57+
uses: docker/build-push-action@v6
58+
with:
59+
context: .
60+
target: production
61+
push: true
62+
provenance: false
63+
sbom: false
64+
cache-from: type=gha
65+
cache-to: type=gha,mode=max
66+
tags: |
67+
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:mirror-${{ github.sha }}
68+
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:mirror-latest
69+
labels: ${{ steps.meta.outputs.labels }}
70+
71+
- name: Start SSH agent
72+
uses: webfactory/ssh-agent@v0.9.0
73+
with:
74+
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
75+
76+
- name: Add known hosts
77+
run: |
78+
mkdir -p ~/.ssh
79+
ssh-keyscan -H "${{ secrets.SSH_HOST_DEV }}" >> ~/.ssh/known_hosts
80+
81+
- name: Deploy over SSH
82+
env:
83+
SSH_USER: ${{ secrets.SSH_USER }}
84+
SSH_HOST: ${{ secrets.SSH_HOST_DEV }}
85+
REPO: ${{ github.repository }}
86+
BRANCH: ${{ github.ref_name }}
87+
GHCR_USER: ${{ secrets.GHCR_USER }}
88+
GHCR_TOKEN: ${{ secrets.GHCR_TOKEN }}
89+
IMAGE_TAG: mirror-${{ github.sha }}
90+
S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
91+
S3_REGION: ${{ secrets.S3_REGION }}
92+
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
93+
S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
94+
S3_BUCKET: ${{ secrets.S3_BUCKET }}
95+
run: |
96+
ssh "${SSH_USER}@${SSH_HOST}" \
97+
"env GHCR_USER='${GHCR_USER}' GHCR_TOKEN='${GHCR_TOKEN}' IMAGE_TAG='${IMAGE_TAG}' S3_ENDPOINT='${S3_ENDPOINT}' S3_REGION='${S3_REGION}' S3_ACCESS_KEY='${S3_ACCESS_KEY}' S3_SECRET_KEY='${S3_SECRET_KEY}' S3_BUCKET='${S3_BUCKET}' bash -s -- '${REPO}' '${BRANCH}'" <<'EOS'
98+
set -euo pipefail
99+
100+
REPO="${1:?missing repo}"
101+
BRANCH="${2:-main}"
102+
103+
: "${IMAGE_TAG:?missing IMAGE_TAG}"
104+
: "${GHCR_USER:?missing GHCR_USER}"
105+
: "${GHCR_TOKEN:?missing GHCR_TOKEN}"
106+
107+
STACK_NAME="underlay-mirror"
108+
REPO_NAME="${REPO##*/}"
109+
APP_DIR="/srv/${REPO_NAME}-mirror"
110+
REPO_SSH="git@github.com:${REPO}.git"
111+
112+
ssh-keyscan -H github.com >> ~/.ssh/known_hosts 2>/dev/null
113+
chmod 600 ~/.ssh/known_hosts
114+
115+
if [[ ! -d "${APP_DIR}/.git" ]]; then
116+
sudo mkdir -p "${APP_DIR}"
117+
sudo chown -R "$USER:$USER" "${APP_DIR}"
118+
git clone --branch "${BRANCH}" "${REPO_SSH}" "${APP_DIR}"
119+
fi
120+
121+
cd "${APP_DIR}"
122+
git fetch --prune --tags origin
123+
git checkout "${BRANCH}"
124+
git pull origin "${BRANCH}"
125+
126+
# Init swarm if not already active
127+
if ! sudo docker info --format '{{.Swarm.LocalNodeState}}' | grep -qx active; then
128+
sudo docker swarm init
129+
fi
130+
131+
echo "$GHCR_TOKEN" | sudo docker login ghcr.io -u "$GHCR_USER" --password-stdin
132+
133+
sudo docker pull "ghcr.io/${REPO}:${IMAGE_TAG}"
134+
135+
# Deploy using docker-compose.mirror.yml — Postgres is self-contained,
136+
# only S3 credentials need to be passed through for file storage.
137+
sudo env \
138+
IMAGE="ghcr.io/${REPO}" IMAGE_TAG="$IMAGE_TAG" \
139+
S3_ENDPOINT="$S3_ENDPOINT" S3_REGION="$S3_REGION" \
140+
S3_ACCESS_KEY="$S3_ACCESS_KEY" S3_SECRET_KEY="$S3_SECRET_KEY" \
141+
S3_BUCKET="${S3_BUCKET:-underlay}" \
142+
SESSION_SECRET="$(openssl rand -hex 32)" \
143+
docker stack deploy -c docker-compose.mirror.yml \
144+
--with-registry-auth --resolve-image always --prune "${STACK_NAME}"
145+
146+
sudo docker stack services "${STACK_NAME}"
147+
echo "Mirror deployed as ${STACK_NAME} (image: ${IMAGE_TAG})"
148+
EOS

0 commit comments

Comments
 (0)