- 品牌: Go 模块/数据文件/二进制/构建部署资产全部 opsx→lokistack;前端 localStorage 命名空间迁移(读旧写新,含按用户 id 前缀迁移);修复 nginx upstream 与 Makefile 引用已改名服务的断裂 - i18n: react-i18next 落地,common + 11 个页面域命名空间全站中英(菜单/顶栏/登录/列表页/表单/确认弹窗/状态徽章);设置页语言即时切换;修复词典自注册导致的循环导入白屏 - 用户管理: 批量删除(POST /users/batch-delete,不删自己/最后管理员,部分失败不阻断)+ 行复选/全选/批量工具条 - 主题: 浅色侧栏(中性灰激活态)、四态模式(浅色/深色/跟随系统/定时切换,按时区判定)、顶栏太阳月亮二态、设置页紧凑分段选择器 - UI: 登录记住用户名、CardActionButton 统一五页卡片操作钮、shadcn Badge 替换手写徽章、语义色修正 - 清理: 移除主机 Web 终端(前后端)、k8s-helm/Helm 遗留代码与字段、README 重写精简 - 修复: 侧栏与日志告警 order 重复、路由标题 i18n key 未翻译、词典双逗号等
239 lines
6.8 KiB
Markdown
239 lines
6.8 KiB
Markdown
# Kubernetes 部署
|
||
|
||
清单在仓库 `kubernetes/` 目录,域名与 IP 已脱敏。
|
||
|
||
## 1. 命名空间与密钥
|
||
|
||
```bash
|
||
kubectl create namespace log # 已存在可跳过
|
||
|
||
kubectl -n log create secret generic lokistack-secrets \
|
||
--from-literal=JWT_SECRET="$(openssl rand -hex 32)" \
|
||
--from-literal=ENCRYPTION_KEY="$(openssl rand -hex 32)"
|
||
```
|
||
|
||
> `ENCRYPTION_KEY` 必须固定保存:DB 里的 kubeconfig、对象存储 AK/SK、SSH 私钥都用它加密,丢失后无法解密。
|
||
> 从旧实例迁移时,必须使用**原实例相同的** `JWT_SECRET` / `ENCRYPTION_KEY`。
|
||
|
||
## 2. 数据卷
|
||
|
||
`kubernetes/pvc.yaml`:
|
||
|
||
```yaml
|
||
apiVersion: v1
|
||
kind: PersistentVolumeClaim
|
||
metadata:
|
||
name: lokistack-data
|
||
namespace: log
|
||
spec:
|
||
accessModes: [ReadWriteOnce]
|
||
resources:
|
||
requests:
|
||
storage: 30Gi
|
||
```
|
||
|
||
不写 `storageClassName`,使用集群默认 StorageClass。没有默认 SC 时按云填写:
|
||
|
||
| 云 | StorageClass |
|
||
|---|---|
|
||
| 阿里云 ACK | `alicloud-disk-essd` |
|
||
| AWS EKS | `gp3` |
|
||
| 腾讯云 TKE | `cbs` |
|
||
| 华为云 CCE | `csi-disk` |
|
||
|
||
## 3. 工作负载
|
||
|
||
```bash
|
||
kubectl apply -f kubernetes/namespace.yaml \
|
||
-f kubernetes/pvc.yaml \
|
||
-f kubernetes/deployment.yaml \
|
||
-f kubernetes/service.yaml
|
||
```
|
||
|
||
关键约束(`deployment.yaml` 已内置):
|
||
|
||
- `replicas: 1`:JSON DB 单写者,多副本会互相覆盖。
|
||
- `strategy: Recreate`:滚动更新会同时挂同一个 RWO PVC。
|
||
- `DATA_DIR=/app/data`,挂 PVC;`runAsUser/fsGroup: 1000`。
|
||
- 镜像 `lghost/lokistack:latest`,`imagePullPolicy: Always`。
|
||
- 探针:`/api/v1/health`。
|
||
|
||
## 4. Service
|
||
|
||
```yaml
|
||
apiVersion: v1
|
||
kind: Service
|
||
metadata:
|
||
name: lokistack
|
||
namespace: log
|
||
spec:
|
||
type: ClusterIP
|
||
selector:
|
||
app: lokistack
|
||
ports:
|
||
- name: http
|
||
port: 8080
|
||
targetPort: http
|
||
```
|
||
|
||
需要主机 nginx 反代时,额外创建 NodePort(`kubernetes/service-nodeport.yaml`,30080)。
|
||
|
||
## 5. Ingress(ALB)
|
||
|
||
`log.xxx.io` 指向 Loki/平台入口,使用阿里云 ALB IngressClass:
|
||
|
||
```yaml
|
||
apiVersion: networking.k8s.io/v1
|
||
kind: Ingress
|
||
metadata:
|
||
name: loki.xxx.io
|
||
namespace: log
|
||
labels:
|
||
app: lokistack
|
||
spec:
|
||
ingressClassName: alb
|
||
rules:
|
||
- host: log.xxx.io
|
||
http:
|
||
paths:
|
||
- path: /
|
||
pathType: Prefix
|
||
backend:
|
||
service:
|
||
name: lokistack
|
||
port:
|
||
number: 8080
|
||
```
|
||
|
||
```bash
|
||
kubectl apply -f kubernetes/ingress.yaml
|
||
kubectl -n log get ingress
|
||
```
|
||
|
||
ALB 会分配一个地址(如 `alb-xxxx.<region>.alb.aliyuncsslbintl.com`),把域名的 CNAME 指过去即可。
|
||
|
||
> 其他云把 `ingressClassName` 换成对应实现:TKE `qcloud`、CCE `nginx`/`cce`、自建 `nginx`。
|
||
|
||
## 6. 数据迁移(从主机/旧实例)
|
||
|
||
JSON DB 是单文件,迁移时先停旧实例,再写入 PVC:
|
||
|
||
```bash
|
||
# 1) 缩容到 0,避免应用关机时覆盖
|
||
kubectl -n log scale deploy/lokistack --replicas=0
|
||
|
||
# 2) 临时 Pod 挂 PVC 拷数据(与业务 Pod 同节点,RWO 盘才能挂上)
|
||
kubectl apply -f - <<'EOF'
|
||
apiVersion: v1
|
||
kind: Pod
|
||
metadata: {name: pvc-loader, namespace: log}
|
||
spec:
|
||
restartPolicy: Never
|
||
securityContext: {runAsUser: 1000, runAsGroup: 1000, fsGroup: 1000}
|
||
containers:
|
||
- name: loader
|
||
image: busybox:1.36
|
||
command: ["sleep", "1800"]
|
||
volumeMounts: [{name: data, mountPath: /data}]
|
||
volumes:
|
||
- name: data
|
||
persistentVolumeClaim: {claimName: lokistack-data}
|
||
EOF
|
||
|
||
kubectl -n log cp ./lokistack.json pvc-loader:/data/lokistack.json
|
||
kubectl -n log cp ./known_hosts pvc-loader:/data/known_hosts
|
||
|
||
kubectl -n log delete pod pvc-loader
|
||
kubectl -n log scale deploy/lokistack --replicas=1
|
||
```
|
||
|
||
> 不要在业务 Pod 运行时 `kubectl cp` 覆盖 DB:应用退出时会用内存数据回写,覆盖你拷进去的文件。
|
||
|
||
## 7. 验证
|
||
|
||
```bash
|
||
kubectl -n log get pods,pvc,svc,ingress
|
||
kubectl -n log logs deploy/lokistack --tail=20
|
||
kubectl -n log exec deploy/lokistack -- wget -qO- http://127.0.0.1:8080/api/v1/health
|
||
```
|
||
|
||
## 8. 升级
|
||
|
||
```bash
|
||
kubectl -n log set image deploy/lokistack lokistack=lghost/lokistack:v0.2
|
||
kubectl -n log rollout status deploy/lokistack
|
||
```
|
||
|
||
`Recreate` 会先停旧 Pod 再起新 Pod,期间平台短暂不可用(单写者约束的代价)。
|
||
|
||
## 9. Token 接入(长期有效,仅 `log` 命名空间)
|
||
|
||
平台支持 ServiceAccount Token 接入。**推荐使用长期 Token + 命名空间级 Role**:
|
||
Token 不过期,但权限只覆盖 `log` 命名空间,泄露影响面同样仅限于 `log`,不会波及其他命名空间。
|
||
|
||
在集群里执行一次(管理员权限),然后取 Token:
|
||
|
||
```bash
|
||
kubectl apply -f - <<'EOF'
|
||
apiVersion: v1
|
||
kind: Namespace
|
||
metadata:
|
||
name: log
|
||
---
|
||
apiVersion: v1
|
||
kind: ServiceAccount
|
||
metadata:
|
||
name: lokistack
|
||
namespace: log
|
||
---
|
||
apiVersion: rbac.authorization.k8s.io/v1
|
||
kind: Role
|
||
metadata:
|
||
name: lokistack
|
||
namespace: log
|
||
rules:
|
||
- apiGroups: [""]
|
||
resources: ["pods", "pods/log", "services", "configmaps", "secrets", "persistentvolumeclaims", "events", "serviceaccounts"]
|
||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||
- apiGroups: ["apps"]
|
||
resources: ["statefulsets", "daemonsets", "deployments"]
|
||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||
- apiGroups: ["networking.k8s.io"]
|
||
resources: ["ingresses"]
|
||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||
---
|
||
apiVersion: rbac.authorization.k8s.io/v1
|
||
kind: RoleBinding
|
||
metadata:
|
||
name: lokistack
|
||
namespace: log
|
||
subjects:
|
||
- kind: ServiceAccount
|
||
name: lokistack
|
||
namespace: log
|
||
roleRef:
|
||
kind: Role
|
||
name: lokistack
|
||
apiGroup: rbac.authorization.k8s.io
|
||
---
|
||
apiVersion: v1
|
||
kind: Secret
|
||
metadata:
|
||
name: lokistack-token
|
||
namespace: log
|
||
annotations:
|
||
kubernetes.io/service-account.name: lokistack
|
||
type: kubernetes.io/service-account-token
|
||
EOF
|
||
|
||
kubectl -n log get secret lokistack-token -o jsonpath='{.data.token}' | base64 -d
|
||
```
|
||
|
||
- 这个 Token **不会自动过期**,但只绑定 `log` 命名空间的 Role:能操作该命名空间的 Pod、日志、工作负载、Service、ConfigMap、Secret、PVC,**无权访问其他命名空间和集群级资源**。
|
||
- 平台展示节点数需要 `nodes` 只读权限;命名空间级 Token 没有该权限时,平台会跳过节点信息,不影响集群接入与部署。
|
||
- 平台收到 Token 后会转成 kubeconfig,并用 `ENCRYPTION_KEY` 加密存 DB(`ENC:` 前缀),接口不返回明文。
|
||
- 轮换:删除 Secret 后重建,旧 Token 立即失效。
|
||
- 如果集群策略要求短期凭证,可改用 `kubectl -n log create token lokistack --duration=24h` 定期轮换。
|
||
- 上面的 Namespace 由管理员创建,平台 Token 本身没有集群级权限;只有确实需要平台自建命名空间时,才额外授予 `namespaces: create/get` 的 ClusterRole(create 无法按名称限制,预建 `log` 更安全)。
|
||
|