Flagsmith 常用命令与运维实战

Flagsmith v2.287.0 自托管运维实战:manage.py 核心命令(migrate/collectstatic/createsuperuser/bootstrap/shell)实测、REST API 管理面与 SDK 求值端点全链路实测回显、Prometheus 指标观测、pg_dump 备份与卷盘点、升级回滚与高频排障。

Flagsmith特性开关自托管2026/10/28

Flagsmith 常用命令与运维实战

目标:面向已按部署篇完成 Flagsmith v2.287.0 自托管安装的运维/后端工程师,覆盖 Django manage.py 核心命令、REST API 管理面全链路(认证→组织/项目/环境→特性→分段→开关切换)、SDK 端点求值实测、Prometheus 指标观测、pg_dump 备份与卷盘点,以及升级回滚与高频排障。所有命令与回显均在部署篇同环境(PostgreSQL 15.5 + 统一镜像三服务,端口 8142)实测采集,逐行真实。

一、环境信息

项值
Flagsmith 版本v2.287.0(flagsmith/flagsmith:latest,metrics 端点 flagsmith_build_info 实证)
部署形态Compose 三服务(api / task-processor / postgres),服务端口 8142→8000
管理账号admin@flagsmith.local(会话 Token 认证)、root@flagsmith.local(Django 超管),密码 Q1w2e3r4@2026
示例数据组织 Quzuo Demo Org(id=1)、项目 demo-app(id=1)、环境 Development/Production、特性 banner-toggle(id=1)/checkout-v2(id=2)
密钥客户端环境密钥 TinUTVci4mXtPVbBAyJjvw、服务端密钥 ser.S9JAfMUEgrtrPWmrqrw97E(实测值,生产请替换)
管理会话 Token448f55d8eacc1475514de7ab2a71f71081303ef0(注册接口返回,下文 $TOKEN)

二、常用命令速查

命令用途生效方式
docker compose ps / docker compose logs -f api服务状态/日志即时
curl http://localhost:8142/health库/缓存健康自检即时
curl http://localhost:9100/metrics(容器内端口)Prometheus 指标即时
python manage.py migrate数据库结构迁移需进服务内部执行
python manage.py collectstatic --noinput收集静态资源(升级后)需进服务内部执行
python manage.py createsuperuser --noinput ...建 Django 超管需进服务内部执行
python manage.py bootstrap空库一键初始化(超管+组织+项目)需 ALLOW_ADMIN_INITIATION_VIA_CLI=true
python manage.py shell / dbshellDjango ORM / 数据库直连需进服务内部执行
docker exec flagsmith-2.287.0-postgres pg_dump ...逻辑备份即时
docker compose pull && docker compose up -d升级版本自动补跑迁移

💡 「进服务内部执行」的统一姿势:docker exec flagsmith-2.287.0-api sh -c "cd /app && python manage.py <命令>";服务默认工作目录为 /app。

三、manage.py 命令实测

3.1 子命令全景

docker exec flagsmith-2.287.0-api sh -c "cd /app && python manage.py help"

实测回显(节选;按 Django 应用分组,重点组如下):

Available subcommands:

[api]
  generate_mcp_tool_catalogue

[app_analytics]
  migrate_analytics
  populate_buckets
  sendapiusagetoinflux

[auth]
  changepassword
  createsuperuser

[authtoken]
  drf_create_token

[axes]
  axes_list_attempts
  axes_reset
  axes_reset_failure_logs
  axes_reset_ip
  axes_reset_ip_username
  axes_reset_logs
  axes_reset_username

[core]
  bootstrap
  docgen
  makemigrations
  rollbackmigrationsappliedafter
  start
  waitfordb

[django]
  check
  compilemessages
  createcachetable

运维高频组解读:[axes] 组是登录防爆破组件的解锁命令(axes_reset 清失败记录,误锁时救命);[core] 组的 waitfordb/start 是镜像入口内部使用;rollbackmigrationsappliedafter 用于迁移回滚场景。

3.2 migrate(迁移)

