Add Nix-based deploy action for isolated builds
- New deploy-nix-site action using Nix flakes - Runs in nixos/nix:latest container for proper isolation - Builds using flake.nix, uploads to S3, deploys to Nomad - Update deploy-site action to install Nomad CLI - Document both actions in README Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
82a08bf071
commit
33c8946041
3 changed files with 241 additions and 2 deletions
78
README.md
78
README.md
|
|
@ -4,9 +4,85 @@ Reusable Forgejo/Gitea actions for toph's infrastructure.
|
||||||
|
|
||||||
## Available Actions
|
## Available Actions
|
||||||
|
|
||||||
|
### `deploy-nix-site` (Recommended)
|
||||||
|
|
||||||
|
Deploy a static site built with Nix flake to S3 and Nomad. Provides proper isolation and reproducibility.
|
||||||
|
|
||||||
|
**Requirements:**
|
||||||
|
- Repository must have a `flake.nix` with a default package output
|
||||||
|
- Runner label: `nix` (uses `docker://nixos/nix:latest`)
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: Deploy
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: nix
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: https://git.toph.so/toph/ci-actions/deploy-nix-site@main
|
||||||
|
with:
|
||||||
|
site-name: mysite
|
||||||
|
traefik-rule: Host(`mysite.example.com`)
|
||||||
|
env:
|
||||||
|
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
|
||||||
|
S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Inputs:**
|
||||||
|
- `site-name` (required): Site identifier
|
||||||
|
- `traefik-rule` (required): Traefik routing rule
|
||||||
|
- `flake-output` (optional): Nix flake output, defaults to `.#`
|
||||||
|
- `s3-endpoint` (optional): S3 endpoint, defaults to `https://s3.toph.so`
|
||||||
|
|
||||||
|
**Example flake.nix:**
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
description = "My static site";
|
||||||
|
|
||||||
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs }:
|
||||||
|
let
|
||||||
|
system = "x86_64-linux";
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
in {
|
||||||
|
packages.${system}.default = pkgs.stdenv.mkDerivation {
|
||||||
|
name = "my-site";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
buildInputs = [ pkgs.nodejs_20 ];
|
||||||
|
|
||||||
|
buildPhase = ''
|
||||||
|
npm ci
|
||||||
|
npm run build
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
cp -r dist $out
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
devShells.${system}.default = pkgs.mkShell {
|
||||||
|
packages = [ pkgs.nodejs_20 pkgs.vite ];
|
||||||
|
shellHook = "echo 'Run: vite'";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `deploy-site`
|
### `deploy-site`
|
||||||
|
|
||||||
Deploy a static site to production via S3 and Nomad.
|
Deploy a static site to production via S3 and Nomad (non-Nix).
|
||||||
|
|
||||||
**Usage:**
|
**Usage:**
|
||||||
|
|
||||||
|
|
|
||||||
150
deploy-nix-site/action.yaml
Normal file
150
deploy-nix-site/action.yaml
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
name: Deploy Nix Site
|
||||||
|
description: Deploy static site built with Nix flake to S3 and Nomad
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
site-name:
|
||||||
|
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
|
||||||
|
|
||||||
|
flake-output:
|
||||||
|
description: 'Nix flake output to build (e.g., .#packages.x86_64-linux.default or .#)'
|
||||||
|
required: false
|
||||||
|
default: '.#'
|
||||||
|
|
||||||
|
s3-endpoint:
|
||||||
|
description: 'S3 endpoint'
|
||||||
|
required: false
|
||||||
|
default: 'https://s3.toph.so'
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Install tools
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
# Install AWS CLI
|
||||||
|
nix profile install nixpkgs#awscli2
|
||||||
|
|
||||||
|
# Install Nomad
|
||||||
|
nix profile install nixpkgs#nomad
|
||||||
|
|
||||||
|
# Make available in PATH
|
||||||
|
export PATH="$HOME/.nix-profile/bin:$PATH"
|
||||||
|
echo "$HOME/.nix-profile/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
|
# Set Nomad address
|
||||||
|
echo "NOMAD_ADDR=http://alvin:4646" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build site with Nix
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
nix build ${{ inputs.flake-output }} --print-build-logs
|
||||||
|
|
||||||
|
# Find the result
|
||||||
|
if [ -L result ]; then
|
||||||
|
BUILD_OUTPUT="result"
|
||||||
|
else
|
||||||
|
echo "Error: No result symlink found after nix build"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "BUILD_OUTPUT=$BUILD_OUTPUT" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Package and upload to S3
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
ARTIFACT_NAME="${{ github.sha }}.tar.gz"
|
||||||
|
|
||||||
|
# Package the built output
|
||||||
|
tar czf "/tmp/${ARTIFACT_NAME}" -C "$BUILD_OUTPUT" .
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Upload to S3
|
||||||
|
aws s3 cp "/tmp/${ARTIFACT_NAME}" "s3://artifacts/${ARTIFACT_NAME}"
|
||||||
|
|
||||||
|
# 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: |
|
||||||
|
cat > /tmp/deploy-${{ inputs.site-name }}.nomad.json <<'NOMAD_EOF'
|
||||||
|
{
|
||||||
|
"Job": {
|
||||||
|
"ID": "${{ inputs.site-name }}",
|
||||||
|
"Name": "${{ inputs.site-name }}",
|
||||||
|
"Type": "service",
|
||||||
|
"Datacenters": ["contabo"],
|
||||||
|
"Constraints": [{
|
||||||
|
"LTarget": "${node.unique.name}",
|
||||||
|
"RTarget": "alvin",
|
||||||
|
"Operand": "="
|
||||||
|
}],
|
||||||
|
"TaskGroups": [{
|
||||||
|
"Name": "web",
|
||||||
|
"Count": 1,
|
||||||
|
"Networks": [{
|
||||||
|
"Mode": "bridge",
|
||||||
|
"DynamicPorts": [{
|
||||||
|
"Label": "http",
|
||||||
|
"To": 8080
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"Services": [{
|
||||||
|
"Name": "${{ inputs.site-name }}",
|
||||||
|
"PortLabel": "http",
|
||||||
|
"Provider": "nomad",
|
||||||
|
"Tags": [
|
||||||
|
"traefik.enable=true",
|
||||||
|
"traefik.http.routers.${{ inputs.site-name }}.rule=${{ inputs.traefik-rule }}",
|
||||||
|
"traefik.http.routers.${{ inputs.site-name }}.entrypoints=websecure",
|
||||||
|
"traefik.http.routers.${{ inputs.site-name }}.tls.certresolver=letsencrypt"
|
||||||
|
]
|
||||||
|
}],
|
||||||
|
"Tasks": [{
|
||||||
|
"Name": "server",
|
||||||
|
"Driver": "docker",
|
||||||
|
"Config": {
|
||||||
|
"image": "joseluisq/static-web-server:2",
|
||||||
|
"ports": ["http"]
|
||||||
|
},
|
||||||
|
"Env": {
|
||||||
|
"SERVER_ROOT": "/local/public",
|
||||||
|
"SERVER_LOG_LEVEL": "info"
|
||||||
|
},
|
||||||
|
"Artifacts": [{
|
||||||
|
"GetterSource": "${{ inputs.s3-endpoint }}/artifacts/${{ github.sha }}.tar.gz",
|
||||||
|
"RelativeDest": "local/public",
|
||||||
|
"GetterMode": "dir"
|
||||||
|
}],
|
||||||
|
"Resources": {
|
||||||
|
"CPU": 100,
|
||||||
|
"MemoryMB": 64
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NOMAD_EOF
|
||||||
|
|
||||||
|
nomad job run /tmp/deploy-${{ inputs.site-name }}.nomad.json
|
||||||
|
|
||||||
|
- name: Deployment summary
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "✅ Deployed ${{ inputs.site-name }}"
|
||||||
|
echo "📋 Traefik rule: ${{ inputs.traefik-rule }}"
|
||||||
|
|
@ -23,15 +23,28 @@ inputs:
|
||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
- name: Install AWS CLI
|
- name: Install AWS CLI and Nomad
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
# Install AWS CLI if not present
|
||||||
if ! command -v aws &> /dev/null; then
|
if ! command -v aws &> /dev/null; then
|
||||||
curl -sL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "/tmp/awscliv2.zip"
|
curl -sL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "/tmp/awscliv2.zip"
|
||||||
unzip -q /tmp/awscliv2.zip -d /tmp
|
unzip -q /tmp/awscliv2.zip -d /tmp
|
||||||
sudo /tmp/aws/install
|
sudo /tmp/aws/install
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Install Nomad if not present
|
||||||
|
if ! command -v nomad &> /dev/null; then
|
||||||
|
NOMAD_VERSION="1.8.4"
|
||||||
|
curl -sL "https://releases.hashicorp.com/nomad/${NOMAD_VERSION}/nomad_${NOMAD_VERSION}_linux_amd64.zip" -o "/tmp/nomad.zip"
|
||||||
|
unzip -q /tmp/nomad.zip -d /tmp
|
||||||
|
sudo mv /tmp/nomad /usr/local/bin/
|
||||||
|
sudo chmod +x /usr/local/bin/nomad
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set Nomad address
|
||||||
|
echo "NOMAD_ADDR=http://alvin:4646" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Package and upload to S3
|
- name: Package and upload to S3
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue