mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-28 05:46:36 +08:00
refactor(layout): adopt wavelet manifest layout for configs and docker while preserving docker-compose
This commit is contained in:
@@ -18,7 +18,7 @@ permissions:
|
||||
|
||||
env:
|
||||
IMAGE_NAME: openflare-agent
|
||||
DOCKERFILE: docker/Dockerfile.agent
|
||||
DOCKERFILE: manifest/docker/Dockerfile.agent
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
@@ -18,7 +18,7 @@ permissions:
|
||||
|
||||
env:
|
||||
IMAGE_NAME: openflare-relay
|
||||
DOCKERFILE: docker/Dockerfile.relay
|
||||
DOCKERFILE: manifest/docker/Dockerfile.relay
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
@@ -24,7 +24,7 @@ permissions:
|
||||
|
||||
env:
|
||||
IMAGE_NAME: openflare
|
||||
DOCKERFILE: docker/Dockerfile
|
||||
DOCKERFILE: manifest/docker/Dockerfile
|
||||
|
||||
jobs:
|
||||
# Resolve version / registries once. No checkout: triggers alone determine the tag.
|
||||
|
||||
@@ -18,7 +18,7 @@ permissions:
|
||||
|
||||
env:
|
||||
IMAGE_NAME: openflared
|
||||
DOCKERFILE: docker/Dockerfile.flared
|
||||
DOCKERFILE: manifest/docker/Dockerfile.flared
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
# config
|
||||
config.yaml
|
||||
manifest/config/config.yaml
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
+3
-3
@@ -95,10 +95,10 @@ cd refreshing
|
||||
### 2. 配置环境
|
||||
|
||||
```bash
|
||||
cp config.example.yaml config.yaml
|
||||
cp manifest/config/config.default.yaml manifest/config/config.yaml
|
||||
```
|
||||
|
||||
编辑 `config.yaml`,配置数据库和 Redis。OIDC 认证源统一在管理后台的系统设置页面运行时配置。
|
||||
编辑 `manifest/config/config.yaml`,配置数据库和 Redis。OIDC 认证源统一在管理后台的系统设置页面运行时配置。
|
||||
|
||||
### 3. 初始化数据库
|
||||
|
||||
@@ -156,7 +156,7 @@ pnpm dev
|
||||
|
||||
## ⚙️ 配置说明
|
||||
|
||||
主要配置项(完整说明请参考 `config.example.yaml`):
|
||||
主要配置项(完整说明请参考 `manifest/config/config.default.yaml`):
|
||||
|
||||
| 配置项 | 说明 | 示例 |
|
||||
|--------|------|------|
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
# OpenFlare default compose file (`docker compose` / `docker-compose.yaml`).
|
||||
# The Wavelet upstream stack is in docker-compose.wavelet.yml and is not used here.
|
||||
services:
|
||||
openflare:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile
|
||||
args:
|
||||
VERSION: v0.9.9
|
||||
# image: ghcr.io/rain-kl/openflare:latest
|
||||
restart: unless-stopped
|
||||
env_file: .env
|
||||
environment:
|
||||
TZ: ${TZ:-Asia/Shanghai}
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://jaeger:4317}
|
||||
OTEL_EXPORTER_OTLP_INSECURE: ${OTEL_EXPORTER_OTLP_INSECURE:-true}
|
||||
OTEL_SAMPLING_RATE: ${OTEL_SAMPLING_RATE:-1.0}
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- ./uploads:/app/uploads
|
||||
- ./data/sqlite:/app/data
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
jaeger:
|
||||
condition: service_started
|
||||
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
POSTGRES_DB: ${DB_NAME:-openflare}
|
||||
POSTGRES_USER: ${DB_USERNAME:-openflare}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD:-replace-with-strong-password}
|
||||
volumes:
|
||||
- ./data/postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME:-openflare} -d ${DB_NAME:-openflare}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
redis:
|
||||
image: valkey/valkey:8.0-alpine
|
||||
restart: unless-stopped
|
||||
command: ["valkey-server", "--appendonly", "yes"]
|
||||
ports:
|
||||
- "${REDIS_PORT:-6379}:6379"
|
||||
volumes:
|
||||
- ./data/valkey:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "valkey-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 5s
|
||||
|
||||
jaeger:
|
||||
image: jaegertracing/jaeger:${JAEGER_VERSION:-2.19.0}
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: ${TZ:-Asia/Shanghai}
|
||||
ports:
|
||||
- "${JAEGER_UI_PORT:-16686}:16686"
|
||||
- "${JAEGER_OTLP_GRPC_PORT:-4317}:4317"
|
||||
- "${JAEGER_OTLP_HTTP_PORT:-4318}:4318"
|
||||
|
||||
clickhouse:
|
||||
image: clickhouse/clickhouse-server:25.3-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
CLICKHOUSE_DB: ${CLICKHOUSE_NAME:-openflare}
|
||||
CLICKHOUSE_USER: ${CLICKHOUSE_USERNAME:-default}
|
||||
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-replace-with-clickhouse-password}
|
||||
CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
|
||||
TZ: ${TZ:-Asia/Shanghai}
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 262144
|
||||
hard: 262144
|
||||
ports:
|
||||
- "8123:8123"
|
||||
- "9000:9000"
|
||||
volumes:
|
||||
- ./data/clickhouse_data:/var/lib/clickhouse
|
||||
- ./config/clickhouse/performance.xml:/etc/clickhouse-server/config.d/performance.xml:ro
|
||||
healthcheck:
|
||||
test: ["CMD", "clickhouse-client", "--user", "${CLICKHOUSE_USERNAME:-default}", "--password", "${CLICKHOUSE_PASSWORD:-replace-with-clickhouse-password}", "--query", "SELECT 1"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 15s
|
||||
|
||||
agent:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile.agent
|
||||
container_name: openflare-agent
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "127.0.0.1:18081:18081"
|
||||
volumes:
|
||||
- ./data/agent/:/data
|
||||
environment:
|
||||
OPENFLARE_SERVER_URL: "http://host.docker.internal:3000"
|
||||
OPENFLARE_AGENT_TOKEN: "7c7c4c13df0f3a77866bcd8cde492610"
|
||||
LOG_LEVEL: "debug"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
|
||||
relay:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile.relay
|
||||
container_name: openflare-relay
|
||||
network_mode: host
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./data/relay/:/app/data
|
||||
environment:
|
||||
OPENFLARE_SERVER_URL: http://host.docker.internal:3000
|
||||
OPENFLARE_DISCOVERY_TOKEN: 85464eeb72c49abc430569d6b9c77f78
|
||||
LOG_LEVEL: "debug"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
|
||||
flared:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile.flared
|
||||
container_name: openflare-flared
|
||||
network_mode: "host"
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./data/flared/:/app/data
|
||||
environment:
|
||||
OPENFLARE_SERVER_URL: "http://host.docker.internal:3000"
|
||||
OPENFLARE_TUNNEL_TOKEN: deb0783ac1e264a9d86440169aca0f09
|
||||
+147
-6
@@ -1,6 +1,147 @@
|
||||
# Isolated Wavelet compose filename.
|
||||
# OpenFlare's default stack is docker-compose.yaml (`docker compose` prefers
|
||||
# that name over this one). This stub is kept so `git merge wavelet/main`
|
||||
# cannot restore a wavelet product stack under the default compose name.
|
||||
include:
|
||||
- path: docker-compose.yaml
|
||||
# OpenFlare default compose file (`docker compose` / `docker-compose.yaml`).
|
||||
# The Wavelet upstream stack is in docker-compose.wavelet.yml and is not used here.
|
||||
services:
|
||||
openflare:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: manifest/docker/Dockerfile
|
||||
args:
|
||||
VERSION: v0.9.9
|
||||
# image: ghcr.io/rain-kl/openflare:latest
|
||||
restart: unless-stopped
|
||||
env_file: .env
|
||||
environment:
|
||||
TZ: ${TZ:-Asia/Shanghai}
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://jaeger:4317}
|
||||
OTEL_EXPORTER_OTLP_INSECURE: ${OTEL_EXPORTER_OTLP_INSECURE:-true}
|
||||
OTEL_SAMPLING_RATE: ${OTEL_SAMPLING_RATE:-1.0}
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- ./uploads:/app/uploads
|
||||
- ./data/sqlite:/app/data
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
jaeger:
|
||||
condition: service_started
|
||||
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
POSTGRES_DB: ${DB_NAME:-openflare}
|
||||
POSTGRES_USER: ${DB_USERNAME:-openflare}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD:-replace-with-strong-password}
|
||||
volumes:
|
||||
- ./data/postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME:-openflare} -d ${DB_NAME:-openflare}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
redis:
|
||||
image: valkey/valkey:8.0-alpine
|
||||
restart: unless-stopped
|
||||
command: ["valkey-server", "--appendonly", "yes"]
|
||||
ports:
|
||||
- "${REDIS_PORT:-6379}:6379"
|
||||
volumes:
|
||||
- ./data/valkey:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "valkey-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 5s
|
||||
|
||||
jaeger:
|
||||
image: jaegertracing/jaeger:${JAEGER_VERSION:-2.19.0}
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: ${TZ:-Asia/Shanghai}
|
||||
ports:
|
||||
- "${JAEGER_UI_PORT:-16686}:16686"
|
||||
- "${JAEGER_OTLP_GRPC_PORT:-4317}:4317"
|
||||
- "${JAEGER_OTLP_HTTP_PORT:-4318}:4318"
|
||||
|
||||
clickhouse:
|
||||
image: clickhouse/clickhouse-server:25.3-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
CLICKHOUSE_DB: ${CLICKHOUSE_NAME:-openflare}
|
||||
CLICKHOUSE_USER: ${CLICKHOUSE_USERNAME:-default}
|
||||
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-replace-with-clickhouse-password}
|
||||
CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
|
||||
TZ: ${TZ:-Asia/Shanghai}
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 262144
|
||||
hard: 262144
|
||||
ports:
|
||||
- "8123:8123"
|
||||
- "9000:9000"
|
||||
volumes:
|
||||
- ./data/clickhouse_data:/var/lib/clickhouse
|
||||
- ./config/clickhouse/performance.xml:/etc/clickhouse-server/config.d/performance.xml:ro
|
||||
healthcheck:
|
||||
test: ["CMD", "clickhouse-client", "--user", "${CLICKHOUSE_USERNAME:-default}", "--password", "${CLICKHOUSE_PASSWORD:-replace-with-clickhouse-password}", "--query", "SELECT 1"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 15s
|
||||
|
||||
agent:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: manifest/docker/Dockerfile.agent
|
||||
container_name: openflare-agent
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "127.0.0.1:18081:18081"
|
||||
volumes:
|
||||
- ./data/agent/:/data
|
||||
environment:
|
||||
OPENFLARE_SERVER_URL: "http://host.docker.internal:3000"
|
||||
OPENFLARE_AGENT_TOKEN: "7c7c4c13df0f3a77866bcd8cde492610"
|
||||
LOG_LEVEL: "debug"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
|
||||
relay:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: manifest/docker/Dockerfile.relay
|
||||
container_name: openflare-relay
|
||||
network_mode: host
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./data/relay/:/app/data
|
||||
environment:
|
||||
OPENFLARE_SERVER_URL: http://host.docker.internal:3000
|
||||
OPENFLARE_DISCOVERY_TOKEN: 85464eeb72c49abc430569d6b9c77f78
|
||||
LOG_LEVEL: "debug"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
|
||||
flared:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: manifest/docker/Dockerfile.flared
|
||||
container_name: openflare-flared
|
||||
network_mode: "host"
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./data/flared/:/app/data
|
||||
environment:
|
||||
OPENFLARE_SERVER_URL: "http://host.docker.internal:3000"
|
||||
OPENFLARE_TUNNEL_TOKEN: deb0783ac1e264a9d86440169aca0f09
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
# syntax=docker/dockerfile:1.7
|
||||
|
||||
ARG GO_VERSION=1.25
|
||||
ARG NODE_VERSION=22
|
||||
ARG ALPINE_VERSION=3.23
|
||||
|
||||
FROM node:${NODE_VERSION}-alpine AS frontend-builder
|
||||
|
||||
ARG VERSION=dev
|
||||
ARG BUILD_DATE=""
|
||||
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_STANDALONE_EXPORT=true
|
||||
ENV NEXT_PUBLIC_APP_VERSION=${VERSION}
|
||||
ENV NEXT_PUBLIC_APP_BUILD_DATE=${BUILD_DATE}
|
||||
|
||||
RUN corepack enable && corepack prepare pnpm@10.10.0 --activate
|
||||
|
||||
WORKDIR /workspace/frontend
|
||||
|
||||
COPY frontend/package.json frontend/pnpm-lock.yaml frontend/pnpm-workspace.yaml ./
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
COPY frontend/ ./
|
||||
|
||||
# Assert index.html so a silent export failure cannot ship an API-only binary.
|
||||
RUN pnpm build:embed && test -f out/index.html
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine AS backend-builder
|
||||
|
||||
ARG VERSION=dev
|
||||
ARG BUILD_DATE=""
|
||||
|
||||
RUN apk add --no-cache ca-certificates git
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
# Cache dependency layer
|
||||
COPY backend/go.mod backend/go.sum ./backend/
|
||||
RUN cd backend && go mod download
|
||||
|
||||
COPY . .
|
||||
|
||||
# Drop any stale bundle carried in the context, then overlay the fresh export so
|
||||
# `//go:embed all:dist` in driver_http picks up exactly this frontend build.
|
||||
RUN rm -rf backend/plugins/drivers/driver_http/dist
|
||||
COPY --from=frontend-builder /workspace/frontend/out backend/plugins/drivers/driver_http/dist
|
||||
|
||||
WORKDIR /workspace/backend
|
||||
|
||||
RUN test -f plugins/drivers/driver_http/dist/index.html && \
|
||||
CGO_ENABLED=0 GOOS=linux go build \
|
||||
-tags embed_frontend \
|
||||
-trimpath \
|
||||
-ldflags="-s -w -X Wavelet/pkg/buildinfo.Version=${VERSION} -X Wavelet/pkg/buildinfo.BuildTime=${BUILD_DATE}" \
|
||||
-o /out/openflare-server \
|
||||
./main.go
|
||||
|
||||
FROM alpine:${ALPINE_VERSION}
|
||||
|
||||
ARG TZ=Asia/Shanghai
|
||||
|
||||
RUN apk add --no-cache ca-certificates tzdata postgresql-client && \
|
||||
cp /usr/share/zoneinfo/${TZ} /etc/localtime && \
|
||||
echo "${TZ}" > /etc/timezone
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=backend-builder /out/openflare-server ./openflare-server
|
||||
COPY docs ./docs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENTRYPOINT ["./openflare-server"]
|
||||
CMD ["all"]
|
||||
@@ -20,6 +20,7 @@ sidebar: false
|
||||
|
||||
### 💄 其他/体验
|
||||
|
||||
- 对齐 Wavelet 架构配置与构建布局(提交 807343c8):配置收敛至 `manifest/config/`(以 `config.default.yaml` 作为基础配置并支持 `config.yaml` 覆盖),Docker 镜像构建文件统一收敛至 `manifest/docker/` 并清理根目录冗余 `docker/` 目录,根目录 docker-compose 配置保持不变并切至新构建路径。
|
||||
- 内嵌前端拷贝目标改为 `backend/plugins/drivers/driver_http/dist`,与上游 `//go:embed all:dist` 对齐;发布工作流改为读取 `backend/go.mod`。仓库内 `.gitconfig` 提供 `merge.ours` 驱动,合并上游时保留 OpenFlare 自有路径;Wavelet 的 `build-image.yml` 与 `docker-compose.yml` 已隔离,避免 canary 发布成 wavelet 镜像。
|
||||
- 后端代码整体迁入 `backend/`,与上游 Wavelet 的仓库布局对齐(Cordis 插件化改造第一阶段),模块名保持 `Wavelet` 以保证上游包路径逐字一致。构建、测试、镜像与发布链路已同步调整,`make build-all` / `make dev` / `make swagger` 等本地命令用法不变;HTTP 接口与控制台行为均无变化。
|
||||
- 引入上游 Cordis 微内核与平台插件到 `backend/{core,pkg,plugins}`(与上游逐字一致,可用 `scripts/sync-upstream.sh` 重复同步),并新增 `backend/openflare/share/` 承载多插件共享资源(控制消息协议、GeoIP、边缘日志)。此阶段仅落位结构与共享层,尚未改变运行时行为。
|
||||
|
||||
@@ -83,7 +83,7 @@ OpenFlare 已收敛为**单 monorepo**(Go 模块 `OpenFlare`)。控制面 Se
|
||||
| `pkg/` | 跨组件共享库(协议、渲染、GeoIP 等) |
|
||||
| `scripts/` | Swagger 生成、安装脚本等 |
|
||||
| `docs/` | VitePress 文档站与设计基线 |
|
||||
| `docker/` | 各组件 Dockerfile |
|
||||
| `manifest/docker/` | 各组件 Dockerfile |
|
||||
| `uploads/`、`data/` | 运行时上传目录与静态数据(`.gitignore` 忽略) |
|
||||
|
||||
### 1. Server 分层(`main.go` + `internal/`)
|
||||
|
||||
@@ -83,7 +83,7 @@ When contributing code, strictly follow this physical layering and directory div
|
||||
| `pkg/` | cross-component shared libs (protocol, rendering, GeoIP, etc.) |
|
||||
| `scripts/` | Swagger generation, install scripts, etc. |
|
||||
| `docs/` | VitePress docs site and design baseline |
|
||||
| `docker/` | per-component Dockerfiles |
|
||||
| `manifest/docker/` | per-component Dockerfiles |
|
||||
| `uploads/`, `data/` | runtime upload dir and static data (`.gitignore`d) |
|
||||
|
||||
### 1. Server Layering (`main.go` + `internal/`)
|
||||
|
||||
@@ -55,7 +55,7 @@ RUN test -f plugins/drivers/driver_http/dist/index.html && \
|
||||
-tags embed_frontend \
|
||||
-trimpath \
|
||||
-ldflags="-s -w -X Wavelet/pkg/buildinfo.Version=${VERSION} -X Wavelet/pkg/buildinfo.BuildTime=${BUILD_DATE}" \
|
||||
-o /out/wavelet \
|
||||
-o /out/openflare-server \
|
||||
./main.go
|
||||
|
||||
FROM alpine:${ALPINE_VERSION}
|
||||
@@ -68,10 +68,10 @@ RUN apk add --no-cache ca-certificates tzdata postgresql-client && \
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=backend-builder /out/wavelet ./wavelet
|
||||
COPY --from=backend-builder /out/openflare-server ./openflare-server
|
||||
COPY docs ./docs
|
||||
|
||||
EXPOSE 8000
|
||||
EXPOSE 3000
|
||||
|
||||
ENTRYPOINT ["./wavelet"]
|
||||
ENTRYPOINT ["./openflare-server"]
|
||||
CMD ["all"]
|
||||
|
||||
Reference in New Issue
Block a user