首次建库由部署篇编排的 migrate-db 服务完成(614 条 Applying ... OK,见部署篇 4.2)。升级或手动补跑时直接执行:

docker exec flagsmith-2.287.0-api sh -c "cd /app && python manage.py migrate"

实测回显(库已最新时的幂等输出,仅提示缓存表已存在,无任何迁移动作):

Cache table 'environment-documents' already exists.
Cache table 'onboarding-request-throttle' already exists.

3.3 collectstatic(静态资源)

docker exec flagsmith-2.287.0-api sh -c "cd /app && python manage.py collectstatic --noinput"

实测回显(镜像已内置收集产物,重复执行为零拷贝):

0 static files copied to '/app/static', 161 unmodified.

统一镜像内置控制台静态资源,正常运行无需手动执行;该命令主要在自定义前端构建/挂载场景下使用。

3.4 createsuperuser(创建超管)

Django Admin(/admin/)入口账号。实测(完整参数形态与缺参报错见部署篇 Q6):

docker exec flagsmith-2.287.0-api sh -c \
  "cd /app && DJANGO_SUPERUSER_PASSWORD='Q1w2e3r4@2026' \
   python manage.py createsuperuser --noinput \
   --email root@flagsmith.local --first_name Root --last_name Admin \
   --sign_up_type NO_INVITE"

实测行为:成功时静默、退出码 0;重复执行同邮箱报 user with this Email address already exists.;对既有普通账号可经 manage.py shell 将 is_staff/is_superuser 置 True 提升为超管(运维篇推荐路径,避免重复账号)。

3.5 bootstrap(空库一键初始化)

官方设计的一键初始化命令(创建默认超管+组织+项目),先看参数面:

docker exec flagsmith-2.287.0-api sh -c "cd /app && python manage.py help bootstrap"

实测回显(节选):

usage: manage.py bootstrap [-h] [--email ADMIN_EMAIL]
                           [--organisation-name ORGANISATION_NAME]
                           [--project-name PROJECT_NAME] [--version]
                           ...
options:
  -h, --help            show this help message and exit
  --email ADMIN_EMAIL   Email address for the superuser
  --organisation-name ORGANISATION_NAME
                        Project name
  --project-name PROJECT_NAME
                        Project name

实测两条关键行为(排障实录):

  1. 必须显式开开关:环境变量 ALLOW_ADMIN_INITIATION_VIA_CLI=true(settings 默认 False,官方文档同口径)。实测不开时命令执行后无任何创建动作。
  2. 非空库静默跳过:在已有用户的库上执行(本环境实测),命令正常退出(exit 0)但不创建任何对象——源码判定为「库里存在任意用户即跳过」(should_skip_create_initial_superuser() 返回 FFAdminUser.objects.exists()),组织/项目同构判定。因此 bootstrap 只适用于全新空库;已有实例要补账号/组织请走 3.4 与 REST API。

另注:bootstrap 创建的初始超管密码为空(源码 password=None),设计上配合首次登录设密流程;脚本化初始化建议直接用 3.4 的 createsuperuser + REST API 组合,行为更可控。官方还提供无控制台环境的 Web 初始化端点 /api/v1/users/config/init/(表单式,见官方文档)。

3.6 shell 与 dbshell(ORM/SQL 直连)

# ORM 通道:查任务队列积压、查运行时元数据等
docker exec flagsmith-2.287.0-api sh -c "cd /app && python manage.py shell -c \"
from task_processor.models import Task
print('total tasks:', Task.objects.count())
for t in Task.objects.all()[:5]: print(' -', t.task_name, t.status)\""

实测回显:

total tasks: 7
 - create-environment 1 SUCCESS
 - create-environment 2 SUCCESS
 - create-project 1 SUCCESS
...
# SQL 通道
docker exec -it flagsmith-2.287.0-postgres psql -U postgres -d flagsmith

运维用法示例(创建服务端环境密钥,实测;服务端密钥无管理 API,ORM 是官方通道):

