fix(ui): 前端用户可见文案 opsx-loki → lokistack
修正用户能看到/会复制走的旧名(你反馈的 K8s 示例 token 命令在内):
1. 界面标题(4 处)
App.tsx 浏览器标题栏
Layout.tsx 侧边栏 logo / 页面标题 fallback / 移动端导航
login/index.tsx 登录页大标题
settings/index.tsx 「关于 lokistack」
2. 集群接入示例(用户直接复制到集群执行,5 处)
ClusterFormDialog.tsx:
Role / ServiceAccount 名: opsx-loki → lokistack
token Secret 名: opsx-loki-token → lokistack-token
取 token 命令: get secret opsx-loki-token → lokistack-token
3. 文档
docs/deployment/README.md, host-nginx.md 旧名全量修正
README.md 迁移章节之外的示例命令修正;
迁移章节(从 opsx-loki 升级)保留旧名作历史对照
【刻意不改】
a) localStorage key(9 个)
opsxloki.auth.{token,refresh-token,user}
opsxloki.theme.mode / layout.collapsed / chunk-reloaded
opsxloki.logs.{query-history,range-history}
原因:改了所有在线用户立即掉登录,主题/折叠/查询历史全丢。
要改必须配套迁移(参考 main.tsx 中 lokideploy.* → opsxloki.* 的写法)。
b) 数据文件名 opsxloki.json(后端硬编码,改了读不到 DB)
c) Go module 路径 opsxloki/...(159 处 import)
属编译期内部标识,最终用户不可见;改名需全仓重构 + go.mod 变更。
This commit is contained in:
1 parent
3c9388658b
commit
d0b9b6b71d
8 files changed
+43
-43
No files matched your search
@@ -1,4 +1,4 @@
|
|||||||
# opsx-loki v2 — 安全的 K8s Loki 部署平台
|
# lokistack v2 — 安全的 K8s Loki 部署平台
|
||||||
|
|
||||||
一个轻量级的 **Gin + React + JSON 文件存储** 平台,用于通过 SSH 或 kubeconfig 把 Grafana Loki
|
一个轻量级的 **Gin + React + JSON 文件存储** 平台,用于通过 SSH 或 kubeconfig 把 Grafana Loki
|
||||||
日志聚合系统部署到 Kubernetes 集群或裸金属主机上。
|
日志聚合系统部署到 Kubernetes 集群或裸金属主机上。
|
||||||
@@ -128,8 +128,8 @@ echo "export ENCRYPTION_KEY=$ENCRYPTION_KEY" >> ~/.bashrc
|
|||||||
### 第 2 步:用 Docker Compose 启动(推荐)
|
### 第 2 步:用 Docker Compose 启动(推荐)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/your/opsx-loki.git
|
git clone https://github.com/your/lokistack.git
|
||||||
cd opsx-loki
|
cd lokistack
|
||||||
|
|
||||||
# 设置密钥(见第 1 步)
|
# 设置密钥(见第 1 步)
|
||||||
export JWT_SECRET=$(openssl rand -hex 32)
|
export JWT_SECRET=$(openssl rand -hex 32)
|
||||||
@@ -150,7 +150,7 @@ docker compose logs -f
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 容器级健康检查(内部)
|
# 容器级健康检查(内部)
|
||||||
docker inspect --format='{{.State.Health.Status}}' opsxloki
|
docker inspect --format='{{.State.Health.Status}}' lokistack
|
||||||
|
|
||||||
# 期望输出:"healthy"
|
# 期望输出:"healthy"
|
||||||
|
|
||||||
@@ -169,32 +169,32 @@ curl http://localhost:8080/index.html
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 方式 1(推荐):从容器内读文件 —— 日志轮转后依然可查
|
# 方式 1(推荐):从容器内读文件 —— 日志轮转后依然可查
|
||||||
docker compose exec opsxloki cat /app/data/initial-admin-password.txt
|
docker compose exec lokistack cat /app/data/initial-admin-password.txt
|
||||||
|
|
||||||
# 方式 2:首次启动日志(只打印一次,重启后不会再有)
|
# 方式 2:首次启动日志(只打印一次,重启后不会再有)
|
||||||
docker compose logs opsxloki | grep -A6 "已生成管理员账号"
|
docker compose logs lokistack | grep -A6 "已生成管理员账号"
|
||||||
|
|
||||||
# 方式 3:容器已停止时也能用(不要求 running)
|
# 方式 3:容器已停止时也能用(不要求 running)
|
||||||
docker cp opsxloki:/app/data/initial-admin-password.txt ./
|
docker cp lokistack:/app/data/initial-admin-password.txt ./
|
||||||
|
|
||||||
# 方式 4:直接读 named volume(宿主机 root)
|
# 方式 4:直接读 named volume(宿主机 root)
|
||||||
sudo cat /var/lib/docker/volumes/opsx-loki_opsxloki-data/_data/initial-admin-password.txt
|
sudo cat /var/lib/docker/volumes/lokistack_lokistack-data/_data/initial-admin-password.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
> ⚠️ **为什么不能只靠日志**:`docker logs` 只在**首次启动**打印一次;日志轮转或容器重启后,
|
> ⚠️ **为什么不能只靠日志**:`docker logs` 只在**首次启动**打印一次;日志轮转或容器重启后,
|
||||||
> 数据库里已有用户,**不会再打印**。所以**文件才是可靠来源**。
|
> 数据库里已有用户,**不会再打印**。所以**文件才是可靠来源**。
|
||||||
>
|
>
|
||||||
> 💡 容器名说明:本 compose 指定了 `container_name: opsxloki`,所以可直接用 `opsxloki`。
|
> 💡 容器名说明:本 compose 指定了 `container_name: lokistack`,所以可直接用 `lokistack`。
|
||||||
> 若你的部署没有指定,用服务名形式更通用:`docker compose exec opsxloki cat ...`
|
> 若你的部署没有指定,用服务名形式更通用:`docker compose exec lokistack cat ...`
|
||||||
|
|
||||||
**Kubernetes 环境(同一个文件)**:
|
**Kubernetes 环境(同一个文件)**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 读文件(推荐)
|
# 读文件(推荐)
|
||||||
kubectl -n log exec deploy/opsx-loki -- cat /app/data/initial-admin-password.txt
|
kubectl -n log exec deploy/lokistack -- cat /app/data/initial-admin-password.txt
|
||||||
|
|
||||||
# 首次启动日志
|
# 首次启动日志
|
||||||
kubectl -n log logs deploy/opsx-loki | grep -A6 "已生成管理员账号"
|
kubectl -n log logs deploy/lokistack | grep -A6 "已生成管理员账号"
|
||||||
|
|
||||||
# 拷到本地
|
# 拷到本地
|
||||||
kubectl -n log cp <pod-name>:/app/data/initial-admin-password.txt ./
|
kubectl -n log cp <pod-name>:/app/data/initial-admin-password.txt ./
|
||||||
@@ -214,7 +214,7 @@ docker compose up -d
|
|||||||
|
|
||||||
| 项 | 说明 |
|
| 项 | 说明 |
|
||||||
|----|------|
|
|----|------|
|
||||||
| 密码文件权限 | `0600`,属主 `opsxloki` |
|
| 密码文件权限 | `0600`,属主 `lokistack` |
|
||||||
| 自动清理 | **admin 首次修改密码后,该文件自动删除**(见 `seed.CleanupInitPassword`) |
|
| 自动清理 | **admin 首次修改密码后,该文件自动删除**(见 `seed.CleanupInitPassword`) |
|
||||||
| 日志内容 | 仅在首次启动打印,且容器日志由运行时轮转 |
|
| 日志内容 | 仅在首次启动打印,且容器日志由运行时轮转 |
|
||||||
| 忘了密码 | 数据卷里文件仍在;若文件已删,用 `ADMIN_INIT_PASSWORD` 重新初始化(需清空数据卷) |
|
| 忘了密码 | 数据卷里文件仍在;若文件已删,用 `ADMIN_INIT_PASSWORD` 重新初始化(需清空数据卷) |
|
||||||
@@ -244,11 +244,11 @@ docker compose -f docker-compose.prod.yml up -d
|
|||||||
docker swarm init
|
docker swarm init
|
||||||
|
|
||||||
# 创建 secrets
|
# 创建 secrets
|
||||||
echo "$(openssl rand -hex 32)" | docker secret create opsxloki_jwt -
|
echo "$(openssl rand -hex 32)" | docker secret create lokistack_jwt -
|
||||||
echo "$(openssl rand -hex 32)" | docker secret create opsxloki_key -
|
echo "$(openssl rand -hex 32)" | docker secret create lokistack_key -
|
||||||
|
|
||||||
# 部署
|
# 部署
|
||||||
docker stack deploy -c docker-compose.prod.yml opsxloki
|
docker stack deploy -c docker-compose.prod.yml lokistack
|
||||||
```
|
```
|
||||||
|
|
||||||
### 安全清单
|
### 安全清单
|
||||||
@@ -368,7 +368,7 @@ cd frontend && npm run lint # ESLint
|
|||||||
| | | ~/.kube (只读) |
|
| | | ~/.kube (只读) |
|
||||||
| +-------------+ | | ~/.ssh (只读) |
|
| +-------------+ | | ~/.ssh (只读) |
|
||||||
| | 容器 | | | ./data (读写) |
|
| | 容器 | | | ./data (读写) |
|
||||||
| | (opsxloki | | +---------------------+
|
| | (lokistack | | +---------------------+
|
||||||
| | UID:1000) | |
|
| | UID:1000) | |
|
||||||
| | no-new-privs| |
|
| | no-new-privs| |
|
||||||
| | cap_drop:ALL| |
|
| | cap_drop:ALL| |
|
||||||
@@ -410,7 +410,7 @@ wget --spider http://localhost:8080/index.html
|
|||||||
curl http://localhost:8080/index.html
|
curl http://localhost:8080/index.html
|
||||||
|
|
||||||
# Docker inspect
|
# Docker inspect
|
||||||
docker inspect --format='{{.State.Health}}' opsxloki
|
docker inspect --format='{{.State.Health}}' lokistack
|
||||||
```
|
```
|
||||||
|
|
||||||
健康检查参数:
|
健康检查参数:
|
||||||
@@ -563,7 +563,7 @@ docker compose up -d
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 查看容器状态
|
# 查看容器状态
|
||||||
docker inspect --format='{{.State.Health}}' opsxloki
|
docker inspect --format='{{.State.Health}}' lokistack
|
||||||
|
|
||||||
# 查看日志
|
# 查看日志
|
||||||
docker compose logs --tail=50
|
docker compose logs --tail=50
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# 部署说明
|
# 部署说明
|
||||||
|
|
||||||
本文档描述 `opsx-loki` 的两种部署方式,域名与 IP 均为脱敏示例:
|
本文档描述 `lokistack` 的两种部署方式,域名与 IP 均为脱敏示例:
|
||||||
|
|
||||||
- `opsx-loki.xxx.io` —— 平台 UI 域名
|
- `lokistack.xxx.io` —— 平台 UI 域名
|
||||||
- `log.xxx.io` —— Loki 查询域名(Ingress)
|
- `log.xxx.io` —— Loki 查询域名(Ingress)
|
||||||
- `192.168.x.x` —— 内网地址占位
|
- `192.168.x.x` —— 内网地址占位
|
||||||
|
|
||||||
@@ -18,10 +18,10 @@
|
|||||||
└─ K8s 部署:proxy_pass http://<NodeIP>:30080
|
└─ K8s 部署:proxy_pass http://<NodeIP>:30080
|
||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
Service opsx-loki:8080
|
Service lokistack:8080
|
||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
Deployment opsx-loki(1 副本)
|
Deployment lokistack(1 副本)
|
||||||
│
|
│
|
||||||
┌────────────────┴────────────────┐
|
┌────────────────┴────────────────┐
|
||||||
▼ ▼
|
▼ ▼
|
||||||
|
|||||||
@@ -6,15 +6,15 @@
|
|||||||
|
|
||||||
## nginx vhost
|
## nginx vhost
|
||||||
|
|
||||||
`/etc/nginx/conf.d/opsx-loki.xxx.io.conf`:
|
`/etc/nginx/conf.d/lokistack.xxx.io.conf`:
|
||||||
|
|
||||||
```nginx
|
```nginx
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name opsx-loki.xxx.io;
|
server_name lokistack.xxx.io;
|
||||||
|
|
||||||
access_log /var/log/nginx/opsx-loki.xxx.io_access.log main;
|
access_log /var/log/nginx/lokistack.xxx.io_access.log main;
|
||||||
error_log /var/log/nginx/opsx-loki.xxx.io_error.log;
|
error_log /var/log/nginx/lokistack.xxx.io_error.log;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://127.0.0.1:8081;
|
proxy_pass http://127.0.0.1:8081;
|
||||||
@@ -62,8 +62,8 @@ nginx -t && nginx -s reload
|
|||||||
## 验证
|
## 验证
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -I -H "Host: opsx-loki.xxx.io" http://127.0.0.1/
|
curl -I -H "Host: lokistack.xxx.io" http://127.0.0.1/
|
||||||
curl -s -X POST http://opsx-loki.xxx.io/api/v1/auth/login \
|
curl -s -X POST http://lokistack.xxx.io/api/v1/auth/login \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d '{"username":"admin","password":"<你的密码>"}'
|
-d '{"username":"admin","password":"<你的密码>"}'
|
||||||
```
|
```
|
||||||
@@ -41,7 +41,7 @@ function useDocumentTitle() {
|
|||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const title = findRouteMeta(location.pathname)?.title
|
const title = findRouteMeta(location.pathname)?.title
|
||||||
document.title = title && location.pathname !== '/login' ? `${title} · opsx-loki` : 'opsx-loki'
|
document.title = title && location.pathname !== '/login' ? `${title} · lokistack` : 'lokistack'
|
||||||
}, [location.pathname])
|
}, [location.pathname])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ function SidebarLogo({ collapsed }: { collapsed: boolean }) {
|
|||||||
<div className="w-8 h-8 rounded-lg border border-sidebar-primary/30 bg-sidebar-primary/15 flex items-center justify-center">
|
<div className="w-8 h-8 rounded-lg border border-sidebar-primary/30 bg-sidebar-primary/15 flex items-center justify-center">
|
||||||
<Activity className="w-5 h-5 text-sidebar-primary" />
|
<Activity className="w-5 h-5 text-sidebar-primary" />
|
||||||
</div>
|
</div>
|
||||||
<span className="font-bold text-lg tracking-tight">opsx-loki</span>
|
<span className="font-bold text-lg tracking-tight">lokistack</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -140,7 +140,7 @@ const Layout = memo(function Layout({ children }: { children: React.ReactNode })
|
|||||||
const user = getUser()
|
const user = getUser()
|
||||||
|
|
||||||
// 顶栏标题来自路由 meta
|
// 顶栏标题来自路由 meta
|
||||||
const pageTitle = findRouteMeta(location.pathname)?.title || 'opsx-loki'
|
const pageTitle = findRouteMeta(location.pathname)?.title || 'lokistack'
|
||||||
|
|
||||||
// 折叠状态持久化(仅桌面端语义)
|
// 折叠状态持久化(仅桌面端语义)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -190,7 +190,7 @@ const Layout = memo(function Layout({ children }: { children: React.ReactNode })
|
|||||||
<Sheet open={mobileOpen} onOpenChange={setMobileOpen}>
|
<Sheet open={mobileOpen} onOpenChange={setMobileOpen}>
|
||||||
<SheetContent side="left" className="bg-sidebar text-sidebar-accent-foreground border-none p-0 w-72">
|
<SheetContent side="left" className="bg-sidebar text-sidebar-accent-foreground border-none p-0 w-72">
|
||||||
<SheetHeader className="sr-only">
|
<SheetHeader className="sr-only">
|
||||||
<SheetTitle className="text-white">opsx-loki 导航</SheetTitle>
|
<SheetTitle className="text-white">lokistack 导航</SheetTitle>
|
||||||
</SheetHeader>
|
</SheetHeader>
|
||||||
<div className="flex flex-col h-full">
|
<div className="flex flex-col h-full">
|
||||||
<SidebarLogo collapsed={false} />
|
<SidebarLogo collapsed={false} />
|
||||||
|
|||||||
@@ -270,13 +270,13 @@ metadata:
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ServiceAccount
|
kind: ServiceAccount
|
||||||
metadata:
|
metadata:
|
||||||
name: opsx-loki
|
name: lokistack
|
||||||
namespace: log
|
namespace: log
|
||||||
---
|
---
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: Role
|
kind: Role
|
||||||
metadata:
|
metadata:
|
||||||
name: opsx-loki
|
name: lokistack
|
||||||
namespace: log
|
namespace: log
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
@@ -292,29 +292,29 @@ rules:
|
|||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: RoleBinding
|
kind: RoleBinding
|
||||||
metadata:
|
metadata:
|
||||||
name: opsx-loki
|
name: lokistack
|
||||||
namespace: log
|
namespace: log
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: opsx-loki
|
name: lokistack
|
||||||
namespace: log
|
namespace: log
|
||||||
roleRef:
|
roleRef:
|
||||||
kind: Role
|
kind: Role
|
||||||
name: opsx-loki
|
name: lokistack
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: opsx-loki-token
|
name: lokistack-token
|
||||||
namespace: log
|
namespace: log
|
||||||
annotations:
|
annotations:
|
||||||
kubernetes.io/service-account.name: opsx-loki
|
kubernetes.io/service-account.name: lokistack
|
||||||
type: kubernetes.io/service-account-token
|
type: kubernetes.io/service-account-token
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# 2) 取出长期 Token(不自动过期),粘贴到 Token 输入框
|
# 2) 取出长期 Token(不自动过期),粘贴到 Token 输入框
|
||||||
kubectl -n log get secret opsx-loki-token -o jsonpath='{.data.token}' | base64 -d`}</pre>
|
kubectl -n log get secret lokistack-token -o jsonpath='{.data.token}' | base64 -d`}</pre>
|
||||||
<p>
|
<p>
|
||||||
上面的 Namespace 由管理员创建,平台 Token 本身没有任何集群级权限。
|
上面的 Namespace 由管理员创建,平台 Token 本身没有任何集群级权限。
|
||||||
只有确实需要平台自建命名空间时,才额外授予
|
只有确实需要平台自建命名空间时,才额外授予
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ const Login = memo(function Login() {
|
|||||||
<div className="inline-flex items-center justify-center w-14 h-14 rounded-2xl bg-primary mb-3">
|
<div className="inline-flex items-center justify-center w-14 h-14 rounded-2xl bg-primary mb-3">
|
||||||
<Activity className="w-8 h-8 text-primary-foreground" />
|
<Activity className="w-8 h-8 text-primary-foreground" />
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-2xl font-bold text-foreground">opsx-loki</h1>
|
<h1 className="text-2xl font-bold text-foreground">lokistack</h1>
|
||||||
<p className="text-sm text-muted-foreground mt-1">Kubernetes Loki 日志部署平台</p>
|
<p className="text-sm text-muted-foreground mt-1">Kubernetes Loki 日志部署平台</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ const SettingsPage = memo(function SettingsPage() {
|
|||||||
<CardHeader className="pb-3">
|
<CardHeader className="pb-3">
|
||||||
<CardTitle className="text-base flex items-center gap-2">
|
<CardTitle className="text-base flex items-center gap-2">
|
||||||
<SettingsIcon className="w-4 h-4" />
|
<SettingsIcon className="w-4 h-4" />
|
||||||
关于 opsx-loki
|
关于 lokistack
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
|
|||||||
Reference in new issue
Block a user