Files
LokiStack/docs/deployment/kubernetes.md
T
logan b433b5f9dd
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
fix: 删除操作清理远端资源并拦截悬空引用
- 部署删除: k8s 模式清理 StatefulSet/Service/ConfigMap 与 PVC,先卸载关联采集器
- 采集器删除: 同步卸载成功后再删记录,失败保留避免孤儿
- 集群/存储/主机删除: 有部署或采集器引用时拒绝,避免悬空外键
- Token RBAC 补 services/proxy,保证 cluster-svc 数据源可查询
2026-10-30 01:17:26 +08:00

239 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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", "services/proxy", "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` 更安全)。