Skip to content

Commit

Permalink
Hetzner deploy
Browse files Browse the repository at this point in the history
  • Loading branch information
Erikvv committed Nov 12, 2024
1 parent 096b788 commit 7624652
Show file tree
Hide file tree
Showing 15 changed files with 204 additions and 25 deletions.
108 changes: 95 additions & 13 deletions .github/workflows/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ jobs:
VERSION_TAG: ${{ fromJson(steps.variables.outputs.result).VERSION_TAG }}
ZTOR_PR_CONTAINER_APP_NAME: ${{ fromJson(steps.variables.outputs.result).ZTOR_PR_CONTAINER_APP_NAME }}
GITHUB_ENVIRONMENT: ${{ fromJson(steps.variables.outputs.result).GITHUB_ENVIRONMENT }}
GITHUB_SWARM_ENVIRONMENT: ${{ fromJson(steps.variables.outputs.result).GITHUB_SWARM_ENVIRONMENT }}
FRONTEND_HOSTNAME: ${{ fromJson(steps.variables.outputs.result).FRONTEND_HOSTNAME }}
ZTOR_HOSTNAME: ${{ fromJson(steps.variables.outputs.result).ZTOR_HOSTNAME }}
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -70,23 +73,46 @@ jobs:
## Buildx is needed for caching
- name: Set up Buildx
uses: docker/setup-buildx-action@v2
## TODO: this is under erikvv's GitHub Container Registry (ghcr.io)
## because Zenmo used to be on a legacy GitHub plan.
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
push: true
file: ./docker/production/ztor/Dockerfile
tags: ghcr.io/zenmo/ztor:${{ needs.variables.outputs.VERSION_TAG }}
cache-from: type=gha
cache-to: type=gha,mode=max

build-frontend:
needs: variables
environment: ${{ needs.variables.outputs.GITHUB_SWARM_ENVIRONMENT }}
runs-on: ubuntu-latest
steps:
## Buildx is needed for caching
- name: Set up Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Azure Container Registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ghcr.io
username: erikvv
password: ${{ secrets.ERIKVV_GHCR_PUSH_PASSWORD }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
uses: docker/build-push-action@v6
with:
push: true
tags: ghcr.io/erikvv/ztor:${{ needs.variables.outputs.VERSION_TAG }}
file: ./docker/production/frontend/Dockerfile
tags: ghcr.io/zenmo/zero-frontend:${{ needs.variables.outputs.VERSION_TAG }}
build-args: VITE_ZTOR_URL=https://${{ vars.ZTOR_HOSTNAME || needs.variables.outputs.ZTOR_HOSTNAME }}
cache-from: type=gha
cache-to: type=gha,mode=max

migrate:
migrate-azure:
needs:
- variables
environment: ${{ needs.variables.outputs.GITHUB_ENVIRONMENT }}
Expand All @@ -108,9 +134,31 @@ jobs:
- name: migrate
run: flyway migrate

deploy-ztor:
migrate-swarm:
needs:
- variables
environment: ${{ needs.variables.outputs.GITHUB_SWARM_ENVIRONMENT }}
runs-on: ubuntu-latest
container:
image: redgate/flyway:10.2.0
env:
## TODO: in case of pull request, copy and migrate test database
FLYWAY_URL: jdbc:postgresql://postgres.zenmo.com:5432/${{ vars.DB_NAME }}
FLYWAY_USER: ${{ vars.DB_NAME }}
FLYWAY_PASSWORD: ${{ secrets.DB_PASSWORD }}
FLYWAY_LOCATIONS: filesystem:./migrations
FLYWAY_BASELINE_ON_MIGRATE: true
steps:
- name: Checkout
uses: actions/checkout@v4
with:
sparse-checkout: migrations
- name: migrate
run: flyway migrate

deploy-ztor-azure:
needs:
- migrate
- migrate-azure
- build-ztor
- variables
- environment-variables
Expand Down Expand Up @@ -147,14 +195,48 @@ jobs:
BASE_URL=https://${{ needs.environment-variables.outputs.ZTOR_CONTAINER_APP_NAME }}.zero.zenmo.com
--ingress external
--tags branch=${{ github.head_ref || github.ref_name }}
--image ghcr.io/erikvv/ztor:${{ needs.variables.outputs.VERSION_TAG }}
--registry-username erikvv
--registry-password ${{ secrets.ERIKVV_GHCR_PULL_PASSWORD }}
--image ghcr.io/zenmo/ztor:${{ needs.variables.outputs.VERSION_TAG }}
--registry-username ${{ github.actor }}
--registry-password ${{ secrets.GITHUB_TOKEN }}
--registry-server ghcr.io
--cpu 1.5
--memory 3
--min-replicas 0
deploy-swarm:
needs:
- migrate-swarm
- build-ztor
- build-frontend
- variables
- environment-variables
environment: ${{ needs.variables.outputs.GITHUB_SWARM_ENVIRONMENT }}
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
sparse-checkout: docker/production
- name: Deploy to Docker Swarm
uses: sagebind/docker-swarm-deploy-action@v2
env:
TAG: ${{ needs.variables.outputs.VERSION_TAG }}
FRONTEND_HOSTNAME: ${{ vars.FRONTEND_HOSTNAME || needs.variables.outputs.FRONTEND_HOSTNAME }}
ZTOR_HOSTNAME: ${{ vars.ZTOR_HOSTNAME || needs.variables.outputs.ZTOR_HOSTNAME }}
DB_NAME: ${{ vars.DB_NAME }}
POSTGRES_PASSWORD: ${{ secrets.DB_PASSWORD }}
AZURE_STORAGE_ACCOUNT_NAME: zerostore
AZURE_STORAGE_ACCOUNT_KEY: ${{ secrets.AZURE_STORAGE_ACCOUNT_KEY }}
AZURE_STORAGE_CONTAINER: ${{ vars.AZURE_STORAGE_CONTAINER }}
CORS_ALLOW_ORIGIN_PATTERN: ${{ vars.CORS_ALLOW_ORIGIN_PATTERN }}
OAUTH_CLIENT_ID: ${{ vars.OAUTH_CLIENT_ID }}
OAUTH_CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }}
with:
remote_host: ssh://[email protected]
ssh_private_key: ${{ secrets.SWARM_SSH_PRIVATE_KEY }}
ssh_public_key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ1E4LUG22qgzc8U7oNYGWCn0cyA31+iyX2pck9wcPMS
args: stack deploy --compose-file ./docker/production/compose.yaml zero-${{ needs.variables.outputs.GITHUB_ENVIRONMENT }}

