Files
LokiStack/docs/deployment/kubernetes.md
T
opsx f3733f0bfc feat: 品牌统一 LokiStack + 全站中英 i18n + 用户批量删除 + 主题定时切换与浅色侧栏
- 品牌: 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 未翻译、词典双逗号等
2026-10-27 17:11:38 +08:00

6.8 KiB
Raw Blame History

Kubernetes 部署

清单在仓库 kubernetes/ 目录,域名与 IP 已脱敏。

1. 命名空间与密钥

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:

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. 工作负载

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

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:

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
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:

# 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. 验证

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. 升级

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:

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 更安全)。