docker exec flagsmith-2.287.0-api sh -c "cd /app && python manage.py shell -c \"
from environments.models import Environment, EnvironmentAPIKey
key = EnvironmentAPIKey.objects.create(environment=Environment.objects.get(id=1), name='server-side-demo')
print('SERVER_KEY=' + key.key)\""

实测回显:

SERVER_KEY=ser.S9JAfMUEgrtrPWmrqrw97E

四、REST API 管理面实测

管理面统一以 Authorization: Token <管理Token> 认证(Token 来自注册/登录接口的 key 字段)。以下为组织/项目/环境/特性/分段全链路实测记录。

4.1 组织、项目与环境

# 建组织
curl -s -X POST http://localhost:8142/api/v1/organisations/ \
  -H "Authorization: Token $TOKEN" -H 'Content-Type: application/json' \
  -d '{"name":"Quzuo Demo Org"}'

实测回显(精简):

{'id': 1, 'name': 'Quzuo Demo Org', 'created_date': '2026-10-28T04:16:02.913385Z', 'stop_serving_flags': False, 'persist_trait_data': True, 'num_seats': 3, ...}
# 建项目
curl -s -X POST http://localhost:8142/api/v1/projects/ \
  -H "Authorization: Token $TOKEN" -H 'Content-Type: application/json' \
  -d '{"name":"demo-app","organisation":1,"hide_disabled_flags":false}'
# 实测:{'id': 1, 'name': 'demo-app', 'organisation': 1, ...}

# 建环境(v2.287.0 项目创建不自动建环境,需显式创建)
curl -s -X POST http://localhost:8142/api/v1/environments/ \
  -H "Authorization: Token $TOKEN" -H 'Content-Type: application/json' \
  -d '{"name":"Development","project":1}'

实测回显(环境返回体即携带两类 SDK 密钥):

id: 1 | name: Development | api_key(client): TinUTVci4mXtPVbBAyJjvw | server_key: ser.S9JAfMUEgrtrPWmrqrw97E

4.2 特性创建与环境状态

# 建特性(注意 initial_value 必须字符串形态)
curl -s -X POST http://localhost:8142/api/v1/projects/1/features/ \
  -H "Authorization: Token $TOKEN" -H 'Content-Type: application/json' \
  -d '{"name":"checkout-v2","description":"新版结算流程","initial_value":"false","default_enabled":false}'

实测回显:

{'id': 2, 'name': 'checkout-v2', 'description': '新版结算流程', 'default_enabled': False}
# 查环境特性状态(客户端密钥当路径段用)
curl -s "http://localhost:8142/api/v1/environments/TinUTVci4mXtPVbBAyJjvw/featurestates/" \
  -H "Authorization: Token $TOKEN"

实测回显(精简):

count: 3
 fs_id: 1 | feature: banner-toggle | enabled: True | value: {'type': 'unicode', 'value': None}
 fs_id: 2 | feature: checkout-v2 | enabled: False | value: {'type': 'unicode', 'value': 'false'}

4.3 开关切换(PATCH featurestates)

curl -s -X PATCH http://localhost:8142/api/v1/environments/TinUTVci4mXtPVbBAyJjvw/featurestates/3/ \
  -H "Authorization: Token $TOKEN" -H 'Content-Type: application/json' \
  -d '{"enabled":true,"feature_state_value":true}'

实测回显(version 自增,供 SDK 增量同步比对):

fs_id: 3 | enabled: True | value: True | version: 1

切换后 SDK 侧立即生效(求值实测见第五章)。

4.4 分段(Segment)与条件圈人

创建「email 含 @flagsmith.local 即 VIP」的分段(规则两层嵌套:ALL → ANY → conditions):

curl -s -X POST http://localhost:8142/api/v1/projects/1/segments/ \
  -H "Authorization: Token $TOKEN" -H 'Content-Type: application/json' \
  -d '{"name":"vip-users","rules":[{"type":"ALL","rules":[{"type":"ANY","conditions":[{"operator":"CONTAINS","property":"email","value":"@flagsmith.local"}]}],"conditions":[]}]}'

实测回显:

