Add deployment setup
This commit is contained in:
parent
1c10241d4d
commit
98d8a8190b
2 changed files with 260 additions and 26 deletions
230
README.md
230
README.md
|
|
@ -6,7 +6,7 @@ Reusable Forgejo/Gitea actions for toph's infrastructure.
|
|||
|
||||
### `deploy-site`
|
||||
|
||||
Deploy a static site to production.
|
||||
Deploy a static site to production via S3 and Nomad.
|
||||
|
||||
**Usage:**
|
||||
|
||||
|
|
@ -29,20 +29,228 @@ jobs:
|
|||
uses: https://git.toph.so/toph/ci-actions/deploy-site@main
|
||||
with:
|
||||
site-name: mysite
|
||||
traefik-rule: Host(`mysite.example.com`)
|
||||
source-dir: dist # optional, defaults to current dir
|
||||
env:
|
||||
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
|
||||
S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- Packages your site
|
||||
- Uploads to deployment server
|
||||
- Triggers Nomad deployment
|
||||
- Site becomes available at `https://{site-name}.toph.so`
|
||||
**Inputs:**
|
||||
- `site-name` (required): Site identifier used as Nomad service name
|
||||
- `traefik-rule` (required): Traefik routing rule (see examples below)
|
||||
- `source-dir` (optional): Directory with built files, defaults to `.`
|
||||
- `s3-endpoint` (optional): S3 endpoint, defaults to `https://s3.toph.so`
|
||||
|
||||
**No configuration needed** - infrastructure handles:
|
||||
- Docker images
|
||||
- Resource limits
|
||||
- Domains & SSL
|
||||
- Load balancing
|
||||
**Environment variables:**
|
||||
- `S3_ACCESS_KEY`: S3 access key (set via Forgejo secrets)
|
||||
- `S3_SECRET_KEY`: S3 secret key (set via Forgejo secrets)
|
||||
|
||||
**What it does:**
|
||||
1. Packages the site directory as a tarball
|
||||
2. Uploads to S3 at `s3://artifacts/<commit-sha>.tar.gz`
|
||||
3. Sets public-read ACL on the artifact
|
||||
4. Dispatches Nomad job to deploy the site
|
||||
5. Site becomes available via the specified Traefik rule with Let's Encrypt SSL
|
||||
|
||||
**Infrastructure handles:**
|
||||
- Docker containers (static-web-server)
|
||||
- Resource limits (100 CPU, 64MB RAM)
|
||||
- Traefik routing & Let's Encrypt SSL
|
||||
- Automatic restarts
|
||||
|
||||
## Traefik Rule Examples
|
||||
|
||||
**Single domain:**
|
||||
```yaml
|
||||
traefik-rule: Host(`example.com`)
|
||||
```
|
||||
|
||||
**Multiple domains (with www):**
|
||||
```yaml
|
||||
traefik-rule: Host(`example.com`) || Host(`www.example.com`)
|
||||
```
|
||||
|
||||
**Subdomain:**
|
||||
```yaml
|
||||
traefik-rule: Host(`blog.example.com`)
|
||||
```
|
||||
|
||||
**toph.so domain:**
|
||||
```yaml
|
||||
traefik-rule: Host(`mysite.toph.so`)
|
||||
```
|
||||
|
||||
**Path-based routing:**
|
||||
```yaml
|
||||
traefik-rule: Host(`example.com`) && PathPrefix(`/docs`)
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Deploy S3 service (SeaweedFS)
|
||||
|
||||
```bash
|
||||
cd /srv/infra
|
||||
bosun dispatch s3
|
||||
```
|
||||
|
||||
### 2. Create artifacts bucket
|
||||
|
||||
```bash
|
||||
# Configure AWS CLI
|
||||
export AWS_ACCESS_KEY_ID=<your-access-key>
|
||||
export AWS_SECRET_ACCESS_KEY=<your-secret-key>
|
||||
export AWS_ENDPOINT_URL=https://s3.toph.so
|
||||
export AWS_EC2_METADATA_DISABLED=true
|
||||
|
||||
# Create bucket
|
||||
aws s3 mb s3://artifacts
|
||||
|
||||
# Set public-read policy for the bucket
|
||||
aws s3api put-bucket-acl --bucket artifacts --acl public-read
|
||||
```
|
||||
|
||||
### 3. Deploy static-site parameterized job
|
||||
|
||||
```bash
|
||||
cd /srv/infra
|
||||
bosun dispatch static-site-dispatch
|
||||
```
|
||||
|
||||
### 4. Add Forgejo secrets
|
||||
|
||||
In your repository settings (or organization settings for global secrets):
|
||||
- `S3_ACCESS_KEY`: The access key from S3 credentials
|
||||
- `S3_SECRET_KEY`: The secret key from S3 credentials
|
||||
|
||||
## Examples
|
||||
|
||||
### Simple HTML site
|
||||
|
||||
```yaml
|
||||
name: Deploy
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: https://git.toph.so/toph/ci-actions/deploy-site@main
|
||||
with:
|
||||
site-name: mysite
|
||||
traefik-rule: Host(`mysite.toph.so`)
|
||||
source-dir: . # HTML files in repo root
|
||||
env:
|
||||
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
|
||||
S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
|
||||
```
|
||||
|
||||
### Node.js/Vite site with custom domain
|
||||
|
||||
```yaml
|
||||
name: Deploy
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install & build
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
|
||||
- uses: https://git.toph.so/toph/ci-actions/deploy-site@main
|
||||
with:
|
||||
site-name: myapp
|
||||
traefik-rule: Host(`app.example.com`) || Host(`www.app.example.com`)
|
||||
source-dir: dist
|
||||
env:
|
||||
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
|
||||
S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
|
||||
```
|
||||
|
||||
### Hugo site
|
||||
|
||||
```yaml
|
||||
name: Deploy
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true # For Hugo themes
|
||||
|
||||
- name: Setup Hugo
|
||||
run: |
|
||||
wget https://github.com/gohugoio/hugo/releases/download/v0.121.0/hugo_extended_0.121.0_linux-amd64.tar.gz
|
||||
tar xzf hugo_extended_0.121.0_linux-amd64.tar.gz
|
||||
sudo mv hugo /usr/local/bin/
|
||||
|
||||
- name: Build
|
||||
run: hugo --minify
|
||||
|
||||
- uses: https://git.toph.so/toph/ci-actions/deploy-site@main
|
||||
with:
|
||||
site-name: myblog
|
||||
traefik-rule: Host(`blog.example.com`)
|
||||
source-dir: public
|
||||
env:
|
||||
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
|
||||
S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
|
||||
```
|
||||
|
||||
## S3 Access
|
||||
|
||||
- **API endpoint**: https://s3.toph.so
|
||||
- **Console**: https://s3-console.toph.so (restricted to Tailscale)
|
||||
- **Credentials**: Stored in Nomad variables at `nomad/jobs/s3`
|
||||
- **Backend**: SeaweedFS (S3-compatible)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### AWS CLI not found
|
||||
The action automatically installs AWS CLI if not present on the runner.
|
||||
|
||||
### Access denied during upload
|
||||
Check that:
|
||||
1. `S3_ACCESS_KEY` and `S3_SECRET_KEY` are set in Forgejo secrets
|
||||
2. The credentials match those in the S3 Nomad job config
|
||||
3. S3 service is running: `nomad job status s3`
|
||||
|
||||
### Nomad dispatch fails
|
||||
Ensure the `static-site` parameterized job is running:
|
||||
```bash
|
||||
nomad job status static-site
|
||||
# If not found:
|
||||
bosun dispatch static-site-dispatch
|
||||
```
|
||||
|
||||
### Site not accessible
|
||||
Check:
|
||||
1. Nomad allocation is running: `nomad job status static-site`
|
||||
2. Traefik has picked up the service: check Traefik dashboard
|
||||
3. DNS resolves: `dig <site-name>.toph.so`
|
||||
4. Certificate is valid: `curl -v https://<site-name>.toph.so`
|
||||
|
||||
## Development
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
name: Deploy Site
|
||||
description: Deploy static site via Nomad dispatch
|
||||
description: Deploy static site via S3 and Nomad dispatch
|
||||
|
||||
inputs:
|
||||
site-name:
|
||||
description: 'Site identifier'
|
||||
description: 'Site identifier (used as service name in Nomad)'
|
||||
required: true
|
||||
|
||||
traefik-rule:
|
||||
description: 'Traefik routing rule (e.g., Host(`example.com`) or Host(`example.com`) || Host(`www.example.com`))'
|
||||
required: true
|
||||
|
||||
source-dir:
|
||||
|
|
@ -11,35 +15,57 @@ inputs:
|
|||
required: false
|
||||
default: '.'
|
||||
|
||||
s3-endpoint:
|
||||
description: 'S3 endpoint'
|
||||
required: false
|
||||
default: 'https://s3.toph.so'
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Package artifact
|
||||
- name: Install AWS CLI
|
||||
shell: bash
|
||||
run: |
|
||||
if ! command -v aws &> /dev/null; then
|
||||
curl -sL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "/tmp/awscliv2.zip"
|
||||
unzip -q /tmp/awscliv2.zip -d /tmp
|
||||
sudo /tmp/aws/install
|
||||
fi
|
||||
|
||||
- name: Package and upload to S3
|
||||
shell: bash
|
||||
run: |
|
||||
cd "${{ inputs.source-dir }}"
|
||||
tar czf /tmp/${{ inputs.site-name }}.tar.gz .
|
||||
ARTIFACT_NAME="${{ github.sha }}.tar.gz"
|
||||
tar czf "/tmp/${ARTIFACT_NAME}" .
|
||||
|
||||
- name: Upload artifact
|
||||
shell: bash
|
||||
run: |
|
||||
ARTIFACT_URL="http://artifacts.toph.so/${{ github.sha }}.tar.gz"
|
||||
# Configure AWS CLI for S3
|
||||
export AWS_ACCESS_KEY_ID="${{ env.S3_ACCESS_KEY }}"
|
||||
export AWS_SECRET_ACCESS_KEY="${{ env.S3_SECRET_KEY }}"
|
||||
export AWS_ENDPOINT_URL="${{ inputs.s3-endpoint }}"
|
||||
export AWS_EC2_METADATA_DISABLED=true
|
||||
|
||||
curl -X PUT \
|
||||
--data-binary @/tmp/${{ inputs.site-name }}.tar.gz \
|
||||
"$ARTIFACT_URL"
|
||||
# Upload to S3
|
||||
aws s3 cp "/tmp/${ARTIFACT_NAME}" "s3://artifacts/${ARTIFACT_NAME}"
|
||||
|
||||
echo "artifact_url=$ARTIFACT_URL" >> $GITHUB_OUTPUT
|
||||
# Make publicly readable
|
||||
aws s3api put-object-acl \
|
||||
--bucket artifacts \
|
||||
--key "${ARTIFACT_NAME}" \
|
||||
--acl public-read
|
||||
|
||||
echo "📦 Artifact uploaded: ${{ inputs.s3-endpoint }}/artifacts/${ARTIFACT_NAME}"
|
||||
|
||||
- name: Deploy via Nomad
|
||||
shell: bash
|
||||
run: |
|
||||
nomad job dispatch static-site \
|
||||
-meta site_name=${{ inputs.site-name }} \
|
||||
-meta artifact_url=http://artifacts.toph.so/${{ github.sha }}.tar.gz
|
||||
-meta traefik_rule="${{ inputs.traefik-rule }}" \
|
||||
-meta artifact_url=${{ inputs.s3-endpoint }}/artifacts/${{ github.sha }}.tar.gz
|
||||
|
||||
- name: Summary
|
||||
- name: Deployment summary
|
||||
shell: bash
|
||||
run: |
|
||||
echo "✅ Deployed ${{ inputs.site-name }}"
|
||||
echo "🌐 https://${{ inputs.site-name }}.toph.so"
|
||||
echo "📋 Traefik rule: ${{ inputs.traefik-rule }}"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue