diff --git a/.gitignore b/.gitignore index 70b7e4302..b558346c6 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,7 @@ .svn .tmp .download -output +output/ .*.swp .*.swo /**/y.output @@ -25,7 +25,6 @@ profile.out coverage.txt .idea/* .vscode/* -bfe dist/* conf/wasm_plugin diff --git a/Dockerfile b/Dockerfile index b110cbcbb..29da58dfa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,20 +12,134 @@ # See the License for the specific language governing permissions and # limitations under the License. # -FROM --platform=${BUILDPLATFORM} golang:1.17.5-alpine3.15 AS build +FROM --platform=${BUILDPLATFORM} golang:1.22.2-alpine3.19 AS build ARG TARGETARCH ARG TARGETOS -WORKDIR /bfe +WORKDIR /src COPY . . -RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags "-X main.version=`cat VERSION`" -FROM alpine:3.15 AS run -RUN apk update && apk add --no-cache ca-certificates -COPY --from=build /bfe/bfe /bfe/bin/ -COPY conf /bfe/conf/ +RUN set -ex; \ + mkdir -p /out; \ + CGO_ENABLED=0 \ + GOOS=${TARGETOS:-linux} \ + GOARCH=${TARGETARCH:-$(go env GOARCH)} \ + go build -ldflags "-X main.version=$(cat VERSION)" -o /out/bfe + +FROM alpine:3.19 AS confagent +ARG TARGETARCH +ARG CONF_AGENT_VERSION=0.0.2 + +RUN apk add --no-cache ca-certificates wget tar + +RUN set -ex; \ + CONF_AGENT_VERSION_NO_V="${CONF_AGENT_VERSION#v}"; \ + CONF_AGENT_VERSION_TAG="v${CONF_AGENT_VERSION_NO_V}"; \ + ARCH="${TARGETARCH:-}"; \ + if [ -z "${ARCH}" ]; then \ + ARCH="$(uname -m)"; \ + fi; \ + case "${ARCH}" in \ + amd64|x86_64) CONF_AGENT_ARCH="amd64" ;; \ + arm64|aarch64) CONF_AGENT_ARCH="arm64" ;; \ + *) echo "Unsupported architecture: ${ARCH}"; exit 1 ;; \ + esac; \ + CONF_AGENT_URL="https://github.com/bfenetworks/conf-agent/releases/download/${CONF_AGENT_VERSION_TAG}/conf-agent_${CONF_AGENT_VERSION_NO_V}_linux_${CONF_AGENT_ARCH}.tar.gz"; \ + wget -O /tmp/conf-agent.tar.gz "${CONF_AGENT_URL}"; \ + tar -xzf /tmp/conf-agent.tar.gz -C /tmp; \ + mkdir -p /out; \ + mv /tmp/conf-agent /out/conf-agent; \ + if [ -d /tmp/conf ]; then mv /tmp/conf /out/conf-agent-conf; else mkdir -p /out/conf-agent-conf; fi; \ + chmod +x /out/conf-agent + +FROM alpine:3.19 +ARG VARIANT=prod + +RUN set -ex; \ + apk add --no-cache ca-certificates; \ + if [ "${VARIANT}" = "debug" ]; then \ + apk add --no-cache bash curl wget vim; \ + fi + +RUN mkdir -p /home/work/conf-agent/conf \ + && mkdir -p /home/work/conf-agent/log \ + && mkdir -p /home/work/bfe/bin \ + && mkdir -p /home/work/bfe/conf \ + && mkdir -p /home/work/bfe/log + +COPY --from=confagent /out/conf-agent /home/work/conf-agent/conf-agent +COPY --from=confagent /out/conf-agent-conf /home/work/conf-agent/conf +COPY --from=build /out/bfe /home/work/bfe/bin/bfe +COPY --from=build /src/conf /home/work/bfe/conf/ + +# COPY deploy/docker/entrypoint.sh /home/work/entrypoint.sh +# Generate entrypoint.sh inside the image to avoid external file dependency +RUN set -ex; \ + cat > /home/work/entrypoint.sh <<'EOF' +#!/bin/sh +set -eu + +# Log function +log() { + echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" +} + +# Start conf-agent in background +start_conf_agent() { + if [ -f "/home/work/conf-agent/conf-agent" ]; then + log "Starting conf-agent..." + cd /home/work/conf-agent + nohup ./conf-agent -c ./conf > /home/work/conf-agent/log/stdout.log 2>&1 & + CONF_AGENT_PID=$! + log "conf-agent started, PID: $CONF_AGENT_PID" + cd /home/work + else + log "Warning: conf-agent binary not found, skipping startup" + fi +} + +# Start bfe in foreground +start_bfe() { + log "Starting bfe..." + cd /home/work/bfe/bin + exec ./bfe -c ../conf/ -l ../log/ -s +} + +# Signal handler +handle_signal() { + log "Received termination signal, shutting down..." + + # Terminate conf-agent + if [ -n "$CONF_AGENT_PID" ]; then + log "Stopping conf-agent (PID: $CONF_AGENT_PID)..." + kill -TERM "$CONF_AGENT_PID" 2>/dev/null || true + wait "$CONF_AGENT_PID" 2>/dev/null || true + fi + + exit 0 +} + +# Register signal handlers +trap 'handle_signal' TERM INT + +# Main process +log "========================================" +log "BFE Container Startup Script" +log "========================================" + +# 1. Start conf-agent if exists +start_conf_agent + +# Wait for conf-agent initialization +sleep 2 + +# 2. Start bfe in foreground +start_bfe +EOF + +RUN chmod +x /home/work/entrypoint.sh + EXPOSE 8080 8443 8421 -WORKDIR /bfe/bin -ENTRYPOINT ["./bfe"] -CMD ["-c", "../conf/", "-l", "../log"] +WORKDIR /home/work +ENTRYPOINT ["/home/work/entrypoint.sh"] diff --git a/Makefile b/Makefile index 4c7ec07b4..983b3bae1 100644 --- a/Makefile +++ b/Makefile @@ -138,12 +138,120 @@ license-check: license-fix: $(LICENSEEYE) header fix -# make docker + +# Docker image build targets +BFE_IMAGE_NAME ?= bfe +# conf-agent version used in Docker image build. +# Default: 0.0.2 +# Override example: make docker CONF_AGENT_VERSION=0.0.2 +CONF_AGENT_VERSION ?= 0.0.2 +NO_CACHE ?= false + +# Optional cleanup controls +# - CLEAN_DANGLING=true will remove dangling images (":") after build. +# - CLEAN_BUILDKIT_CACHE=true will prune build cache (can slow down next builds). +CLEAN_DANGLING ?= false +CLEAN_BUILDKIT_CACHE ?= false + +# Optional buildx (multi-arch) settings +PLATFORMS ?= linux/amd64,linux/arm64 +BUILDER_NAME ?= bfe-builder + +# buildx helpers +# - make docker (local build) does NOT require buildx. +# - make docker-push (multi-arch push) requires buildx and will auto-init a builder. +buildx-check: + @docker buildx version >/dev/null 2>&1 || ( \ + echo "Error: docker buildx is not available."; \ + echo "- If you use Docker Desktop: update/enable BuildKit/buildx."; \ + echo "- If you use docker-ce: install the buildx plugin."; \ + exit 1; \ + ) + +buildx-init: buildx-check + @docker buildx inspect $(BUILDER_NAME) >/dev/null 2>&1 || docker buildx create --name $(BUILDER_NAME) --driver docker-container --use + @docker buildx use $(BUILDER_NAME) + @docker buildx inspect --bootstrap >/dev/null 2>&1 || true + +# make docker: Build BFE docker images (prod + debug) docker: + @echo "Building BFE docker images (prod + debug)..." + @NORM_BFE_VERSION=$$(echo "$(BFE_VERSION)" | sed 's/^v*/v/'); \ + NORM_CONF_VERSION=$$(echo "$(CONF_AGENT_VERSION)" | sed 's/^v*/v/'); \ + echo "BFE version: $$NORM_BFE_VERSION"; \ + echo "conf-agent version: $$NORM_CONF_VERSION"; \ + echo "Step 1/2: build prod image"; \ docker build \ - -t bfe:$(BFE_VERSION) \ + $$(if [ "$(NO_CACHE)" = "true" ]; then echo "--no-cache"; fi) \ + --build-arg VARIANT=prod \ + --build-arg CONF_AGENT_VERSION=$$NORM_CONF_VERSION \ + -t $(BFE_IMAGE_NAME):$$NORM_BFE_VERSION \ + -t $(BFE_IMAGE_NAME):latest \ + -f Dockerfile \ + .; \ + echo "Step 2/2: build debug image"; \ + docker build \ + $$(if [ "$(NO_CACHE)" = "true" ]; then echo "--no-cache"; fi) \ + --build-arg VARIANT=debug \ + --build-arg CONF_AGENT_VERSION=$$NORM_CONF_VERSION \ + -t $(BFE_IMAGE_NAME):$$NORM_BFE_VERSION-debug \ -f Dockerfile \ . + @$(MAKE) docker-prune + +# docker-prune: optional post-build cleanup (safe-by-default) +docker-prune: + @if [ "$(CLEAN_DANGLING)" = "true" ]; then \ + echo "Pruning dangling images ()..."; \ + docker image prune -f; \ + fi + @if [ "$(CLEAN_BUILDKIT_CACHE)" = "true" ]; then \ + echo "Pruning build cache (BuildKit)..."; \ + docker builder prune -f; \ + fi + +# make docker-push: Build & push multi-arch images using buildx (REGISTRY is required) +# Usage: make docker-push REGISTRY=ghcr.io/your-org +docker-push: + @if [ -z "$(REGISTRY)" ]; then \ + echo "Error: REGISTRY is required"; \ + echo "Usage: make docker-push REGISTRY=ghcr.io/your-org"; \ + exit 1; \ + fi + @echo "Building and pushing multi-arch images via buildx..." + @echo "Platforms: $(PLATFORMS)" + @$(MAKE) buildx-init + @NORM_BFE_VERSION=$$(echo "$(BFE_VERSION)" | sed 's/^v*/v/'); \ + NORM_CONF_VERSION=$$(echo "$(CONF_AGENT_VERSION)" | sed 's/^v*/v/'); \ + NO_CACHE_OPT=$$(if [ "$(NO_CACHE)" = "true" ]; then echo "--no-cache"; fi); \ + echo "BFE version: $$NORM_BFE_VERSION"; \ + echo "conf-agent version: $$NORM_CONF_VERSION"; \ + echo "Step 1/2: build+push prod (multi-arch)"; \ + docker buildx build \ + --platform $(PLATFORMS) \ + $$NO_CACHE_OPT \ + --build-arg VARIANT=prod \ + --build-arg CONF_AGENT_VERSION=$$NORM_CONF_VERSION \ + -t $(REGISTRY)/$(BFE_IMAGE_NAME):$$NORM_BFE_VERSION \ + -t $(REGISTRY)/$(BFE_IMAGE_NAME):latest \ + -f Dockerfile \ + --push \ + .; \ + echo "Step 2/2: build+push debug (multi-arch)"; \ + docker buildx build \ + --platform $(PLATFORMS) \ + $$NO_CACHE_OPT \ + --build-arg VARIANT=debug \ + --build-arg CONF_AGENT_VERSION=$$NORM_CONF_VERSION \ + -t $(REGISTRY)/$(BFE_IMAGE_NAME):$$NORM_BFE_VERSION-debug \ + -f Dockerfile \ + --push \ + .; \ + echo "Pushed multi-arch:"; \ + echo " - $(REGISTRY)/$(BFE_IMAGE_NAME):$$NORM_BFE_VERSION"; \ + echo " - $(REGISTRY)/$(BFE_IMAGE_NAME):$$NORM_BFE_VERSION-debug"; \ + echo " - $(REGISTRY)/$(BFE_IMAGE_NAME):latest (prod)" + @$(MAKE) docker-prune # make clean clean: @@ -153,4 +261,4 @@ clean: rm -rf $(GOPATH)/pkg/linux_amd64 # avoid filename conflict and speed up build -.PHONY: all prepare compile test package clean build +.PHONY: all prepare compile test package clean build docker docker-push docker-prune buildx-check buildx-init diff --git a/README-CN.md b/README-CN.md index cecb0f823..be83630a8 100644 --- a/README-CN.md +++ b/README-CN.md @@ -50,6 +50,7 @@ BFE的架构说明见[概览](docs/zh_cn/introduction/overview.md)文档 - 数据平面:BFE核心转发引擎的[编译及运行](docs/zh_cn/installation/install_from_source.md) - 控制平面:请参考控制平面的[部署说明](https://github.com/bfenetworks/api-server/blob/develop/docs/zh_cn/deploy.md) +- Kubernetes 部署示例(kustomize):[examples/kubernetes/README.md](examples/kubernetes/README.md) ## 运行测试 diff --git a/README.md b/README.md index abeb155d6..e177f348f 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ Besides, we also implement [BFE Ingress Controller](https://github.com/bfenetwor - Data plane: BFE Server [build and run](docs/en_us/installation/install_from_source.md) - Control plane: English document coming soon. [Chinese version](https://github.com/bfenetworks/api-server/blob/develop/docs/zh_cn/deploy.md) +- Kubernetes example (kustomize): [examples/kubernetes/README.md](examples/kubernetes/README.md) ## Running the tests diff --git a/docs/images/bfe-k8s.png b/docs/images/bfe-k8s.png new file mode 100644 index 000000000..fb26b861d Binary files /dev/null and b/docs/images/bfe-k8s.png differ diff --git a/docs/zh_cn/installation/install_using_docker.md b/docs/zh_cn/installation/install_using_docker.md index edf43b3fd..75ba4e530 100644 --- a/docs/zh_cn/installation/install_using_docker.md +++ b/docs/zh_cn/installation/install_using_docker.md @@ -1,22 +1,60 @@ -# docker安装 +# Docker 安装 -## 安装 && 运行 +本章介绍如何通过 Docker 运行 BFE。 -- 基于示例配置运行BFE: +## 方式一:直接运行已有镜像 + +如果你已经有可用镜像(例如 `bfenetworks/bfe`,或你自己构建并推送到私有仓库的镜像),可以直接运行: ```bash -docker run -p 8080:8080 -p 8443:8443 -p 8421:8421 bfenetworks/bfe +docker run --rm \ + -p 8080:8080 -p 8443:8443 -p 8421:8421 \ + ``` -你可以访问 http://127.0.0.1:8080/ 因为没有匹配的配置,将得到 status code 500 -你可以访问 http://127.0.0.1:8421/ 查看监控信息 +你可以访问: +- http://127.0.0.1:8080/ (如果配置未命中,可能返回 500) +- http://127.0.0.1:8421/monitor (监控信息) + +## 方式二:从源码构建镜像(推荐) -- 自定义配置文件路径 +在仓库根目录执行: ```bash -// 事先准备好你自己的配置放到 (可以参考 配置 章节) /Users/BFE/conf +# 一次构建 prod + debug 两个镜像 +make docker + +# 可选:指定 conf-agent 版本(默认 0.0.2) +make docker CONF_AGENT_VERSION=0.0.2 +``` + +构建后的镜像标签(以 VERSION=1.8.0 为例): +- `bfe:v1.8.0`(prod) +- `bfe:v1.8.0-debug`(debug) +- `bfe:latest`(始终指向 prod) -docker run -p 8080:8080 -p 8443:8443 -p 8421:8421 -v /Users/BFE/Desktop/log:/bfe/log -v /Users/BFE/Desktop/conf:/bfe/conf bfenetworks/bfe +## 自定义配置(挂载本地目录) + +镜像内目录约定: +- BFE 配置目录:`/home/work/bfe/conf` +- BFE 日志目录:`/home/work/bfe/log` +- conf-agent 配置目录:`/home/work/conf-agent/conf` +- conf-agent 日志目录:`/home/work/conf-agent/log` + +示例:挂载你本地准备好的配置与日志目录(按需修改路径): + +```bash +# 事先准备好你自己的配置: +# - /Users/BFE/Desktop/conf/ (BFE 配置目录) +# - /Users/BFE/Desktop/conf-agent/ (conf-agent 配置目录,里面放 conf-agent.toml) +# - /Users/BFE/Desktop/log/ (BFE 日志目录) + +docker run --rm \ + -p 8080:8080 -p 8443:8443 -p 8421:8421 \ + -v /Users/BFE/Desktop/conf:/home/work/bfe/conf \ + -v /Users/BFE/Desktop/log:/home/work/bfe/log \ + -v /Users/BFE/Desktop/conf-agent:/home/work/conf-agent/conf \ + bfe:latest ``` ## 下一步 diff --git a/examples/kubernetes/README.md b/examples/kubernetes/README.md new file mode 100644 index 000000000..675884aa4 --- /dev/null +++ b/examples/kubernetes/README.md @@ -0,0 +1,166 @@ +# BFE Kubernetes 部署示例 + +## 概述 + +![BFE Kubernetes](../../docs/images/bfe-k8s.png) + +本示例在 `bfe-system` 命名空间中演示了若干关键组件及其交互: +- 数据面(bfe 与 conf-agent)负责流量转发与接入控制; +- 控制面(api-server 与 dashboard)负责策略下发与管理; +- 服务发现(service-controller)负责发现并同步后端服务; +- 示例服务 whoami 用于验证路由; +- 组件间通过 Kubernetes Service/DNS 相互通信,如: + - api-server.bfe-system.svc.cluster.local + - mysql.bfe-system.svc.cluster.local + +注意: +- api-server 与 MySQL 提供持久化与控制数据; + - 示例中的 MySQL 会随清单重建并重新初始化 + - 不能直接用于生产环境 + + +主要文件概览: + +| **文件名** | **说明** | +|---|---| +| `namespace.yaml` | 命名空间定义(bfe-system) | +| `kustomization.yaml` | kustomize 资源汇总与启用/禁用项 | +| `bfe-configmap.yaml` | bfe 配置(bfe.conf、conf-agent.toml 等) | +| `bfe-deploy.yaml` | bfe 数据面 Deployment 清单 | +| `api-server-configmap.yaml` | API Server 配置(DB 连接、鉴权示例) | +| `api-server-deploy.yaml` | API Server Deployment 清单 | +| `mysql-deploy.yaml` | MySQL Deployment(示例数据库与存储配置) | +| `service-controller-deploy.yaml` | 服务发现控制器 Deployment 清单 | +| `whoami-deploy.yaml` | 示例测试服务 whoami 的 Deployment 清单 | + +## 前提条件 + +- 版本约束:kubectl 必须支持 -k 参数 + - 建议 kubectl >= 1.20 或任意能执行 `kubectl apply -k .` 的版本。 + +- 集群访问权限:kubectl 能访问目标集群并有权限创建 Namespace、Deployment、Service、ConfigMap、Secret 等资源。 + +- 镜像可拉取:若使用外部镜像仓库,确保集群节点能拉取示例镜像,或在 `*-deploy.yaml` 中替换为可访问的镜像地址。 + +- 可选工具:若 kubectl 无内置 kustomize,请安装 kustomize 或使用带 kustomize 的 kubectl 版本。 + + +## 部署 + +- 部署 bfe 服务(数据面、控制面、服务发现) + +```bash +cd examples/kubernetes +kubectl apply -k . +``` + +- 部署测试服务(验证 bfe 服务启动成功后) + +```bash +cd examples/kubernetes +kubectl apply -f whoami-deploy.yaml +``` + +## 验证 + +- 检查命名空间、Pod 与服务状态: + +```bash +[root@iTM ~]# kubectl get ns bfe-system +NAME STATUS AGE +bfe-system Active 29h + +[root@iTM ~]# kubectl -n bfe-system get pods +NAME READY STATUS RESTARTS AGE +api-server-655fdffbf-hwvgw 1/1 Running 0 29h +bfe-85f4d45ddf-4xwdz 1/1 Running 0 29h +bfe-85f4d45ddf-srnxd 1/1 Running 0 29h +bfe-service-controller-6867d57767-92b5m 1/1 Running 0 29h +mysql-d768d5d4d-fj4j5 1/1 Running 0 29h + +[root@iTM ~]# kubectl -n bfe-system get service +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +api-server NodePort 10.105.122.39 8183:30083/TCP,8284:30786/TCP 29h +bfe NodePort 10.108.55.8 8080:30080/TCP,8443:30443/TCP,8421:30421/TCP 29h +mysql ClusterIP None 3306/TCP 29h +[root@iTM ~]# +``` + +- 登陆 dashboard: + - 浏览器访问 http://{NodeIP}:30083 + - 默认账号/密码:admin/admin + +## 清理 + +- 清理测试服务 + +```bash +cd examples/kubernetes +kubectl delete -f whoami-deploy.yaml +``` + +- 清理 bfe 服务(数据面、控制面、服务发现) + +```bash +cd examples/kubernetes +kubectl delete -k . +``` + +- 按需删除单个资源: + +```bash +# bfe +kubectl -n bfe-system delete -f whoami-deploy.yaml +kubectl -n bfe-system delete -f service-controller-deploy.yaml +kubectl -n bfe-system delete -f api-server-deploy.yaml +kubectl -n bfe-system delete -f api-server-configmap.yaml +kubectl -n bfe-system delete -f mysql-deploy.yaml +kubectl -n bfe-system delete -f bfe-deploy.yaml +kubectl -n bfe-system delete -f bfe-configmap.yaml + +# whoami +kubectl delete -f whoami-deploy.yaml +``` + +## 重启 + +示例中 MySQL Pod 每次重启时会重新初始化并丢失已有数据, +若希望在仅更新其它 Pod(例如修改配置后 `kubectl apply -k .`)时保留已有数据库, +可在 `examples/kubernetes/kustomization.yaml` 中临时注释或移除 `mysql-deploy.yaml`。 +然后再执行 `kubectl apply -k .` 进行重启。 + +## 关键配置 + +### 数据面 bfe + +- 镜像:bfe-deploy.yaml 中 spec.template.spec.containers[].image,请替换为可信仓库地址并使用带标签的镜像。 + +- 配置挂载:bfe-configmap.yaml 包含 bfe.conf 与 conf-agent.toml,确认 volumeMounts 的容器路径与配置文件中引用路径一致。 + +- 监控端口:示例暴露 8421,用于健康与监控接口,可通过 Service 或 kubectl port-forward 验证。 + +- 服务端口:示例暴露 8080,NodePort 30080,用于对外提供服务。 + +### 控制面 api-server 与 mysql + +- 数据库连接:api-server-configmap.yaml 中 DB_HOST / DB_PORT / DB_USER / DB_PASSWORD(示例为明文)。 + - 在生产环境请改为 Kubernetes Secret。 + +- 鉴权 Token:示例 Token 已经预置在 `api-server-configmap.yaml` 与 `service-controller-deploy.yaml` 中。 + - 生产环境必须使用 Secret、短期或动态凭证。 + - 生产环境需要预先在控制面 [dashboard](https://github.com/bfenetworks/dashboard/blob/develop/README.md) 中创建 Token。 + +- MySQL 存储:mysql-deploy.yaml 为方便一键部署快速搭建,使用了 emptyDir 卷,重启 pod 后数据会丢失,不适用于生产环境。 + - 生产必须使用 PV/PVC、指定 StorageClass,并配置备份策略。 + + +- 更多请参见:[dashboard](https://github.com/bfenetworks/dashboard/blob/develop/README.md) + +### 服务发现 service-controller 与 whoami + +- 发现规则:service-controller-deploy.yaml 中 args 或 env 定义发现策略、标签选择器或 API Server 地址,按需调整以匹配你的服务标签/注解。 + +- whoami 端口:whoami-deploy.yaml 中 spec.template.spec.containers[].ports 必须与对应 Service 的端口一致。 + +- 更多请参见:[service-controller](https://github.com/bfenetworks/service-controller/blob/main/README.md) + diff --git a/examples/kubernetes/api-server-configmap.yaml b/examples/kubernetes/api-server-configmap.yaml new file mode 100644 index 000000000..193df2f8c --- /dev/null +++ b/examples/kubernetes/api-server-configmap.yaml @@ -0,0 +1,100 @@ +# Copyright (c) 2026 The BFE Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: ConfigMap +metadata: + name: api-server-conf +data: + api_server.toml: |- + # --------------------------------- + # API Server Config + [Server] + # server port + ServerPort = 8183 + # server graceful exit timeout + GracefulTimeOutInMs = 5000 + # monitor port, don't start monitor server if less than 0 + MonitorPort = 8284 + + # --------------------------------- + # Logger Config + # access log config + [Loggers.access] + LogName = "access" + LogLevel = "INFO" + RotateWhen = "MIDNIGHT" + BackupCount = 1 + Format = "[%D %T] [%L] [%S] %M" + StdOut = false + + # sql log, you can skip this config if RunTime.RecordSQL is false + [Loggers.sql] + LogName = "sql" + LogLevel = "INFO" + RotateWhen = "MIDNIGHT" + BackupCount = 1 + Format = "[%D %T] %M" + StdOut = false + + # --------------------------------- + # Database Config + # see https://github.com/go-sql-driver/mysql/blob/master/dsn.go#L37 + [Databases.bfe_db] + DBName = "open_bfe" + # MySQL service in the same namespace + Addr = "mysql.bfe-system.svc.cluster.local:3306" + Net = "tcp" + User = "root" + Passwd = "bfe123456" + MultiStatements = true + MaxAllowedPacket = 67108864 + ParseTime = true + AllowNativePasswords = true + + Driver = "mysql" + MaxOpenConns = 500 + MaxIdleConns = 100 + ConnMaxIdleTimeInMs = 500000 + ConnMaxLifetimeInMs = 5000000 + + + # --------------------------------- + # Dependence Config + [Depends] + # NavTreeFile path + NavTreeFile = "${conf_dir}/nav_tree.toml" + # i18n conf dir path + I18nDir = "${conf_dir}/i18n" + # dashboard icon + UIIcon = "https://raw.githubusercontent.com/bfenetworks/bfe/develop/docs/images/logo/icon/color/bfe-icon-color.svg" + # dashboard logo + UILogo = "https://raw.githubusercontent.com/bfenetworks/bfe/develop/docs/images/logo/horizontal/color/bfe-horizontal-color.png" + + + # --------------------------------- + # Runtime Config + [RunTime] + # you can use "Skip {role_name} as authorization header to access api server if open this optional + # eg: Headers[Authorization] = "Skip System" + # don't open it on production environment + SkipTokenValidate = false + # sql will be record to log file when this option be opend + RecordSQL = false + # how long use must login again + SessionExpireInDay = 10 + # static file path, when dynamic router not be matched, static file will be return if found + StaticFilePath = "./static" + # debug info will be add to response when this option be opend + Debug = false diff --git a/examples/kubernetes/api-server-deploy.yaml b/examples/kubernetes/api-server-deploy.yaml new file mode 100644 index 000000000..576e6890e --- /dev/null +++ b/examples/kubernetes/api-server-deploy.yaml @@ -0,0 +1,97 @@ +# Copyright (c) 2026 The BFE Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: api-server +spec: + replicas: 1 + selector: + matchLabels: + app: api-server + template: + metadata: + labels: + app: api-server + spec: + securityContext: + runAsUser: 10001 + runAsGroup: 10001 + fsGroup: 10001 + initContainers: + # Wait for MySQL init job to complete + - name: wait-for-db-init + image: busybox:1.36 + command: + - sh + - -c + - | + echo "Waiting for database initialization..." + until nc -z mysql.bfe-system.svc.cluster.local 3306; do + echo "MySQL is not ready, waiting..." + sleep 5 + done + echo "MySQL is ready, waiting for init job to complete..." + sleep 15 + echo "Database should be initialized now!" + containers: + - name: api-server + # Update this image to your registry. + image: ghcr.io/bfenetworks/api-server:latest + imagePullPolicy: IfNotPresent + ports: + - name: http + containerPort: 8183 + - name: monitor + containerPort: 8284 + volumeMounts: + - name: conf + mountPath: /home/work/api-server/conf/api_server.toml + subPath: api_server.toml + readOnly: true + readinessProbe: + httpGet: + path: /monitor + port: 8284 + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + httpGet: + path: /monitor + port: 8284 + initialDelaySeconds: 15 + periodSeconds: 20 + volumes: + - name: conf + configMap: + name: api-server-conf + +--- +apiVersion: v1 +kind: Service +metadata: + name: api-server +spec: + selector: + app: api-server + ports: + - name: http + port: 8183 + targetPort: 8183 + nodePort: 30083 + - name: monitor + port: 8284 + targetPort: 8284 + type: NodePort diff --git a/examples/kubernetes/bfe-configmap.yaml b/examples/kubernetes/bfe-configmap.yaml new file mode 100644 index 000000000..708d3ac83 --- /dev/null +++ b/examples/kubernetes/bfe-configmap.yaml @@ -0,0 +1,251 @@ +# Copyright (c) 2026 The BFE Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: ConfigMap +metadata: + name: bfe-config +data: + bfe.conf: | + [Server] + # listen port for http request + HttpPort = 8080 + # listen port for https request + HttpsPort = 8443 + # listen port for monitor request + MonitorPort = 8421 + # if false, disable monitor server + MonitorEnabled = true + + # max number of CPUs to use (0 to use all CPUs) + MaxCpus = 0 + + # type of layer-4 load balancer (PROXY/NONE), default NONE + Layer4LoadBalancer = "" + + # tls handshake timeout, in seconds + TlsHandshakeTimeout = 30 + + # read timeout, in seconds + ClientReadTimeout = 60 + + # write timeout, in seconds + ClientWriteTimeout = 60 + + # if false, client connection is shutdown disregard of http headers + KeepAliveEnabled = true + + # timeout for graceful shutdown (maximum 300 sec) + GracefulShutdownTimeout = 10 + + # max header length in bytes in request + MaxHeaderBytes = 1048576 + + # max URI(in header) length in bytes in request + MaxHeaderUriBytes = 8192 + + # server_data_conf related confs + HostRuleConf = server_data_conf/host_rule.data + VipRuleConf = server_data_conf/vip_rule.data + RouteRuleConf = server_data_conf/route_rule.data + ClusterConf = server_data_conf/cluster_conf.data + NameConf = server_data_conf/name_conf.data + + # gslb related confs + ClusterTableConf = cluster_conf/cluster_table.data + GslbConf = cluster_conf/gslb.data + + Modules = mod_trust_clientip + # Modules = mod_tcp_keepalive + Modules = mod_block + Modules = mod_header + Modules = mod_rewrite + Modules = mod_redirect + Modules = mod_logid + Modules = mod_tag + Modules = mod_trace + #Modules = mod_userid + #Modules = mod_key_log + Modules = mod_access + Modules = mod_prison + #Modules = mod_auth_request + # Modules = mod_cors + Modules = mod_wasm + + Modules = mod_unified_waf + Modules = mod_ai_token_auth + Modules = mod_body_process + + # interval for get diff of proxy-state + MonitorInterval = 20 + + DebugServHttp = false + DebugBfeRoute = false + DebugBal = false + DebugHealthCheck = false + + [HttpsBasic] + # cert conf for https + ServerCertConf = tls_conf/server_cert_conf.data + + # tls rule for https + TlsRuleConf = tls_conf/tls_rule_conf.data + + # supported cipherSuites preference settings + + # ciphersuites implemented in golang + # TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + # TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + # TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + # TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + # TLS_ECDHE_RSA_WITH_RC4_128_SHA + # TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + # TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + # TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + # TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + # TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + # TLS_RSA_WITH_RC4_128_SHA + # TLS_RSA_WITH_AES_128_CBC_SHA + # TLS_RSA_WITH_AES_256_CBC_SHA + # TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + # TLS_RSA_WITH_3DES_EDE_CBC_SHA + # + # Note: + # -. Do not use cipher suite with 3DES which is insecure now + # and with poor performance + # + # -. Equivalent cipher suites (cipher suites with same priority in server side): + # CipherSuites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256|TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + # CipherSuites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256|TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + # + CipherSuites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256|TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + CipherSuites=TLS_ECDHE_RSA_WITH_RC4_128_SHA + CipherSuites=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + CipherSuites=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + CipherSuites=TLS_RSA_WITH_RC4_128_SHA + CipherSuites=TLS_RSA_WITH_AES_128_CBC_SHA + CipherSuites=TLS_RSA_WITH_AES_256_CBC_SHA + + # supported curve preference settings + # + # curves implemented in golang: + # CurveP256 + # CurveP384 + # CurveP521 + # + # Note: + # - Do not use CurveP384/CurveP521 which is with poor performance + # + CurvePreferences=CurveP256 + + # support Sslv2 ClientHello for compatible with ancient + # TLS capable clients (mozilla 5, java 5/6, openssl 0.9.8 etc) + EnableSslv2ClientHello = true + + # client ca certificates base directory + # Note: filename suffix for ca certificate file should be ".crt", eg. example_ca_bundle.crt + ClientCABaseDir = tls_conf/client_ca + + # client certificate crl base directory + # Note: filename suffix for crl file should be ".crl", eg. example_ca_bundle.crl + ClientCRLBaseDir = tls_conf/client_crl + + [SessionCache] + # disable tls session cache or not + SessionCacheDisabled = true + + # tcp address of redis server + Servers = "example.redis.cluster" + + # prefix for cache key + KeyPrefix = "bfe" + + # connection params (ms) + ConnectTimeout = 50 + ReadTimeout = 50 + WriteTimeout = 50 + + # max idle connections in connection pool + MaxIdle = 20 + + # expire time for tls session state (second) + SessionExpire = 3600 + + [SessionTicket] + # disable tls session ticket or not + SessionTicketsDisabled = true + # session ticket key + SessionTicketKeyFile = tls_conf/session_ticket_key.data + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: conf-agent-config +data: + conf-agent.toml: | + [Logger] + LogDir = "./log/" + LogName = "conf_agent" + LogLevel = "INFO" + RotateWhen = "MIDNIGHT" + BackupCount = 2 + Format = "[%D %T] [%L] [%S] %M" + StdOut = false + + [Basic] + BFECluster = "BFE-demo.szyf" + BFEConfDir = "/home/work/bfe/conf" + BFEMonitorPort = 8421 + BFEReloadTimeoutMs = 1500 + + ReloadIntervalMs = 5000 + + ConfServer = "http://api-server.bfe-system.svc.cluster.local:8183" + # Token 获取参考 https://github.com/bfenetworks/dashboard/blob/develop/docs/zh-cn/user-guide/system-view/user-management.md#token%E7%AE%A1%E7%90%86 + ConfTaskHeaders = {"Authorization" = "Token c5QFb-MrlKktJbOid2M3"} + ConfTaskTimeoutMs = 1500 + + ExtraFileServer = "http://api-server.bfe-system.svc.cluster.local:8183/inner-api/v1/configs/extra_files/" + # Token 获取参考 https://github.com/bfenetworks/dashboard/blob/develop/docs/zh-cn/user-guide/system-view/user-management.md#token%E7%AE%A1%E7%90%86 + ExtraFileTaskHeaders = {"Authorization" = "Token c5QFb-MrlKktJbOid2M3"} + ExtraFileTaskTimeoutMs = 1500 + + + # reloader for server_data_config files, detail see https://www.bfe-networks.net/en_us/configuration/server_data_conf/host_rule.data/ + [Reloaders.server_data_conf] + CopyFiles = ["cluster_conf.data", "host_rule.data", "name_conf.data", "route_rule.data", "vip_rule.data"] + [[Reloaders.server_data_conf.MultiKeyFileTasks]] + ConfAPI = "/inner-api/v1/configs/tls_conf/server_data_conf" + Key2ConfFile = {"HostTable" = "host_rule.data", "RouteTable" = "route_rule.data", "ClusterConf" = "cluster_conf.data"} + + # # reloader for cluster_conf files, detail see https://www.bfe-networks.net/en_us/configuration/cluster_conf/gslb.data/ + [Reloaders.cluster_conf] + BFEReloadAPI = "/reload/gslb_data_conf" + CopyFiles = ["cluster_table.data", "gslb.data"] + [[Reloaders.cluster_conf.NormalFileTasks]] + ConfAPI = "/inner-api/v1/configs/gslb_data/cluster_table" + ConfFileName = "cluster_table.data" + [[Reloaders.cluster_conf.NormalFileTasks]] + ConfAPI = "/inner-api/v1/configs/gslb_data/gslb" + ConfFileName = "gslb.data" + + # # reloader for tls_conf files, detail see https://www.bfe-networks.net/en_us/configuration/tls_conf/server_cert_conf.data/ + #[Reloaders.tls_conf] + #CopyFiles = ["client_ca", "client_crl", "server_cert_conf.data", "session_ticket_key.data", "tls_rule_conf.data"] + #[[Reloaders.tls_conf.ExtraFileTasks]] + #ConfAPI = "/inner-api/v1/configs/protocol/server_cert_conf" + #ConfFileName = "server_cert_conf.data" + #ExtraFileJSONPaths = ["$.Config.CertConf.*.ServerCertFile", "$.Config.CertConf.*.ServerKeyFile"] + diff --git a/examples/kubernetes/bfe-deploy.yaml b/examples/kubernetes/bfe-deploy.yaml new file mode 100644 index 000000000..52e369b6a --- /dev/null +++ b/examples/kubernetes/bfe-deploy.yaml @@ -0,0 +1,109 @@ +# Copyright (c) 2026 The BFE Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: bfe + namespace: bfe-system + labels: + app: bfe +spec: + replicas: 2 + selector: + matchLabels: + app: bfe + template: + metadata: + labels: + app: bfe + spec: + containers: + - name: bfe + image: ghcr.io/bfenetworks/bfe:v1.8.0-debug # 替换为实际镜像 + imagePullPolicy: IfNotPresent + ports: + - name: http + containerPort: 8080 + protocol: TCP + - name: https + containerPort: 8443 + protocol: TCP + - name: monitor + containerPort: 8421 + protocol: TCP + volumeMounts: + - name: bfe-conf + mountPath: /home/work/bfe/conf/bfe.conf + subPath: bfe.conf + readOnly: false + - name: conf-agent-conf + mountPath: /home/work/conf-agent/conf/conf-agent.toml + subPath: conf-agent.toml + readOnly: false + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 1000m + memory: 512Mi + livenessProbe: + httpGet: + path: /monitor + port: 8421 + initialDelaySeconds: 10 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /monitor + port: 8421 + initialDelaySeconds: 5 + periodSeconds: 5 + volumes: + - name: bfe-conf + configMap: + name: bfe-config + - name: conf-agent-conf + configMap: + name: conf-agent-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: bfe + namespace: bfe-system + labels: + app: bfe +spec: + selector: + app: bfe + ports: + - name: http + port: 8080 + targetPort: 8080 + protocol: TCP + nodePort: 30080 + - name: https + port: 8443 + targetPort: 8443 + protocol: TCP + nodePort: 30443 + - name: monitor + port: 8421 + targetPort: 8421 + protocol: TCP + nodePort: 30421 + type: NodePort diff --git a/examples/kubernetes/kustomization.yaml b/examples/kubernetes/kustomization.yaml new file mode 100644 index 000000000..20a9868f4 --- /dev/null +++ b/examples/kubernetes/kustomization.yaml @@ -0,0 +1,27 @@ +# Copyright (c) 2026 The BFE Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: bfe-system + +resources: + - namespace.yaml + - service-controller-deploy.yaml + - api-server-configmap.yaml + - api-server-deploy.yaml + - bfe-configmap.yaml + - bfe-deploy.yaml + - mysql-deploy.yaml diff --git a/examples/kubernetes/mysql-deploy.yaml b/examples/kubernetes/mysql-deploy.yaml new file mode 100644 index 000000000..40064e140 --- /dev/null +++ b/examples/kubernetes/mysql-deploy.yaml @@ -0,0 +1,441 @@ +# Copyright (c) 2026 The BFE Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# MySQL Database Components for API Server +# This file contains all MySQL-related Kubernetes resources: +# - Secret (credentials) +# - emptyDir (ephemeral storage, for test/demo only) +# - Service (network) +# - Deployment (MySQL server) +# - ConfigMap (db_ddl.sql initialization script) +# - Job (database initialization) + +--- +apiVersion: v1 +kind: Secret +metadata: + name: mysql-secret +type: Opaque +stringData: + mysql-root-password: "bfe123456" + mysql-database: "open_bfe" + + +--- +apiVersion: v1 +kind: Service +metadata: + name: mysql +spec: + selector: + app: mysql + ports: + - name: mysql + port: 3306 + targetPort: 3306 + clusterIP: None + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mysql +spec: + replicas: 1 + selector: + matchLabels: + app: mysql + strategy: + type: Recreate + template: + metadata: + labels: + app: mysql + spec: + containers: + - name: mysql + image: mysql:8.0 + env: + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: mysql-secret + key: mysql-root-password + - name: MYSQL_DATABASE + valueFrom: + secretKeyRef: + name: mysql-secret + key: mysql-database + ports: + - name: mysql + containerPort: 3306 + volumeMounts: + - name: mysql-data + mountPath: /var/lib/mysql + livenessProbe: + exec: + command: + - mysqladmin + - ping + - -h + - localhost + - -uroot + - -p$(MYSQL_ROOT_PASSWORD) + initialDelaySeconds: 60 + timeoutSeconds: 5 + failureThreshold: 5 + periodSeconds: 10 + readinessProbe: + exec: + command: + - mysqladmin + - ping + - -h + - localhost + - -uroot + - -p$(MYSQL_ROOT_PASSWORD) + initialDelaySeconds: 60 + timeoutSeconds: 5 + failureThreshold: 5 + periodSeconds: 10 + volumes: + - name: mysql-data + emptyDir: {} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: mysql-init +data: + db_ddl.sql: | + DROP DATABASE IF EXISTS `open_bfe`; + CREATE DATABASE open_bfe; + + USE open_bfe; + + -- create bfe_clusters + DROP TABLE IF EXISTS `bfe_clusters`; + CREATE TABLE `bfe_clusters` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `pool_name` varchar(255) NOT NULL DEFAULT '', + `capacity` bigint(20) NOT NULL, + `enabled` tinyint(1) NOT NULL DEFAULT '1', + `gtc_enabled` tinyint(1) NOT NULL DEFAULT '1', + `gtc_manual_enabled` tinyint(1) NOT NULL DEFAULT '1', + `exempt_traffic_check` tinyint(1) NOT NULL DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `name_uni` (`name`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + -- create products + DROP TABLE IF EXISTS `products`; + CREATE TABLE `products` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL , + `mail_list` varchar(4096) NOT NULL , + `contact_person` varchar(4096) NOT NULL , + `sms_list` varchar(4096) NOT NULL DEFAULT "no sms" , + `description` varchar(1024) NOT NULL DEFAULT "no desc" , + `created_at` datetime NOT NULL , + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + PRIMARY KEY (`id`), + UNIQUE KEY `name_uni` (`name`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + -- create domains + DROP TABLE IF EXISTS `domains`; + CREATE TABLE `domains` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, + `product_id` bigint(20) NOT NULL, + `type` int(11) NOT NULL, + `using_advanced_redirect` tinyint(1) NOT NULL DEFAULT 0, + `using_advanced_hsts` tinyint(1) NOT NULL DEFAULT 0, + `created_at` datetime NOT NULL, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `name_uni` (`name`), + INDEX `product_id` (`product_id`), + INDEX `type` (`type`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + -- create clusters + DROP TABLE IF EXISTS `clusters`; + CREATE TABLE `clusters` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, + `description` varchar(1024) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT "no desc", + `product_id` bigint(20) NOT NULL, + `max_idle_conn_per_host` smallint(6) NOT NULL DEFAULT '2', + `timeout_conn_serv` int(11) NOT NULL DEFAULT '50000', + `timeout_response_header` int(11) NOT NULL DEFAULT '50000', + `timeout_readbody_client` int(11) NOT NULL DEFAULT '30000', + `timeout_read_client_again` int(11) NOT NULL DEFAULT '30000', + `timeout_write_client` int(11) NOT NULL DEFAULT '60000', + `healthcheck_schem` varchar(16) NOT NULL DEFAULT 'http', + `healthcheck_interval` int(11) NOT NULL DEFAULT '1000', + `healthcheck_failnum` int(11) NOT NULL DEFAULT '10', + `healthcheck_host` varchar(255) NOT NULL, + `healthcheck_uri` varchar(255) NOT NULL, + `healthcheck_statuscode` int(11) NOT NULL DEFAULT '200', + `clientip_carry` tinyint(4) NOT NULL DEFAULT '0', + `port_carry` tinyint(1) NOT NULL DEFAULT '0', + `max_retry_in_cluster` tinyint(4) NOT NULL DEFAULT '3', + `max_retry_cross_cluster` tinyint(4) NOT NULL DEFAULT '0', + `ready` tinyint(1) NOT NULL DEFAULT '1', + `hash_strategy` int NOT NULL DEFAULT '0', + `cookie_key` varchar(255) NOT NULL DEFAULT 'BAIDUID', + `hash_header` varchar(255) NOT NULL DEFAULT 'Cookie:BAIDUID', + `session_sticky` tinyint(1) NOT NULL DEFAULT '0', + `req_write_buffer_size` int(11) NOT NULL DEFAULT '512', + `req_flush_interval` int(11) NOT NULL DEFAULT '0', + `res_flush_interval` int(11) NOT NULL DEFAULT '20', + `cancel_on_client_close` tinyint(1) NOT NULL DEFAULT '0', + `failure_status` tinyint(1) NOT NULL DEFAULT '0', + `max_conns_per_host` int(11) NOT NULL DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `name_index` (`name`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + -- create lb_matrices + DROP TABLE IF EXISTS `lb_matrices`; + CREATE TABLE `lb_matrices` ( + `cluster_id` bigint(20) NOT NULL AUTO_INCREMENT, + `lb_matrix` varchar(8192) NOT NULL, + `product_id` bigint(20) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`cluster_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + -- create sub_clusters + DROP TABLE IF EXISTS `sub_clusters`; + CREATE TABLE `sub_clusters` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `cluster_id` bigint(20) NOT NULL, + `product_id` bigint(20) NOT NULL, + `description` varchar(1024) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT "no desc", + `bns_name_id` bigint(20) NOT NULL, + `enabled` tinyint(1) NOT NULL DEFAULT '1', + `created_at` datetime NOT NULL, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `name_product_index` (`name`, `product_id`), + INDEX `cluster_id` (`cluster_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + -- create pools + DROP TABLE IF EXISTS `pools`; + CREATE TABLE `pools` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `product_id` bigint(20) NOT NULL DEFAULT 0, + `ready` boolean NOT NULL DEFAULT 1, + `instance_detail` mediumtext, + `type` tinyint(4) NOT NULL DEFAULT 1, + `tag` tinyint(4) NOT NULL DEFAULT 0, + `created_at` datetime NOT NULL, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `name_uni` (`name`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + -- create route_basic_rules + DROP TABLE IF EXISTS `route_basic_rules`; + CREATE TABLE `route_basic_rules` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `description` varchar(1024) NOT NULL DEFAULT '', + `product_id` bigint(20) NOT NULL, + `host_names` text NOT NULL, + `paths` text NOT NULL, + `cluster_id` bigint(20) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + INDEX `product_id` (`product_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + -- create route_advance_rules + DROP TABLE IF EXISTS `route_advance_rules`; + CREATE TABLE `route_advance_rules` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `description` varchar(1024) NOT NULL DEFAULT '', + `product_id` bigint(20) NOT NULL, + `expression` varchar(4096) binary NOT NULL, + `cluster_id` bigint(20) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + INDEX `product_id` (`product_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + -- create forward_cases + DROP TABLE IF EXISTS `route_cases`; + CREATE TABLE `route_cases` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `description` varchar(1024) NOT NULL DEFAULT '', + `product_id` bigint(20) NOT NULL, + `url` varchar(4096) NOT NULL, + `method` varchar(255) NOT NULL DEFAULT "", + `protocol` varchar(255) NOT NULL DEFAULT "", + `header` varchar(4096) NOT NULL, + `body` varchar(4096) NOT NULL DEFAULT "", + `expect_cluster` varchar(255) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + INDEX `product_id` (`product_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + -- create certificates + DROP TABLE IF EXISTS `certificates`; + CREATE TABLE `certificates` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `cert_name` varchar(255) NOT NULL, + `description` varchar(1024) NOT NULL DEFAULT 'no desc', + `is_default` tinyint(1) NOT NULL DEFAULT '0', + `expired_date` varchar(255) NOT NULL, + `cert_file_name` varchar(255) NOT NULL, + `cert_file_path` varchar(255) NOT NULL, + `key_file_name` varchar(255) NOT NULL, + `key_file_path` varchar(255) NOT NULL, + + `created_at` datetime NOT NULL, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `name` (`cert_name`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + -- create extra_files + DROP TABLE IF EXISTS `extra_files`; + CREATE TABLE `extra_files` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `product_id` bigint(20) NOT NULL DEFAULT 0, + `description` varchar(1024) NOT NULL DEFAULT '', + `md5` varchar(64) NOT NULL, + `content` mediumtext, + `created_at` datetime NOT NULL , + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + PRIMARY KEY (`id`), + UNIQUE KEY `name_product` (`name`, `product_id`), + INDEX `product_id` (`product_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + DROP TABLE IF EXISTS `config_versions`; + CREATE TABLE `config_versions` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `data_sign` varchar(255) NOT NULL, + `version` varchar(255) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + + -- create users + DROP TABLE IF EXISTS `users`; + CREATE TABLE `users` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `type` tinyint(1) NOT NULL DEFAULT '0', + `password` varchar(255) NOT NULL DEFAULT '', + `ticket` varchar(20) NOT NULL DEFAULT '', + `ticket_created_at` datetime NOT NULL DEFAULT '0000-01-01 00:00:00', + `scopes` varchar(2048) NOT NULL DEFAULT '', + `created_at` datetime NOT NULL, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `name_uni` (`name`, `type`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + -- create user_products + DROP TABLE IF EXISTS `user_products`; + CREATE TABLE `user_products` ( + `user_id` bigint(20) NOT NULL, + `product_id` bigint(20) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`user_id`, `product_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + + insert into users (id, name, password, scopes, created_at) values(1, 'admin', 'admin', 'System', now()); + insert into users (id, name, type, password, ticket, ticket_created_at, scopes, created_at) values (2, 'demo', 1, '', 'eT5QWkLhQmp6lO4NWxAc', now(), 'Product', now()); + insert into users (id, name, type, password, ticket, ticket_created_at, scopes, created_at) values (3, 'conf-agent', 1, '', 'c5QFb-MrlKktJbOid2M3', now(), 'System', now()); + + insert into products (id, name, `description`, mail_list, contact_person, created_at) values (1, 'BFE', 'Build-in Product, User by System Manager', 'bfe@cncf.com', 'bfe', now()); + insert into products (id, name, `description`, mail_list, contact_person, created_at) values (2, 'demo', 'k8s demo', '', '', now()); + insert into user_products (user_id, product_id, created_at, updated_at) values (2, 2, now(), now()); + +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: mysql-init-job +spec: + ttlSecondsAfterFinished: 100 + template: + metadata: + labels: + app: mysql-init + spec: + restartPolicy: OnFailure + initContainers: + # Wait for MySQL to be ready + - name: wait-for-mysql + image: busybox:1.36 + command: + - sh + - -c + - | + echo "Waiting for MySQL to be ready..." + until nc -z mysql.bfe-system.svc.cluster.local 3306; do + echo "MySQL is not ready yet, sleeping 5s..." + sleep 5 + done + echo "MySQL is ready!" + sleep 10 + containers: + - name: mysql-init + image: mysql:8.0 + env: + - name: MYSQL_PWD + valueFrom: + secretKeyRef: + name: mysql-secret + key: mysql-root-password + command: + - sh + - -c + - | + echo "Starting database initialization..." + mysql -h mysql.bfe-system.svc.cluster.local -uroot < /init-scripts/db_ddl.sql + echo "Database initialization completed!" + volumeMounts: + - name: init-scripts + mountPath: /init-scripts + volumes: + - name: init-scripts + configMap: + name: mysql-init + diff --git a/examples/kubernetes/namespace.yaml b/examples/kubernetes/namespace.yaml new file mode 100644 index 000000000..b89eed56a --- /dev/null +++ b/examples/kubernetes/namespace.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2026 The BFE Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: Namespace +metadata: + name: bfe-system + labels: + name: bfe-system diff --git a/examples/kubernetes/service-controller-deploy.yaml b/examples/kubernetes/service-controller-deploy.yaml new file mode 100644 index 000000000..596dc91cf --- /dev/null +++ b/examples/kubernetes/service-controller-deploy.yaml @@ -0,0 +1,117 @@ +# Copyright (c) 2025 The BFE Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bfe-service-controller + labels: + app.kubernetes.io/name: bfe-service-controller + app.kubernetes.io/instance: bfe-service-controller + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + #namespace as postfix + name: bfe-service-controller-default +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: +- kind: ServiceAccount + name: bfe-service-controller + namespace: bfe-system + +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + name: bfe-service-controller + labels: + app.kubernetes.io/name: bfe-service-controller + app.kubernetes.io/instance: bfe-service-controller +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app.kubernetes.io/name: bfe-service-controller + app.kubernetes.io/instance: bfe-service-controller + template: + metadata: + labels: + app.kubernetes.io/name: bfe-service-controller + app.kubernetes.io/instance: bfe-service-controller + spec: + serviceAccountName: bfe-service-controller + containers: + - name: bfe-service-controller + imagePullPolicy: Always + image: ghcr.io/bfenetworks/service-controller:x86_64-v1.0.0 + command: [ "/service-controller" ] + args: + - '-bfe-api-addr=http://api-server.bfe-system.svc.cluster.local:8183' + - '-bfe-api-token=Token eT5QWkLhQmp6lO4NWxAc' + - '-k8s-cluster-name=szyf' + - '-namespace=bfe-system' + ports: + - containerPort: 9081 + livenessProbe: + httpGet: + path: /healthz + port: 9081 + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 2 + successThreshold: 1 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /readyz + port: 9081 + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 2 + successThreshold: 1 + failureThreshold: 3 + securityContext: + runAsUser: 1000 # bfeuser defined in Dockerfile + runAsGroup: 1000 # bfegroup defined in Dockerfile + runAsNonRoot: true + privileged: false + allowPrivilegeEscalation: false + capabilities: + drop: ["ALL"] + readOnlyRootFilesystem: true + resources: + requests: + cpu: "500m" + memory: "500Mi" + limits: + cpu: "1" + memory: "2Gi" + volumeMounts: + - name: tmp + mountPath: /tmp + - name: var-run + mountPath: /var/run + volumes: + - name: tmp + emptyDir: {} + - name: var-run + emptyDir: {} \ No newline at end of file diff --git a/examples/kubernetes/whoami-deploy.yaml b/examples/kubernetes/whoami-deploy.yaml new file mode 100644 index 000000000..f822f81f0 --- /dev/null +++ b/examples/kubernetes/whoami-deploy.yaml @@ -0,0 +1,61 @@ +# Copyright (c) 2025 The BFE Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: whoami + namespace: bfe-system + labels: + app.kubernetes.io/name: whoami + app.kubernetes.io/instance: whoami +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: whoami + app.kubernetes.io/instance: whoami + template: + metadata: + labels: + app.kubernetes.io/name: whoami + app.kubernetes.io/instance: whoami + spec: + containers: + - name: whoami + imagePullPolicy: IfNotPresent + image: traefik/whoami + ports: + - containerPort: 80 + +--- +apiVersion: v1 +kind: Service +metadata: + name: whoami + namespace: bfe-system + labels: + bfe-product: demo +spec: + ports: + - name: http + port: 8080 + targetPort: 80 + # - name: http2 #multiple port demo + # port: 8090 + # targetPort: 80 + selector: + app.kubernetes.io/name: whoami + #app.kubernetes.io/instance: whoami