{'id': 1, 'name': 'vip-users', 'uuid': 'e21d0c0e-7f9c-42a8-bc37-4cfa25e37d68'}

给分段做特性覆盖(优先级高于环境默认值):先建覆盖关系,再建带 feature_segment 的状态:

# 建覆盖关系
curl -s -X POST http://localhost:8142/api/v1/features/feature-segments/ \
  -H "Authorization: Token $TOKEN" -H 'Content-Type: application/json' \
  -d '{"feature":1,"segment":1,"environment":1}'
# 实测:{'id': 1, 'feature': 1, 'segment': 1, 'environment': 1, 'priority': 1, 'uuid': '...'}

# 建覆盖状态(值用 {type, string_value} 包装结构;type 取 unicode/bool/int/float)
curl -s -X POST http://localhost:8142/api/v1/features/featurestates/ \
  -H "Authorization: Token $TOKEN" -H 'Content-Type: application/json' \
  -d '{"environment":1,"feature":1,"feature_segment":1,"enabled":true,"feature_state_value":{"type":"unicode","string_value":"vip-banner"}}'

实测回显:

fs_id: 4 | feature_segment: 1 | enabled: True | value: {'type': 'unicode', 'value': 'vip-banner'}

排障实录(结构踩坑三连,均为真实报错):

  • 条件块字段名是 conditions 而非 rules(传错报 {'rules': ['Invalid rule.']});操作符是 CONTAINS 等大写枚举(传 % 报 {'operator': ['"%" is not a valid choice.']})。
  • 覆盖值必须 {type, string_value} 包装(裸字符串报 {'feature_state_value': ['Invalid data. Expected a dictionary with keys...']})。
  • 带覆盖值的 featurestate 用平铺端点 POST /api/v1/features/featurestates/ 创建(不是嵌套在 feature-segments 下)。

五、SDK 端点实测

5.1 客户端密钥拉取开关(GET /api/v1/flags/)

curl -s "http://localhost:8142/api/v1/flags/" -H "X-Environment-Key: TinUTVci4mXtPVbBAyJjvw"

实测回显(checkout-v2 切换开启后;switch 前该特性 enabled: false):

[
    {
        "enabled": true,
        "feature_state_value": null,
        "feature": {
            "id": 2,
            "name": "checkout-v2",
            "type": "STANDARD"
        },
        "feature_segment": null
    },
    {
        "enabled": true,
        "feature_state_value": null,
        "feature": {
            "id": 1,
            "name": "banner-toggle",
            "type": "MULTIVARIATE"
        },
        "feature_segment": null
    }
]

5.2 身份求值(POST /api/v1/identities/)

对单个身份求值并落身份特征,分段命中实时体现(对照实验:user-1 命中 vip 分段,user-2 不命中):

curl -s -X POST http://localhost:8142/api/v1/identities/ \
  -H "X-Environment-Key: TinUTVci4mXtPVbBAyJjvw" -H 'Content-Type: application/json' \
  -d '{"identifier":"user-1","traits":[{"trait_key":"email","trait_value":"alice@flagsmith.local"}]}'

实测回显(精简,命中 vip-users 分段 → banner-toggle 值为覆盖值):

 - banner-toggle | enabled: True | value: vip-banner | segment: True
 - checkout-v2   | enabled: True | value: True      | segment: False

对照身份(不匹配条件):

# user-2:email bob@example.com

实测回显:

 - banner-toggle | enabled: True | value: None | segment: False
 - checkout-v2   | enabled: True | value: True  | segment: False

5.3 服务端密钥拉取环境文档(GET /api/v1/environment-document/)

本地求值(Local Evaluation)模式的数据源,ser. 前缀密钥认证:

curl -s "http://localhost:8142/api/v1/environment-document/" \
  -H "X-Environment-Key: ser.S9JAfMUEgrtrPWmrqrw97E"

实测回显(结构精简):

api_key: ser.S9JAfMUEgrtrPWmrqrw97E
project: demo-app | env: Development
 - banner-toggle | enabled: True | value: None
 - checkout-v2 | enabled: True | value: True
 - another-flag | enabled: False | value: None