build-deploy-static-site:
name: Build and deploy static site
runs-on: ubuntu-latest
Expand Down
15 changes: 8 additions & 7 deletions docker-compose.yaml → compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ services:
- ./migrations:/flyway/sql
command: migrate
env_file:
- ./docker/flyway.env
- docker/local/flyway.env
environment:
FLYWAY_URL: jdbc:postgresql://postgres:5432/postgres
FLYWAY_USER: postgres
Expand Down Expand Up @@ -44,20 +44,21 @@ services:
- gradle-zorm-test-home:/home/gradle/.gradle
command: zorm:test --no-daemon
env_file:
- ./docker/ztor.env
- docker/local/ztor.env
environment:
POSTGRES_URL: jdbc:postgresql://postgres:5432/test
POSTGRES_USER: postgres

## Production version
ztor-production:
build:
dockerfile: ./docker/production/ztor/Dockerfile
context: .
user: 1000:1000
ports:
- 127.0.0.1:8082:8082
env_file:
- ./docker/ztor.env
- docker/local/ztor.env
environment:
POSTGRES_URL: jdbc:postgresql://postgres:5432/postgres
POSTGRES_USER: postgres
Expand All @@ -82,7 +83,7 @@ services:
depends_on:
- postgres
env_file:
- ./docker/ztor.env
- docker/local/ztor.env
environment:
POSTGRES_URL: jdbc:postgresql://postgres:5432/postgres
POSTGRES_USER: postgres
Expand Down Expand Up @@ -166,7 +167,7 @@ services:
depends_on:
- postgres
env_file:
- ./docker/ztor.env
- docker/local/ztor.env
environment:
POSTGRES_URL: jdbc:postgresql://postgres:5432/postgres
POSTGRES_USER: postgres
Expand Down Expand Up @@ -202,7 +203,7 @@ services:
## first run `docker-compose run --rm npm run build`
frontend-static:
build:
context: ./docker/caddy
context: docker/local/caddy
volumes:
- ./frontend/dist:/srv
ports:
Expand All @@ -216,7 +217,7 @@ services:
- postgres:/var/lib/postgresql/data
command: "-c log_statement=all"
env_file:
- ./docker/postgres.env
- docker/local/postgres.env

volumes:
gradle-vallum-test-cache:
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
53 changes: 53 additions & 0 deletions docker/production/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
version: "3.8"

# Compose file for Docker Swarm
services:
frontend:
image: ghcr.io/zenmo/zero-frontend:${TAG}
networks:
- caddy_default
labels:
caddy: ${FRONTEND_HOSTNAME}
caddy.reverse_proxy: "{{upstreams 2015}}"
# This certificate only works for the pullrequest domain.
# It should fall back to Let's Encrypt for the main domain.
# Except it doesn't.
#caddy.tls: /static_certs/wildcard.zero.zenmo.com/fullchain.pem /static_certs/wildcard.zero.zenmo.com/privkey.pem
deploy:
resources:
limits:
cpus: "2"
memory: 2G

