feat(monitoring): replace Dozzle with full observability stack
Replace the single-purpose Dozzle log viewer with a comprehensive monitoring stack covering metrics, container telemetry, and persistent log aggregation. Stack changes (docker-stack-service.yml -> docker-stack-monitoring.yml): - remove Dozzle service and dozzle_users Docker secret - add Portainer CE + portainer-agent (Swarm management UI) - add node-exporter (global) — host CPU, memory, disk, network metrics - add cAdvisor (global) — per-container resource usage metrics - add Loki (replicated, service node) — persistent log storage, 31-day retention - add Promtail (global) — Docker service discovery; ships logs with service, stack, container, and project labels; sends to Loki - rename stack to iklimco-monitoring; add loki-vl persistent volume Workflow (.gitea/workflows/deploy-prod.yml -> deploy-monitoring-prod.yml): - rename file and add paths filter (Environment_Monitoring/**) - remove Dozzle secret creation and auth handling - add IMAGE_LOKI / IMAGE_PROMTAIL; clean up legacy dozzle_users Docker secret - update SWAG step to loop swag/site-confs/*.conf.tpl (portainer only) - remove DOZZLE_SUBDOMAIN; remove dozzle DNS record; keep portainer DNS - replace "Wait for Dozzle" with "Wait for Loki" SWAG: - remove swag/dozzle.conf.tpl (Dozzle no longer in stack) - add swag/site-confs/portainer.conf.tpl (moved from main repo template dir; monitoring stack manages its own SWAG configs independently) - remove init/apisix-dozzle.sh (superseded by SWAG reverse proxy) README: - rewrite in Turkish; document Portainer, node-exporter, cAdvisor, Loki, Promtail - add Grafana log viewing guide: datasource setup, label filter table, LogQL examples, metric-log correlation workflow, adding log panels to dashboards Requires IMAGE_LOKI and IMAGE_PROMTAIL to be defined in .env and corresponding custom images (build/loki/, build/promtail/) pushed to Harbor.
This commit is contained in:
parent
94dc1d2fe3
commit
735d957dfa
@ -4,6 +4,8 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- prod-env
|
||||
paths:
|
||||
- 'Environment_Monitoring/**'
|
||||
|
||||
concurrency:
|
||||
group: prod-monitoring-deploy
|
||||
@ -47,104 +49,81 @@ jobs:
|
||||
test -s .env
|
||||
test -s .env.secrets.swag
|
||||
|
||||
- name: Create Dozzle Auth Secret
|
||||
env:
|
||||
DOZZLE_USERS_YML_B64: ${{ secrets.DOZZLE_USERS_YML_B64 }}
|
||||
DOZZLE_USERS_YML: ${{ secrets.DOZZLE_USERS_YML }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ -n "${DOZZLE_USERS_YML_B64:-}" ]; then
|
||||
printf '%s' "$DOZZLE_USERS_YML_B64" | base64 -d > /tmp/dozzle-users.yml
|
||||
elif [ -n "${DOZZLE_USERS_YML:-}" ]; then
|
||||
printf '%s\n' "$DOZZLE_USERS_YML" > /tmp/dozzle-users.yml
|
||||
else
|
||||
echo "DOZZLE_USERS_YML_B64 or DOZZLE_USERS_YML secret is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
grep -q '^users:' /tmp/dozzle-users.yml
|
||||
docker service rm iklimco_dozzle || true
|
||||
for i in $(seq 1 24); do
|
||||
if ! docker service inspect iklimco_dozzle >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
echo "Waiting for old iklimco_dozzle service to be removed..."
|
||||
sleep 5
|
||||
done
|
||||
docker secret rm dozzle_users || true
|
||||
docker secret create dozzle_users /tmp/dozzle-users.yml >/dev/null
|
||||
shred -u /tmp/dozzle-users.yml || rm -f /tmp/dozzle-users.yml
|
||||
|
||||
- name: Deploy Dozzle Stack
|
||||
- name: Deploy Monitoring Stack
|
||||
run: |
|
||||
set -a; . ./.env; set +a
|
||||
export IMAGE_DOZZLE="${IMAGE_DOZZLE:-amir20/dozzle:v10.6.6}"
|
||||
export DOZZLE_USERS_SECRET_NAME=dozzle_users
|
||||
export IMAGE_LOKI="${IMAGE_LOKI}"
|
||||
export IMAGE_PROMTAIL="${IMAGE_PROMTAIL}"
|
||||
|
||||
# Remove leftover dozzle_users Docker secret from previous setup
|
||||
docker secret rm dozzle_users 2>/dev/null || true
|
||||
|
||||
docker stack deploy \
|
||||
--with-registry-auth \
|
||||
--resolve-image changed \
|
||||
-c docker-stack-service.yml \
|
||||
iklimco
|
||||
-c Environment_Monitoring/docker-stack-monitoring.yml \
|
||||
iklimco-monitoring
|
||||
|
||||
- name: Wait for Dozzle
|
||||
- name: Wait for Loki
|
||||
run: |
|
||||
for i in $(seq 1 36); do
|
||||
REPLICAS=$(docker service ls --filter name=iklimco_dozzle --format "{{.Replicas}}" | head -1)
|
||||
REPLICAS=$(docker service ls --filter name=iklimco-monitoring_loki --format "{{.Replicas}}" | head -1)
|
||||
if echo "$REPLICAS" | awk -F'[/ ]' '$1>0 && $1==$2{found=1} END{exit !found}'; then
|
||||
echo "Dozzle is ready: $REPLICAS"
|
||||
echo "Loki is ready: $REPLICAS"
|
||||
exit 0
|
||||
fi
|
||||
echo "Dozzle not ready yet (${REPLICAS:-missing}), waiting 5s..."
|
||||
echo "Loki not ready yet (${REPLICAS:-missing}), waiting 5s..."
|
||||
sleep 5
|
||||
done
|
||||
docker service ps iklimco_dozzle || true
|
||||
docker service ps iklimco-monitoring_loki || true
|
||||
exit 1
|
||||
|
||||
- name: Configure SWAG Reverse Proxy
|
||||
run: |
|
||||
set -a; . ./.env; . ./.env.secrets.swag; set +a
|
||||
export DOZZLE_SUBDOMAIN="${DOZZLE_SUBDOMAIN:-dozzle.iklim.co}"
|
||||
envsubst '${DOZZLE_SUBDOMAIN}' < swag/dozzle.conf.tpl | docker run --rm -i \
|
||||
export PORTAINER_SUBDOMAIN="${PORTAINER_SUBDOMAIN:-portainer.iklim.co}"
|
||||
export RESTRICTED_IPS_BLOCK="$(echo "$RESTRICTED_IPS" | tr ',' '\n' | sed 's|.*| allow &;|')"
|
||||
|
||||
SWAG_VARS='${PORTAINER_SUBDOMAIN}${RESTRICTED_IPS_BLOCK}'
|
||||
for tpl in Environment_Monitoring/swag/site-confs/*.conf.tpl; do
|
||||
fname=$(basename "${tpl%.tpl}")
|
||||
envsubst "$SWAG_VARS" < "$tpl" | docker run --rm -i \
|
||||
-v "${SWAG_SITE_CONFS_DIR}:/output" \
|
||||
alpine sh -c "cat > /output/dozzle.conf"
|
||||
alpine sh -c "cat > /output/${fname}"
|
||||
echo "${fname} written"
|
||||
done
|
||||
|
||||
SWAG_CTR=$(docker ps -q -f name=iklimco_swag 2>/dev/null | head -1)
|
||||
if [ -n "$SWAG_CTR" ]; then
|
||||
docker exec "$SWAG_CTR" nginx -t && docker exec "$SWAG_CTR" nginx -s reload
|
||||
fi
|
||||
|
||||
- name: Configure APISIX Reverse Proxy
|
||||
run: |
|
||||
set -a; . ./.env; set +a
|
||||
export SPRING_PROFILES_ACTIVE=prod
|
||||
export DOZZLE_SUBDOMAIN="${DOZZLE_SUBDOMAIN:-dozzle.iklim.co}"
|
||||
/bin/bash init/apisix-dozzle.sh
|
||||
|
||||
- name: Update DNS Record
|
||||
- name: Update DNS Records
|
||||
run: |
|
||||
set -a; . ./.env; . ./.env.secrets.swag; set +a
|
||||
FLOATING_IP="${{ vars.PROD_FLOATING_IP }}"
|
||||
DOMAIN="iklim.co"
|
||||
RECORD="${DOZZLE_DNS_RECORD:-dozzle}"
|
||||
|
||||
for record in portainer; do
|
||||
CURRENT=$(curl -s \
|
||||
-H "Authorization: sso-key ${GODADDY_KEY}:${GODADDY_SECRET}" \
|
||||
"https://api.godaddy.com/v1/domains/${DOMAIN}/records/A/${RECORD}" \
|
||||
"https://api.godaddy.com/v1/domains/${DOMAIN}/records/A/${record}" \
|
||||
2>/dev/null | jq -r '.[0].data // empty' 2>/dev/null || true)
|
||||
|
||||
if [ "$CURRENT" = "$FLOATING_IP" ]; then
|
||||
echo "${RECORD}.${DOMAIN} -> ${FLOATING_IP} exists, skipping"
|
||||
echo "${record}.${DOMAIN} -> ${FLOATING_IP} exists, skipping"
|
||||
else
|
||||
curl -sf -X PUT \
|
||||
-H "Authorization: sso-key ${GODADDY_KEY}:${GODADDY_SECRET}" \
|
||||
-H "Content-Type: application/json" \
|
||||
"https://api.godaddy.com/v1/domains/${DOMAIN}/records/A/${RECORD}" \
|
||||
"https://api.godaddy.com/v1/domains/${DOMAIN}/records/A/${record}" \
|
||||
-d "[{\"data\":\"${FLOATING_IP}\",\"ttl\":600}]"
|
||||
echo "${RECORD}.${DOMAIN} -> ${FLOATING_IP} added/updated"
|
||||
echo "${record}.${DOMAIN} -> ${FLOATING_IP} added/updated"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Verify Deployment
|
||||
run: |
|
||||
docker service ps iklimco_dozzle \
|
||||
docker service ps iklimco-monitoring_loki \
|
||||
--filter "desired-state=running" \
|
||||
--format "table {{.Name}}\t{{.Node}}\t{{.CurrentState}}\t{{.Image}}" | head -20
|
||||
151
README.md
151
README.md
@ -1,36 +1,143 @@
|
||||
# Environment Monitoring
|
||||
|
||||
Dozzle is deployed as a separate Swarm monitoring service.
|
||||
Tüm izleme servisleri `docker-stack-monitoring.yml` stack'inde yönetilir: Portainer, node-exporter, cAdvisor, Loki ve Promtail.
|
||||
|
||||
## Production
|
||||
## Servisler
|
||||
|
||||
- Swarm mode is enabled with `DOZZLE_MODE=swarm`.
|
||||
- The service uses `deploy.mode: global` so one Dozzle task runs on every Swarm node.
|
||||
- Dozzle is attached to both `dozzle` and `iklimco-net`.
|
||||
- Docker socket is mounted read-only.
|
||||
- Simple authentication is enabled with `DOZZLE_AUTH_PROVIDER=simple`.
|
||||
- The real `users.yml` must be supplied through Gitea secret `DOZZLE_USERS_YML_B64` or `DOZZLE_USERS_YML`.
|
||||
- Prefer `roles: none` for read-only log viewing. Dozzle defaults to full action access when roles are omitted.
|
||||
### Portainer
|
||||
|
||||
Generate a bcrypt-backed users file with Dozzle itself:
|
||||
Docker Swarm yönetim arayüzü.
|
||||
|
||||
- `portainer-agent` — global mode, tüm node'larda çalışır; Docker socket ve volume bilgisini Portainer CE'ye aktarır
|
||||
- `portainer` — tek replica, manager node'da; `portainer-net` overlay üzerinden agent'lara bağlanır
|
||||
- Dış erişim SWAG üzerinden: `portainer.iklim.co`
|
||||
|
||||
### node-exporter
|
||||
|
||||
Host / işletim sistemi metriklerini Prometheus'a aktarır. Her node'da çalışır (`deploy.mode: global`).
|
||||
|
||||
Toplanan metrikler: CPU kullanımı, bellek, disk I/O, ağ trafiği, sistem yükü, dosya sistemi doluluk oranları.
|
||||
|
||||
### cAdvisor
|
||||
|
||||
Container ve Swarm servis bazlı kaynak tüketimini Prometheus'a aktarır. Her node'da çalışır (`deploy.mode: global`).
|
||||
|
||||
Toplanan metrikler: container başına CPU/bellek/ağ/disk I/O.
|
||||
|
||||
### Loki
|
||||
|
||||
Container loglarını toplayan ve saklayan log aggregation servisi. Grafana'nın native Loki datasource entegrasyonu ile metriklerle birlikte sorgulanabilir.
|
||||
|
||||
- Tek replica, `node.labels.type == service` node'unda çalışır
|
||||
- Log saklama süresi: 31 gün (`limits_config.retention_period`)
|
||||
- Konfigürasyon: `build/loki/loki.yml`
|
||||
|
||||
### Promtail
|
||||
|
||||
Her node'daki container loglarını Docker API üzerinden toplayarak Loki'ye gönderir. Her node'da çalışır (`deploy.mode: global`).
|
||||
|
||||
- Docker service discovery: container adı, servis adı, stack adı ve proje label'larını otomatik etiket olarak ekler
|
||||
- Konfigürasyon: `build/promtail/promtail.yml`
|
||||
|
||||
### Health Agent
|
||||
|
||||
Cluster içi servis sağlığını Uptime Kuma'ya push eden Python servisi. Ayrıntılar için `health-agent/README.md`.
|
||||
|
||||
---
|
||||
|
||||
## Grafana'da Log Görüntüleme
|
||||
|
||||
### İlk Kurulum — Loki Datasource Ekleme
|
||||
|
||||
Loki deploy edildikten sonra tek seferlik yapılır:
|
||||
|
||||
1. Grafana UI → Sol menü → **Connections → Data sources**
|
||||
2. **Add new data source** → **Loki** seç
|
||||
3. URL: `http://loki:3100`
|
||||
4. **Save & test** — "Data source connected" mesajı görünmeli
|
||||
|
||||
Alternatif olarak `template/grafana/provisioning/datasources/loki.yaml` dosyasını Grafana'nın provisioning dizinine kopyalayarak otomatik yüklenebilir:
|
||||
|
||||
```bash
|
||||
docker run -it --rm amir20/dozzle:v10.6.6 generate admin \
|
||||
--password '<strong-password>' \
|
||||
--email admin@iklim.co \
|
||||
--name 'Admin' \
|
||||
--user-roles none > users.yml
|
||||
# Grafana veri dizinine provisioning dosyasını kopyala
|
||||
cp template/grafana/provisioning/datasources/loki.yaml \
|
||||
<GRAFANA_DATA_DIR>/provisioning/datasources/loki.yaml
|
||||
# Grafana'yı yeniden başlat
|
||||
docker service update --force iklimco_grafana
|
||||
```
|
||||
|
||||
Store the result as either:
|
||||
### Log Görüntüleme — Explore
|
||||
|
||||
- `DOZZLE_USERS_YML_B64`: `base64 -w0 users.yml`
|
||||
- `DOZZLE_USERS_YML`: raw multiline file content
|
||||
1. Sol menü → **Explore** (pusula ikonu)
|
||||
2. Üst sol köşeden datasource olarak **Loki** seç
|
||||
3. **Label filters** ile filtrele:
|
||||
|
||||
Default public hostname:
|
||||
| Etiket | Açıklama | Örnek |
|
||||
|--------|----------|-------|
|
||||
| `service` | Swarm servis adı | `iklimco_vault` |
|
||||
| `stack` | Stack adı | `iklimco` |
|
||||
| `container` | Container adı | `iklimco_vault.1.xxx` |
|
||||
| `project` | project label değeri | `co.iklim` |
|
||||
| `logstream` | stdout / stderr | `stderr` |
|
||||
|
||||
```text
|
||||
dozzle.iklim.co
|
||||
### LogQL Örnekleri
|
||||
|
||||
```logql
|
||||
# Belirli bir servisin tüm logları
|
||||
{service="iklimco_vault"}
|
||||
|
||||
# Tüm stack'teki hata logları
|
||||
{stack="iklimco"} |= "ERROR"
|
||||
|
||||
# Exception içeren loglar (tüm servisler)
|
||||
{project="co.iklim"} |= "Exception"
|
||||
|
||||
# APISIX erişim logları — sadece 5xx'ler
|
||||
{service="iklimco_apisix"} | json | status >= 500
|
||||
|
||||
# Belirli zaman aralığında servis logları (UI'dan zaman seçimi de yapılabilir)
|
||||
{service="iklimco_rabbitmq"} |= "error" | line_format "{{.line}}"
|
||||
```
|
||||
|
||||
The workflow writes SWAG reverse proxy config, configures APISIX, updates DNS, deploys the Swarm stack, and verifies `iklimco_dozzle`.
|
||||
### Metrik — Log Korelasyonu
|
||||
|
||||
Grafana'nın en güçlü özelliklerinden biri: bir Prometheus metriğinde anomali gördüğünde aynı zaman aralığındaki logları yan yana inceleyebilirsin.
|
||||
|
||||
1. Prometheus dashboard panelinde anomali noktasına tıkla
|
||||
2. **Explore** linkine tıkla → aynı zaman aralığı Explore'da açılır
|
||||
3. Datasource'u Loki'ye geçir, ilgili servisi filtrele
|
||||
4. Metrik spike'ı ile log hataları aynı anda görünür
|
||||
|
||||
### Dashboard'a Log Paneli Ekleme
|
||||
|
||||
Mevcut dashboard'lara log paneli eklemek için:
|
||||
|
||||
1. Dashboard → **Edit** → **Add visualization**
|
||||
2. Panel tipi: **Logs** seç
|
||||
3. Datasource: **Loki**
|
||||
4. Query: `{service="<servis_adı>"}`
|
||||
5. **Deduplication** seçeneğini açabilirsin (tekrar eden satırları gizler)
|
||||
|
||||
---
|
||||
|
||||
## Ağ Yapısı
|
||||
|
||||
| Network | Tür | Kullananlar |
|
||||
|---------|-----|-------------|
|
||||
| `iklimco-net` | external overlay | Portainer, node-exporter, cAdvisor, Loki, Promtail, Health Agent |
|
||||
| `portainer-net` | stack overlay | portainer-agent ↔ portainer iletişimi |
|
||||
|
||||
---
|
||||
|
||||
## Deployment
|
||||
|
||||
```bash
|
||||
docker stack deploy \
|
||||
--with-registry-auth \
|
||||
-c Environment_Monitoring/docker-stack-monitoring.yml \
|
||||
iklimco-monitoring
|
||||
```
|
||||
|
||||
Prod için Gitea workflow'u: `Environment_Monitoring/.gitea/workflows/deploy-monitoring-prod.yml`
|
||||
|
||||
> **Not:** Loki ve Promtail custom image kullanır (`build/loki/`, `build/promtail/`). Deploy öncesinde imajların Harbor'a build edilip push edilmesi gerekir. `.env` dosyasında `IMAGE_LOKI` ve `IMAGE_PROMTAIL` değişkenlerinin tanımlı olması zorunludur.
|
||||
|
||||
118
docker-stack-monitoring.yml
Normal file
118
docker-stack-monitoring.yml
Normal file
@ -0,0 +1,118 @@
|
||||
services:
|
||||
portainer-agent:
|
||||
image: portainer/agent:lts
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /var/lib/docker/volumes:/var/lib/docker/volumes
|
||||
networks:
|
||||
- portainer-net
|
||||
deploy:
|
||||
mode: global
|
||||
placement:
|
||||
constraints:
|
||||
- node.platform.os == linux
|
||||
restart_policy:
|
||||
condition: any
|
||||
delay: 5s
|
||||
labels:
|
||||
project: co.iklim
|
||||
|
||||
portainer:
|
||||
image: portainer/portainer-ce:lts
|
||||
command: -H tcp://tasks.portainer-agent:9001 --tlsskipverify
|
||||
volumes:
|
||||
- portainer_data:/data
|
||||
networks:
|
||||
- portainer-net
|
||||
- iklimco-net
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: 1
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
restart_policy:
|
||||
condition: any
|
||||
delay: 5s
|
||||
labels:
|
||||
project: co.iklim
|
||||
|
||||
node-exporter:
|
||||
image: prom/node-exporter:latest
|
||||
command:
|
||||
- '--path.procfs=/host/proc'
|
||||
- '--path.sysfs=/host/sys'
|
||||
- '--path.rootfs=/rootfs'
|
||||
volumes:
|
||||
- /:/rootfs:ro
|
||||
- /proc:/host/proc:ro
|
||||
- /sys:/host/sys:ro
|
||||
networks:
|
||||
- iklimco-net
|
||||
deploy:
|
||||
mode: global
|
||||
restart_policy:
|
||||
condition: any
|
||||
delay: 5s
|
||||
labels:
|
||||
project: co.iklim
|
||||
|
||||
cadvisor:
|
||||
image: gcr.io/cadvisor/cadvisor:latest
|
||||
volumes:
|
||||
- /:/rootfs:ro
|
||||
- /var/run:/var/run:ro
|
||||
- /sys:/sys:ro
|
||||
- /var/lib/docker:/var/lib/docker:ro
|
||||
networks:
|
||||
- iklimco-net
|
||||
deploy:
|
||||
mode: global
|
||||
restart_policy:
|
||||
condition: any
|
||||
delay: 5s
|
||||
labels:
|
||||
project: co.iklim
|
||||
|
||||
loki:
|
||||
image: ${CUSTOM_IMAGE_REGISTRY}${IMAGE_LOKI}
|
||||
volumes:
|
||||
- loki-vl:/loki
|
||||
networks:
|
||||
- iklimco-net
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: 1
|
||||
placement:
|
||||
constraints:
|
||||
- node.labels.type == service
|
||||
restart_policy:
|
||||
condition: any
|
||||
delay: 5s
|
||||
labels:
|
||||
project: co.iklim
|
||||
|
||||
promtail:
|
||||
image: ${CUSTOM_IMAGE_REGISTRY}${IMAGE_PROMTAIL}
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
networks:
|
||||
- iklimco-net
|
||||
deploy:
|
||||
mode: global
|
||||
restart_policy:
|
||||
condition: any
|
||||
delay: 5s
|
||||
labels:
|
||||
project: co.iklim
|
||||
|
||||
networks:
|
||||
portainer-net:
|
||||
driver: overlay
|
||||
attachable: true
|
||||
iklimco-net:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
portainer_data:
|
||||
loki-vl:
|
||||
@ -1,38 +0,0 @@
|
||||
services:
|
||||
dozzle:
|
||||
image: ${IMAGE_DOZZLE:-amir20/dozzle:v10.6.6}
|
||||
environment:
|
||||
- DOZZLE_MODE=swarm
|
||||
- DOZZLE_AUTH_PROVIDER=simple
|
||||
- DOZZLE_NO_ANALYTICS=true
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
secrets:
|
||||
- source: dozzle_users
|
||||
target: /data/users.yml
|
||||
mode: 0400
|
||||
networks:
|
||||
- dozzle
|
||||
- iklimco-net
|
||||
deploy:
|
||||
mode: global
|
||||
restart_policy:
|
||||
condition: any
|
||||
delay: 5s
|
||||
update_config:
|
||||
parallelism: 1
|
||||
order: start-first
|
||||
labels:
|
||||
project: co.iklim
|
||||
|
||||
secrets:
|
||||
dozzle_users:
|
||||
external: true
|
||||
name: ${DOZZLE_USERS_SECRET_NAME:-dozzle_users}
|
||||
|
||||
networks:
|
||||
dozzle:
|
||||
driver: overlay
|
||||
attachable: true
|
||||
iklimco-net:
|
||||
external: true
|
||||
@ -1,59 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
PROFILE=${SPRING_PROFILES_ACTIVE:-prod}
|
||||
|
||||
if [[ "$PROFILE" == "dev" ]]; then
|
||||
APISIX_ADMIN_URL=http://${LAN_IP:-127.0.0.1}:9180/apisix/admin
|
||||
else
|
||||
APISIX_ADMIN_URL=http://apisix:9180/apisix/admin
|
||||
fi
|
||||
|
||||
API_KEY=${APISIX_ADMIN_KEY:?APISIX_ADMIN_KEY is required}
|
||||
DOZZLE_HOST=${DOZZLE_SUBDOMAIN:-dozzle.iklim.co}
|
||||
DOZZLE_NODE=${DOZZLE_NODE:-dozzle:8080}
|
||||
ERRORS=0
|
||||
|
||||
call_api() {
|
||||
local label="$1"; shift
|
||||
local http_code
|
||||
http_code=$(curl -sS -o /tmp/apisix_dozzle_resp.json -w "%{http_code}" "$@")
|
||||
if [[ "$http_code" -ge 400 ]]; then
|
||||
echo "ERROR: $label (HTTP $http_code)"
|
||||
cat /tmp/apisix_dozzle_resp.json
|
||||
echo
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
until curl -sf -o /dev/null -H "X-API-KEY: $API_KEY" "$APISIX_ADMIN_URL/upstreams"; do
|
||||
echo "APISIX not ready, retrying in 3s..."
|
||||
sleep 3
|
||||
done
|
||||
|
||||
HC='"checks":{"active":{"type":"http","http_path":"/","timeout":5,"healthy":{"interval":10,"successes":1},"unhealthy":{"interval":5,"http_failures":3}},"passive":{"healthy":{"http_statuses":[200,201,204,302],"successes":2},"unhealthy":{"http_statuses":[429,500,502,503,504],"http_failures":3,"tcp_failures":3}}}'
|
||||
|
||||
if [[ "$PROFILE" != "dev" ]]; then
|
||||
DOZZLE_ROUTE_PLUGINS=',"plugins":{"limit-count":{"count":120,"time_window":60,"key":"remote_addr","rejected_code":429,"policy":"local"}}'
|
||||
else
|
||||
DOZZLE_ROUTE_PLUGINS=""
|
||||
fi
|
||||
|
||||
call_api "upstream dozzle" -X PUT "$APISIX_ADMIN_URL/upstreams/dozzle-upstream" \
|
||||
-H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
|
||||
-d '{"name":"dozzle-upstream","type":"roundrobin","nodes":{"'"$DOZZLE_NODE"'":1},'"$HC"'}'
|
||||
|
||||
call_api "service dozzle" -X PUT "$APISIX_ADMIN_URL/services/dozzle-service" \
|
||||
-H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
|
||||
-d '{"name":"dozzle-service","upstream_id":"dozzle-upstream","enable_websocket":true}'
|
||||
|
||||
call_api "route dozzle" -X PUT "$APISIX_ADMIN_URL/routes/dozzle-route" \
|
||||
-H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
|
||||
-d '{"name":"dozzle-route","hosts":["'"$DOZZLE_HOST"'"],"uri":"/*","methods":["GET","POST","PUT","DELETE","PATCH","OPTIONS"],"service_id":"dozzle-service","enable_websocket":true'"$DOZZLE_ROUTE_PLUGINS"'}'
|
||||
|
||||
if [ "$ERRORS" -gt 0 ]; then
|
||||
echo "Dozzle APISIX init completed with $ERRORS error(s)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Dozzle APISIX route configured for https://${DOZZLE_HOST}"
|
||||
@ -2,7 +2,7 @@ server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
http2 on;
|
||||
server_name ${DOZZLE_SUBDOMAIN};
|
||||
server_name ${PORTAINER_SUBDOMAIN};
|
||||
|
||||
include /config/nginx/ssl.conf;
|
||||
include /config/nginx/resolver.conf;
|
||||
@ -10,10 +10,13 @@ server {
|
||||
client_max_body_size 0;
|
||||
|
||||
location / {
|
||||
${RESTRICTED_IPS_BLOCK}
|
||||
deny all;
|
||||
|
||||
include /config/nginx/proxy.conf;
|
||||
include /config/nginx/resolver.conf;
|
||||
set $upstream_app apisix;
|
||||
set $upstream_port 9080;
|
||||
set $upstream_app portainer;
|
||||
set $upstream_port 9000;
|
||||
set $upstream_proto http;
|
||||
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user