六、备份与卷盘点

6.1 卷与网络清单

docker volume ls --format '{{.Name}}' | grep flagsmith
docker network ls --format '{{.Name}}' | grep flagsmith

实测回显(命名卷 1 个 + 专用网络 1 个;项目名的点号被规范化):

flagsmith-22870-stack_pgdata
flagsmith-22870-stack_flagsmith_net

盘点结论:Flagsmith 自托管的数据面只有 PostgreSQL 一处——pgdata 卷承载全部业务数据(组织/项目/环境/开关/身份/分段/任务记录),分析数据经 USE_POSTGRES_FOR_ANALYTICS 也在库内;镜像与静态资源无状态,可随时重建。

6.2 逻辑备份(pg_dump)

docker exec flagsmith-2.287.0-postgres \
  pg_dump -U postgres -d flagsmith > /opt/flagsmith/backup/flagsmith_20261028.sql

实测产物:646K,标准 PostgreSQL 转储(头部 -- Dumped from database version 15.5),COPY 数据段 169 个。完整性核对命令与回显:

grep -c "^COPY" /opt/flagsmith/backup/flagsmith_20261028.sql
169

恢复(演练到新库的等价命令):

cat /opt/flagsmith/backup/flagsmith_20261028.sql | \
  docker exec -i flagsmith-2.287.0-postgres psql -U postgres -d flagsmith

运维建议:升级前必备份;恢复目标库必须是空库(否则对象冲突);备份文件含用户敏感信息,按密级存放。

七、监控与日志

健康自检(DB/Cache 两项自检,均 Working 为健康):

curl http://localhost:8142/health

实测回显(HTML 表格形态,节选):

<td style="text-align: center; background-color: #464646;">
    <p style="font-size: 1.2em">DB</p>
</td>
<td style="text-align: center; background-color: #3c763d;">
    <p style="font-size: 1.2em">Working</p>
</td>

Prometheus 指标(PROMETHEUS_ENABLED=true 时容器内 :9100):

docker exec flagsmith-2.287.0-api sh -c \
  "python -c \"import urllib.request; d=urllib.request.urlopen('http://localhost:9100/metrics').read().decode(); lines=[l for l in d.splitlines() if l.startswith('flagsmith')]; print(len(lines),'flagsmith lines'); print(chr(10).join(lines[:6]))\""

实测回显(961 条 flagsmith_* 指标行,摘录):

961 flagsmith lines
flagsmith_segment_membership_backfill_identities_total 0.0
flagsmith_segment_membership_refresh_failures_total 0.0
flagsmith_cohorts_csv_syncs_total 0.0
flagsmith_build_info{ci_commit_sha="c582d5b573e639c6343ee9c21913681baed9118a",version="2.287.0"} 1.0
flagsmith_http_server_requests_total{method="GET",response_status="200",route="/health"} 1.0
flagsmith_http_server_requests_total{method="POST",response_status="201",route="/api/v1/auth/users/"} 1.0

监控要点:flagsmith_build_info 直接暴露版本号(资产盘点/升级核对);flagsmith_http_server_requests_total 按 method/status/route 统计请求(SDK 流量水位);任务侧盯 flagsmith_segment_membership_refresh_failures_total 等失败计数。

日志:docker compose logs -f api(Gunicorn worker/请求日志)与 docker compose logs task-processor(任务轮询/执行日志);经 LOG_FORMAT=json 可切结构化采集。

资源水位实测(docker stats --no-stream,空载):

flagsmith-2.287.0-api: CPU 0.11% MEM 583.5MiB / 15.36GiB
flagsmith-2.287.0-task-processor: CPU 0.09% MEM 503.5MiB / 15.36GiB
flagsmith-2.287.0-postgres: CPU 0.01% MEM 80.1MiB / 15.36GiB

八、升级与回滚

标准升级路径(官方语义:结构变更由 Django Migrations 自动执行):

