Add portfolio to homelab
This commit is contained in:
parent
26c4234dc6
commit
01e7a48403
10
.env.example
10
.env.example
@ -14,4 +14,14 @@ GITEA_RUNNER_TOKEN=your_token_here
|
|||||||
# Grafana admin password
|
# Grafana admin password
|
||||||
GRAFANA_ADMIN_PASSWORD=your_password_here
|
GRAFANA_ADMIN_PASSWORD=your_password_here
|
||||||
|
|
||||||
|
# Authentik secrets
|
||||||
AUTHENTIK_PROXY_TOKEN=your_token_here
|
AUTHENTIK_PROXY_TOKEN=your_token_here
|
||||||
|
AUTHENTIK_GITEA_CLIENT_ID=your_client_id_here
|
||||||
|
AUTHENTIK_GITEA_CLIENT_SECRET=your_client_secret_here
|
||||||
|
AUTHENTIK_GRAFANA_CLIENT_ID=your_client_id_here
|
||||||
|
AUTHENTIK_GRAFANA_CLIENT_SECRET=your_client_secret_here
|
||||||
|
|
||||||
|
# Gitea container registry credentials
|
||||||
|
REGISTRY_SERVER=your_registry_server_here
|
||||||
|
REGISTRY_USER=your_username_here
|
||||||
|
REGISTRY_PASSWORD=your_token_here
|
||||||
@ -1,6 +1,6 @@
|
|||||||
# Apply: kubectl apply -f manifests/network/ddns-cronjob.yaml
|
# Apply: kubectl apply -f manifests/network/ddns-cronjob.yaml
|
||||||
# Delete: kubectl delete -f manifests/network/ddns-cronjob.yaml
|
# Delete: kubectl delete -f manifests/network/ddns-cronjob.yaml
|
||||||
# Description: CronJob that updates home.nik4nao.com DNS on Porkbun every 5 minutes.
|
# Description: CronJob that updates nik4nao.com and home.nik4nao.com DNS on Porkbun every 5 minutes.
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
metadata:
|
metadata:
|
||||||
@ -42,8 +42,6 @@ spec:
|
|||||||
apk add --no-cache curl jq -q
|
apk add --no-cache curl jq -q
|
||||||
|
|
||||||
DOMAIN="nik4nao.com"
|
DOMAIN="nik4nao.com"
|
||||||
RECORD_NAME="home"
|
|
||||||
RECORD_FQDN="${RECORD_NAME}.${DOMAIN}"
|
|
||||||
TTL=300
|
TTL=300
|
||||||
|
|
||||||
timestamp() { date +"%Y-%m-%d %H:%M:%S%z"; }
|
timestamp() { date +"%Y-%m-%d %H:%M:%S%z"; }
|
||||||
@ -56,68 +54,74 @@ spec:
|
|||||||
fi
|
fi
|
||||||
echo "[$(timestamp)] WAN IP: $WAN_IP"
|
echo "[$(timestamp)] WAN IP: $WAN_IP"
|
||||||
|
|
||||||
# Get current DNS records from Porkbun API
|
# Get all DNS records once (reused for all iterations)
|
||||||
RECORDS="$(curl -sf -X POST \
|
RECORDS="$(curl -sf -X POST \
|
||||||
"https://api.porkbun.com/api/json/v3/dns/retrieve/${DOMAIN}" \
|
"https://api.porkbun.com/api/json/v3/dns/retrieve/${DOMAIN}" \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d "{\"apikey\":\"$PORKBUN_API_KEY\",\"secretapikey\":\"$PORKBUN_SECRET_KEY\"}")"
|
-d "{\"apikey\":\"$PORKBUN_API_KEY\",\"secretapikey\":\"$PORKBUN_SECRET_KEY\"}")"
|
||||||
|
|
||||||
# Get all A record IDs for this subdomain
|
for RECORD_NAME in "" "home"; do
|
||||||
RECORD_IDS="$(echo "$RECORDS" | jq -r \
|
RECORD_FQDN="${DOMAIN}"
|
||||||
--arg fqdn "$RECORD_FQDN" \
|
[ -n "$RECORD_NAME" ] && RECORD_FQDN="${RECORD_NAME}.${DOMAIN}"
|
||||||
'.records[] | select(.type=="A" and .name==$fqdn) | .id')"
|
echo "[$(timestamp)] Processing: ${RECORD_FQDN}"
|
||||||
|
|
||||||
# Get the current DNS IP from the first record
|
# Get all A record IDs for this record
|
||||||
DNS_IP="$(echo "$RECORDS" | jq -r \
|
RECORD_IDS="$(echo "$RECORDS" | jq -r \
|
||||||
--arg fqdn "$RECORD_FQDN" \
|
--arg fqdn "$RECORD_FQDN" \
|
||||||
'.records[] | select(.type=="A" and .name==$fqdn) | .content' | head -1)"
|
'.records[] | select(.type=="A" and .name==$fqdn) | .id')"
|
||||||
|
|
||||||
echo "[$(timestamp)] DNS IP: ${DNS_IP:-none}"
|
# Get the current DNS IP from the first record
|
||||||
|
DNS_IP="$(echo "$RECORDS" | jq -r \
|
||||||
|
--arg fqdn "$RECORD_FQDN" \
|
||||||
|
'.records[] | select(.type=="A" and .name==$fqdn) | .content' | head -1)"
|
||||||
|
|
||||||
# Delete all stale duplicate records (keep none — we'll create/update cleanly)
|
echo "[$(timestamp)] DNS IP: ${DNS_IP:-none}"
|
||||||
RECORD_COUNT="$(echo "$RECORD_IDS" | grep -c . || true)"
|
|
||||||
if [ "$RECORD_COUNT" -gt 1 ]; then
|
# Delete all stale duplicate records
|
||||||
echo "[$(timestamp)] Found $RECORD_COUNT duplicate records, deleting all..."
|
RECORD_COUNT="$(echo "$RECORD_IDS" | grep -c . || true)"
|
||||||
for ID in $RECORD_IDS; do
|
if [ "$RECORD_COUNT" -gt 1 ]; then
|
||||||
curl -sf -X POST \
|
echo "[$(timestamp)] Found $RECORD_COUNT duplicate records, deleting all..."
|
||||||
"https://api.porkbun.com/api/json/v3/dns/delete/${DOMAIN}/${ID}" \
|
for ID in $RECORD_IDS; do
|
||||||
|
curl -sf -X POST \
|
||||||
|
"https://api.porkbun.com/api/json/v3/dns/delete/${DOMAIN}/${ID}" \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d "{\"apikey\":\"$PORKBUN_API_KEY\",\"secretapikey\":\"$PORKBUN_SECRET_KEY\"}" > /dev/null
|
||||||
|
echo "[$(timestamp)] Deleted record ID $ID"
|
||||||
|
done
|
||||||
|
DNS_IP=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the single remaining record ID (if any)
|
||||||
|
RECORD_ID="$(echo "$RECORDS" | jq -r \
|
||||||
|
--arg fqdn "$RECORD_FQDN" \
|
||||||
|
'.records[] | select(.type=="A" and .name==$fqdn) | .id' | head -1)"
|
||||||
|
|
||||||
|
# Skip if already correct
|
||||||
|
if [ "$RECORD_COUNT" -le 1 ] && [ "$WAN_IP" = "$DNS_IP" ]; then
|
||||||
|
echo "[$(timestamp)] No change, skipping."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[$(timestamp)] IP changed ${DNS_IP:-none} -> $WAN_IP, updating..."
|
||||||
|
|
||||||
|
if [ -z "$RECORD_ID" ] || [ "$RECORD_COUNT" -gt 1 ]; then
|
||||||
|
# Create fresh record
|
||||||
|
echo "[$(timestamp)] Creating new record..."
|
||||||
|
RESP="$(curl -sf -X POST \
|
||||||
|
"https://api.porkbun.com/api/json/v3/dns/create/${DOMAIN}" \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d "{\"apikey\":\"$PORKBUN_API_KEY\",\"secretapikey\":\"$PORKBUN_SECRET_KEY\"}" > /dev/null
|
-d "{\"apikey\":\"$PORKBUN_API_KEY\",\"secretapikey\":\"$PORKBUN_SECRET_KEY\",\"type\":\"A\",\"name\":\"$RECORD_NAME\",\"content\":\"$WAN_IP\",\"ttl\":$TTL}")"
|
||||||
echo "[$(timestamp)] Deleted record ID $ID"
|
else
|
||||||
done
|
# Update existing single record
|
||||||
DNS_IP=""
|
echo "[$(timestamp)] Updating record ID $RECORD_ID..."
|
||||||
fi
|
RESP="$(curl -sf -X POST \
|
||||||
|
"https://api.porkbun.com/api/json/v3/dns/edit/${DOMAIN}/${RECORD_ID}" \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d "{\"apikey\":\"$PORKBUN_API_KEY\",\"secretapikey\":\"$PORKBUN_SECRET_KEY\",\"type\":\"A\",\"name\":\"$RECORD_NAME\",\"content\":\"$WAN_IP\",\"ttl\":$TTL}")"
|
||||||
|
fi
|
||||||
|
|
||||||
# Get the single remaining record ID (if any)
|
echo "[$(timestamp)] Response: $(echo "$RESP" | jq -c .)"
|
||||||
RECORD_ID="$(echo "$RECORDS" | jq -r \
|
echo "$RESP" | grep -q '"status":"SUCCESS"' && \
|
||||||
--arg fqdn "$RECORD_FQDN" \
|
echo "[$(timestamp)] Update successful" || \
|
||||||
'.records[] | select(.type=="A" and .name==$fqdn) | .id' | head -1)"
|
echo "[$(timestamp)] Update failed"
|
||||||
|
done
|
||||||
# Skip if already correct (single record, correct IP)
|
|
||||||
if [ "$RECORD_COUNT" -le 1 ] && [ "$WAN_IP" = "$DNS_IP" ]; then
|
|
||||||
echo "[$(timestamp)] No change, skipping."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "[$(timestamp)] IP changed ${DNS_IP:-none} -> $WAN_IP, updating..."
|
|
||||||
|
|
||||||
if [ -z "$RECORD_ID" ] || [ "$RECORD_COUNT" -gt 1 ]; then
|
|
||||||
# Create fresh record
|
|
||||||
echo "[$(timestamp)] Creating new record..."
|
|
||||||
RESP="$(curl -sf -X POST \
|
|
||||||
"https://api.porkbun.com/api/json/v3/dns/create/${DOMAIN}" \
|
|
||||||
-H 'Content-Type: application/json' \
|
|
||||||
-d "{\"apikey\":\"$PORKBUN_API_KEY\",\"secretapikey\":\"$PORKBUN_SECRET_KEY\",\"type\":\"A\",\"name\":\"$RECORD_NAME\",\"content\":\"$WAN_IP\",\"ttl\":$TTL}")"
|
|
||||||
else
|
|
||||||
# Update existing single record
|
|
||||||
echo "[$(timestamp)] Updating record ID $RECORD_ID..."
|
|
||||||
RESP="$(curl -sf -X POST \
|
|
||||||
"https://api.porkbun.com/api/json/v3/dns/edit/${DOMAIN}/${RECORD_ID}" \
|
|
||||||
-H 'Content-Type: application/json' \
|
|
||||||
-d "{\"apikey\":\"$PORKBUN_API_KEY\",\"secretapikey\":\"$PORKBUN_SECRET_KEY\",\"type\":\"A\",\"name\":\"$RECORD_NAME\",\"content\":\"$WAN_IP\",\"ttl\":$TTL}")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "[$(timestamp)] Response: $(echo "$RESP" | jq -c .)"
|
|
||||||
echo "$RESP" | grep -q '"status":"SUCCESS"' && \
|
|
||||||
echo "[$(timestamp)] Update successful" || \
|
|
||||||
echo "[$(timestamp)] Update failed"
|
|
||||||
77
manifests/portfolio/portfolio.yaml
Normal file
77
manifests/portfolio/portfolio.yaml
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: portfolio
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: portfolio
|
||||||
|
namespace: portfolio
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: portfolio
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: portfolio
|
||||||
|
spec:
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: gitea-registry
|
||||||
|
containers:
|
||||||
|
- name: portfolio
|
||||||
|
image: gitea.nik4nao.com/nik/portfolio:latest
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 128Mi
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: portfolio
|
||||||
|
namespace: portfolio
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: portfolio
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
|
---
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: portfolio-tls
|
||||||
|
namespace: portfolio
|
||||||
|
spec:
|
||||||
|
secretName: portfolio-tls
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt-prod
|
||||||
|
kind: ClusterIssuer
|
||||||
|
dnsNames:
|
||||||
|
- nik4nao.com
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: portfolio
|
||||||
|
namespace: portfolio
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`nik4nao.com`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: portfolio
|
||||||
|
port: 80
|
||||||
|
tls:
|
||||||
|
secretName: portfolio-tls
|
||||||
12
manifests/portfolio/registry-secret.sh
Normal file
12
manifests/portfolio/registry-secret.sh
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
source "$SCRIPT_DIR/../../.env"
|
||||||
|
|
||||||
|
kubectl create secret docker-registry gitea-registry \
|
||||||
|
--namespace portfolio \
|
||||||
|
--docker-server="$REGISTRY_SERVER" \
|
||||||
|
--docker-username="$REGISTRY_USER" \
|
||||||
|
--docker-password="$REGISTRY_PASSWORD" \
|
||||||
|
--dry-run=client -o yaml | kubectl apply -f -
|
||||||
Loading…
x
Reference in New Issue
Block a user