ztor:
image: ghcr.io/zenmo/ztor:${TAG}
environment:
POSTGRES_URL: jdbc:postgresql://postgres:5432/${DB_NAME}
# POSTGRES_URL: jdbc:postgresql://postgres.zenmo.com:5432/${DB_NAME}
POSTGRES_USER: ${DB_NAME}
POSTGRES_PASSWORD: ${DB_PASSWORD}
AZURE_STORAGE_ACCOUNT_NAME: zerostore
AZURE_STORAGE_ACCOUNT_KEY: ${AZURE_STORAGE_ACCOUNT_KEY}
AZURE_STORAGE_CONTAINER: ${AZURE_STORAGE_CONTAINER}
CORS_ALLOW_ORIGIN_PATTERN: ${CORS_ALLOW_ORIGIN_PATTERN}
OAUTH_CLIENT_ID: ${OAUTH_CLIENT_ID}
OAUTH_CLIENT_SECRET: ${OAUTH_CLIENT_SECRET}
BASE_URL: https://${ZTOR_HOSTNAME}
networks:
- caddy_default
- postgres_default
labels:
caddy: ${ZTOR_HOSTNAME}
caddy.reverse_proxy: "{{upstreams 8082}}"
caddy.tls: /static_certs/wildcard.zero.zenmo.com/fullchain.pem /static_certs/wildcard.zero.zenmo.com/privkey.pem
deploy:
resources:
limits:
cpus: "4"
memory: 8G

networks:
caddy_default:
external: true
postgres_default:
external: true
5 changes: 5 additions & 0 deletions docker/production/frontend/Caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
:2015 {
root /srv
file_server
try_files {path} /index.html
}
30 changes: 30 additions & 0 deletions docker/production/frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# syntax=docker/dockerfile:1.7-labs
# for COPY --exclude support
FROM gradle:8.10.0-jdk21 AS gradle
# TODO: copies too much, breaks caching
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN --mount=type=cache,target=/home/gradle/.gradle/caches gradle zummon:jsBrowserProductionLibraryDistribution --no-daemon

FROM node:22 AS node
ARG VITE_ZTOR_URL

RUN mkdir -p /app/frontend
RUN mkdir -p /app/build/js/packages
WORKDIR /app/frontend
COPY --from=gradle /home/gradle/src/build/js /app/build/js

# first do this so it is cached in a docker layer
COPY frontend/package.json frontend/package-lock.json ./
RUN --mount=type=cache,target=/root/.npm npm install

COPY --exclude=frontend/dist --exclude=frontend/node_modules frontend* ./
RUN npm run build

FROM caddy:2.8.4

COPY docker/production/frontend/Caddyfile /etc/caddy/Caddyfile
COPY --from=node /app/frontend/dist /srv
RUN caddy validate --config /etc/caddy/Caddyfile

CMD caddy run --config /etc/caddy/Caddyfile
1 change: 1 addition & 0 deletions Dockerfile → docker/production/ztor/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## For production

FROM gradle:8.10.0-jdk21 AS build
# TODO: gradle projects should be put in a separate directory
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN --mount=type=cache,target=/home/gradle/.gradle/caches gradle ztor:buildFatJar --no-daemon
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/excel-import/feedback.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {FunctionComponent} from "react"
import {SurveyWithErrors, SurveyValidator, ValidationResult, Status, KtList} from "zero-zummon"
import {SurveyWithErrors, surveyValidator, ValidationResult, Status, KtList} from "zero-zummon"
import {Button} from "primereact/button"
import {MessageDisplay} from "./message-display"
import { Panel } from 'primereact/panel';
Expand All @@ -14,8 +14,7 @@ export const Feedback: FunctionComponent<{
surveyWithErrors: SurveyWithErrors
navigateNext: () => void
}> = ({surveyWithErrors, navigateNext}) => {
const surveyValidator = new SurveyValidator()
const results = surveyValidator.validate(surveyWithErrors.survey)
const results = surveyValidator.get().validate(surveyWithErrors.survey)

return (
<>
Expand Down
10 changes: 8 additions & 2 deletions github-actions/get-variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,16 @@ module.exports = (context) => {
.substring(0, maxBranchLength)
.replaceAll(/-*$/g, '') // remove trailing dashes because it would lead to an invalid name

const versionIdentifier = `${shortBranch}-${context.runNumber}`

return {
ZTOR_PR_CONTAINER_APP_NAME: `${containerAppBaseName}-${shortBranch}-${context.runNumber}`,
VERSION_TAG: `${shortBranch}-${context.runNumber}-${shortCommit}`,
ZTOR_PR_CONTAINER_APP_NAME: `${containerAppBaseName}-${versionIdentifier}`,
VERSION_TAG: `${versionIdentifier}-${shortCommit}`,
GITHUB_ENVIRONMENT: getEnvironment(context),
GITHUB_SWARM_ENVIRONMENT: `swarm-${getEnvironment(context)}`,
// handled by wildcard certificate
FRONTEND_HOSTNAME: `frontend-${versionIdentifier}.zero.zenmo.com`,
ZTOR_HOSTNAME: `ztor-${versionIdentifier}.zero.zenmo.com`,
}
}

Expand Down
2 changes: 2 additions & 0 deletions zummon/src/commonMain/kotlin/companysurvey/Validation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.zenmo.zummon.companysurvey
import kotlin.js.ExperimentalJsExport
import kotlin.js.JsExport

@OptIn(ExperimentalJsExport::class)
@JsExport
fun interface Validator<T> {
fun validate(item: T): List<ValidationResult>
}
Expand Down

0 comments on commit 7624652

Please sign in to comment.