migration and deployment aligned
This commit is contained in:
parent
69d9613e22
commit
042deb0f6c
3 changed files with 120 additions and 116 deletions
92
.github/workflows/deploy-postgres-env.yml
vendored
92
.github/workflows/deploy-postgres-env.yml
vendored
|
|
@ -1,92 +0,0 @@
|
||||||
name: Deploy Postgres (dev & prod, .env MVP)
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- "feature/*"
|
|
||||||
tags:
|
|
||||||
- "*"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
deploy:
|
|
||||||
runs-on: mealcraft-runners
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# kubectl
|
|
||||||
# -----------------------------
|
|
||||||
- name: Install kubectl
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y curl ca-certificates gettext
|
|
||||||
curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
|
|
||||||
sudo install -m 0755 kubectl /usr/local/bin/kubectl
|
|
||||||
|
|
||||||
- name: Configure kubeconfig (in-cluster)
|
|
||||||
run: |
|
|
||||||
KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT"
|
|
||||||
SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
|
|
||||||
CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
|
|
||||||
|
|
||||||
kubectl config set-cluster microk8s \
|
|
||||||
--server="$KUBE_HOST" \
|
|
||||||
--certificate-authority="$CA_CERT"
|
|
||||||
|
|
||||||
kubectl config set-credentials runner --token="$SA_TOKEN"
|
|
||||||
|
|
||||||
kubectl config set-context runner-context \
|
|
||||||
--cluster=microk8s \
|
|
||||||
--user=runner
|
|
||||||
|
|
||||||
kubectl config use-context runner-context
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Decide env
|
|
||||||
# -----------------------------
|
|
||||||
- name: Set environment
|
|
||||||
run: |
|
|
||||||
if [[ "$GITHUB_REF" == refs/heads/main || "$GITHUB_REF" == refs/tags/* ]]; then
|
|
||||||
echo "ENV=prod" >> $GITHUB_ENV
|
|
||||||
echo "NAMESPACE=default" >> $GITHUB_ENV
|
|
||||||
echo "RUNTIME_SECRET=postgres-prod" >> $GITHUB_ENV
|
|
||||||
echo "POSTGRES_HOST=postgres-prod.default.svc.cluster.local" >> $GITHUB_ENV
|
|
||||||
echo "POSTGRES_DB=stripe_invoice" >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo "ENV=dev" >> $GITHUB_ENV
|
|
||||||
echo "NAMESPACE=dev" >> $GITHUB_ENV
|
|
||||||
echo "RUNTIME_SECRET=postgres-dev" >> $GITHUB_ENV
|
|
||||||
echo "POSTGRES_HOST=postgres-dev.dev.svc.cluster.local" >> $GITHUB_ENV
|
|
||||||
echo "POSTGRES_DB=stripe_invoice_dev" >> $GITHUB_ENV
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Load DB creds from db/.env
|
|
||||||
run: |
|
|
||||||
set -a
|
|
||||||
source db/.env
|
|
||||||
set +a
|
|
||||||
|
|
||||||
if [[ "$ENV" == "prod" ]]; then
|
|
||||||
USER="$PROD_POSTGRES_USER"
|
|
||||||
PASS="$PROD_POSTGRES_PASSWORD"
|
|
||||||
else
|
|
||||||
USER="$DEV_POSTGRES_USER"
|
|
||||||
PASS="$DEV_POSTGRES_PASSWORD"
|
|
||||||
fi
|
|
||||||
|
|
||||||
DATABASE_URL="postgres://${USER}:${PASS}@${POSTGRES_HOST}:5432/${POSTGRES_DB}?sslmode=disable"
|
|
||||||
|
|
||||||
echo "DATABASE_URL=$DATABASE_URL" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Create runtime secret
|
|
||||||
# -----------------------------
|
|
||||||
- name: Apply runtime DATABASE_URL secret
|
|
||||||
run: |
|
|
||||||
kubectl create secret generic $RUNTIME_SECRET \
|
|
||||||
--namespace $NAMESPACE \
|
|
||||||
--from-literal=DATABASE_URL="$DATABASE_URL" \
|
|
||||||
--dry-run=client -o yaml | kubectl apply -f -
|
|
||||||
96
.github/workflows/stripe-to-invoice.yml
vendored
96
.github/workflows/stripe-to-invoice.yml
vendored
|
|
@ -1,4 +1,4 @@
|
||||||
name: Build & Deploy stripe-to-invoice
|
name: Build & Deploy stripe-to-invoice (with DB secrets)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
|
@ -8,10 +8,15 @@ on:
|
||||||
- release/**
|
- release/**
|
||||||
tags:
|
tags:
|
||||||
- "*"
|
- "*"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
# --------------------------------------------------
|
||||||
|
# BUILD IMAGE
|
||||||
|
# --------------------------------------------------
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
|
@ -35,7 +40,11 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
docker push docker.io/kimjunte/stripe_to_invoice:$GITHUB_REF_SLUG
|
docker push docker.io/kimjunte/stripe_to_invoice:$GITHUB_REF_SLUG
|
||||||
|
|
||||||
deploy:
|
# --------------------------------------------------
|
||||||
|
# APPLY DB SECRETS
|
||||||
|
# --------------------------------------------------
|
||||||
|
secrets:
|
||||||
|
name: Apply runtime DB secret
|
||||||
runs-on: mealcraft-runners
|
runs-on: mealcraft-runners
|
||||||
needs: build
|
needs: build
|
||||||
|
|
||||||
|
|
@ -49,7 +58,81 @@ jobs:
|
||||||
curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
|
curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
|
||||||
sudo install -m 0755 kubectl /usr/local/bin/kubectl
|
sudo install -m 0755 kubectl /usr/local/bin/kubectl
|
||||||
|
|
||||||
- name: Configure kubeconfig
|
- name: Configure kubeconfig (in-cluster)
|
||||||
|
run: |
|
||||||
|
KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT"
|
||||||
|
SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
|
||||||
|
CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
|
||||||
|
|
||||||
|
kubectl config set-cluster microk8s \
|
||||||
|
--server="$KUBE_HOST" \
|
||||||
|
--certificate-authority="$CA_CERT"
|
||||||
|
|
||||||
|
kubectl config set-credentials runner --token="$SA_TOKEN"
|
||||||
|
|
||||||
|
kubectl config set-context runner-context \
|
||||||
|
--cluster=microk8s \
|
||||||
|
--user=runner
|
||||||
|
|
||||||
|
kubectl config use-context runner-context
|
||||||
|
|
||||||
|
- name: Decide environment
|
||||||
|
run: |
|
||||||
|
if [[ "$GITHUB_REF" == refs/heads/main || "$GITHUB_REF" == refs/tags/* || "$GITHUB_REF" == refs/heads/release/* ]]; then
|
||||||
|
echo "ENV=prod" >> $GITHUB_ENV
|
||||||
|
echo "NAMESPACE=default" >> $GITHUB_ENV
|
||||||
|
echo "RUNTIME_SECRET=postgres-prod" >> $GITHUB_ENV
|
||||||
|
echo "POSTGRES_HOST=postgres-prod.default.svc.cluster.local" >> $GITHUB_ENV
|
||||||
|
echo "POSTGRES_DB=stripe_invoice" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "ENV=dev" >> $GITHUB_ENV
|
||||||
|
echo "NAMESPACE=dev" >> $GITHUB_ENV
|
||||||
|
echo "RUNTIME_SECRET=postgres-dev" >> $GITHUB_ENV
|
||||||
|
echo "POSTGRES_HOST=postgres-dev.dev.svc.cluster.local" >> $GITHUB_ENV
|
||||||
|
echo "POSTGRES_DB=stripe_invoice_dev" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Load DB creds from db/.env and apply secret
|
||||||
|
run: |
|
||||||
|
set -a
|
||||||
|
source db/.env
|
||||||
|
set +a
|
||||||
|
|
||||||
|
if [[ "$ENV" == "prod" ]]; then
|
||||||
|
USER="$PROD_POSTGRES_USER"
|
||||||
|
PASS="$PROD_POSTGRES_PASSWORD"
|
||||||
|
else
|
||||||
|
USER="$DEV_POSTGRES_USER"
|
||||||
|
PASS="$DEV_POSTGRES_PASSWORD"
|
||||||
|
fi
|
||||||
|
|
||||||
|
DATABASE_URL="postgres://${USER}:${PASS}@${POSTGRES_HOST}:5432/${POSTGRES_DB}?sslmode=disable"
|
||||||
|
|
||||||
|
kubectl create secret generic $RUNTIME_SECRET \
|
||||||
|
--namespace $NAMESPACE \
|
||||||
|
--from-literal=DATABASE_URL="$DATABASE_URL" \
|
||||||
|
--dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
|
# --------------------------------------------------
|
||||||
|
# DEPLOY APP
|
||||||
|
# --------------------------------------------------
|
||||||
|
deploy:
|
||||||
|
runs-on: mealcraft-runners
|
||||||
|
needs:
|
||||||
|
- build
|
||||||
|
- secrets
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install kubectl
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y curl ca-certificates gettext
|
||||||
|
curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
|
||||||
|
sudo install -m 0755 kubectl /usr/local/bin/kubectl
|
||||||
|
|
||||||
|
- name: Configure kubeconfig (in-cluster)
|
||||||
run: |
|
run: |
|
||||||
KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT"
|
KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT"
|
||||||
SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
|
SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
|
||||||
|
|
@ -64,7 +147,7 @@ jobs:
|
||||||
- name: Inject slug variables
|
- name: Inject slug variables
|
||||||
uses: rlespinasse/github-slug-action@v4
|
uses: rlespinasse/github-slug-action@v4
|
||||||
|
|
||||||
- name: Set environment
|
- name: Decide environment
|
||||||
run: |
|
run: |
|
||||||
if [[ "$GITHUB_REF" == refs/heads/release/* || "$GITHUB_REF" == refs/tags/* ]]; then
|
if [[ "$GITHUB_REF" == refs/heads/release/* || "$GITHUB_REF" == refs/tags/* ]]; then
|
||||||
echo "NAMESPACE=default" >> $GITHUB_ENV
|
echo "NAMESPACE=default" >> $GITHUB_ENV
|
||||||
|
|
@ -75,8 +158,9 @@ jobs:
|
||||||
echo "DB_ENV=dev" >> $GITHUB_ENV
|
echo "DB_ENV=dev" >> $GITHUB_ENV
|
||||||
echo "HOSTNAME=stripe-to-invoice.dev.juntekim.com" >> $GITHUB_ENV
|
echo "HOSTNAME=stripe-to-invoice.dev.juntekim.com" >> $GITHUB_ENV
|
||||||
fi
|
fi
|
||||||
- name: Deploy
|
|
||||||
|
- name: Deploy application
|
||||||
run: |
|
run: |
|
||||||
export IMAGE="docker.io/kimjunte/stripe_to_invoice:$GITHUB_REF_SLUG"
|
export IMAGE="docker.io/kimjunte/stripe_to_invoice:$GITHUB_REF_SLUG"
|
||||||
export NAMESPACE DB_ENV
|
export NAMESPACE DB_ENV HOSTNAME
|
||||||
envsubst < stripe_to_invoice/deployment/deployment.yaml | kubectl apply -f -
|
envsubst < stripe_to_invoice/deployment/deployment.yaml | kubectl apply -f -
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ mkdir -p "$BACKUP_DIR"
|
||||||
# NEVER touch raw Postgres data
|
# NEVER touch raw Postgres data
|
||||||
TAR_EXCLUDES=(
|
TAR_EXCLUDES=(
|
||||||
"$K8S_STORAGE_ROOT/postgres"
|
"$K8S_STORAGE_ROOT/postgres"
|
||||||
|
"$K8S_STORAGE_ROOT/lost+found"
|
||||||
)
|
)
|
||||||
|
|
||||||
# ==================================================
|
# ==================================================
|
||||||
|
|
@ -31,7 +32,7 @@ TAR_EXCLUDES=(
|
||||||
# ==================================================
|
# ==================================================
|
||||||
case "$ENVIRONMENT" in
|
case "$ENVIRONMENT" in
|
||||||
dev)
|
dev)
|
||||||
PG_SECRET_NAME="postgres-secret"
|
PG_SECRET_NAME="postgres-dev"
|
||||||
PG_POD_SELECTOR="app=postgres-dev"
|
PG_POD_SELECTOR="app=postgres-dev"
|
||||||
S3_PREFIX="dev"
|
S3_PREFIX="dev"
|
||||||
NAMESPACE="dev"
|
NAMESPACE="dev"
|
||||||
|
|
@ -43,7 +44,7 @@ case "$ENVIRONMENT" in
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PG_SECRET_NAME="postgres-prod-secret"
|
PG_SECRET_NAME="postgres-prod"
|
||||||
PG_POD_SELECTOR="app=postgres-prod"
|
PG_POD_SELECTOR="app=postgres-prod"
|
||||||
S3_PREFIX="prod"
|
S3_PREFIX="prod"
|
||||||
NAMESPACE="default"
|
NAMESPACE="default"
|
||||||
|
|
@ -56,14 +57,15 @@ esac
|
||||||
|
|
||||||
echo "=== Backup started ($(date -u)) ==="
|
echo "=== Backup started ($(date -u)) ==="
|
||||||
echo "Environment: $ENVIRONMENT"
|
echo "Environment: $ENVIRONMENT"
|
||||||
|
echo "Namespace: $NAMESPACE"
|
||||||
|
|
||||||
# ==================================================
|
# ==================================================
|
||||||
# POSTGRES DUMP (SAFE)
|
# LOCATE POSTGRES POD
|
||||||
# ==================================================
|
# ==================================================
|
||||||
POSTGRES_POD=$(kubectl get pods \
|
POSTGRES_POD=$(kubectl get pods \
|
||||||
-n "$NAMESPACE" \
|
-n "$NAMESPACE" \
|
||||||
-l "$PG_POD_SELECTOR" \
|
-l "$PG_POD_SELECTOR" \
|
||||||
-o jsonpath='{.items[*].metadata.name}' | awk '{print $1}')
|
-o jsonpath='{.items[0].metadata.name}')
|
||||||
|
|
||||||
if [[ -z "$POSTGRES_POD" ]]; then
|
if [[ -z "$POSTGRES_POD" ]]; then
|
||||||
echo "❌ No Postgres pod found for selector: $PG_POD_SELECTOR"
|
echo "❌ No Postgres pod found for selector: $PG_POD_SELECTOR"
|
||||||
|
|
@ -71,26 +73,36 @@ if [[ -z "$POSTGRES_POD" ]]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
POSTGRES_USER=$(kubectl get secret "$PG_SECRET_NAME" \
|
echo "Using Postgres pod: $POSTGRES_POD"
|
||||||
-n "$NAMESPACE" \
|
|
||||||
-o jsonpath='{.data.POSTGRES_USER}' | base64 -d)
|
|
||||||
|
|
||||||
POSTGRES_DB=$(kubectl get secret "$PG_SECRET_NAME" \
|
# ==================================================
|
||||||
|
# READ DATABASE_URL FROM SECRET
|
||||||
|
# ==================================================
|
||||||
|
DATABASE_URL=$(kubectl get secret "$PG_SECRET_NAME" \
|
||||||
-n "$NAMESPACE" \
|
-n "$NAMESPACE" \
|
||||||
-o jsonpath='{.data.POSTGRES_DB}' 2>/dev/null | base64 -d || true)
|
-o jsonpath='{.data.DATABASE_URL}' | base64 -d)
|
||||||
|
|
||||||
if [[ -z "$POSTGRES_DB" ]]; then
|
if [[ -z "$DATABASE_URL" ]]; then
|
||||||
echo "❌ POSTGRES_DB missing in secret $PG_SECRET_NAME"
|
echo "❌ DATABASE_URL missing in secret $PG_SECRET_NAME"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Dumping database: $POSTGRES_DB"
|
# Parse DATABASE_URL
|
||||||
|
POSTGRES_USER="$(echo "$DATABASE_URL" | sed -E 's|.*://([^:]+):.*|\1|')"
|
||||||
|
POSTGRES_DB="$(echo "$DATABASE_URL" | sed -E 's|.*/([^?]+).*|\1|')"
|
||||||
|
|
||||||
|
if [[ -z "$POSTGRES_USER" || -z "$POSTGRES_DB" ]]; then
|
||||||
|
echo "❌ Failed to parse DATABASE_URL"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Dumping database: $POSTGRES_DB (user: $POSTGRES_USER)"
|
||||||
|
|
||||||
|
# ==================================================
|
||||||
|
# POSTGRES LOGICAL DUMP (SAFE)
|
||||||
|
# ==================================================
|
||||||
kubectl exec -n "$NAMESPACE" "$POSTGRES_POD" -- \
|
kubectl exec -n "$NAMESPACE" "$POSTGRES_POD" -- \
|
||||||
pg_dump \
|
pg_dump "$POSTGRES_DB" \
|
||||||
-h localhost \
|
|
||||||
-U "$POSTGRES_USER" \
|
|
||||||
"$POSTGRES_DB" \
|
|
||||||
> "$BACKUP_DIR/postgres.sql"
|
> "$BACKUP_DIR/postgres.sql"
|
||||||
|
|
||||||
echo "✔ pg_dump complete ($(du -h "$BACKUP_DIR/postgres.sql" | cut -f1))"
|
echo "✔ pg_dump complete ($(du -h "$BACKUP_DIR/postgres.sql" | cut -f1))"
|
||||||
|
|
@ -145,6 +157,6 @@ echo " sudo tar -xzf k8s_storage_$DATE.tar.gz -C /"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Restore Postgres:"
|
echo "Restore Postgres:"
|
||||||
echo " kubectl exec -n $NAMESPACE -i $POSTGRES_POD -- \\"
|
echo " kubectl exec -n $NAMESPACE -i $POSTGRES_POD -- \\"
|
||||||
echo " psql -U $POSTGRES_USER $POSTGRES_DB < postgres.sql"
|
echo " psql $POSTGRES_DB < postgres.sql"
|
||||||
echo ""
|
echo ""
|
||||||
echo "=== Backup completed successfully ==="
|
echo "=== Backup completed successfully ==="
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue