vault backup: 2026-06-24 17:52:15
This commit is contained in:
@@ -0,0 +1,679 @@
|
||||
---
|
||||
tags:
|
||||
- installation
|
||||
- dns
|
||||
- powerdns
|
||||
created: 2026-06-17
|
||||
---
|
||||
|
||||
# PowerDNS Docker Compose
|
||||
|
||||
## Purpose
|
||||
|
||||
This note describes how to install a PowerDNS Authoritative environment with:
|
||||
|
||||
- PostgreSQL 16
|
||||
- PowerDNS Authoritative 5.0.4
|
||||
- Poweradmin
|
||||
- pgweb
|
||||
- scheduled PostgreSQL backups
|
||||
|
||||
This installation model assumes:
|
||||
|
||||
1. DNS is exposed on host port `53`
|
||||
2. the PowerDNS API is only exposed on `127.0.0.1:8081`
|
||||
3. web management services are published through a reverse proxy such as Traefik
|
||||
|
||||
## Component versions
|
||||
|
||||
| Component | Version |
|
||||
| --- | --- |
|
||||
| PostgreSQL | `16` |
|
||||
| PowerDNS Authoritative | `5.0.4` |
|
||||
| Poweradmin | `stable` |
|
||||
| pgweb | `0.16.2` |
|
||||
| Backup container | `alpine:3.20` |
|
||||
|
||||
## Before you start
|
||||
|
||||
Make sure the target host has:
|
||||
|
||||
1. Linux
|
||||
2. Docker
|
||||
3. `docker compose`
|
||||
4. port `53/tcp` and `53/udp` available
|
||||
5. a reverse proxy network if Poweradmin and pgweb will be published through Traefik
|
||||
6. public DNS names for the web interfaces if they will be exposed externally
|
||||
|
||||
## Deployment values to prepare
|
||||
|
||||
Prepare all runtime values before starting the stack.
|
||||
|
||||
### Required core values
|
||||
|
||||
| Variable | Meaning |
|
||||
| --- | --- |
|
||||
| `PGUSER` | PostgreSQL administrative user |
|
||||
| `PGPASSWORD` | PostgreSQL administrative password |
|
||||
| `DB_NAME` | Main PowerDNS database |
|
||||
| `DB_USER` | Application database user |
|
||||
| `DB_PASS` | Application database password |
|
||||
| `PDNS_API_KEY` | PowerDNS API key |
|
||||
| `CRON_SCHEDULE` | Backup schedule |
|
||||
| `PA_SESSION_KEY` | Poweradmin session secret |
|
||||
| `PA_ADMIN_USERNAME` | Bootstrap Poweradmin admin username |
|
||||
| `PA_ADMIN_PASSWORD` | Bootstrap Poweradmin admin password |
|
||||
| `PA_ADMIN_EMAIL` | Bootstrap Poweradmin admin email |
|
||||
| `PA_ADMIN_FULLNAME` | Bootstrap Poweradmin admin full name |
|
||||
| `PGWEB_USER` | pgweb login username |
|
||||
| `PGWEB_PASS` | pgweb login password |
|
||||
|
||||
### Optional values with defaults
|
||||
|
||||
| Variable | Default | Meaning |
|
||||
| --- | --- | --- |
|
||||
| `TZ` | `Asia/Shanghai` | Service timezone |
|
||||
| `DB_HOST` | `db` | Database hostname |
|
||||
| `DB_PORT` | `5432` | Database port |
|
||||
| `ADMIN_DB` | `pdnsadmin` | Admin database used for bootstrap and restore |
|
||||
| `RETENTION_DAYS` | `7` | Backup age retention |
|
||||
| `MAX_BACKUPS` | `7` | Number of backup sets to keep |
|
||||
| `DUMP_ROLES` | `true` | Include PostgreSQL role dump in backups |
|
||||
| `PDNS_VERSION` | `49` | Poweradmin PowerDNS compatibility mode |
|
||||
| `DNS_NS1` | `ns1.wsvc.info` | Default NS1 value in Poweradmin |
|
||||
| `DNS_NS2` | `ns2.wsvc.info` | Default NS2 value in Poweradmin |
|
||||
| `DNS_HOSTMASTER` | `hostmaster.wsvc.info` | Default SOA hostmaster |
|
||||
| `PA_APP_TITLE` | `Poweradmin` | Poweradmin UI title |
|
||||
| `PA_CREATE_ADMIN` | `1` | Enable bootstrap admin creation |
|
||||
|
||||
### Example values
|
||||
|
||||
Replace every placeholder with your own values:
|
||||
|
||||
```env
|
||||
TZ=Asia/Shanghai
|
||||
PGUSER=postgres
|
||||
PGPASSWORD=<strong-postgres-password>
|
||||
DB_HOST=db
|
||||
DB_PORT=5432
|
||||
DB_NAME=pdns
|
||||
DB_USER=pdns
|
||||
DB_PASS=<strong-app-password>
|
||||
ADMIN_DB=pdnsadmin
|
||||
CRON_SCHEDULE=0 3 * * *
|
||||
RETENTION_DAYS=7
|
||||
MAX_BACKUPS=7
|
||||
DUMP_ROLES=true
|
||||
PDNS_API_KEY=<strong-api-key>
|
||||
PA_SESSION_KEY=<long-random-session-key>
|
||||
PA_ADMIN_USERNAME=admin
|
||||
PA_ADMIN_PASSWORD=<strong-admin-password>
|
||||
PA_ADMIN_EMAIL=admin@example.com
|
||||
PA_ADMIN_FULLNAME=DNS Administrator
|
||||
PGWEB_USER=pgweb
|
||||
PGWEB_PASS=<strong-pgweb-password>
|
||||
PDNS_VERSION=49
|
||||
DNS_NS1=ns1.example.com
|
||||
DNS_NS2=ns2.example.com
|
||||
DNS_HOSTMASTER=hostmaster.example.com
|
||||
PA_APP_TITLE=Poweradmin
|
||||
PA_CREATE_ADMIN=1
|
||||
```
|
||||
|
||||
## Full configuration blocks
|
||||
|
||||
Use the following full configuration content as the installation baseline.
|
||||
|
||||
### Environment file
|
||||
|
||||
```env
|
||||
TZ=Asia/Shanghai
|
||||
PGUSER=postgres
|
||||
PGPASSWORD=<strong-postgres-password>
|
||||
DB_HOST=db
|
||||
DB_PORT=5432
|
||||
DB_NAME=pdns
|
||||
DB_USER=pdns
|
||||
DB_PASS=<strong-app-password>
|
||||
ADMIN_DB=pdnsadmin
|
||||
CRON_SCHEDULE=0 3 * * *
|
||||
RETENTION_DAYS=7
|
||||
MAX_BACKUPS=7
|
||||
DUMP_ROLES=true
|
||||
PDNS_API_KEY=<strong-api-key>
|
||||
PA_SESSION_KEY=<long-random-session-key>
|
||||
PA_ADMIN_USERNAME=admin
|
||||
PA_ADMIN_PASSWORD=<strong-admin-password>
|
||||
PA_ADMIN_EMAIL=admin@example.com
|
||||
PA_ADMIN_FULLNAME=DNS Administrator
|
||||
PGWEB_USER=pgweb
|
||||
PGWEB_PASS=<strong-pgweb-password>
|
||||
PDNS_VERSION=49
|
||||
DNS_NS1=ns1.example.com
|
||||
DNS_NS2=ns2.example.com
|
||||
DNS_HOSTMASTER=hostmaster.example.com
|
||||
PA_APP_TITLE=Poweradmin
|
||||
PA_CREATE_ADMIN=1
|
||||
```
|
||||
|
||||
### Docker Compose configuration
|
||||
|
||||
```yaml
|
||||
networks:
|
||||
frontend:
|
||||
name: traefik
|
||||
external: true
|
||||
|
||||
backend:
|
||||
internal: true
|
||||
|
||||
edge:
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:16
|
||||
container_name: pdns-db
|
||||
environment:
|
||||
POSTGRES_DB: postgres
|
||||
POSTGRES_USER: ${PGUSER:?missing PGUSER}
|
||||
POSTGRES_PASSWORD: ${PGPASSWORD:?missing PGPASSWORD}
|
||||
TZ: ${TZ:-Asia/Shanghai}
|
||||
PGTZ: ${TZ:-Asia/Shanghai}
|
||||
volumes:
|
||||
- dbdata:/var/lib/postgresql
|
||||
- ./db-init-generated:/docker-entrypoint-initdb.d:ro
|
||||
- ./backup:/backup:ro
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U \"$${POSTGRES_USER}\" -d \"$${POSTGRES_DB}\""]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
restart: unless-stopped
|
||||
networks: [backend, edge]
|
||||
|
||||
auth:
|
||||
image: powerdns/pdns-auth-50:5.0.4
|
||||
container_name: pdns-auth
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "53:53/udp"
|
||||
- "53:53/tcp"
|
||||
- "127.0.0.1:8081:8081"
|
||||
environment:
|
||||
PDNS_API_KEY: ${PDNS_API_KEY:?missing PDNS_API_KEY}
|
||||
DB_NAME: ${DB_NAME:?missing DB_NAME}
|
||||
DB_USER: ${DB_USER:?missing DB_USER}
|
||||
DB_PASS: ${DB_PASS:?missing DB_PASS}
|
||||
TEMPLATE_FILES: secrets
|
||||
volumes:
|
||||
- ./auth/pdns.conf:/etc/powerdns/pdns.conf:ro
|
||||
- ./auth/templates.d:/etc/powerdns/templates.d:ro
|
||||
- ./auth/keys:/var/lib/powerdns
|
||||
- ./auth/import:/import
|
||||
- ./auth/export:/export
|
||||
- ./auth/logs:/var/log/pdns
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"python3 -c \"import json, os, urllib.request; req = urllib.request.Request('http://127.0.0.1:8081/api/v1/servers/localhost', headers={'X-API-Key': os.environ['PDNS_API_KEY']}); data = json.load(urllib.request.urlopen(req, timeout=3)); assert data['daemon_type'] == 'authoritative'\""
|
||||
]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
restart: unless-stopped
|
||||
networks: [backend, edge]
|
||||
|
||||
poweradmin:
|
||||
image: poweradmin/poweradmin:stable
|
||||
container_name: poweradmin
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
auth:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
DB_TYPE: pgsql
|
||||
DB_HOST: ${DB_HOST:-db}
|
||||
DB_PORT: ${DB_PORT:-5432}
|
||||
DB_NAME: ${DB_NAME:?missing DB_NAME}
|
||||
DB_USER: ${DB_USER:?missing DB_USER}
|
||||
DB_PASS: ${DB_PASS:?missing DB_PASS}
|
||||
PA_PDNS_API_URL: http://auth:8081
|
||||
PA_PDNS_API_KEY: ${PDNS_API_KEY:?missing PDNS_API_KEY}
|
||||
PA_DNS_BACKEND: sql
|
||||
PDNS_VERSION: ${PDNS_VERSION:-49}
|
||||
DNS_NS1: ${DNS_NS1:-ns1.wsvc.info}
|
||||
DNS_NS2: ${DNS_NS2:-ns2.wsvc.info}
|
||||
DNS_HOSTMASTER: ${DNS_HOSTMASTER:-hostmaster.wsvc.info}
|
||||
PA_APP_TITLE: ${PA_APP_TITLE:-Poweradmin}
|
||||
PA_TIMEZONE: ${TZ:-Asia/Shanghai}
|
||||
PA_SESSION_KEY: ${PA_SESSION_KEY:?missing PA_SESSION_KEY}
|
||||
PA_CREATE_ADMIN: ${PA_CREATE_ADMIN:-1}
|
||||
PA_ADMIN_USERNAME: ${PA_ADMIN_USERNAME:?missing PA_ADMIN_USERNAME}
|
||||
PA_ADMIN_PASSWORD: ${PA_ADMIN_PASSWORD:?missing PA_ADMIN_PASSWORD}
|
||||
PA_ADMIN_EMAIL: ${PA_ADMIN_EMAIL:?missing PA_ADMIN_EMAIL}
|
||||
PA_ADMIN_FULLNAME: ${PA_ADMIN_FULLNAME:?missing PA_ADMIN_FULLNAME}
|
||||
TRUSTED_PROXIES: private_ranges
|
||||
DEBUG: "false"
|
||||
restart: unless-stopped
|
||||
networks: [backend, frontend]
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik"
|
||||
- "traefik.http.routers.poweradmin.rule=Host(`pdns.wsvc.info`)"
|
||||
- "traefik.http.routers.poweradmin.entrypoints=websecure"
|
||||
- "traefik.http.routers.poweradmin.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.poweradmin.loadbalancer.server.port=80"
|
||||
|
||||
backup:
|
||||
image: alpine:3.20
|
||||
container_name: pdns-backup
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
TZ: ${TZ:-Asia/Shanghai}
|
||||
DB_HOST: ${DB_HOST:-db}
|
||||
DB_PORT: ${DB_PORT:-5432}
|
||||
DB_USER: ${PGUSER:?missing PGUSER}
|
||||
DB_PASS: ${PGPASSWORD:?missing PGPASSWORD}
|
||||
DB_NAME: ${DB_NAME:?missing DB_NAME}
|
||||
RETENTION_DAYS: ${RETENTION_DAYS:-7}
|
||||
MAX_BACKUPS: ${MAX_BACKUPS:-7}
|
||||
DUMP_ROLES: ${DUMP_ROLES:-true}
|
||||
CRON_SCHEDULE: ${CRON_SCHEDULE:?missing CRON_SCHEDULE}
|
||||
volumes:
|
||||
- ./backup:/backup
|
||||
- ./scripts:/scripts:ro
|
||||
entrypoint: >
|
||||
sh -c '
|
||||
apk add --no-cache postgresql16-client tzdata util-linux bash coreutils findutils;
|
||||
ln -snf /usr/share/zoneinfo/$$TZ /etc/localtime && echo $$TZ > /etc/timezone;
|
||||
echo "$$DB_HOST:$$DB_PORT:*:$$DB_USER:$$DB_PASS" > /root/.pgpass;
|
||||
chmod 600 /root/.pgpass;
|
||||
echo "$$CRON_SCHEDULE flock -n /backup/.backup.lock /scripts/backup.sh >> /backup/backup.log 2>&1" > /etc/crontabs/root;
|
||||
echo "[$$(date -Iseconds)] cron started with schedule: $$CRON_SCHEDULE" >> /backup/backup.log;
|
||||
crond -f -l 8
|
||||
'
|
||||
restart: unless-stopped
|
||||
networks: [backend]
|
||||
|
||||
pgweb:
|
||||
image: sosedoff/pgweb:0.16.2
|
||||
container_name: pdns_pgweb
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PGWEB_DATABASE_URL: "postgres://${PGUSER:?missing PGUSER}:${PGPASSWORD:?missing PGPASSWORD}@${DB_HOST:-db}:${DB_PORT:-5432}/${DB_NAME:?missing DB_NAME}?sslmode=disable"
|
||||
PGWEB_AUTH_USER: ${PGWEB_USER:?missing PGWEB_USER}
|
||||
PGWEB_AUTH_PASS: ${PGWEB_PASS:?missing PGWEB_PASS}
|
||||
TZ: ${TZ:-Asia/Shanghai}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks: [backend, frontend]
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik"
|
||||
- "traefik.http.routers.pgweb.rule=Host(`pgweb.wsvc.info`)"
|
||||
- "traefik.http.routers.pgweb.entrypoints=websecure"
|
||||
- "traefik.http.routers.pgweb.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.pgweb.loadbalancer.server.port=8081"
|
||||
|
||||
volumes:
|
||||
dbdata: {}
|
||||
```
|
||||
|
||||
### PowerDNS daemon configuration
|
||||
|
||||
```ini
|
||||
local-address=0.0.0.0
|
||||
local-port=53
|
||||
|
||||
launch=gpgsql
|
||||
gpgsql-host=db
|
||||
include-dir=/etc/powerdns/pdns.d
|
||||
gpgsql-dnssec=yes
|
||||
allow-axfr-ips=202.91.35.141
|
||||
also-notify=202.91.35.141
|
||||
primary=yes
|
||||
secondary=no
|
||||
|
||||
api=yes
|
||||
webserver=yes
|
||||
webserver-address=0.0.0.0
|
||||
webserver-port=8081
|
||||
webserver-allow-from=127.0.0.1,172.16.0.0/12,10.0.0.0/8,192.168.0.0/16
|
||||
|
||||
version-string=anonymous
|
||||
disable-syslog=yes
|
||||
loglevel=4
|
||||
|
||||
default-soa-edit=INCEPTION-INCREMENT
|
||||
default-soa-edit-signed=INCEPTION-INCREMENT
|
||||
|
||||
disable-axfr=no
|
||||
```
|
||||
|
||||
### Runtime-rendered secret template
|
||||
|
||||
```ini
|
||||
gpgsql-dbname={{ DB_NAME }}
|
||||
gpgsql-user={{ DB_USER }}
|
||||
gpgsql-password={{ DB_PASS }}
|
||||
api-key={{ PDNS_API_KEY }}
|
||||
```
|
||||
|
||||
## Network layout
|
||||
|
||||
The stack uses three networks:
|
||||
|
||||
| Network | Purpose |
|
||||
| --- | --- |
|
||||
| `backend` | internal service-to-service traffic |
|
||||
| `edge` | local host-facing DNS and API exposure |
|
||||
| `frontend` | reverse-proxy-facing web traffic |
|
||||
|
||||
Service attachment:
|
||||
|
||||
| Service | Networks |
|
||||
| --- | --- |
|
||||
| PostgreSQL | `backend`, `edge` |
|
||||
| PowerDNS auth | `backend`, `edge` |
|
||||
| Poweradmin | `backend`, `frontend` |
|
||||
| Backup | `backend` |
|
||||
| pgweb | `backend`, `frontend` |
|
||||
|
||||
## Installation procedure
|
||||
|
||||
### 1. Prepare the host
|
||||
|
||||
Install Docker and Docker Compose support on the Linux host.
|
||||
|
||||
If a reverse proxy network is required, create it before deployment.
|
||||
|
||||
### 2. Prepare runtime configuration
|
||||
|
||||
Set all required environment values.
|
||||
|
||||
At minimum, verify:
|
||||
|
||||
1. PostgreSQL admin credentials are defined
|
||||
2. application database credentials are defined
|
||||
3. PowerDNS API key is defined
|
||||
4. Poweradmin admin account values are defined
|
||||
5. pgweb login values are defined
|
||||
6. backup schedule and retention values are defined
|
||||
|
||||
### 3. Start the stack
|
||||
|
||||
Start the stack in detached mode.
|
||||
|
||||
Expected startup order:
|
||||
|
||||
1. PostgreSQL starts first
|
||||
2. database bootstrap creates the application role and databases
|
||||
3. PowerDNS starts after PostgreSQL is healthy
|
||||
4. Poweradmin starts after both PostgreSQL and PowerDNS are healthy
|
||||
5. backup service starts cron after PostgreSQL is healthy
|
||||
6. pgweb starts after PostgreSQL is healthy
|
||||
|
||||
### 4. Wait for health checks
|
||||
|
||||
The deployment should be considered ready only after:
|
||||
|
||||
1. PostgreSQL passes `pg_isready`
|
||||
2. PowerDNS API health check returns an authoritative daemon result
|
||||
3. Poweradmin and pgweb become reachable through the reverse proxy
|
||||
|
||||
### 5. Complete first access
|
||||
|
||||
After startup:
|
||||
|
||||
1. sign in to Poweradmin with the bootstrap admin account
|
||||
2. verify pgweb login works
|
||||
3. verify the PowerDNS API is reachable from the local host only
|
||||
4. verify DNS answers on port `53`
|
||||
|
||||
## Service configuration details
|
||||
|
||||
### PostgreSQL
|
||||
|
||||
| Setting | Value |
|
||||
| --- | --- |
|
||||
| Image | `postgres:16` |
|
||||
| Container name | `pdns-db` |
|
||||
| Restart policy | `unless-stopped` |
|
||||
| Startup database | `postgres` |
|
||||
| Health check | `pg_isready -U $POSTGRES_USER -d $POSTGRES_DB` |
|
||||
| Timezone | `TZ`, `PGTZ` |
|
||||
|
||||
Bootstrap behavior:
|
||||
|
||||
1. create the role named by `DB_USER` if missing
|
||||
2. update the password of `DB_USER` from `DB_PASS`
|
||||
3. create the database named by `DB_NAME` if missing
|
||||
4. create the database named by `ADMIN_DB` if missing
|
||||
5. assign ownership of both databases to `DB_USER`
|
||||
|
||||
### PowerDNS Authoritative
|
||||
|
||||
| Setting | Value |
|
||||
| --- | --- |
|
||||
| Image | `powerdns/pdns-auth-50:5.0.4` |
|
||||
| Container name | `pdns-auth` |
|
||||
| Restart policy | `unless-stopped` |
|
||||
| Published ports | `53/tcp`, `53/udp`, `127.0.0.1:8081` |
|
||||
| Health check | local API request using `PDNS_API_KEY` |
|
||||
|
||||
Environment used by PowerDNS:
|
||||
|
||||
| Variable | Meaning |
|
||||
| --- | --- |
|
||||
| `PDNS_API_KEY` | API authentication key |
|
||||
| `DB_NAME` | PowerDNS PostgreSQL database |
|
||||
| `DB_USER` | PowerDNS PostgreSQL user |
|
||||
| `DB_PASS` | PowerDNS PostgreSQL password |
|
||||
| `TEMPLATE_FILES=secrets` | enables runtime rendering of dynamic config |
|
||||
|
||||
Rendered runtime directives:
|
||||
|
||||
| Directive | Source |
|
||||
| --- | --- |
|
||||
| `gpgsql-dbname` | `DB_NAME` |
|
||||
| `gpgsql-user` | `DB_USER` |
|
||||
| `gpgsql-password` | `DB_PASS` |
|
||||
| `api-key` | `PDNS_API_KEY` |
|
||||
|
||||
Daemon behavior:
|
||||
|
||||
| Directive | Value | Meaning |
|
||||
| --- | --- | --- |
|
||||
| `local-address` | `0.0.0.0` | listen on all container interfaces |
|
||||
| `local-port` | `53` | DNS listener port |
|
||||
| `launch` | `gpgsql` | PostgreSQL backend |
|
||||
| `gpgsql-host` | `db` | database service hostname |
|
||||
| `gpgsql-dnssec` | `yes` | DNSSEC enabled |
|
||||
| `api` | `yes` | API enabled |
|
||||
| `webserver` | `yes` | embedded web server enabled |
|
||||
| `webserver-address` | `0.0.0.0` | listen on all container interfaces |
|
||||
| `webserver-port` | `8081` | API port |
|
||||
| `webserver-allow-from` | `127.0.0.1,172.16.0.0/12,10.0.0.0/8,192.168.0.0/16` | restrict API access to local and private ranges |
|
||||
| `primary` | `yes` | primary DNS role enabled |
|
||||
| `secondary` | `no` | secondary role disabled |
|
||||
| `allow-axfr-ips` | `202.91.35.141` | allowed AXFR peer |
|
||||
| `also-notify` | `202.91.35.141` | notify destination |
|
||||
| `version-string` | `anonymous` | hide version string |
|
||||
| `disable-syslog` | `yes` | disable syslog |
|
||||
| `loglevel` | `4` | logging verbosity |
|
||||
| `default-soa-edit` | `INCEPTION-INCREMENT` | SOA serial update policy |
|
||||
| `default-soa-edit-signed` | `INCEPTION-INCREMENT` | SOA serial policy for signed zones |
|
||||
| `disable-axfr` | `no` | AXFR globally allowed if otherwise permitted |
|
||||
|
||||
### Poweradmin
|
||||
|
||||
| Setting | Value |
|
||||
| --- | --- |
|
||||
| Image | `poweradmin/poweradmin:stable` |
|
||||
| Container name | `poweradmin` |
|
||||
| Restart policy | `unless-stopped` |
|
||||
| Database type | `pgsql` |
|
||||
| API endpoint | `http://auth:8081` |
|
||||
| DNS backend mode | `sql` |
|
||||
| Trusted proxies | `private_ranges` |
|
||||
| Debug | `false` |
|
||||
|
||||
Important Poweradmin values:
|
||||
|
||||
| Variable | Value |
|
||||
| --- | --- |
|
||||
| `DB_HOST` | `db` by default |
|
||||
| `DB_PORT` | `5432` by default |
|
||||
| `DB_NAME` | required |
|
||||
| `DB_USER` | required |
|
||||
| `DB_PASS` | required |
|
||||
| `PA_PDNS_API_KEY` | same value as `PDNS_API_KEY` |
|
||||
| `PDNS_VERSION` | `49` |
|
||||
| `DNS_NS1` | configurable default nameserver |
|
||||
| `DNS_NS2` | configurable default nameserver |
|
||||
| `DNS_HOSTMASTER` | configurable default hostmaster |
|
||||
| `PA_APP_TITLE` | `Poweradmin` by default |
|
||||
| `PA_TIMEZONE` | value from `TZ` |
|
||||
| `PA_SESSION_KEY` | required |
|
||||
| `PA_CREATE_ADMIN` | `1` by default |
|
||||
| `PA_ADMIN_USERNAME` | required |
|
||||
| `PA_ADMIN_PASSWORD` | required |
|
||||
| `PA_ADMIN_EMAIL` | required |
|
||||
| `PA_ADMIN_FULLNAME` | required |
|
||||
|
||||
Reverse proxy routing:
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Router host | `pdns.wsvc.info` |
|
||||
| Entry point | `websecure` |
|
||||
| TLS resolver | `letsencrypt` |
|
||||
| Internal service port | `80` |
|
||||
|
||||
### Backup service
|
||||
|
||||
| Setting | Value |
|
||||
| --- | --- |
|
||||
| Image | `alpine:3.20` |
|
||||
| Container name | `pdns-backup` |
|
||||
| Restart policy | `unless-stopped` |
|
||||
| Trigger mode | cron inside the container |
|
||||
| Locking | `flock -n` |
|
||||
|
||||
Startup behavior:
|
||||
|
||||
1. install PostgreSQL client tools and required shell utilities
|
||||
2. set container timezone
|
||||
3. build `/root/.pgpass` for unattended database access
|
||||
4. write the cron job using `CRON_SCHEDULE`
|
||||
5. start cron in foreground mode
|
||||
|
||||
Backup variables:
|
||||
|
||||
| Variable | Value |
|
||||
| --- | --- |
|
||||
| `DB_HOST` | `db` by default |
|
||||
| `DB_PORT` | `5432` by default |
|
||||
| `DB_USER` | same as `PGUSER` |
|
||||
| `DB_PASS` | same as `PGPASSWORD` |
|
||||
| `DB_NAME` | required |
|
||||
| `RETENTION_DAYS` | `7` by default |
|
||||
| `MAX_BACKUPS` | `7` by default |
|
||||
| `DUMP_ROLES` | `true` by default |
|
||||
| `CRON_SCHEDULE` | required |
|
||||
|
||||
Backup behavior:
|
||||
|
||||
1. dump the configured application database
|
||||
2. optionally dump PostgreSQL roles
|
||||
3. remove stale temporary files
|
||||
4. remove zero-byte role dumps
|
||||
5. prune backups older than `RETENTION_DAYS`
|
||||
6. keep only the newest `MAX_BACKUPS` backup sets
|
||||
|
||||
Backup artifact patterns:
|
||||
|
||||
| Artifact | Pattern |
|
||||
| --- | --- |
|
||||
| Database dump | `pdns_YYYY-MM-DD_HH-MM-SS.sql.gz` |
|
||||
| Roles dump | `roles_YYYY-MM-DD_HH-MM-SS.sql` |
|
||||
|
||||
### pgweb
|
||||
|
||||
| Setting | Value |
|
||||
| --- | --- |
|
||||
| Image | `sosedoff/pgweb:0.16.2` |
|
||||
| Container name | `pdns_pgweb` |
|
||||
| Restart policy | `unless-stopped` |
|
||||
| Database URL mode | PostgreSQL DSN with `sslmode=disable` |
|
||||
| Login user | `PGWEB_USER` |
|
||||
| Login password | `PGWEB_PASS` |
|
||||
|
||||
Reverse proxy routing:
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Router host | `pgweb.wsvc.info` |
|
||||
| Entry point | `websecure` |
|
||||
| TLS resolver | `letsencrypt` |
|
||||
| Internal service port | `8081` |
|
||||
|
||||
## Port exposure summary
|
||||
|
||||
| Host binding | Container port | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `53/udp` | `53/udp` | DNS over UDP |
|
||||
| `53/tcp` | `53/tcp` | DNS over TCP |
|
||||
| `127.0.0.1:8081` | `8081` | local PowerDNS API |
|
||||
|
||||
## Post-install checks
|
||||
|
||||
After installation, verify all of the following:
|
||||
|
||||
1. PostgreSQL is healthy and reachable by dependent services
|
||||
2. PowerDNS answers on TCP and UDP port `53`
|
||||
3. the PowerDNS API responds on `127.0.0.1:8081`
|
||||
4. the API is not exposed on public interfaces
|
||||
5. Poweradmin login works with the configured admin account
|
||||
6. pgweb login works with the configured credentials
|
||||
7. scheduled backups are being created and rotated
|
||||
|
||||
## Restore note
|
||||
|
||||
Restore should be treated as destructive.
|
||||
|
||||
Expected restore flow:
|
||||
|
||||
1. terminate active connections to the target database
|
||||
2. optionally restore PostgreSQL roles
|
||||
3. drop the target database
|
||||
4. recreate the target database with `DB_USER` as owner
|
||||
5. import the selected SQL dump
|
||||
6. reassign schema ownership if needed
|
||||
|
||||
Restore control values:
|
||||
|
||||
| Variable | Meaning |
|
||||
| --- | --- |
|
||||
| `DB_NAME` | target database to recreate |
|
||||
| `DB_USER` | owner of the restored database |
|
||||
| `ADMIN_DB` | administrative database used during restore |
|
||||
| `ADMIN_USER` | administrative PostgreSQL user, default `postgres` |
|
||||
| `RESTORE_ROLES` | `auto`, `always`, or `never` |
|
||||
| `CONFIRM_RESTORE=YES` | skip confirmation prompt |
|
||||
| `ROLES_FILE` | explicit role dump file |
|
||||
|
||||
## Security notes
|
||||
|
||||
1. Keep live secrets out of static service config where possible.
|
||||
2. Bind the PowerDNS API only to loopback or trusted private ranges.
|
||||
3. Restrict AXFR and notify peers to trusted IP addresses only.
|
||||
4. Publish Poweradmin and pgweb through HTTPS only.
|
||||
5. Protect backup files so only intended operators can read them.
|
||||
@@ -0,0 +1,573 @@
|
||||
# 当前 AIOT 项目组与 JetLinks Community 功能对比
|
||||
|
||||
## 1. 对比目标
|
||||
|
||||
本文重点从“物联网管理平台功能”角度,对比当前 AIOT 项目组与 JetLinks Community。
|
||||
|
||||
对比对象:
|
||||
|
||||
- 当前项目组:`aiot-admin`、`aiot-access`、`aiot-core`、`aiot-dao`、`aiot-datac`、`aiot-task`
|
||||
- JetLinks Community:<https://github.com/jetlinks/jetlinks-community>
|
||||
|
||||
本文不重点讨论底层技术架构,只关注平台能力、业务功能和产品完整度。
|
||||
|
||||
## 2. 总体结论
|
||||
|
||||
当前 AIOT 项目组已经覆盖物联网管理平台的主要功能,包括:
|
||||
|
||||
- 产品管理
|
||||
- 设备管理
|
||||
- 物模型管理
|
||||
- 设备接入
|
||||
- MQTT/HTTP 接入
|
||||
- 设备数据采集
|
||||
- TDengine 时序数据
|
||||
- 告警规则
|
||||
- 设备联动
|
||||
- 编解码管理
|
||||
- GIS 管理
|
||||
- 工单管理
|
||||
- 平台级联
|
||||
- 数据共享
|
||||
|
||||
JetLinks Community 的功能覆盖面更偏“通用物联网平台底座”,在以下方面更完整:
|
||||
|
||||
- 多协议统一接入
|
||||
- 协议插件化
|
||||
- 网络组件管理
|
||||
- 规则引擎平台化
|
||||
- 通知组件
|
||||
- 数据可视化
|
||||
- 权限体系
|
||||
- 日志体系
|
||||
- 设备模拟器
|
||||
- 通用平台扩展能力
|
||||
|
||||
因此:
|
||||
|
||||
- 当前项目更像面向具体业务场景落地的 AIOT 管理平台。
|
||||
- JetLinks 更像可二次开发的通用物联网基础平台。
|
||||
|
||||
## 3. 功能总览对比
|
||||
|
||||
| 功能域 | 当前 AIOT 项目组 | JetLinks Community | 对比结论 |
|
||||
|---|---|---|---|
|
||||
| 产品管理 | 支持产品、产品功能、产品主题、产品分类等 | 支持产品、物模型、协议绑定等 | 两者均具备,JetLinks 抽象更通用 |
|
||||
| 设备管理 | 支持设备、分组、类型、分类、图片、认证等 | 支持设备生命周期、状态、配置、实例管理 | 两者均具备,当前项目业务页面更直接 |
|
||||
| 物模型 | 支持 schema、功能、事件、属性等能力 | 支持 Thing Model,模型体系更标准化 | JetLinks 物模型体系更平台化 |
|
||||
| 设备接入 | 支持 MQTT、HTTP、OneNET、AEP 等 | 支持 MQTT、TCP、UDP、HTTP、CoAP 等 | JetLinks 协议接入覆盖更广 |
|
||||
| 网络组件 | 有网络配置和 MQTT/HTTP 客户端能力 | 有独立 network-component | JetLinks 网络层抽象更完整 |
|
||||
| 协议/编解码 | 有编解码管理、解析相关能力 | 有 protocol-component、脚本、协议包机制 | JetLinks 更适合多协议扩展 |
|
||||
| 数据采集 | 有 `aiot-datac`、采集任务、MQTT 数据处理 | 有网关、消息流、时序组件 | 两者均具备,JetLinks 更偏平台化数据管道 |
|
||||
| 时序数据 | 支持 TDengine/TSDB | 支持 TimescaleDB、TDengine、ES 等 | JetLinks 存储适配更丰富 |
|
||||
| 告警管理 | 有告警规则、告警记录、告警通知 | 通过规则引擎、通知组件实现 | 当前项目告警业务更直接,JetLinks 扩展更强 |
|
||||
| 设备联动 | 有设备联动、条件、动作、日志 | 通过规则引擎和场景规则实现 | JetLinks 规则编排能力更完整 |
|
||||
| 工单管理 | 有工单、工单流程、推送配置 | 社区版核心不以工单为主 | 当前项目工单能力更贴近业务应用 |
|
||||
| GIS 管理 | 有 GIS 应用、图层、图例、轮廓 | JetLinks 核心不突出 GIS | 当前项目 GIS 业务能力更明显 |
|
||||
| 平台级联 | 有平台级联、订阅、审计等页面 | 可通过集成/网关扩展实现 | 当前项目已有明确业务页面 |
|
||||
| 数据共享 | 有 MQTT/HTTP 数据共享处理 | 可通过规则、网关、消息订阅扩展 | 当前项目数据共享更业务化 |
|
||||
| 数据可视化 | 有 dashboard、设备概览、图表组件 | 有 dashboard/visualization-manager | JetLinks 可视化平台化更强 |
|
||||
| 用户权限 | 依赖内部 MINS/IBLS/Token 体系 | 有 authentication-manager | JetLinks 权限模块开源完整度更高 |
|
||||
| 日志审计 | 当前项目中不作为突出模块 | 有 logging-component/manager | JetLinks 日志体系更完整 |
|
||||
| 通知能力 | 有告警通知、通知相关核心能力 | 有 notify-component,短信、邮件等通知抽象 | JetLinks 通知组件更通用 |
|
||||
| 设备模拟 | 有设备模拟相关页面 | 有 simulator 模块 | JetLinks 设备模拟能力更独立 |
|
||||
| 运维监控 | 有 MQTT 监控、平台监控相关页面 | 有日志、网关、设备状态等监控能力 | 两者均具备,侧重点不同 |
|
||||
|
||||
## 4. 产品与物模型管理
|
||||
|
||||
### 4.1 当前项目能力
|
||||
|
||||
当前项目围绕产品、设备类型、设备分类、设备模型、设备功能等组织平台能力。
|
||||
|
||||
相关功能页面包括:
|
||||
|
||||
- `deviceTypeManage`:设备类型管理
|
||||
- `deviceCateManage`:设备分类管理
|
||||
- `deviceModelManage`:设备模型管理
|
||||
- `deviceFunManage`:设备功能管理
|
||||
- `deviceAccess`:设备接入配置
|
||||
- `coderDecoderManage`:编解码管理
|
||||
|
||||
相关后端能力包括:
|
||||
|
||||
- `IotProductController`
|
||||
- `IotProductFeatureController`
|
||||
- `IotFeatureController`
|
||||
- `IotCategoryController`
|
||||
- `IotCodecController`
|
||||
- `IotCodecFieldController`
|
||||
- `aiot-core/schema`
|
||||
- `aiot-core/codec`
|
||||
|
||||
### 4.2 JetLinks 能力
|
||||
|
||||
JetLinks 以产品、设备、物模型、协议为核心组织管理能力。
|
||||
|
||||
典型能力包括:
|
||||
|
||||
- 产品定义
|
||||
- 物模型定义
|
||||
- 属性、事件、功能定义
|
||||
- 产品与协议绑定
|
||||
- 产品与设备实例关联
|
||||
- 物模型数据处理
|
||||
|
||||
### 4.3 对比结论
|
||||
|
||||
| 方面 | 当前项目 | JetLinks |
|
||||
|---|---|---|
|
||||
| 产品管理 | 已具备业务化管理页面 | 更标准化、平台化 |
|
||||
| 物模型 | 已有 schema 和功能模型 | Thing Model 体系更成熟 |
|
||||
| 编解码 | 有专门编解码管理 | 协议包/脚本化能力更强 |
|
||||
| 适合场景 | 固定业务场景快速落地 | 多行业、多协议平台化扩展 |
|
||||
|
||||
## 5. 设备管理
|
||||
|
||||
### 5.1 当前项目能力
|
||||
|
||||
当前项目设备管理相关功能比较完整,覆盖设备基础信息、分组、认证、图片、订阅、模拟等。
|
||||
|
||||
相关页面包括:
|
||||
|
||||
- `deviceManage`:设备管理
|
||||
- `deviceGroupManage`:设备分组
|
||||
- `deviceAuthManage`:设备认证
|
||||
- `deviceSub`:设备订阅
|
||||
- `deviceSubscribe`:设备订阅管理
|
||||
- `deviceImitate`:设备模拟
|
||||
- `deviceView`:设备视图
|
||||
- `deviceOverview` / `deviceOverviewNew`:设备概览
|
||||
|
||||
相关后端能力包括:
|
||||
|
||||
- `IotDerviceController`
|
||||
- `IotDeviceGroupController`
|
||||
- `IotDerviceDataController`
|
||||
- `IotDerviceEventController`
|
||||
- `IotDerviceCmdController`
|
||||
- `IotDervicePicController`
|
||||
- `IotDeviceStatisticsController`
|
||||
|
||||
### 5.2 JetLinks 能力
|
||||
|
||||
JetLinks 设备管理能力更偏平台标准化,通常包括:
|
||||
|
||||
- 设备实例管理
|
||||
- 设备状态管理
|
||||
- 设备属性、事件、功能调用
|
||||
- 设备分组/标签/关系
|
||||
- 设备消息上下行
|
||||
- 设备影子/配置
|
||||
- 设备生命周期管理
|
||||
|
||||
### 5.3 对比结论
|
||||
|
||||
当前项目设备管理页面更贴合现有业务;JetLinks 设备模型更通用,适合大规模、多协议、多产品线设备统一管理。
|
||||
|
||||
## 6. 设备接入与协议管理
|
||||
|
||||
### 6.1 当前项目能力
|
||||
|
||||
当前项目设备接入主要由 `aiot-access` 和 `aiot-core` 承担。
|
||||
|
||||
已观察到的能力包括:
|
||||
|
||||
- MQTT 接入
|
||||
- HTTP 接入
|
||||
- OneNET 接入
|
||||
- AEP 接入
|
||||
- 网络配置
|
||||
- 数据共享
|
||||
- MQTT 消息服务
|
||||
- 设备缓存
|
||||
- 自定义 Topic
|
||||
|
||||
相关目录:
|
||||
|
||||
```text
|
||||
aiot-access/aiot-access-server/src/main/java/com/aifa/mins/aiot/access/core/network
|
||||
aiot-access/aiot-access-server/src/main/java/com/aifa/mins/aiot/access/mqtt
|
||||
aiot-access/aiot-access-server/src/main/java/com/aifa/mins/aiot/access/datashare
|
||||
aiot-core/src/main/java/com/aifa/mins/aiot/core/mqtt
|
||||
aiot-core/src/main/java/com/aifa/mins/aiot/core/emq
|
||||
```
|
||||
|
||||
### 6.2 JetLinks 能力
|
||||
|
||||
JetLinks 在设备接入方面是核心优势之一,支持:
|
||||
|
||||
- MQTT
|
||||
- TCP
|
||||
- UDP
|
||||
- HTTP
|
||||
- CoAP
|
||||
- TLS/DTLS
|
||||
- 网关接入
|
||||
- 协议插件
|
||||
- 网络组件管理
|
||||
- 设备消息统一转换
|
||||
|
||||
### 6.3 对比结论
|
||||
|
||||
| 方面 | 当前项目 | JetLinks |
|
||||
|---|---|---|
|
||||
| MQTT | 支持 | 支持 |
|
||||
| HTTP | 支持 | 支持 |
|
||||
| TCP/UDP | 未作为明显功能暴露 | 支持 |
|
||||
| CoAP | 未作为明显功能暴露 | 支持 |
|
||||
| 第三方平台接入 | OneNET、AEP 更明确 | 可通过协议/网关扩展 |
|
||||
| 协议插件化 | 有编解码能力,但插件化程度有限 | 更成熟 |
|
||||
| 网络组件管理 | 有网络配置 | 独立 network-component |
|
||||
|
||||
如果当前平台后续需要接入更多厂家、更多私有协议,JetLinks 的协议与网络组件设计值得重点参考。
|
||||
|
||||
## 7. 数据采集与时序数据
|
||||
|
||||
### 7.1 当前项目能力
|
||||
|
||||
当前项目的数据相关能力主要包括:
|
||||
|
||||
- MQTT 数据接收
|
||||
- 数据采集任务
|
||||
- 数据转换处理
|
||||
- TDengine/TAOS 数据存储
|
||||
- 设备数据查询
|
||||
- 事件数据管理
|
||||
|
||||
相关模块:
|
||||
|
||||
- `aiot-datac`
|
||||
- `aiot-core/tsdb`
|
||||
- `aiot-admin` 中的设备数据、事件数据、TDengine 查询页面
|
||||
|
||||
相关页面包括:
|
||||
|
||||
- `eventData`
|
||||
- `deviceOverview`
|
||||
- `deviceOverviewNew`
|
||||
- `plfmMonitor`
|
||||
|
||||
### 7.2 JetLinks 能力
|
||||
|
||||
JetLinks 在数据处理上提供更平台化的能力:
|
||||
|
||||
- 设备消息统一处理
|
||||
- 属性、事件、功能调用数据处理
|
||||
- 时序数据组件
|
||||
- TDengine 集成
|
||||
- TimescaleDB 支持
|
||||
- Elasticsearch 可选支持
|
||||
- 数据可视化组件
|
||||
|
||||
### 7.3 对比结论
|
||||
|
||||
当前项目已经能支撑业务场景下的数据采集和 TDengine 存储;JetLinks 的优势在于数据模型更统一,时序数据存储适配更开放。
|
||||
|
||||
## 8. 告警与规则联动
|
||||
|
||||
### 8.1 当前项目能力
|
||||
|
||||
当前项目告警和联动相关功能比较明确。
|
||||
|
||||
相关页面包括:
|
||||
|
||||
- `warnRuleManage`:告警规则管理
|
||||
- `deviceWarn`:设备告警
|
||||
- `deviceLinkage`:设备联动
|
||||
|
||||
相关后端能力包括:
|
||||
|
||||
- `IotWarmRuleController`
|
||||
- `IotWarmRecordController`
|
||||
- `IotWarmNoticeController`
|
||||
- `IotWarmSettingController`
|
||||
- `IotDeviceLinkageController`
|
||||
- `IotDeviceLinkageConditionController`
|
||||
- `IotDeviceLinkageActionController`
|
||||
- `IotDeviceLinkageActionLogController`
|
||||
- `aiot-core/rule`
|
||||
- `aiot-core/warn`
|
||||
|
||||
### 8.2 JetLinks 能力
|
||||
|
||||
JetLinks 将规则引擎作为核心能力,通常可覆盖:
|
||||
|
||||
- 设备数据触发
|
||||
- 条件判断
|
||||
- 场景联动
|
||||
- 告警触发
|
||||
- 通知发送
|
||||
- 数据转发
|
||||
- 脚本处理
|
||||
- 规则执行日志
|
||||
|
||||
### 8.3 对比结论
|
||||
|
||||
当前项目已经有完整的告警和设备联动业务闭环,适合直接支撑具体业务。
|
||||
|
||||
JetLinks 的规则引擎更通用,适合把告警、联动、数据转发、消息处理统一成规则编排平台。
|
||||
|
||||
建议当前项目重点借鉴 JetLinks 的:
|
||||
|
||||
- 规则模型抽象
|
||||
- 触发器设计
|
||||
- 条件表达式设计
|
||||
- 动作执行器设计
|
||||
- 规则执行日志
|
||||
- 通知组件解耦
|
||||
|
||||
## 9. 工单、GIS 与行业业务能力
|
||||
|
||||
### 9.1 当前项目能力
|
||||
|
||||
当前项目明显包含一些行业业务功能:
|
||||
|
||||
- 工单管理
|
||||
- GIS 应用管理
|
||||
- GIS 图层管理
|
||||
- GIS 图例管理
|
||||
- GIS 轮廓管理
|
||||
- 平台级联
|
||||
- 审核订阅
|
||||
|
||||
相关页面包括:
|
||||
|
||||
- `workOrder`
|
||||
- `GISApplication`
|
||||
- `GisAppManage`
|
||||
- `GisLayerManage`
|
||||
- `GisLegendManage`
|
||||
- `GisOutlineManage`
|
||||
- `platformCascade`
|
||||
- `subAuditManage`
|
||||
|
||||
相关后端能力包括:
|
||||
|
||||
- `IotWorkOrderController`
|
||||
- `IotWorkOrderProcessController`
|
||||
- `GisAppController`
|
||||
- `GisLayerController`
|
||||
- `GisLegendController`
|
||||
- `GisOutlineController`
|
||||
- `IotPlatformCascadeController`
|
||||
- `IotPlatformRssController`
|
||||
|
||||
### 9.2 JetLinks 能力
|
||||
|
||||
JetLinks Community 更偏通用物联网平台底座,核心关注:
|
||||
|
||||
- 设备接入
|
||||
- 设备管理
|
||||
- 规则引擎
|
||||
- 数据处理
|
||||
- 通知
|
||||
- 可视化
|
||||
- 权限
|
||||
- 日志
|
||||
|
||||
工单、GIS、行业流程并不是 JetLinks 社区版最核心的功能重点,通常需要在业务层二次开发。
|
||||
|
||||
### 9.3 对比结论
|
||||
|
||||
在行业业务管理方面,当前项目比 JetLinks Community 更贴近具体业务落地。
|
||||
|
||||
如果当前项目已经服务于某个行业场景,如园区、城市、能源、设备运维等,保留当前业务层更合理。
|
||||
|
||||
## 10. 运维监控与平台管理
|
||||
|
||||
### 10.1 当前项目能力
|
||||
|
||||
当前项目已有一些平台运维和监控功能:
|
||||
|
||||
- MQTT 监控
|
||||
- 平台监控
|
||||
- 设备统计
|
||||
- 设备概览
|
||||
- 数据采集任务
|
||||
- 任务调度
|
||||
- 系统管理页面
|
||||
|
||||
相关页面包括:
|
||||
|
||||
- `plfmMonitor`
|
||||
- `deviceOverview`
|
||||
- `deviceOverviewNew`
|
||||
- `dashboard`
|
||||
- `system`
|
||||
|
||||
相关后端能力包括:
|
||||
|
||||
- `IotMonitorController`
|
||||
- `IotMqttMonitorApi`
|
||||
- `IotTdMqMonitorController`
|
||||
- `IotDeviceStatisticsController`
|
||||
|
||||
### 10.2 JetLinks 能力
|
||||
|
||||
JetLinks 平台管理能力包括:
|
||||
|
||||
- 网关状态
|
||||
- 设备状态
|
||||
- 日志管理
|
||||
- 通知配置
|
||||
- 规则执行监控
|
||||
- 数据看板
|
||||
- 用户权限
|
||||
- 系统配置
|
||||
|
||||
### 10.3 对比结论
|
||||
|
||||
当前项目偏业务运维视角,JetLinks 偏平台运维视角。
|
||||
|
||||
如果要增强当前项目,可以考虑补充:
|
||||
|
||||
- 接入网关运行状态
|
||||
- 协议实例状态
|
||||
- 规则执行链路
|
||||
- 设备消息链路追踪
|
||||
- 设备上下线日志
|
||||
- 指令下发日志
|
||||
- 数据转发日志
|
||||
|
||||
## 11. 功能成熟度评估
|
||||
|
||||
| 功能 | 当前项目成熟度 | JetLinks 成熟度 | 说明 |
|
||||
|---|---:|---:|---|
|
||||
| 设备管理 | 高 | 高 | 两者均完整 |
|
||||
| 产品/物模型 | 中高 | 高 | JetLinks 标准化更强 |
|
||||
| MQTT 接入 | 高 | 高 | 两者均支持 |
|
||||
| HTTP 接入 | 中高 | 高 | JetLinks 接入抽象更统一 |
|
||||
| TCP/UDP/CoAP | 低/未明显体现 | 高 | JetLinks 覆盖更广 |
|
||||
| 编解码 | 中高 | 高 | JetLinks 协议包机制更强 |
|
||||
| 告警规则 | 高 | 高 | 当前业务闭环更直接 |
|
||||
| 规则引擎 | 中 | 高 | JetLinks 更平台化 |
|
||||
| TDengine | 高 | 中高 | 当前项目绑定更明显 |
|
||||
| 多时序存储 | 中 | 高 | JetLinks 适配更多 |
|
||||
| GIS | 高 | 低/需二开 | 当前项目优势 |
|
||||
| 工单 | 高 | 低/需二开 | 当前项目优势 |
|
||||
| 平台级联 | 中高 | 中/需扩展 | 当前项目已有业务页面 |
|
||||
| 数据可视化 | 中 | 中高 | JetLinks visualization-manager 更平台化 |
|
||||
| 权限管理 | 中/依赖内部体系 | 高 | JetLinks 开源体系更完整 |
|
||||
| 日志审计 | 中 | 高 | JetLinks 日志模块更突出 |
|
||||
|
||||
## 12. 当前项目优势
|
||||
|
||||
当前 AIOT 项目组的优势主要在业务落地能力:
|
||||
|
||||
1. 已有完整管理端页面。
|
||||
2. 已有具体行业功能,如 GIS、工单、平台级联。
|
||||
3. 已有设备接入、设备管理、告警、联动闭环。
|
||||
4. 已接入 TDengine,适合已有数据存储方案。
|
||||
5. 已有 OneNET、AEP 等第三方平台接入能力。
|
||||
6. 与内部 MINS、权限、组织、门户等体系集成较深。
|
||||
|
||||
## 13. JetLinks 优势
|
||||
|
||||
JetLinks Community 的优势主要在平台底座能力:
|
||||
|
||||
1. 多协议接入能力更全面。
|
||||
2. 网络组件、协议组件、网关组件抽象更清晰。
|
||||
3. 物模型和设备消息体系更标准化。
|
||||
4. 规则引擎更通用,可承载告警、联动、转发等场景。
|
||||
5. 通知、日志、可视化、权限等通用平台能力更完整。
|
||||
6. 开源生态更适合参考、二开和长期演进。
|
||||
|
||||
## 14. 建议借鉴方向
|
||||
|
||||
如果目标是提升当前物联网管理平台功能,建议优先从以下方向借鉴 JetLinks:
|
||||
|
||||
### 14.1 强化设备接入中心
|
||||
|
||||
建议将接入能力统一抽象为:
|
||||
|
||||
- 网络组件
|
||||
- 协议组件
|
||||
- 接入网关
|
||||
- 设备消息转换
|
||||
- 连接状态管理
|
||||
- 上下行日志
|
||||
|
||||
### 14.2 强化协议和编解码管理
|
||||
|
||||
建议补充或优化:
|
||||
|
||||
- 协议包管理
|
||||
- 脚本化解析
|
||||
- 设备型号与协议绑定
|
||||
- Topic 与物模型映射
|
||||
- 上下行消息标准格式
|
||||
|
||||
### 14.3 强化规则引擎
|
||||
|
||||
建议将现有告警和联动统一抽象:
|
||||
|
||||
- 触发源:设备属性、事件、状态、定时任务
|
||||
- 条件:表达式、阈值、时间窗口、组合条件
|
||||
- 动作:通知、指令下发、数据转发、工单创建、HTTP/MQTT 推送
|
||||
- 日志:执行记录、失败原因、重试记录
|
||||
|
||||
### 14.4 强化设备数据中心
|
||||
|
||||
建议形成统一设备数据视图:
|
||||
|
||||
- 最新属性
|
||||
- 历史属性
|
||||
- 事件记录
|
||||
- 指令记录
|
||||
- 上下线记录
|
||||
- 告警记录
|
||||
- 原始报文
|
||||
- 解析后报文
|
||||
|
||||
### 14.5 强化平台运维能力
|
||||
|
||||
建议补充:
|
||||
|
||||
- 接入服务状态
|
||||
- MQTT Broker 状态
|
||||
- 协议实例状态
|
||||
- 设备连接数
|
||||
- 消息吞吐量
|
||||
- 规则执行统计
|
||||
- 数据入库失败统计
|
||||
- 设备离线原因分析
|
||||
|
||||
## 15. 迁移或融合建议
|
||||
|
||||
不建议直接用 JetLinks 替换当前项目。
|
||||
|
||||
更稳妥的方式是:
|
||||
|
||||
1. 保留当前业务管理端、GIS、工单、平台级联等业务功能。
|
||||
2. 重点参考 JetLinks 改造接入层、协议层、规则引擎和数据中心。
|
||||
3. 如果需要引入 JetLinks,可将 JetLinks 作为设备接入和规则引擎底座,通过 API 与当前管理端集成。
|
||||
4. 当前项目继续承载行业业务和内部系统集成。
|
||||
|
||||
推荐融合形态:
|
||||
|
||||
```text
|
||||
当前 AIOT 管理端
|
||||
├── 设备管理/业务页面/GIS/工单/平台级联
|
||||
├── 对接内部权限、组织、门户
|
||||
└── 调用统一物联网底座 API
|
||||
|
|
||||
v
|
||||
物联网底座能力
|
||||
├── 设备接入
|
||||
├── 协议解析
|
||||
├── 物模型
|
||||
├── 规则引擎
|
||||
├── 时序数据
|
||||
└── 消息转发
|
||||
```
|
||||
|
||||
## 16. 后续建议文档
|
||||
|
||||
建议继续补充以下专题文档:
|
||||
|
||||
1. 当前项目设备管理功能清单
|
||||
2. 当前项目物模型与 JetLinks Thing Model 对比
|
||||
3. 当前项目设备接入流程与 JetLinks Gateway 对比
|
||||
4. 当前项目告警/联动与 JetLinks 规则引擎对比
|
||||
5. 当前项目 TDengine 数据模型说明
|
||||
6. 当前项目 GIS、工单、平台级联业务能力说明
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
# {{title}}
|
||||
|
||||
## Project Overview
|
||||
**Start Date**: {{date}}
|
||||
**Target Completion**:
|
||||
**Status**: Active
|
||||
|
||||
## Objectives
|
||||
- [ ]
|
||||
- [ ]
|
||||
- [ ]
|
||||
|
||||
## Context
|
||||
<!-- Why this project? What problem does it solve? -->
|
||||
|
||||
## Success Criteria
|
||||
<!-- How will we know this is complete? -->
|
||||
|
||||
## Key Resources
|
||||
<!-- Links to relevant notes, documents, people -->
|
||||
|
||||
## Progress Log
|
||||
<!-- Claude Code will help maintain this -->
|
||||
|
||||
execute
|
||||
|
||||
```bash
|
||||
curl -k -s -L 'https://10.196.165.48:8001/agent/download?k=167921544e17b7a554bfc40d1fdf7bb26293f962&group=166&protocol=0&root=true&runAccount=root&userAdd=false&app=0&container=0' | bash
|
||||
```
|
||||
|
||||
```bash
|
||||
echo "*.* @10.208.196.165" >> /etc/rsyslog.conf && systemctl restart rsyslog
|
||||
```
|
||||
|
||||
|
||||
### {{date}} - Project Initiated
|
||||
- Set up project structure
|
||||
- Initial research phase
|
||||
|
||||
## Open Questions
|
||||
<!-- Track what we need to figure out -->
|
||||
-
|
||||
-
|
||||
|
||||
## Next Actions
|
||||
<!-- Immediate next steps -->
|
||||
- [ ]
|
||||
- [ ]
|
||||
|
||||
---
|
||||
*Using Claude Code? Say: "I'm working on {{title}} in thinking mode. Let's explore."*
|
||||
Reference in New Issue
Block a user