Files
LokiStack/docs/deployment/kubernetes.md
T
opsx b65dcc9677 refactor: 镜像名 lghost/opsxloki → lghost/lokistack(跟随项目更名)
只改镜像引用(8 处),K8s 资源名一律不动 —— 改了会丢数据/断服务:

改:
  kubernetes/deployment.yaml        image
  docker-compose.yml                image
  docker-compose.prod.yml           image ×2
  kubernetes/README.md              文档 ×2
  docs/deployment/kubernetes.md     文档 ×2

不改(重要):
  opsxloki-secrets    K8s Secret —— 改名会导致 JWT_SECRET/ENCRYPTION_KEY 重置,
                      历史加密的实例密码无法解密
  opsxloki-data       PVC —— 改名 = 新建空卷,数据全丢
  container_name      docker 容器名 —— 改名会让 docker exec/logs 命令失效
  app: opsx-loki      Pod label —— 改名要同步改 Service selector
  deployment 名称 opsx-loki —— 改名要重建 Deployment

⚠️ 部署顺序(本提交只改代码,尚未 apply 到 K8s):
  1) 推镜像 lghost/lokistack:latest 到 Docker Hub
  2) kubectl apply -f kubernetes/deployment.yaml
  3) 等 Pod 1/1 就绪
  4) 才能删除 lghost/opsxloki
  顺序颠倒会因 imagePullPolicy: Always 拉到不存在的镜像导致服务中断
2026-10-26 17:09:47 +00: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 opsxloki-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: opsxloki-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: opsx-loki
namespace: log
spec:
type: ClusterIP
selector:
app: opsx-loki
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: opsx-loki
spec:
ingressClassName: alb
rules:
- host: log.xxx.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: opsx-loki
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/opsx-loki --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: opsxloki-data}
EOF
kubectl -n log cp ./opsxloki.json pvc-loader:/data/opsxloki.json
kubectl -n log cp ./known_hosts pvc-loader:/data/known_hosts
kubectl -n log delete pod pvc-loader
kubectl -n log scale deploy/opsx-loki --replicas=1
```
> 不要在业务 Pod 运行时 `kubectl cp` 覆盖 DB:应用退出时会用内存数据回写,覆盖你拷进去的文件。
## 7. 验证
```bash
kubectl -n log get pods,pvc,svc,ingress
kubectl -n log logs deploy/opsx-loki --tail=20
kubectl -n log exec deploy/opsx-loki -- wget -qO- http://127.0.0.1:8080/api/v1/health
```
## 8. 升级
```bash
kubectl -n log set image deploy/opsx-loki opsx-loki=lghost/lokistack:v0.2
kubectl -n log rollout status deploy/opsx-loki
```
`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: opsx-loki
namespace: log
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: opsx-loki
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: opsx-loki
namespace: log
subjects:
- kind: ServiceAccount
name: opsx-loki
namespace: log
roleRef:
kind: Role
name: opsx-loki
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: Secret
metadata:
name: opsx-loki-token
namespace: log
annotations:
kubernetes.io/service-account.name: opsx-loki
type: kubernetes.io/service-account-token
EOF
kubectl -n log get secret opsx-loki-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 opsx-loki --duration=24h` 定期轮换。
- 上面的 Namespace 由管理员创建,平台 Token 本身没有集群级权限;只有确实需要平台自建命名空间时,才额外授予 `namespaces: create/get` 的 ClusterRole(create 无法按名称限制,预建 `log` 更安全)。