chore: route cubex deployment through Dockerloid
This commit is contained in:
1 parent
af5261c644
commit
ac735a627e
2 files changed
+44
-45
No files matched your search
+40
-42
@@ -1,7 +1,7 @@
|
|||||||
# Manual PROD deploy to Portainer.
|
# Manual PROD deploy to Dockerloid.
|
||||||
#
|
#
|
||||||
# This does NOT build — build.yml already builds + pushes the api/web images.
|
# This does NOT build — build.yml already builds + pushes the api/web images.
|
||||||
# This workflow (re)applies the deploy/*.stack.yml files to the Portainer Swarm.
|
# This workflow (re)applies the deploy/*.stack.yml files to the Dockerloid Swarm.
|
||||||
# Trigger it by hand from the Actions tab ("Run workflow") and choose:
|
# Trigger it by hand from the Actions tab ("Run workflow") and choose:
|
||||||
# - tag: which already-published image tag to ship (default: latest)
|
# - tag: which already-published image tag to ship (default: latest)
|
||||||
# - scope: how much to deploy
|
# - scope: how much to deploy
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
# own workflow, .gitea/workflows/deploy-galactus.yml.
|
# own workflow, .gitea/workflows/deploy-galactus.yml.
|
||||||
#
|
#
|
||||||
# cssnr/portainer-stack-deploy-action creates each stack on first run and updates
|
# cssnr/portainer-stack-deploy-action creates each stack on first run and updates
|
||||||
# it on every run, so no manual stack pre-creation in the Portainer UI. On a
|
# it on every run, so no manual stack pre-creation in the Dockerloid UI. On a
|
||||||
# `full` deploy the db + minio stacks are applied BEFORE the app (the API depends
|
# `full` deploy the db + minio stacks are applied BEFORE the app (the API depends
|
||||||
# on them). db + minio are stateful + pinned to node label jorgecuadros_db=true
|
# on them). db + minio are stateful + pinned to node label jorgecuadros_db=true
|
||||||
# (see their stack files) — re-applying them is idempotent and keeps their data.
|
# (see their stack files) — re-applying them is idempotent and keeps their data.
|
||||||
@@ -29,13 +29,13 @@
|
|||||||
# Prereqs (once):
|
# Prereqs (once):
|
||||||
# - one swarm node labelled jorgecuadros_db=true (db + minio + api pin there).
|
# - one swarm node labelled jorgecuadros_db=true (db + minio + api pin there).
|
||||||
# - Gitea repo secrets set (Settings > Actions > Secrets):
|
# - Gitea repo secrets set (Settings > Actions > Secrets):
|
||||||
# # Portainer
|
# # Dockerloid
|
||||||
# PORTAINER_URL https://192.168.4.212:9443
|
# DOCKERLOID_URL http://192.168.4.212:7777
|
||||||
# PORTAINER_API_KEY Portainer access token
|
# DOCKERLOID_API_KEY Dockerloid access token
|
||||||
# PORTAINER_ENDPOINT_ID 2 (the local Swarm endpoint)
|
# DOCKERLOID_ENDPOINT_ID 2 (the local Swarm endpoint)
|
||||||
# PORTAINER_APP_STACK_NAME e.g. jorgecuadros-prod-app
|
# DOCKERLOID_APP_STACK_NAME e.g. jorgecuadros-prod-app
|
||||||
# PORTAINER_DB_STACK_NAME e.g. jorgecuadros-prod-db (full only)
|
# DOCKERLOID_DB_STACK_NAME e.g. jorgecuadros-prod-db (full only)
|
||||||
# PORTAINER_MINIO_STACK_NAME e.g. jorgecuadros-prod-minio (full only)
|
# DOCKERLOID_MINIO_STACK_NAME e.g. jorgecuadros-prod-minio (full only)
|
||||||
# # App runtime
|
# # App runtime
|
||||||
# DATABASE_URL mysql://jorgecuadros:<pass>@192.168.4.212:3306/jorgecuadros
|
# DATABASE_URL mysql://jorgecuadros:<pass>@192.168.4.212:3306/jorgecuadros
|
||||||
# SESSION_SECRET 64-hex (openssl rand -hex 32)
|
# SESSION_SECRET 64-hex (openssl rand -hex 32)
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
# # Database stack (full only)
|
# # Database stack (full only)
|
||||||
# MYSQL_PASSWORD app-user password (matches DATABASE_URL)
|
# MYSQL_PASSWORD app-user password (matches DATABASE_URL)
|
||||||
# MYSQL_ROOT_PASSWORD mysql root password
|
# MYSQL_ROOT_PASSWORD mysql root password
|
||||||
# - the runner must reach Portainer (9443). It should also reach MySQL (3306)
|
# - the runner must reach Dockerloid (9443). It should also reach MySQL (3306)
|
||||||
# for the migrate step, but that is no longer load-bearing: dispatch with
|
# for the migrate step, but that is no longer load-bearing: dispatch with
|
||||||
# skip_migrate=true and the api container applies the migrations itself at
|
# skip_migrate=true and the api container applies the migrations itself at
|
||||||
# start (docker/api-entrypoint.sh). `migrate deploy` is idempotent, so the
|
# start (docker/api-entrypoint.sh). `migrate deploy` is idempotent, so the
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
# npx prisma@5 migrate resolve --applied 0000_init \
|
# npx prisma@5 migrate resolve --applied 0000_init \
|
||||||
# --schema packages/database/prisma/schema.prisma
|
# --schema packages/database/prisma/schema.prisma
|
||||||
|
|
||||||
name: Deploy to Portainer
|
name: Deploy via Dockerloid
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -109,12 +109,12 @@ jobs:
|
|||||||
# action's input, not the secret you forgot.
|
# action's input, not the secret you forgot.
|
||||||
- name: Preflight — required secrets
|
- name: Preflight — required secrets
|
||||||
env:
|
env:
|
||||||
PORTAINER_URL: ${{ secrets.PORTAINER_URL }}
|
PORTAINER_URL: ${{ secrets.DOCKERLOID_URL }}
|
||||||
PORTAINER_API_KEY: ${{ secrets.PORTAINER_API_KEY }}
|
PORTAINER_API_KEY: ${{ secrets.DOCKERLOID_API_KEY }}
|
||||||
PORTAINER_ENDPOINT_ID: ${{ secrets.PORTAINER_ENDPOINT_ID }}
|
PORTAINER_ENDPOINT_ID: ${{ secrets.DOCKERLOID_ENDPOINT_ID }}
|
||||||
PORTAINER_APP_STACK_NAME: ${{ secrets.PORTAINER_APP_STACK_NAME }}
|
DOCKERLOID_APP_STACK_NAME: ${{ secrets.DOCKERLOID_APP_STACK_NAME }}
|
||||||
PORTAINER_DB_STACK_NAME: ${{ secrets.PORTAINER_DB_STACK_NAME }}
|
DOCKERLOID_DB_STACK_NAME: ${{ secrets.DOCKERLOID_DB_STACK_NAME }}
|
||||||
PORTAINER_MINIO_STACK_NAME: ${{ secrets.PORTAINER_MINIO_STACK_NAME }}
|
DOCKERLOID_MINIO_STACK_NAME: ${{ secrets.DOCKERLOID_MINIO_STACK_NAME }}
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
SESSION_SECRET: ${{ secrets.SESSION_SECRET }}
|
SESSION_SECRET: ${{ secrets.SESSION_SECRET }}
|
||||||
APP_API_ORIGIN: ${{ secrets.APP_API_ORIGIN }}
|
APP_API_ORIGIN: ${{ secrets.APP_API_ORIGIN }}
|
||||||
@@ -127,11 +127,11 @@ jobs:
|
|||||||
SCOPE: ${{ github.event.inputs.scope }}
|
SCOPE: ${{ github.event.inputs.scope }}
|
||||||
run: |
|
run: |
|
||||||
REQUIRED="PORTAINER_URL PORTAINER_API_KEY PORTAINER_ENDPOINT_ID
|
REQUIRED="PORTAINER_URL PORTAINER_API_KEY PORTAINER_ENDPOINT_ID
|
||||||
PORTAINER_APP_STACK_NAME DATABASE_URL SESSION_SECRET
|
DOCKERLOID_APP_STACK_NAME DATABASE_URL SESSION_SECRET
|
||||||
APP_API_ORIGIN APP_WEB_ORIGIN APP_S3_ENDPOINT
|
APP_API_ORIGIN APP_WEB_ORIGIN APP_S3_ENDPOINT
|
||||||
MINIO_ROOT_USER MINIO_ROOT_PASSWORD MYSQL_ROOT_PASSWORD"
|
MINIO_ROOT_USER MINIO_ROOT_PASSWORD MYSQL_ROOT_PASSWORD"
|
||||||
if [ "$SCOPE" = "full" ]; then
|
if [ "$SCOPE" = "full" ]; then
|
||||||
REQUIRED="$REQUIRED PORTAINER_DB_STACK_NAME PORTAINER_MINIO_STACK_NAME
|
REQUIRED="$REQUIRED DOCKERLOID_DB_STACK_NAME DOCKERLOID_MINIO_STACK_NAME
|
||||||
MYSQL_PASSWORD"
|
MYSQL_PASSWORD"
|
||||||
fi
|
fi
|
||||||
missing=""
|
missing=""
|
||||||
@@ -151,12 +151,12 @@ jobs:
|
|||||||
if: ${{ github.event.inputs.scope == 'full' }}
|
if: ${{ github.event.inputs.scope == 'full' }}
|
||||||
uses: cssnr/portainer-stack-deploy-action@v1
|
uses: cssnr/portainer-stack-deploy-action@v1
|
||||||
with:
|
with:
|
||||||
url: ${{ secrets.PORTAINER_URL }}
|
url: ${{ secrets.DOCKERLOID_URL }}
|
||||||
token: ${{ secrets.PORTAINER_API_KEY }}
|
token: ${{ secrets.DOCKERLOID_API_KEY }}
|
||||||
name: ${{ secrets.PORTAINER_DB_STACK_NAME }}
|
name: ${{ secrets.DOCKERLOID_DB_STACK_NAME }}
|
||||||
file: deploy/jorgecuadros-db.stack.yml
|
file: deploy/jorgecuadros-db.stack.yml
|
||||||
type: file
|
type: file
|
||||||
endpoint: ${{ secrets.PORTAINER_ENDPOINT_ID }}
|
endpoint: ${{ secrets.DOCKERLOID_ENDPOINT_ID }}
|
||||||
env_data: |
|
env_data: |
|
||||||
{
|
{
|
||||||
"MYSQL_SERVER_ID": "1",
|
"MYSQL_SERVER_ID": "1",
|
||||||
@@ -172,12 +172,12 @@ jobs:
|
|||||||
if: ${{ github.event.inputs.scope == 'full' }}
|
if: ${{ github.event.inputs.scope == 'full' }}
|
||||||
uses: cssnr/portainer-stack-deploy-action@v1
|
uses: cssnr/portainer-stack-deploy-action@v1
|
||||||
with:
|
with:
|
||||||
url: ${{ secrets.PORTAINER_URL }}
|
url: ${{ secrets.DOCKERLOID_URL }}
|
||||||
token: ${{ secrets.PORTAINER_API_KEY }}
|
token: ${{ secrets.DOCKERLOID_API_KEY }}
|
||||||
name: ${{ secrets.PORTAINER_MINIO_STACK_NAME }}
|
name: ${{ secrets.DOCKERLOID_MINIO_STACK_NAME }}
|
||||||
file: deploy/jorgecuadros-minio.stack.yml
|
file: deploy/jorgecuadros-minio.stack.yml
|
||||||
type: file
|
type: file
|
||||||
endpoint: ${{ secrets.PORTAINER_ENDPOINT_ID }}
|
endpoint: ${{ secrets.DOCKERLOID_ENDPOINT_ID }}
|
||||||
env_data: |
|
env_data: |
|
||||||
{
|
{
|
||||||
"MINIO_API_PORT": "9000",
|
"MINIO_API_PORT": "9000",
|
||||||
@@ -192,9 +192,9 @@ jobs:
|
|||||||
# unreachable by the only restore path this platform has.
|
# unreachable by the only restore path this platform has.
|
||||||
- name: Pre-migrate backup
|
- name: Pre-migrate backup
|
||||||
env:
|
env:
|
||||||
PORTAINER_URL: ${{ secrets.PORTAINER_URL }}
|
PORTAINER_URL: ${{ secrets.DOCKERLOID_URL }}
|
||||||
PORTAINER_API_KEY: ${{ secrets.PORTAINER_API_KEY }}
|
PORTAINER_API_KEY: ${{ secrets.DOCKERLOID_API_KEY }}
|
||||||
PORTAINER_ENDPOINT_ID: ${{ secrets.PORTAINER_ENDPOINT_ID }}
|
PORTAINER_ENDPOINT_ID: ${{ secrets.DOCKERLOID_ENDPOINT_ID }}
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
# The dump runs as root: --single-transaction issues FLUSH TABLES,
|
# The dump runs as root: --single-transaction issues FLUSH TABLES,
|
||||||
# which needs the global RELOAD privilege the application user
|
# which needs the global RELOAD privilege the application user
|
||||||
@@ -202,9 +202,8 @@ jobs:
|
|||||||
MYSQL_ROOT_PASSWORD: ${{ secrets.MYSQL_ROOT_PASSWORD }}
|
MYSQL_ROOT_PASSWORD: ${{ secrets.MYSQL_ROOT_PASSWORD }}
|
||||||
BACKUP_TAG: ${{ github.event.inputs.tag }}
|
BACKUP_TAG: ${{ github.event.inputs.tag }}
|
||||||
ALLOW_MISSING_CONTAINER: ${{ github.event.inputs.bootstrap }}
|
ALLOW_MISSING_CONTAINER: ${{ github.event.inputs.bootstrap }}
|
||||||
# Portainer serves a self-signed certificate. Scoped to this step
|
# Dockerloid serves a self-signed certificate. Scoped to this step
|
||||||
# only, which does nothing but talk to Portainer.
|
# only, which does nothing but talk to Dockerloid.
|
||||||
NODE_TLS_REJECT_UNAUTHORIZED: "0"
|
|
||||||
run: node deploy/scripts/pre-migrate-backup.mjs
|
run: node deploy/scripts/pre-migrate-backup.mjs
|
||||||
|
|
||||||
# --- schema, forward-only ---------------------------------------------
|
# --- schema, forward-only ---------------------------------------------
|
||||||
@@ -234,28 +233,27 @@ jobs:
|
|||||||
# serving an older build of the same tag.
|
# serving an older build of the same tag.
|
||||||
- name: Pull images
|
- name: Pull images
|
||||||
env:
|
env:
|
||||||
PORTAINER_URL: ${{ secrets.PORTAINER_URL }}
|
PORTAINER_URL: ${{ secrets.DOCKERLOID_URL }}
|
||||||
PORTAINER_API_KEY: ${{ secrets.PORTAINER_API_KEY }}
|
PORTAINER_API_KEY: ${{ secrets.DOCKERLOID_API_KEY }}
|
||||||
PORTAINER_ENDPOINT_ID: ${{ secrets.PORTAINER_ENDPOINT_ID }}
|
PORTAINER_ENDPOINT_ID: ${{ secrets.DOCKERLOID_ENDPOINT_ID }}
|
||||||
REGISTRY: ${{ env.REGISTRY }}
|
REGISTRY: ${{ env.REGISTRY }}
|
||||||
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
|
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
|
||||||
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||||
IMAGES: ${{ github.repository_owner }}/jorgecuadros-api,${{ github.repository_owner }}/jorgecuadros-web
|
IMAGES: ${{ github.repository_owner }}/jorgecuadros-api,${{ github.repository_owner }}/jorgecuadros-web
|
||||||
TAG: ${{ github.event.inputs.tag }}
|
TAG: ${{ github.event.inputs.tag }}
|
||||||
NODE_TLS_REJECT_UNAUTHORIZED: "0"
|
|
||||||
run: node deploy/scripts/pull-images.mjs
|
run: node deploy/scripts/pull-images.mjs
|
||||||
|
|
||||||
# --- always: the app (web + api) -------------------------------------
|
# --- always: the app (web + api) -------------------------------------
|
||||||
- name: Deploy app stack
|
- name: Deploy app stack
|
||||||
uses: cssnr/portainer-stack-deploy-action@v1
|
uses: cssnr/portainer-stack-deploy-action@v1
|
||||||
with:
|
with:
|
||||||
url: ${{ secrets.PORTAINER_URL }}
|
url: ${{ secrets.DOCKERLOID_URL }}
|
||||||
token: ${{ secrets.PORTAINER_API_KEY }}
|
token: ${{ secrets.DOCKERLOID_API_KEY }}
|
||||||
name: ${{ secrets.PORTAINER_APP_STACK_NAME }}
|
name: ${{ secrets.DOCKERLOID_APP_STACK_NAME }}
|
||||||
file: deploy/jorgecuadros-app.stack.yml
|
file: deploy/jorgecuadros-app.stack.yml
|
||||||
type: file
|
type: file
|
||||||
pull: true
|
pull: true
|
||||||
endpoint: ${{ secrets.PORTAINER_ENDPOINT_ID }}
|
endpoint: ${{ secrets.DOCKERLOID_ENDPOINT_ID }}
|
||||||
# NOTE: the block below is parsed as JSON — no comments inside it.
|
# NOTE: the block below is parsed as JSON — no comments inside it.
|
||||||
#
|
#
|
||||||
# API_ORIGIN is deliberately absent. The browser derives the API origin
|
# API_ORIGIN is deliberately absent. The browser derives the API origin
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
# Canonical internal MySQL for the Jorge Cuadros platform.
|
# Canonical internal MySQL for the Jorge Cuadros platform.
|
||||||
#
|
#
|
||||||
# Target: Portainer "local" endpoint on cubex (192.168.4.212:9443), which is a
|
# Target: cubex local endpoint, a 3-node Docker Swarm. The cubex workflow deploys
|
||||||
# 3-node Docker Swarm. This is the source-of-truth database from the plan's
|
# through Dockerloid; the separate Galactus workflow uses its own Portainer. This
|
||||||
|
# is the source-of-truth database from the plan's
|
||||||
# "internal server" — the migration transform+load and the NestJS API both
|
# "internal server" — the migration transform+load and the NestJS API both
|
||||||
# point at it, and (later) it becomes the replication SOURCE for the VPS.
|
# point at it, and (later) it becomes the replication SOURCE for the VPS.
|
||||||
#
|
#
|
||||||
@@ -25,7 +26,7 @@
|
|||||||
# and MySQL will always run there, reusing the same volume.
|
# and MySQL will always run there, reusing the same volume.
|
||||||
#
|
#
|
||||||
# Secrets (MYSQL_ROOT_PASSWORD, MYSQL_PASSWORD) are injected at deploy time via
|
# Secrets (MYSQL_ROOT_PASSWORD, MYSQL_PASSWORD) are injected at deploy time via
|
||||||
# Portainer env_data / stack environment, not committed here.
|
# The stack action env_data / stack environment, not committed here.
|
||||||
|
|
||||||
version: "3.8"
|
version: "3.8"
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user