cd /opt/flagsmith
docker exec flagsmith-2.287.0-postgres pg_dump -U postgres -d flagsmith > backup/pre-upgrade.sql  # 1. 先备份
docker compose pull                                                                               # 2. 拉新镜像
docker compose up -d                                                                              # 3. 滚动重建(migrate-db 服务自动补跑增量迁移)
curl -s http://localhost:8142/health | grep -c Working                                            # 4. 健康自检(期望 2)

回滚:把编排镜像标签改回旧版本(生产建议固定版本标签而非 latest)后 docker compose up -d;数据库如需回退用 pre-upgrade.sql 恢复,或用 [core] 组的 rollbackmigrationsappliedafter 命令处理迁移点。升级后核对 flagsmith_build_info 指标的 version 标签与预期一致。

九、常见问题(运维向排障实录)

Q1:python manage.py bootstrap 执行成功但什么都没创建。 实测行为:exit 0、无输出、库无变化。原因有二(实测均验证):未设 ALLOW_ADMIN_INITIATION_VIA_CLI=true;或库里已有任意用户/组织/项目——初始化判定按「存在记录即跳过」实现(FFAdminUser.objects.exists()),bootstrap 仅适用于空库。解法:空库场景先设开关再跑;非空库用 createsuperuser + REST API。

Q2:createsuperuser --noinput 报 CommandError 缺参。 实测报错:

CommandError: You must use --noinput or --username and --email with --noinput, --first_name and --last_name and --sign_up_type with --noinput.

解法:v2.287.0 用户模型要求全名与注册类型,完整形态见 3.4;密码经 DJANGO_SUPERUSER_PASSWORD 注入。注意密码过弱会命中「too common」校验,用 Q1w2e3r4@2026 这类强口令。

Q3:登录接口多次失败后被锁。 内置 django-axes 防爆破(阈值 AXES_FAILURE_LIMIT 默认 10)。解锁命令(实测可用 [axes] 命令组):

docker exec flagsmith-2.287.0-api sh -c "cd /app && python manage.py axes_reset --username admin@flagsmith.local"

(另有 axes_reset_ip/axes_reset_logs 等变体,见 3.1 清单。)

Q4:任务积压/异步任务长时间不执行。 排查三步(实测路径):确认 TASK_RUN_METHOD=TASK_PROCESSOR 时 task-processor 服务在运行(docker compose ps);经 3.6 的 ORM 查询看 Task 表状态分布;看 docker compose logs task-processor 是否有周期性空转(空闲时每分钟轮询一轮,日志周期性输出属正常)。若误把 TASK_RUN_METHOD 设为 TASK_PROCESSOR 却没起该服务,任务会永久积压——退回默认 SEPARATE_THREAD 或补服务。

Q5:切换开关后部分 SDK 读到旧值。 环境级切换经 PATCH featurestates 即时生效(本篇 4.3→5.1 实测闭环);读到旧值的典型原因是 SDK 本地求值缓存——本地求值模式按轮询/版本号刷新环境文档(featurestate 的 version 自增即为此设计),核对 SDK 轮询周期配置;或改用远程求值模式验证平台侧状态。

Q6:/admin/ 脚本化登录 403。 实测报错 403 Forbidden — CSRF cookie not set.:Django Admin 的 CSRF/会话校验不接受裸 curl 模拟。解法:浏览器登录;脚本验证用 manage.py shell 内 django.test.Client().login(...)(实测 login ok: True);管理面操作统一走 Token 认证的 REST API(本篇第四章)。

Q7:环境列表查不到刚建的项目环境。 v2.287.0 实测行为:项目创建不自动建环境(GET /api/v1/environments/?project=1 短暂 count: 0)。解法:显式 POST /api/v1/environments/(4.1),创建即返回 SDK 密钥。

Q8:服务端密钥在哪查/怎么建。 服务端密钥(ser. 前缀)无管理 API 端点,官方通道为 ORM:3.6 的 EnvironmentAPIKey.objects.create(...) 实测可建;建好后用 5.3 端点验证连通。密钥泄露时同表删除记录即可吊销。

十、参考链接