refactor: 资源名 opsx-loki/opsxloki → lokistack(线上已迁移完成)
【已在线完成,零数据丢失】
K8s ns=log 资源全部改名:
Deployment opsx-loki → lokistack
Service opsx-loki → lokistack
Service opsx-loki-nodeport → lokistack-nodeport
PVC opsxloki-data → lokistack-data
Secret opsxloki-secrets → lokistack-secrets
Label app: opsx-loki → app: lokistack
Ingress log.astx.club 后端 → lokistack-nodeport:8080
镜像 lghost/opsxloki → lghost/lokistack
docker-compose 卷/容器名同步更名
【保留不变(改了会出事)】
namespace: log
数据文件名 opsxloki.json(代码硬编码)
容器内路径 /app/data
【迁移过程】
1. 备份 PVC 数据(32KB) + Secret 原值 + 旧 yaml → /root/lokistack-migration-backup-20261026-171141
2. scale 旧 Deployment → 0,等 Pod 消失
3. 复制 Secret(JWT sha256 校验一致)
4. 新建 PVC lokistack-data(Bound 30Gi cbs)
5. 临时 Pod 恢复数据(chown 1000:1000,opsxloki.json 保留 0600)
6. apply 新 Deployment → 1/1 Running
7. 修复 Ingress 后端(TKE qcloud 要求 NodePort)→ CLB 恢复 200
8. 删除旧 Deployment / 失效 Service
【验证】
lokistack 1/1,0 重启,镜像 lghost/lokistack:latest(statically linked)
/api/v1/health → {"status":"ok","version":"2.0.0"}
/app/data/opsxloki.json 610B 完整(admin 用户 + 配置)
http://log.astx.club/ → HTTP 200
镜像加固:admin123=0、/app/backend/=0、initial-admin-password.txt 存在
【回滚兜底(建议 7 天后删)】
pvc/opsxloki-data、secret/opsxloki-secrets
【文档】
README 新增「从 opsx-loki 升级」章节:
K8s 七步迁移脚本 + docker-compose 卷迁移命令
This commit is contained in:
1 parent
b65dcc9677
commit
3c9388658b
13 files changed
+230
-152
No files matched your search
@@ -21,6 +21,84 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 从 opsx-loki 升级(资源更名说明)
|
||||||
|
|
||||||
|
本版本把所有资源名从 `opsx-loki` / `opsxloki` 统一改为 **`lokistack`**,包括镜像、Deployment、
|
||||||
|
Service、PVC、Secret、docker-compose 卷名。
|
||||||
|
|
||||||
|
### Kubernetes 用户
|
||||||
|
|
||||||
|
资源名已变,**不能直接 `kubectl apply` 覆盖**(会新建空 PVC)。按下面顺序迁移,**零数据丢失**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 0) 先备份(数据只有几十 KB)
|
||||||
|
kubectl -n log exec deploy/opsx-loki -- tar czf - -C /app/data . > /tmp/data.tar.gz
|
||||||
|
kubectl -n log get secret opsxloki-secrets -o yaml > /tmp/secret-old.yaml
|
||||||
|
kubectl -n log get pvc opsxloki-data -o yaml > /tmp/pvc-old.yaml
|
||||||
|
|
||||||
|
# 1) 停旧服务(Recreate + RWO,必须停)
|
||||||
|
kubectl -n log scale deploy opsx-loki --replicas=0
|
||||||
|
kubectl -n log wait --for=delete pod -l app=opsx-loki --timeout=120s
|
||||||
|
|
||||||
|
# 2) 复制 Secret(值不变,密钥才不会失效)
|
||||||
|
kubectl -n log get secret opsxloki-secrets -o yaml \
|
||||||
|
| sed 's/name: opsxloki-secrets/name: lokistack-secrets/' \
|
||||||
|
| kubectl apply -f -
|
||||||
|
|
||||||
|
# 3) 只建新 PVC
|
||||||
|
kubectl apply -f kubernetes/pvc.yaml
|
||||||
|
kubectl -n log wait --for=jsonpath='{.status.phase}'=Bound pvc/lokistack-data --timeout=180s
|
||||||
|
|
||||||
|
# 4) 恢复数据到新 PVC(起临时 Pod 挂载)
|
||||||
|
kubectl -n log run restore --image=alpine:3.20 --restart=Never \
|
||||||
|
--overrides='{"spec":{"containers":[{"name":"r","image":"alpine:3.20","command":["sleep","600"],"volumeMounts":[{"name":"d","mountPath":"/data"}]}],"volumes":[{"name":"d","persistentVolumeClaim":{"claimName":"lokistack-data"}}]}}'
|
||||||
|
kubectl -n log wait --for=condition=Ready pod/restore --timeout=120s
|
||||||
|
kubectl -n log cp /tmp/data.tar.gz restore:/tmp/
|
||||||
|
kubectl -n log exec restore -- sh -c 'cd /data && tar xzf /tmp/data.tar.gz && chown -R 1000:1000 /data'
|
||||||
|
kubectl -n log delete po restore
|
||||||
|
|
||||||
|
# 5) 启动新服务
|
||||||
|
kubectl apply -f kubernetes/deployment.yaml -f kubernetes/service.yaml -f kubernetes/service-nodeport.yaml
|
||||||
|
kubectl -n log rollout status deploy/lokistack --timeout=240s
|
||||||
|
|
||||||
|
# 6) 若有 Ingress,改后端(TKE qcloud 要 NodePort)
|
||||||
|
kubectl -n log patch ingress <你的ingress名> --type=json \
|
||||||
|
-p='[{"op":"replace","path":"/spec/rules/0/http/paths/0/backend/service/name","value":"lokistack-nodeport"}]'
|
||||||
|
|
||||||
|
# 7) 确认服务正常后再删旧资源
|
||||||
|
kubectl -n log delete deploy opsx-loki
|
||||||
|
kubectl -n log delete svc opsx-loki opsx-loki-nodeport
|
||||||
|
# 旧 PVC / Secret 建议保留 7 天做回滚兜底
|
||||||
|
# kubectl -n log delete pvc opsxloki-data
|
||||||
|
# kubectl -n log delete secret opsxloki-secrets
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker Compose 用户
|
||||||
|
|
||||||
|
卷名 `opsxloki-data` → `lokistack-data`。**旧数据不会自动迁移**,需要手动拷:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 停服务
|
||||||
|
docker compose down
|
||||||
|
|
||||||
|
# 创建新卷并迁移数据
|
||||||
|
docker volume create lokistack-data
|
||||||
|
docker run --rm -v opsxloki-data:/from -v lokistack-data:/to alpine \
|
||||||
|
sh -c 'cp -av /from/. /to/ && chown -R 1000:1000 /to'
|
||||||
|
|
||||||
|
# 重新启动(会用新卷)
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
# 验证数据在
|
||||||
|
docker compose exec lokistack cat /app/data/opsxloki.json | head -c 100
|
||||||
|
```
|
||||||
|
|
||||||
|
> **注意**:数据文件名仍叫 `opsxloki.json`(代码里硬编码,不改),只是目录/卷名变了。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 快速开始
|
## 快速开始
|
||||||
|
|
||||||
### 前置条件
|
### 前置条件
|
||||||
|
|||||||
+24
-24
@@ -1,5 +1,5 @@
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
# opsx-loki - Production Docker Compose Configuration
|
# lokistack - Production Docker Compose Configuration
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Features:
|
# Features:
|
||||||
# - Multi-instance deployment with load balancing
|
# - Multi-instance deployment with load balancing
|
||||||
@@ -15,14 +15,14 @@ services:
|
|||||||
# ---- Nginx Load Balancer ----
|
# ---- Nginx Load Balancer ----
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:1.27-alpine
|
image: nginx:1.27-alpine
|
||||||
container_name: opsxloki-lb
|
container_name: lokistack-lb
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
networks:
|
networks:
|
||||||
- opsxloki-net
|
- lokistack-net
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health"]
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
@@ -52,21 +52,21 @@ services:
|
|||||||
- /var/cache/nginx:noexec,nosuid,size=10m
|
- /var/cache/nginx:noexec,nosuid,size=10m
|
||||||
- /var/run:noexec,nosuid,size=5m
|
- /var/run:noexec,nosuid,size=5m
|
||||||
depends_on:
|
depends_on:
|
||||||
opsxloki-1:
|
lokistack-1:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
opsxloki-2:
|
lokistack-2:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
# ---- Application Instance 1 ----
|
# ---- Application Instance 1 ----
|
||||||
opsxloki-1:
|
lokistack-1:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
args:
|
args:
|
||||||
TARGETARCH: ${TARGETARCH:-amd64}
|
TARGETARCH: ${TARGETARCH:-amd64}
|
||||||
image: lghost/lokistack:latest
|
image: lghost/lokistack:latest
|
||||||
container_name: opsxloki-1
|
container_name: lokistack-1
|
||||||
hostname: opsxloki-1
|
hostname: lokistack-1
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
security_opt:
|
security_opt:
|
||||||
@@ -85,16 +85,16 @@ services:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
# Named volume for data persistence
|
# Named volume for data persistence
|
||||||
- opsxloki-data-1:/app/data
|
- lokistack-data-1:/app/data
|
||||||
# kubeconfig read-only (P0: non-root path)
|
# kubeconfig read-only (P0: non-root path)
|
||||||
- ${KUBECONFIG_PATH:-~/.kube}:/home/opsxloki/.kube:ro
|
- ${KUBECONFIG_PATH:-~/.kube}:/home/lokistack/.kube:ro
|
||||||
# SSH keys read-only
|
# SSH keys read-only
|
||||||
- ${SSH_KEY_PATH:-~/.ssh}:/home/opsxloki/.ssh:ro
|
- ${SSH_KEY_PATH:-~/.ssh}:/home/lokistack/.ssh:ro
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
- SERVER_PORT=8080
|
- SERVER_PORT=8080
|
||||||
- DATA_DIR=/app/data
|
- DATA_DIR=/app/data
|
||||||
- KUBECONFIG=/home/opsxloki/.kube/config
|
- KUBECONFIG=/home/lokistack/.kube/config
|
||||||
# Secrets via Docker Secrets file injection
|
# Secrets via Docker Secrets file injection
|
||||||
- JWT_SECRET_FILE=${JWT_SECRET_FILE:-/run/secrets/jwt_secret}
|
- JWT_SECRET_FILE=${JWT_SECRET_FILE:-/run/secrets/jwt_secret}
|
||||||
- ENCRYPTION_KEY_FILE=${ENCRYPTION_KEY_FILE:-/run/secrets/encryption_key}
|
- ENCRYPTION_KEY_FILE=${ENCRYPTION_KEY_FILE:-/run/secrets/encryption_key}
|
||||||
@@ -136,18 +136,18 @@ services:
|
|||||||
|
|
||||||
stop_grace_period: 30s
|
stop_grace_period: 30s
|
||||||
networks:
|
networks:
|
||||||
- opsxloki-net
|
- lokistack-net
|
||||||
|
|
||||||
# ---- Application Instance 2 ----
|
# ---- Application Instance 2 ----
|
||||||
opsxloki-2:
|
lokistack-2:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
args:
|
args:
|
||||||
TARGETARCH: ${TARGETARCH:-amd64}
|
TARGETARCH: ${TARGETARCH:-amd64}
|
||||||
image: lghost/lokistack:latest
|
image: lghost/lokistack:latest
|
||||||
container_name: opsxloki-2
|
container_name: lokistack-2
|
||||||
hostname: opsxloki-2
|
hostname: lokistack-2
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
security_opt:
|
security_opt:
|
||||||
@@ -163,14 +163,14 @@ services:
|
|||||||
- /tmp:noexec,nosuid,size=50m,uid=1000,gid=1000
|
- /tmp:noexec,nosuid,size=50m,uid=1000,gid=1000
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- opsxloki-data-2:/app/data
|
- lokistack-data-2:/app/data
|
||||||
- ${KUBECONFIG_PATH:-~/.kube}:/home/opsxloki/.kube:ro
|
- ${KUBECONFIG_PATH:-~/.kube}:/home/lokistack/.kube:ro
|
||||||
- ${SSH_KEY_PATH:-~/.ssh}:/home/opsxloki/.ssh:ro
|
- ${SSH_KEY_PATH:-~/.ssh}:/home/lokistack/.ssh:ro
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
- SERVER_PORT=8080
|
- SERVER_PORT=8080
|
||||||
- DATA_DIR=/app/data
|
- DATA_DIR=/app/data
|
||||||
- KUBECONFIG=/home/opsxloki/.kube/config
|
- KUBECONFIG=/home/lokistack/.kube/config
|
||||||
- JWT_SECRET_FILE=${JWT_SECRET_FILE:-/run/secrets/jwt_secret}
|
- JWT_SECRET_FILE=${JWT_SECRET_FILE:-/run/secrets/jwt_secret}
|
||||||
- ENCRYPTION_KEY_FILE=${ENCRYPTION_KEY_FILE:-/run/secrets/encryption_key}
|
- ENCRYPTION_KEY_FILE=${ENCRYPTION_KEY_FILE:-/run/secrets/encryption_key}
|
||||||
|
|
||||||
@@ -209,13 +209,13 @@ services:
|
|||||||
|
|
||||||
stop_grace_period: 30s
|
stop_grace_period: 30s
|
||||||
networks:
|
networks:
|
||||||
- opsxloki-net
|
- lokistack-net
|
||||||
|
|
||||||
# ---- Named Volumes ----
|
# ---- Named Volumes ----
|
||||||
volumes:
|
volumes:
|
||||||
opsxloki-data-1:
|
lokistack-data-1:
|
||||||
driver: local
|
driver: local
|
||||||
opsxloki-data-2:
|
lokistack-data-2:
|
||||||
driver: local
|
driver: local
|
||||||
|
|
||||||
# ---- Docker Secrets ----
|
# ---- Docker Secrets ----
|
||||||
@@ -227,7 +227,7 @@ secrets:
|
|||||||
|
|
||||||
# ---- Network ----
|
# ---- Network ----
|
||||||
networks:
|
networks:
|
||||||
opsxloki-net:
|
lokistack-net:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
ipam:
|
ipam:
|
||||||
config:
|
config:
|
||||||
|
|||||||
+14
-14
@@ -1,8 +1,8 @@
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
# opsx-loki - Development Docker Compose Configuration
|
# lokistack - Development Docker Compose Configuration
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# P0 Fixes:
|
# P0 Fixes:
|
||||||
# - Non-root kubeconfig mount (/home/opsxloki/.kube)
|
# - Non-root kubeconfig mount (/home/lokistack/.kube)
|
||||||
# - Healthcheck for orchestration visibility
|
# - Healthcheck for orchestration visibility
|
||||||
# - Resource limits to prevent noisy-neighbor
|
# - Resource limits to prevent noisy-neighbor
|
||||||
# - security_opt: no-new-privileges
|
# - security_opt: no-new-privileges
|
||||||
@@ -14,15 +14,15 @@
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
services:
|
services:
|
||||||
opsxloki:
|
lokistack:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
args:
|
args:
|
||||||
TARGETARCH: ${TARGETARCH:-amd64}
|
TARGETARCH: ${TARGETARCH:-amd64}
|
||||||
image: lghost/lokistack:latest
|
image: lghost/lokistack:latest
|
||||||
container_name: opsxloki
|
container_name: lokistack
|
||||||
hostname: opsxloki
|
hostname: lokistack
|
||||||
|
|
||||||
# ---- P0: Security options ----
|
# ---- P0: Security options ----
|
||||||
security_opt:
|
security_opt:
|
||||||
@@ -43,11 +43,11 @@ services:
|
|||||||
|
|
||||||
# ---- P0: Named volumes for data persistence ----
|
# ---- P0: Named volumes for data persistence ----
|
||||||
volumes:
|
volumes:
|
||||||
- opsxloki-data:/app/data
|
- lokistack-data:/app/data
|
||||||
# P0: Mount kubeconfig to non-root user directory
|
# P0: Mount kubeconfig to non-root user directory
|
||||||
- ${KUBECONFIG_PATH:-${HOME}/.kube}:/home/opsxloki/.kube:ro
|
- ${KUBECONFIG_PATH:-${HOME}/.kube}:/home/lokistack/.kube:ro
|
||||||
# SSH keys for host-based deployments
|
# SSH keys for host-based deployments
|
||||||
- ${SSH_KEY_PATH:-${HOME}/.ssh}:/home/opsxloki/.ssh:ro
|
- ${SSH_KEY_PATH:-${HOME}/.ssh}:/home/lokistack/.ssh:ro
|
||||||
|
|
||||||
# ---- P0: Environment variables (no default secrets) ----
|
# ---- P0: Environment variables (no default secrets) ----
|
||||||
environment:
|
environment:
|
||||||
@@ -60,7 +60,7 @@ services:
|
|||||||
# P0: ENCRYPTION_KEY must be provided externally (AES-256, >=32 字符)
|
# P0: ENCRYPTION_KEY must be provided externally (AES-256, >=32 字符)
|
||||||
- "ENCRYPTION_KEY=${ENCRYPTION_KEY:?ENCRYPTION_KEY is required. Generate: openssl rand -hex 32, then: export ENCRYPTION_KEY=<value>}"
|
- "ENCRYPTION_KEY=${ENCRYPTION_KEY:?ENCRYPTION_KEY is required. Generate: openssl rand -hex 32, then: export ENCRYPTION_KEY=<value>}"
|
||||||
# KUBECONFIG points to non-root user's .kube directory
|
# KUBECONFIG points to non-root user's .kube directory
|
||||||
- KUBECONFIG=/home/opsxloki/.kube/config
|
- KUBECONFIG=/home/lokistack/.kube/config
|
||||||
|
|
||||||
# ---- P0: Healthcheck ----
|
# ---- P0: Healthcheck ----
|
||||||
healthcheck:
|
healthcheck:
|
||||||
@@ -95,21 +95,21 @@ services:
|
|||||||
stop_grace_period: 15s
|
stop_grace_period: 15s
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
- opsxloki-net
|
- lokistack-net
|
||||||
|
|
||||||
# ---- Named volumes ----
|
# ---- Named volumes ----
|
||||||
volumes:
|
volumes:
|
||||||
opsxloki-data:
|
lokistack-data:
|
||||||
driver: local
|
driver: local
|
||||||
labels:
|
labels:
|
||||||
- "com.opsxloki.description=opsx-loki data directory"
|
- "com.lokistack.description=lokistack data directory"
|
||||||
|
|
||||||
# ---- Network isolation ----
|
# ---- Network isolation ----
|
||||||
networks:
|
networks:
|
||||||
opsxloki-net:
|
lokistack-net:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
ipam:
|
ipam:
|
||||||
config:
|
config:
|
||||||
- subnet: 172.28.0.0/16
|
- subnet: 172.28.0.0/16
|
||||||
labels:
|
labels:
|
||||||
- "com.opsxloki.description=opsx-loki internal network"
|
- "com.lokistack.description=lokistack internal network"
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
```bash
|
```bash
|
||||||
kubectl create namespace log # 已存在可跳过
|
kubectl create namespace log # 已存在可跳过
|
||||||
|
|
||||||
kubectl -n log create secret generic opsxloki-secrets \
|
kubectl -n log create secret generic lokistack-secrets \
|
||||||
--from-literal=JWT_SECRET="$(openssl rand -hex 32)" \
|
--from-literal=JWT_SECRET="$(openssl rand -hex 32)" \
|
||||||
--from-literal=ENCRYPTION_KEY="$(openssl rand -hex 32)"
|
--from-literal=ENCRYPTION_KEY="$(openssl rand -hex 32)"
|
||||||
```
|
```
|
||||||
@@ -23,7 +23,7 @@ kubectl -n log create secret generic opsxloki-secrets \
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: PersistentVolumeClaim
|
kind: PersistentVolumeClaim
|
||||||
metadata:
|
metadata:
|
||||||
name: opsxloki-data
|
name: lokistack-data
|
||||||
namespace: log
|
namespace: log
|
||||||
spec:
|
spec:
|
||||||
accessModes: [ReadWriteOnce]
|
accessModes: [ReadWriteOnce]
|
||||||
@@ -64,12 +64,12 @@ kubectl apply -f kubernetes/namespace.yaml \
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: opsx-loki
|
name: lokistack
|
||||||
namespace: log
|
namespace: log
|
||||||
spec:
|
spec:
|
||||||
type: ClusterIP
|
type: ClusterIP
|
||||||
selector:
|
selector:
|
||||||
app: opsx-loki
|
app: lokistack
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
port: 8080
|
port: 8080
|
||||||
@@ -89,7 +89,7 @@ metadata:
|
|||||||
name: loki.xxx.io
|
name: loki.xxx.io
|
||||||
namespace: log
|
namespace: log
|
||||||
labels:
|
labels:
|
||||||
app: opsx-loki
|
app: lokistack
|
||||||
spec:
|
spec:
|
||||||
ingressClassName: alb
|
ingressClassName: alb
|
||||||
rules:
|
rules:
|
||||||
@@ -100,7 +100,7 @@ spec:
|
|||||||
pathType: Prefix
|
pathType: Prefix
|
||||||
backend:
|
backend:
|
||||||
service:
|
service:
|
||||||
name: opsx-loki
|
name: lokistack
|
||||||
port:
|
port:
|
||||||
number: 8080
|
number: 8080
|
||||||
```
|
```
|
||||||
@@ -120,7 +120,7 @@ JSON DB 是单文件,迁移时先停旧实例,再写入 PVC:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1) 缩容到 0,避免应用关机时覆盖
|
# 1) 缩容到 0,避免应用关机时覆盖
|
||||||
kubectl -n log scale deploy/opsx-loki --replicas=0
|
kubectl -n log scale deploy/lokistack --replicas=0
|
||||||
|
|
||||||
# 2) 临时 Pod 挂 PVC 拷数据(与业务 Pod 同节点,RWO 盘才能挂上)
|
# 2) 临时 Pod 挂 PVC 拷数据(与业务 Pod 同节点,RWO 盘才能挂上)
|
||||||
kubectl apply -f - <<'EOF'
|
kubectl apply -f - <<'EOF'
|
||||||
@@ -137,14 +137,14 @@ spec:
|
|||||||
volumeMounts: [{name: data, mountPath: /data}]
|
volumeMounts: [{name: data, mountPath: /data}]
|
||||||
volumes:
|
volumes:
|
||||||
- name: data
|
- name: data
|
||||||
persistentVolumeClaim: {claimName: opsxloki-data}
|
persistentVolumeClaim: {claimName: lokistack-data}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
kubectl -n log cp ./opsxloki.json pvc-loader:/data/opsxloki.json
|
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 cp ./known_hosts pvc-loader:/data/known_hosts
|
||||||
|
|
||||||
kubectl -n log delete pod pvc-loader
|
kubectl -n log delete pod pvc-loader
|
||||||
kubectl -n log scale deploy/opsx-loki --replicas=1
|
kubectl -n log scale deploy/lokistack --replicas=1
|
||||||
```
|
```
|
||||||
|
|
||||||
> 不要在业务 Pod 运行时 `kubectl cp` 覆盖 DB:应用退出时会用内存数据回写,覆盖你拷进去的文件。
|
> 不要在业务 Pod 运行时 `kubectl cp` 覆盖 DB:应用退出时会用内存数据回写,覆盖你拷进去的文件。
|
||||||
@@ -153,15 +153,15 @@ kubectl -n log scale deploy/opsx-loki --replicas=1
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl -n log get pods,pvc,svc,ingress
|
kubectl -n log get pods,pvc,svc,ingress
|
||||||
kubectl -n log logs deploy/opsx-loki --tail=20
|
kubectl -n log logs deploy/lokistack --tail=20
|
||||||
kubectl -n log exec deploy/opsx-loki -- wget -qO- http://127.0.0.1:8080/api/v1/health
|
kubectl -n log exec deploy/lokistack -- wget -qO- http://127.0.0.1:8080/api/v1/health
|
||||||
```
|
```
|
||||||
|
|
||||||
## 8. 升级
|
## 8. 升级
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl -n log set image deploy/opsx-loki opsx-loki=lghost/lokistack:v0.2
|
kubectl -n log set image deploy/lokistack lokistack=lghost/lokistack:v0.2
|
||||||
kubectl -n log rollout status deploy/opsx-loki
|
kubectl -n log rollout status deploy/lokistack
|
||||||
```
|
```
|
||||||
|
|
||||||
`Recreate` 会先停旧 Pod 再起新 Pod,期间平台短暂不可用(单写者约束的代价)。
|
`Recreate` 会先停旧 Pod 再起新 Pod,期间平台短暂不可用(单写者约束的代价)。
|
||||||
@@ -183,13 +183,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: [""]
|
||||||
@@ -205,34 +205,34 @@ 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
|
||||||
|
|
||||||
kubectl -n log get secret opsx-loki-token -o jsonpath='{.data.token}' | base64 -d
|
kubectl -n log get secret lokistack-token -o jsonpath='{.data.token}' | base64 -d
|
||||||
```
|
```
|
||||||
|
|
||||||
- 这个 Token **不会自动过期**,但只绑定 `log` 命名空间的 Role:能操作该命名空间的 Pod、日志、工作负载、Service、ConfigMap、Secret、PVC,**无权访问其他命名空间和集群级资源**。
|
- 这个 Token **不会自动过期**,但只绑定 `log` 命名空间的 Role:能操作该命名空间的 Pod、日志、工作负载、Service、ConfigMap、Secret、PVC,**无权访问其他命名空间和集群级资源**。
|
||||||
- 平台展示节点数需要 `nodes` 只读权限;命名空间级 Token 没有该权限时,平台会跳过节点信息,不影响集群接入与部署。
|
- 平台展示节点数需要 `nodes` 只读权限;命名空间级 Token 没有该权限时,平台会跳过节点信息,不影响集群接入与部署。
|
||||||
- 平台收到 Token 后会转成 kubeconfig,并用 `ENCRYPTION_KEY` 加密存 DB(`ENC:` 前缀),接口不返回明文。
|
- 平台收到 Token 后会转成 kubeconfig,并用 `ENCRYPTION_KEY` 加密存 DB(`ENC:` 前缀),接口不返回明文。
|
||||||
- 轮换:删除 Secret 后重建,旧 Token 立即失效。
|
- 轮换:删除 Secret 后重建,旧 Token 立即失效。
|
||||||
- 如果集群策略要求短期凭证,可改用 `kubectl -n log create token opsx-loki --duration=24h` 定期轮换。
|
- 如果集群策略要求短期凭证,可改用 `kubectl -n log create token lokistack --duration=24h` 定期轮换。
|
||||||
- 上面的 Namespace 由管理员创建,平台 Token 本身没有集群级权限;只有确实需要平台自建命名空间时,才额外授予 `namespaces: create/get` 的 ClusterRole(create 无法按名称限制,预建 `log` 更安全)。
|
- 上面的 Namespace 由管理员创建,平台 Token 本身没有集群级权限;只有确实需要平台自建命名空间时,才额外授予 `namespaces: create/get` 的 ClusterRole(create 无法按名称限制,预建 `log` 更安全)。
|
||||||
|
|
||||||
+38
-38
@@ -1,4 +1,4 @@
|
|||||||
# opsx-loki 部署到 Kubernetes
|
# lokistack 部署到 Kubernetes
|
||||||
|
|
||||||
命名空间固定:**`log`**(日志相关资源统一放这里)
|
命名空间固定:**`log`**(日志相关资源统一放这里)
|
||||||
|
|
||||||
@@ -13,11 +13,11 @@ bash kubernetes/install.sh
|
|||||||
脚本会依次完成:
|
脚本会依次完成:
|
||||||
|
|
||||||
1. 创建 `log` 命名空间
|
1. 创建 `log` 命名空间
|
||||||
2. **生成随机密钥** `JWT_SECRET` / `ENCRYPTION_KEY` 写入 Secret `opsxloki-secrets`
|
2. **生成随机密钥** `JWT_SECRET` / `ENCRYPTION_KEY` 写入 Secret `lokistack-secrets`
|
||||||
(已存在则跳过,**不会覆盖**)
|
(已存在则跳过,**不会覆盖**)
|
||||||
3. 创建 PVC `opsxloki-data`(30 GiB,使用集群默认 StorageClass)
|
3. 创建 PVC `lokistack-data`(30 GiB,使用集群默认 StorageClass)
|
||||||
4. 部署 `opsx-loki`(单副本 + Recreate)
|
4. 部署 `lokistack`(单副本 + Recreate)
|
||||||
5. 创建 Service `opsx-loki:8080`(ClusterIP)
|
5. 创建 Service `lokistack:8080`(ClusterIP)
|
||||||
6. 等待 Pod 就绪并输出访问方式
|
6. 等待 Pod 就绪并输出访问方式
|
||||||
|
|
||||||
**需要 NodePort(配 ingress 时)**:
|
**需要 NodePort(配 ingress 时)**:
|
||||||
@@ -40,7 +40,7 @@ WITH_NODEPORT=1 bash kubernetes/install.sh
|
|||||||
| 指定 SC(自建用 local-path)| `STORAGE_CLASS=local-path bash kubernetes/install.sh` |
|
| 指定 SC(自建用 local-path)| `STORAGE_CLASS=local-path bash kubernetes/install.sh` |
|
||||||
| **自建集群强制用节点本地盘**(hostPath)| `LOCAL_STORAGE=force bash kubernetes/install.sh` |
|
| **自建集群强制用节点本地盘**(hostPath)| `LOCAL_STORAGE=force bash kubernetes/install.sh` |
|
||||||
| 只诊断不动手(无变更)| `LOCAL_STORAGE=off bash kubernetes/install.sh` |
|
| 只诊断不动手(无变更)| `LOCAL_STORAGE=off bash kubernetes/install.sh` |
|
||||||
| **指定本地存储的节点/路径/容量** | `NODE_NAME=node1 PV_PATH=/data/opsxloki PV_SIZE=50Gi bash kubernetes/install.sh` |
|
| **指定本地存储的节点/路径/容量** | `NODE_NAME=node1 PV_PATH=/data/lokistack PV_SIZE=50Gi bash kubernetes/install.sh` |
|
||||||
| 组合:自建 + 指定节点 + NodePort | `LOCAL_STORAGE=force NODE_NAME=node1 WITH_NODEPORT=1 bash kubernetes/install.sh` |
|
| 组合:自建 + 指定节点 + NodePort | `LOCAL_STORAGE=force NODE_NAME=node1 WITH_NODEPORT=1 bash kubernetes/install.sh` |
|
||||||
|
|
||||||
**环境变量一览**:
|
**环境变量一览**:
|
||||||
@@ -51,7 +51,7 @@ WITH_NODEPORT=1 bash kubernetes/install.sh
|
|||||||
| `STORAGE_CLASS` | 空(自动探测)| 显式指定 StorageClass 名称 |
|
| `STORAGE_CLASS` | 空(自动探测)| 显式指定 StorageClass 名称 |
|
||||||
| `LOCAL_STORAGE` | `auto` | `auto` 无 SC 时自动建本地 PV / `off` 只诊断 / `force` 强制本地盘 |
|
| `LOCAL_STORAGE` | `auto` | `auto` 无 SC 时自动建本地 PV / `off` 只诊断 / `force` 强制本地盘 |
|
||||||
| `NODE_NAME` | 空(第一个 Ready 节点)| hostPath PV 绑定的节点 |
|
| `NODE_NAME` | 空(第一个 Ready 节点)| hostPath PV 绑定的节点 |
|
||||||
| `PV_PATH` | `/var/lib/opsxloki-data` | hostPath 在宿主机上的路径 |
|
| `PV_PATH` | `/var/lib/lokistack-data` | hostPath 在宿主机上的路径 |
|
||||||
| `PV_SIZE` | `30Gi` | PV 容量声明 |
|
| `PV_SIZE` | `30Gi` | PV 容量声明 |
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -95,13 +95,13 @@ WITH_NODEPORT=1 bash kubernetes/install.sh
|
|||||||
检测到集群完全没有 SC 时,脚本自动创建一个**静态 local PV**:
|
检测到集群完全没有 SC 时,脚本自动创建一个**静态 local PV**:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
StorageClass: opsxloki-local
|
StorageClass: lokistack-local
|
||||||
provisioner: kubernetes.io/no-provisioner
|
provisioner: kubernetes.io/no-provisioner
|
||||||
volumeBindingMode: WaitForFirstConsumer # 先定 Pod 再绑 PV
|
volumeBindingMode: WaitForFirstConsumer # 先定 Pod 再绑 PV
|
||||||
reclaimPolicy: Retain # 误删 PVC 不丢数据
|
reclaimPolicy: Retain # 误删 PVC 不丢数据
|
||||||
|
|
||||||
PersistentVolume: opsxloki-data-pv
|
PersistentVolume: lokistack-data-pv
|
||||||
hostPath: { path: /var/lib/opsxloki-data, type: DirectoryOrCreate }
|
hostPath: { path: /var/lib/lokistack-data, type: DirectoryOrCreate }
|
||||||
nodeAffinity: 锁定一台节点
|
nodeAffinity: 锁定一台节点
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ LOCAL_STORAGE=off bash kubernetes/install.sh
|
|||||||
| **Longhorn** | Helm,每节点装 | 需要副本/高可用 | 每节点约 1C2G 开销 |
|
| **Longhorn** | Helm,每节点装 | 需要副本/高可用 | 每节点约 1C2G 开销 |
|
||||||
| **NFS + nfs-subdir-provisioner** | 需现成 NFS 服务器 | 多节点共享 | 依赖外部 NFS |
|
| **NFS + nfs-subdir-provisioner** | 需现成 NFS 服务器 | 多节点共享 | 依赖外部 NFS |
|
||||||
|
|
||||||
> 对 opsx-loki 这类**单副本 + JSON DB 单写者**的应用,**local PV 完全够用**,
|
> 对 lokistack 这类**单副本 + JSON DB 单写者**的应用,**local PV 完全够用**,
|
||||||
> 不需要为了"高可用"上 Longhorn —— 副本存储反而会和"单写者"约束冲突。
|
> 不需要为了"高可用"上 Longhorn —— 副本存储反而会和"单写者"约束冲突。
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -155,12 +155,12 @@ LOCAL_STORAGE=off bash kubernetes/install.sh
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1) 找到 PV 绑定的节点和路径
|
# 1) 找到 PV 绑定的节点和路径
|
||||||
kubectl get pv opsxloki-data-pv -o custom-columns=\
|
kubectl get pv lokistack-data-pv -o custom-columns=\
|
||||||
'NAME:.metadata.name,PATH:.spec.hostPath.path,NODE:.spec.nodeAffinity.required.nodeSelectorTerms[0].matchExpressions[0].values[0]'
|
'NAME:.metadata.name,PATH:.spec.hostPath.path,NODE:.spec.nodeAffinity.required.nodeSelectorTerms[0].matchExpressions[0].values[0]'
|
||||||
|
|
||||||
# 2) 去那台节点上看
|
# 2) 去那台节点上看
|
||||||
NODE=<上面的 NODE 值>
|
NODE=<上面的 NODE 值>
|
||||||
ssh root@${NODE} 'ls -la /var/lib/opsxloki-data/'
|
ssh root@${NODE} 'ls -la /var/lib/lokistack-data/'
|
||||||
# 应看到:opsxloki.json kubeconfigs/ known_hosts
|
# 应看到:opsxloki.json kubeconfigs/ known_hosts
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -169,8 +169,8 @@ ssh root@${NODE} 'ls -la /var/lib/opsxloki-data/'
|
|||||||
```bash
|
```bash
|
||||||
NODE=<节点>
|
NODE=<节点>
|
||||||
TS=$(date +%Y%m%d-%H%M%S)
|
TS=$(date +%Y%m%d-%H%M%S)
|
||||||
ssh root@${NODE} "tar czf /tmp/opsxloki-backup-${TS}.tar.gz -C /var/lib opsxloki-data"
|
ssh root@${NODE} "tar czf /tmp/lokistack-backup-${TS}.tar.gz -C /var/lib lokistack-data"
|
||||||
scp root@${NODE}:/tmp/opsxloki-backup-${TS}.tar.gz ./
|
scp root@${NODE}:/tmp/lokistack-backup-${TS}.tar.gz ./
|
||||||
```
|
```
|
||||||
|
|
||||||
> `opsxloki.json` 写入是原子的(临时文件 + fsync + rename),**热备份安全**,不用停 Pod。
|
> `opsxloki.json` 写入是原子的(临时文件 + fsync + rename),**热备份安全**,不用停 Pod。
|
||||||
@@ -181,41 +181,41 @@ scp root@${NODE}:/tmp/opsxloki-backup-${TS}.tar.gz ./
|
|||||||
OLD=<旧节点> NEW=<新节点>
|
OLD=<旧节点> NEW=<新节点>
|
||||||
|
|
||||||
# 1) 停止写入
|
# 1) 停止写入
|
||||||
kubectl -n log scale deploy opsx-loki --replicas=0
|
kubectl -n log scale deploy lokistack --replicas=0
|
||||||
|
|
||||||
# 2) 从旧节点拉取数据
|
# 2) 从旧节点拉取数据
|
||||||
ssh root@${OLD} 'tar czf - -C /var/lib opsxloki-data' > /tmp/opsxloki-data.tar.gz
|
ssh root@${OLD} 'tar czf - -C /var/lib lokistack-data' > /tmp/lokistack-data.tar.gz
|
||||||
|
|
||||||
# 3) 推到新节点并解包
|
# 3) 推到新节点并解包
|
||||||
scp /tmp/opsxloki-data.tar.gz root@${NEW}:/tmp/
|
scp /tmp/lokistack-data.tar.gz root@${NEW}:/tmp/
|
||||||
ssh root@${NEW} 'mkdir -p /var/lib && tar xzf /tmp/opsxloki-data.tar.gz -C /var/lib && ls -la /var/lib/opsxloki-data'
|
ssh root@${NEW} 'mkdir -p /var/lib && tar xzf /tmp/lokistack-data.tar.gz -C /var/lib && ls -la /var/lib/lokistack-data'
|
||||||
|
|
||||||
# 4) 改 PV 的 nodeAffinity 指向新节点
|
# 4) 改 PV 的 nodeAffinity 指向新节点
|
||||||
kubectl patch pv opsxloki-data-pv --type=json -p \
|
kubectl patch pv lokistack-data-pv --type=json -p \
|
||||||
"[{\"op\":\"replace\",\"path\":\"/spec/nodeAffinity/required/nodeSelectorTerms/0/matchExpressions/0/values\",\"value\":[\"${NEW}\"]}]"
|
"[{\"op\":\"replace\",\"path\":\"/spec/nodeAffinity/required/nodeSelectorTerms/0/matchExpressions/0/values\",\"value\":[\"${NEW}\"]}]"
|
||||||
|
|
||||||
# 5) 恢复
|
# 5) 恢复
|
||||||
kubectl -n log scale deploy opsx-loki --replicas=1
|
kubectl -n log scale deploy lokistack --replicas=1
|
||||||
kubectl -n log rollout status deploy/opsx-loki
|
kubectl -n log rollout status deploy/lokistack
|
||||||
```
|
```
|
||||||
|
|
||||||
### 卸载但保留数据
|
### 卸载但保留数据
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 删工作负载和服务(数据卷保留)
|
# 删工作负载和服务(数据卷保留)
|
||||||
kubectl -n log delete deploy opsx-loki svc opsx-loki
|
kubectl -n log delete deploy lokistack svc lokistack
|
||||||
|
|
||||||
# PVC 保留(Retain 策略,删了也不会丢 PV 里的数据)
|
# PVC 保留(Retain 策略,删了也不会丢 PV 里的数据)
|
||||||
# 想彻底清掉的话:
|
# 想彻底清掉的话:
|
||||||
# kubectl delete pvc opsxloki-data
|
# kubectl delete pvc lokistack-data
|
||||||
# kubectl delete pv opsxloki-data-pv
|
# kubectl delete pv lokistack-data-pv
|
||||||
# 然后去节点上 rm -rf /var/lib/opsxloki-data
|
# 然后去节点上 rm -rf /var/lib/lokistack-data
|
||||||
|
|
||||||
# 如果要连脏数据一起重置重装:
|
# 如果要连脏数据一起重置重装:
|
||||||
kubectl -n log delete pvc opsxloki-data
|
kubectl -n log delete pvc lokistack-data
|
||||||
kubectl delete pv opsxloki-data-pv
|
kubectl delete pv lokistack-data-pv
|
||||||
kubectl delete sc opsxloki-local
|
kubectl delete sc lokistack-local
|
||||||
ssh root@${NODE} 'rm -rf /var/lib/opsxloki-data'
|
ssh root@${NODE} 'rm -rf /var/lib/lokistack-data'
|
||||||
# 然后重新 bash install.sh
|
# 然后重新 bash install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -238,7 +238,7 @@ kubernetes/
|
|||||||
├── namespace.yaml # log 命名空间
|
├── namespace.yaml # log 命名空间
|
||||||
├── pvc.yaml # 数据卷 30Gi(storageClassName 留空 → 用默认 SC)
|
├── pvc.yaml # 数据卷 30Gi(storageClassName 留空 → 用默认 SC)
|
||||||
├── deployment.yaml # 平台本体(单副本 + Recreate,必须)
|
├── deployment.yaml # 平台本体(单副本 + Recreate,必须)
|
||||||
├── service.yaml # ClusterIP opsx-loki:8080
|
├── service.yaml # ClusterIP lokistack:8080
|
||||||
├── service-nodeport.yaml # NodePort 30080(配 ingress 时用)
|
├── service-nodeport.yaml # NodePort 30080(配 ingress 时用)
|
||||||
└── examples/ # 云相关配置,不参与默认部署
|
└── examples/ # 云相关配置,不参与默认部署
|
||||||
├── ingress.yaml # 阿里云 ACK(alb class)
|
├── ingress.yaml # 阿里云 ACK(alb class)
|
||||||
@@ -260,7 +260,7 @@ kubectl apply -f kubernetes/namespace.yaml
|
|||||||
|
|
||||||
# 2) 密钥(⚠️ 必须先做,否则 Pod 起不来)
|
# 2) 密钥(⚠️ 必须先做,否则 Pod 起不来)
|
||||||
# 密钥只生成一次,丢失会导致已保存的凭证无法解密
|
# 密钥只生成一次,丢失会导致已保存的凭证无法解密
|
||||||
kubectl -n log create secret generic opsxloki-secrets \
|
kubectl -n log create secret generic lokistack-secrets \
|
||||||
--from-literal=JWT_SECRET="$(openssl rand -hex 32)" \
|
--from-literal=JWT_SECRET="$(openssl rand -hex 32)" \
|
||||||
--from-literal=ENCRYPTION_KEY="$(openssl rand -hex 32)"
|
--from-literal=ENCRYPTION_KEY="$(openssl rand -hex 32)"
|
||||||
|
|
||||||
@@ -270,7 +270,7 @@ kubectl apply -f kubernetes/deployment.yaml
|
|||||||
kubectl apply -f kubernetes/service.yaml
|
kubectl apply -f kubernetes/service.yaml
|
||||||
|
|
||||||
# 4) 等待就绪
|
# 4) 等待就绪
|
||||||
kubectl -n log rollout status deployment/opsx-loki --timeout=180s
|
kubectl -n log rollout status deployment/lokistack --timeout=180s
|
||||||
```
|
```
|
||||||
|
|
||||||
> ❗**不要直接 `kubectl apply -f kubernetes/`**:Secret 不在目录里(密钥不能进 Git),
|
> ❗**不要直接 `kubectl apply -f kubernetes/`**:Secret 不在目录里(密钥不能进 Git),
|
||||||
@@ -283,7 +283,7 @@ kubectl -n log rollout status deployment/opsx-loki --timeout=180s
|
|||||||
**临时(本地端口转发)**:
|
**临时(本地端口转发)**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl -n log port-forward svc/opsx-loki 8080:8080
|
kubectl -n log port-forward svc/lokistack 8080:8080
|
||||||
# 浏览器打开 http://localhost:8080
|
# 浏览器打开 http://localhost:8080
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -304,7 +304,7 @@ vi kubernetes/examples/ingress-tke.yaml # 改 host
|
|||||||
kubectl apply -f kubernetes/examples/ingress-tke.yaml
|
kubectl apply -f kubernetes/examples/ingress-tke.yaml
|
||||||
|
|
||||||
# 3) 查 CLB 分配的公网 IP,把域名解析过去
|
# 3) 查 CLB 分配的公网 IP,把域名解析过去
|
||||||
kubectl -n log get ingress opsx-loki
|
kubectl -n log get ingress lokistack
|
||||||
```
|
```
|
||||||
|
|
||||||
| 云 | ingressClassName | 备注 |
|
| 云 | ingressClassName | 备注 |
|
||||||
@@ -332,12 +332,12 @@ kubectl -n log get ingress opsx-loki
|
|||||||
apiVersion: snapshot.storage.k8s.io/v1
|
apiVersion: snapshot.storage.k8s.io/v1
|
||||||
kind: VolumeSnapshot
|
kind: VolumeSnapshot
|
||||||
metadata:
|
metadata:
|
||||||
name: opsxloki-data-20261025
|
name: lokistack-data-20261025
|
||||||
namespace: log
|
namespace: log
|
||||||
spec:
|
spec:
|
||||||
volumeSnapshotClassName: <集群的 snapshotClass>
|
volumeSnapshotClassName: <集群的 snapshotClass>
|
||||||
source:
|
source:
|
||||||
persistentVolumeClaimName: opsxloki-data
|
persistentVolumeClaimName: lokistack-data
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -383,7 +383,7 @@ spec:
|
|||||||
|
|
||||||
| 现象 | 原因 | 解决 |
|
| 现象 | 原因 | 解决 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| Pod `CreateContainerConfigError` | 缺 Secret `opsxloki-secrets` | 跑 `install.sh`,或手动 `kubectl create secret` |
|
| Pod `CreateContainerConfigError` | 缺 Secret `lokistack-secrets` | 跑 `install.sh`,或手动 `kubectl create secret` |
|
||||||
| Pod `Pending`,PVC `Pending` | 集群没有默认 StorageClass | `pvc.yaml` 里填 `storageClassName` |
|
| Pod `Pending`,PVC `Pending` | 集群没有默认 StorageClass | `pvc.yaml` 里填 `storageClassName` |
|
||||||
| Pod `ImagePullBackOff` | 节点拉不到 `lghost/lokistack:latest` | 换镜像地址(ACR/TCR/SWR/Harbor) |
|
| Pod `ImagePullBackOff` | 节点拉不到 `lghost/lokistack:latest` | 换镜像地址(ACR/TCR/SWR/Harbor) |
|
||||||
| `kubectl apply -f kubernetes/` 报 ingress 错误 | 误把 examples 里的 ingress 一起 apply 了 | 只 apply 根目录的 yaml,ingress 单独处理 |
|
| `kubectl apply -f kubernetes/` 报 ingress 错误 | 误把 examples 里的 ingress 一起 apply 了 | 只 apply 根目录的 yaml,ingress 单独处理 |
|
||||||
|
|||||||
+14
-14
@@ -1,4 +1,4 @@
|
|||||||
# opsx-loki 平台本体
|
# lokistack 平台本体
|
||||||
#
|
#
|
||||||
# 关键约束:
|
# 关键约束:
|
||||||
# 1) replicas 必须为 1:JSON DB 为单写者,多副本会互相覆盖。
|
# 1) replicas 必须为 1:JSON DB 为单写者,多副本会互相覆盖。
|
||||||
@@ -8,28 +8,28 @@
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: opsx-loki
|
name: lokistack
|
||||||
namespace: log
|
namespace: log
|
||||||
labels:
|
labels:
|
||||||
app: opsx-loki
|
app: lokistack
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
strategy:
|
strategy:
|
||||||
type: Recreate
|
type: Recreate
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: opsx-loki
|
app: lokistack
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: opsx-loki
|
app: lokistack
|
||||||
spec:
|
spec:
|
||||||
securityContext:
|
securityContext:
|
||||||
runAsUser: 1000
|
runAsUser: 1000
|
||||||
runAsGroup: 1000
|
runAsGroup: 1000
|
||||||
fsGroup: 1000
|
fsGroup: 1000
|
||||||
containers:
|
containers:
|
||||||
- name: opsx-loki
|
- name: lokistack
|
||||||
image: lghost/lokistack:latest
|
image: lghost/lokistack:latest
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
@@ -38,12 +38,12 @@ spec:
|
|||||||
env:
|
env:
|
||||||
# 可选:指定 admin 初始密码。不设置则自动生成 16 位随机密码,
|
# 可选:指定 admin 初始密码。不设置则自动生成 16 位随机密码,
|
||||||
# 写入 PVC 的 initial-admin-password.txt 并打印到首次启动日志。
|
# 写入 PVC 的 initial-admin-password.txt 并打印到首次启动日志。
|
||||||
# 获取: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
|
||||||
# 自定义:
|
# 自定义:
|
||||||
# - name: ADMIN_INIT_PASSWORD
|
# - name: ADMIN_INIT_PASSWORD
|
||||||
# valueFrom:
|
# valueFrom:
|
||||||
# secretKeyRef:
|
# secretKeyRef:
|
||||||
# name: opsxloki-secrets
|
# name: lokistack-secrets
|
||||||
# key: ADMIN_INIT_PASSWORD
|
# key: ADMIN_INIT_PASSWORD
|
||||||
# optional: true
|
# optional: true
|
||||||
- name: DATA_DIR
|
- name: DATA_DIR
|
||||||
@@ -51,22 +51,22 @@ spec:
|
|||||||
- name: JWT_SECRET
|
- name: JWT_SECRET
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: opsxloki-secrets
|
name: lokistack-secrets
|
||||||
key: JWT_SECRET
|
key: JWT_SECRET
|
||||||
- name: ENCRYPTION_KEY
|
- name: ENCRYPTION_KEY
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: opsxloki-secrets
|
name: lokistack-secrets
|
||||||
key: ENCRYPTION_KEY
|
key: ENCRYPTION_KEY
|
||||||
# 可选:挂载本地集群 kubeconfig 时启用
|
# 可选:挂载本地集群 kubeconfig 时启用
|
||||||
# - name: KUBECONFIG
|
# - name: KUBECONFIG
|
||||||
# value: /home/opsxloki/.kube/config
|
# value: /home/lokistack/.kube/config
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: data
|
- name: data
|
||||||
mountPath: /app/data
|
mountPath: /app/data
|
||||||
# 可选:本地集群 kubeconfig(in-cluster 管理本集群时用)
|
# 可选:本地集群 kubeconfig(in-cluster 管理本集群时用)
|
||||||
# - name: kubeconfig
|
# - name: kubeconfig
|
||||||
# mountPath: /home/opsxloki/.kube
|
# mountPath: /home/lokistack/.kube
|
||||||
# readOnly: true
|
# readOnly: true
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
@@ -91,7 +91,7 @@ spec:
|
|||||||
volumes:
|
volumes:
|
||||||
- name: data
|
- name: data
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: opsxloki-data
|
claimName: lokistack-data
|
||||||
# - name: kubeconfig
|
# - name: kubeconfig
|
||||||
# secret:
|
# secret:
|
||||||
# secretName: opsxloki-kubeconfig
|
# secretName: lokistack-kubeconfig
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
kind: Ingress
|
kind: Ingress
|
||||||
metadata:
|
metadata:
|
||||||
name: opsx-loki
|
name: lokistack
|
||||||
namespace: log
|
namespace: log
|
||||||
annotations:
|
annotations:
|
||||||
# CLB 健康检查(可选,TKE 默认会用 TCP 检查)
|
# CLB 健康检查(可选,TKE 默认会用 TCP 检查)
|
||||||
@@ -28,6 +28,6 @@ spec:
|
|||||||
pathType: Prefix
|
pathType: Prefix
|
||||||
backend:
|
backend:
|
||||||
service:
|
service:
|
||||||
name: opsx-loki-nodeport # ← 必须是 NodePort 类型 Service
|
name: lokistack-nodeport # ← 必须是 NodePort 类型 Service
|
||||||
port:
|
port:
|
||||||
number: 8080
|
number: 8080
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
kind: Ingress
|
kind: Ingress
|
||||||
metadata:
|
metadata:
|
||||||
name: opsx-loki
|
name: lokistack
|
||||||
namespace: log
|
namespace: log
|
||||||
annotations:
|
annotations:
|
||||||
# 阿里云 ALB 示例;其他云改成对应 ingressClass
|
# 阿里云 ALB 示例;其他云改成对应 ingressClass
|
||||||
@@ -12,13 +12,13 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
ingressClassName: alb
|
ingressClassName: alb
|
||||||
rules:
|
rules:
|
||||||
- host: opsx-loki.91ai.io
|
- host: lokistack.91ai.io
|
||||||
http:
|
http:
|
||||||
paths:
|
paths:
|
||||||
- path: /
|
- path: /
|
||||||
pathType: Prefix
|
pathType: Prefix
|
||||||
backend:
|
backend:
|
||||||
service:
|
service:
|
||||||
name: opsx-loki
|
name: lokistack
|
||||||
port:
|
port:
|
||||||
number: 8080
|
number: 8080
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
# 只做模板:不要提交真实密钥。
|
# 只做模板:不要提交真实密钥。
|
||||||
# 推荐直接用命令创建(避免密钥落盘到 Git):
|
# 推荐直接用命令创建(避免密钥落盘到 Git):
|
||||||
# kubectl -n log create secret generic opsxloki-secrets \
|
# kubectl -n log create secret generic lokistack-secrets \
|
||||||
# --from-literal=JWT_SECRET="$(openssl rand -hex 32)" \
|
# --from-literal=JWT_SECRET="$(openssl rand -hex 32)" \
|
||||||
# --from-literal=ENCRYPTION_KEY="$(openssl rand -hex 32)"
|
# --from-literal=ENCRYPTION_KEY="$(openssl rand -hex 32)"
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: opsxloki-secrets
|
name: lokistack-secrets
|
||||||
namespace: log
|
namespace: log
|
||||||
type: Opaque
|
type: Opaque
|
||||||
stringData:
|
stringData:
|
||||||
|
|||||||
+26
-26
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# opsx-loki 一键部署
|
# lokistack 一键部署
|
||||||
#
|
#
|
||||||
# 自动适配:阿里云 ACK / 腾讯云 TKE / AWS EKS / 华为云 CCE / GCP GKE / 自建 K8s
|
# 自动适配:阿里云 ACK / 腾讯云 TKE / AWS EKS / 华为云 CCE / GCP GKE / 自建 K8s
|
||||||
# 命名空间固定:log
|
# 命名空间固定:log
|
||||||
@@ -94,10 +94,10 @@ resolve_storage_class() {
|
|||||||
#
|
#
|
||||||
# 代价:数据固定在一台节点,节点损毁需从备份恢复(README 有 CSI 备份说明)
|
# 代价:数据固定在一台节点,节点损毁需从备份恢复(README 有 CSI 备份说明)
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
LOCAL_SC_NAME="opsxloki-local"
|
LOCAL_SC_NAME="lokistack-local"
|
||||||
LOCAL_PV_NAME="opsxloki-data-pv"
|
LOCAL_PV_NAME="lokistack-data-pv"
|
||||||
LOCAL_PV_SIZE="${PV_SIZE:-30Gi}"
|
LOCAL_PV_SIZE="${PV_SIZE:-30Gi}"
|
||||||
LOCAL_PV_PATH="${PV_PATH:-/var/lib/opsxloki-data}"
|
LOCAL_PV_PATH="${PV_PATH:-/var/lib/lokistack-data}"
|
||||||
|
|
||||||
pick_local_node() {
|
pick_local_node() {
|
||||||
if [ -n "${NODE_NAME:-}" ]; then echo "${NODE_NAME}"; return 0; fi
|
if [ -n "${NODE_NAME:-}" ]; then echo "${NODE_NAME}"; return 0; fi
|
||||||
@@ -129,7 +129,7 @@ kind: PersistentVolume
|
|||||||
metadata:
|
metadata:
|
||||||
name: ${LOCAL_PV_NAME}
|
name: ${LOCAL_PV_NAME}
|
||||||
labels:
|
labels:
|
||||||
app: opsx-loki
|
app: lokistack
|
||||||
spec:
|
spec:
|
||||||
capacity:
|
capacity:
|
||||||
storage: ${LOCAL_PV_SIZE}
|
storage: ${LOCAL_PV_SIZE}
|
||||||
@@ -157,7 +157,7 @@ EOF
|
|||||||
}
|
}
|
||||||
|
|
||||||
CLOUD="$(detect_cloud)"
|
CLOUD="$(detect_cloud)"
|
||||||
info "opsx-loki 部署开始(namespace: ${NS})"
|
info "lokistack 部署开始(namespace: ${NS})"
|
||||||
info "集群: $(kubectl config current-context 2>/dev/null || echo unknown)"
|
info "集群: $(kubectl config current-context 2>/dev/null || echo unknown)"
|
||||||
info "平台: ${CLOUD}"
|
info "平台: ${CLOUD}"
|
||||||
|
|
||||||
@@ -219,11 +219,11 @@ rand_hex() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
if kubectl -n "${NS}" get secret opsxloki-secrets >/dev/null 2>&1; then
|
if kubectl -n "${NS}" get secret lokistack-secrets >/dev/null 2>&1; then
|
||||||
info "Secret opsxloki-secrets 已存在,跳过(不覆盖现有密钥)"
|
info "Secret lokistack-secrets 已存在,跳过(不覆盖现有密钥)"
|
||||||
else
|
else
|
||||||
info "生成随机密钥 JWT_SECRET / ENCRYPTION_KEY"
|
info "生成随机密钥 JWT_SECRET / ENCRYPTION_KEY"
|
||||||
kubectl -n "${NS}" create secret generic opsxloki-secrets \
|
kubectl -n "${NS}" create secret generic lokistack-secrets \
|
||||||
--from-literal=JWT_SECRET="$(rand_hex)" \
|
--from-literal=JWT_SECRET="$(rand_hex)" \
|
||||||
--from-literal=ENCRYPTION_KEY="$(rand_hex)" >/dev/null
|
--from-literal=ENCRYPTION_KEY="$(rand_hex)" >/dev/null
|
||||||
ok "Secret 已创建"
|
ok "Secret 已创建"
|
||||||
@@ -256,33 +256,33 @@ fi
|
|||||||
# 5) 等待就绪(失败时给出按云定制的诊断)
|
# 5) 等待就绪(失败时给出按云定制的诊断)
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
info "等待 Deployment 就绪(最多 180 秒)..."
|
info "等待 Deployment 就绪(最多 180 秒)..."
|
||||||
if ! kubectl -n "${NS}" rollout status deployment/opsx-loki --timeout=180s; then
|
if ! kubectl -n "${NS}" rollout status deployment/lokistack --timeout=180s; then
|
||||||
echo ""
|
echo ""
|
||||||
warn "部署未在 180 秒内就绪,开始诊断:"
|
warn "部署未在 180 秒内就绪,开始诊断:"
|
||||||
echo ""
|
echo ""
|
||||||
kubectl -n "${NS}" get po -l app=opsx-loki -o wide 2>/dev/null | sed 's/^/ /'
|
kubectl -n "${NS}" get po -l app=lokistack -o wide 2>/dev/null | sed 's/^/ /'
|
||||||
|
|
||||||
REASON=$(kubectl -n "${NS}" get po -l app=opsx-loki -o jsonpath='{.items[0].status.containerStatuses[0].state.waiting.reason}' 2>/dev/null || true)
|
REASON=$(kubectl -n "${NS}" get po -l app=lokistack -o jsonpath='{.items[0].status.containerStatuses[0].state.waiting.reason}' 2>/dev/null || true)
|
||||||
echo ""
|
echo ""
|
||||||
case "${REASON}" in
|
case "${REASON}" in
|
||||||
ImagePullBackOff|ErrImagePull)
|
ImagePullBackOff|ErrImagePull)
|
||||||
warn "镜像拉取失败(${REASON})"
|
warn "镜像拉取失败(${REASON})"
|
||||||
echo " → 当前镜像: $(grep -E '^\s+image:' "${DIR}/deployment.yaml" | head -1 | awk '{print $2}')"
|
echo " → 当前镜像: $(grep -E '^\s+image:' "${DIR}/deployment.yaml" | head -1 | awk '{print $2}')"
|
||||||
echo " → 该节点拉不到 Docker Hub。请改为目标云可拉的仓库后重跑:"
|
echo " → 该节点拉不到 Docker Hub。请改为目标云可拉的仓库后重跑:"
|
||||||
echo " 腾讯云 TCR : ccr.ccs.tencentyun.com/<ns>/opsxloki:latest"
|
echo " 腾讯云 TCR : ccr.ccs.tencentyun.com/<ns>/lokistack:latest"
|
||||||
echo " 阿里云 ACR : registry.cn-hangzhou.aliyuncs.com/<ns>/opsxloki:latest"
|
echo " 阿里云 ACR : registry.cn-hangzhou.aliyuncs.com/<ns>/lokistack:latest"
|
||||||
echo " 华为云 SWR : swr.cn-north-4.myhuaweicloud.com/<ns>/opsxloki:latest"
|
echo " 华为云 SWR : swr.cn-north-4.myhuaweicloud.com/<ns>/lokistack:latest"
|
||||||
echo " 自建 Harbor: harbor.your.domain/library/opsxloki:latest"
|
echo " 自建 Harbor: harbor.your.domain/library/lokistack:latest"
|
||||||
;;
|
;;
|
||||||
CreateContainerConfigError)
|
CreateContainerConfigError)
|
||||||
warn "容器配置缺失(通常是 Secret 不存在)"
|
warn "容器配置缺失(通常是 Secret 不存在)"
|
||||||
echo " → 检查: kubectl -n ${NS} get secret opsxloki-secrets"
|
echo " → 检查: kubectl -n ${NS} get secret lokistack-secrets"
|
||||||
;;
|
;;
|
||||||
"")
|
"")
|
||||||
PVC_PHASE=$(kubectl -n "${NS}" get pvc opsxloki-data -o jsonpath='{.status.phase}' 2>/dev/null || echo unknown)
|
PVC_PHASE=$(kubectl -n "${NS}" get pvc lokistack-data -o jsonpath='{.status.phase}' 2>/dev/null || echo unknown)
|
||||||
if [ "${PVC_PHASE}" != "Bound" ]; then
|
if [ "${PVC_PHASE}" != "Bound" ]; then
|
||||||
warn "PVC 未绑定(phase=${PVC_PHASE})"
|
warn "PVC 未绑定(phase=${PVC_PHASE})"
|
||||||
echo " → 检查 StorageClass: kubectl -n ${NS} describe pvc opsxloki-data"
|
echo " → 检查 StorageClass: kubectl -n ${NS} describe pvc lokistack-data"
|
||||||
echo " → ${CLOUD} 建议的 SC:"
|
echo " → ${CLOUD} 建议的 SC:"
|
||||||
case "${CLOUD}" in
|
case "${CLOUD}" in
|
||||||
腾讯云*) echo " cbs" ;;
|
腾讯云*) echo " cbs" ;;
|
||||||
@@ -296,7 +296,7 @@ if ! kubectl -n "${NS}" rollout status deployment/opsx-loki --timeout=180s; then
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
kubectl -n "${NS}" describe po -l app=opsx-loki 2>/dev/null | tail -15 | sed 's/^/ /'
|
kubectl -n "${NS}" describe po -l app=lokistack 2>/dev/null | tail -15 | sed 's/^/ /'
|
||||||
die "部署未完成,请按上面提示处理"
|
die "部署未完成,请按上面提示处理"
|
||||||
fi
|
fi
|
||||||
ok "Deployment 已就绪"
|
ok "Deployment 已就绪"
|
||||||
@@ -304,24 +304,24 @@ ok "Deployment 已就绪"
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
# 6) 输出访问信息
|
# 6) 输出访问信息
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
POD=$(kubectl -n "${NS}" get po -l app=opsx-loki -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || echo "-")
|
POD=$(kubectl -n "${NS}" get po -l app=lokistack -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || echo "-")
|
||||||
POD_IP=$(kubectl -n "${NS}" get po -l app=opsx-loki -o jsonpath='{.items[0].status.podIP}' 2>/dev/null || echo "-")
|
POD_IP=$(kubectl -n "${NS}" get po -l app=lokistack -o jsonpath='{.items[0].status.podIP}' 2>/dev/null || echo "-")
|
||||||
NODE=$(kubectl -n "${NS}" get po -l app=opsx-loki -o jsonpath='{.items[0].spec.nodeName}' 2>/dev/null || echo "-")
|
NODE=$(kubectl -n "${NS}" get po -l app=lokistack -o jsonpath='{.items[0].spec.nodeName}' 2>/dev/null || echo "-")
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "════════════════════════════════════════════════════════"
|
echo "════════════════════════════════════════════════════════"
|
||||||
ok "opsx-loki 部署完成"
|
ok "lokistack 部署完成"
|
||||||
echo "════════════════════════════════════════════════════════"
|
echo "════════════════════════════════════════════════════════"
|
||||||
echo " 平台 : ${CLOUD}"
|
echo " 平台 : ${CLOUD}"
|
||||||
echo " Namespace : ${NS}"
|
echo " Namespace : ${NS}"
|
||||||
echo " 存储类 : ${RESOLVED_SC}"
|
echo " 存储类 : ${RESOLVED_SC}"
|
||||||
echo " Pod : ${POD} (node=${NODE} ip=${POD_IP})"
|
echo " Pod : ${POD} (node=${NODE} ip=${POD_IP})"
|
||||||
echo " Service : opsx-loki.${NS}.svc.cluster.local:8080"
|
echo " Service : lokistack.${NS}.svc.cluster.local:8080"
|
||||||
[ "${WITH_NODEPORT}" = "1" ] && echo " NodePort : <任意节点IP>:30080"
|
[ "${WITH_NODEPORT}" = "1" ] && echo " NodePort : <任意节点IP>:30080"
|
||||||
echo ""
|
echo ""
|
||||||
echo " 初始账号 : admin / admin123 ← 首次登录请立即改密"
|
echo " 初始账号 : admin / admin123 ← 首次登录请立即改密"
|
||||||
echo ""
|
echo ""
|
||||||
echo " 本地访问 : kubectl -n ${NS} port-forward svc/opsx-loki 8080:8080"
|
echo " 本地访问 : kubectl -n ${NS} port-forward svc/lokistack 8080:8080"
|
||||||
echo " 浏览器打开 http://localhost:8080"
|
echo " 浏览器打开 http://localhost:8080"
|
||||||
echo ""
|
echo ""
|
||||||
echo " 配 Ingress(可选,先跑 WITH_NODEPORT=1 bash install.sh):"
|
echo " 配 Ingress(可选,先跑 WITH_NODEPORT=1 bash install.sh):"
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: PersistentVolumeClaim
|
kind: PersistentVolumeClaim
|
||||||
metadata:
|
metadata:
|
||||||
name: opsxloki-data
|
name: lokistack-data
|
||||||
namespace: log
|
namespace: log
|
||||||
spec:
|
spec:
|
||||||
accessModes:
|
accessModes:
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: opsx-loki-nodeport
|
name: lokistack-nodeport
|
||||||
namespace: log
|
namespace: log
|
||||||
labels:
|
labels:
|
||||||
app: opsx-loki
|
app: lokistack
|
||||||
spec:
|
spec:
|
||||||
type: NodePort
|
type: NodePort
|
||||||
selector:
|
selector:
|
||||||
app: opsx-loki
|
app: lokistack
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
port: 8080
|
port: 8080
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: opsx-loki
|
name: lokistack
|
||||||
namespace: log
|
namespace: log
|
||||||
labels:
|
labels:
|
||||||
app: opsx-loki
|
app: lokistack
|
||||||
spec:
|
spec:
|
||||||
type: ClusterIP
|
type: ClusterIP
|
||||||
selector:
|
selector:
|
||||||
app: opsx-loki
|
app: lokistack
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
port: 8080
|
port: 8080
|
||||||
|
|||||||
Reference in new issue
Block a user