feat(install): 零输入一条命令部署 + 双架构发布包
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s

- docker compose up -d 直接启动:entrypoint 在未显式提供密钥时自动生成随机
  JWT_SECRET/ENCRYPTION_KEY 并持久化到数据卷 .secrets.env(0600,重启不变),
  显式环境变量优先(单显式不被持久化文件覆盖,四场景实测);compose 去掉 :? 强制
- build.sh --dist / make dist:linux amd64 + arm64 两个 tar.gz(二进制+docs+homepage+README),
  实测 15M/13M;安装文档重写为三方式(kubernetes/install.sh 一键、compose 一条命令、release 包)
- README 快速开始同步
This commit is contained in:
opsx committed 2026-10-29 15:50:50 +08:00
1 parent 437ff56992
commit 0936234623
6 files changed
+98 -26

No files matched your search

+3
View File
@@ -108,6 +108,9 @@ clean:
@echo "Cleanup complete."
# Linting
dist:
APP_VERSION=$$(git describe --tags --abbrev=0 2>/dev/null || echo dev) bash build.sh --dist
lint:
@echo "Validating Dockerfile..."
@docker run --rm -i hadolint/hadolint < Dockerfile 2>/dev/null || echo "hadolint not available, install from: https://github.com/hadolint/hadolint"
+3 -3
View File
@@ -28,15 +28,15 @@
> 镜像内置全部依赖(Kubernetes 操作走 client-go 直连 API Server),宿主机**无需**安装 `kubectl` / `helm`。
### 1. 生成密钥并启动
### 1. 一条命令启动
```bash
export JWT_SECRET=$(openssl rand -hex 32) # >= 32 字符
export ENCRYPTION_KEY=$(openssl rand -hex 32) # >= 32 字节
docker compose up -d
docker compose ps # 等待 healthy
```
未显式提供密钥时容器自动生成随机 `JWT_SECRET` / `ENCRYPTION_KEY` 并持久化到数据卷(`$DATA_DIR/.secrets.env`),重启不变;生产环境可显式指定或使用 `docker-compose.prod.yml` 密钥文件。
未设置这两个变量时容器会**拒绝启动**,避免不安全的默认部署。
打开 `http://localhost:8080`,管理员初始密码见下一步。
+29
View File
@@ -15,6 +15,33 @@
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# ---- 可选:dist 双架构发布包(linux amd64 + arm64):bash build.sh --dist ----
if [ "${1:-}" = "--dist" ]; then
GO_CMD="go"
BUILD_TIME="$(date -u '+%Y-%m-%d_%H:%M:%S')"
GIT_COMMIT="$(git -C "$SCRIPT_DIR" rev-parse --short HEAD 2>/dev/null || echo unknown)"
APP_VERSION="${APP_VERSION:-dev}"
DIST_DIR="dist"
cd "$SCRIPT_DIR"
rm -rf "$DIST_DIR" && mkdir -p "$DIST_DIR"
for ARCH in amd64 arm64; do
NAME="lokistack-linux-${ARCH}"
echo "==> Building ${NAME}..."
rm -rf "/tmp/${NAME}" && mkdir -p "/tmp/${NAME}"
(cd "$SCRIPT_DIR/backend" && CGO_ENABLED=0 GOOS=linux GOARCH=$ARCH $GO_CMD build -trimpath \
-ldflags="-s -w -X main.version=${APP_VERSION:-dev} -X main.buildTime=${BUILD_TIME} -X main.gitCommit=${GIT_COMMIT}" \
-o "/tmp/${NAME}/lokistack" .)
cp -r docs "/tmp/${NAME}/docs"
cp -r homepage "/tmp/${NAME}/homepage"
cp README.md "/tmp/${NAME}/README.md"
tar -czf "${DIST_DIR}/${NAME}.tar.gz" -C /tmp "${NAME}"
echo " ${DIST_DIR}/${NAME}.tar.gz ($(du -h ${DIST_DIR}/${NAME}.tar.gz | cut -f1))"
done
echo "==> dist 完成: ${DIST_DIR}/lokistack-linux-{amd64,arm64}.tar.gz"
exit 0
fi
echo "========================================"
echo " lokistack Build Script"
echo " Security-hardened build pipeline"
@@ -113,6 +140,8 @@ echo " Binary size: $(du -h bin/lokistack | cut -f1)"
echo " Build time: $BUILD_TIME"
echo " Git commit: $GIT_COMMIT"
# ---- 3. Copy dist to backend for embedded serving ----
echo ""
echo "[3/3] Packaging..."
+4 -6
View File
@@ -53,12 +53,10 @@ services:
environment:
- SERVER_PORT=8080
- DATA_DIR=/app/data
# P0: JWT_SECRET must be provided externally
# Set via .env file or shell export before running docker compose up.
# 注意:错误提示里不要内嵌 $(openssl ...),否则会在 compose 解析时被执行。
- "JWT_SECRET=${JWT_SECRET:?JWT_SECRET is required. Generate: openssl rand -hex 32, then: export JWT_SECRET=<value>}"
# 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>}"
# 密钥零输入启动:不设置时 entrypoint 自动生成随机密钥并持久化到数据卷
# ($DATA_DIR/.secrets.env);需要固定密钥时在 .env / 环境变量里显式提供。
- "JWT_SECRET=${JWT_SECRET:-}"
- "ENCRYPTION_KEY=${ENCRYPTION_KEY:-}"
# KUBECONFIG points to non-root user's .kube directory
- KUBECONFIG=/home/lokistack/.kube/config
+37
View File
@@ -20,6 +20,43 @@ if [ -n "${ENCRYPTION_KEY_FILE:-}" ] && [ -r "$ENCRYPTION_KEY_FILE" ]; then
export ENCRYPTION_KEY
fi
# ---- 零输入启动:未显式提供密钥时自动生成并持久化到数据卷 ----
# docker compose up -d 即可启动;生成的密钥保存在 $DATA_DIR/.secrets.env
# (0600),重启/升级不变。需要固定密钥或接入密钥管理时,显式设置环境变量即可覆盖。
AUTO_SECRETS_FILE="${DATA_DIR:-/app/data}/.secrets.env"
if [ -z "${JWT_SECRET:-}" ] || [ -z "${ENCRYPTION_KEY:-}" ]; then
# 先保存显式传入的值:source 持久化文件时不能覆盖用户显式配置
EXPLICIT_JWT="${JWT_SECRET:-}"
EXPLICIT_ENC="${ENCRYPTION_KEY:-}"
if [ -r "$AUTO_SECRETS_FILE" ]; then
# shellcheck disable=SC1090
. "$AUTO_SECRETS_FILE"
fi
[ -n "$EXPLICIT_JWT" ] && JWT_SECRET="$EXPLICIT_JWT"
[ -n "$EXPLICIT_ENC" ] && ENCRYPTION_KEY="$EXPLICIT_ENC"
CHANGED=0
gen_secret() { head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n'; }
if [ -z "${JWT_SECRET:-}" ]; then
JWT_SECRET="$(gen_secret)"
CHANGED=1
echo "==> JWT_SECRET not provided; generated and persisted to $AUTO_SECRETS_FILE"
fi
if [ -z "${ENCRYPTION_KEY:-}" ]; then
ENCRYPTION_KEY="$(gen_secret)"
CHANGED=1
echo "==> ENCRYPTION_KEY not provided; generated and persisted to $AUTO_SECRETS_FILE"
fi
export JWT_SECRET ENCRYPTION_KEY
if [ "$CHANGED" = "1" ]; then
umask 077
{
echo "# Auto-generated by lokistack entrypoint. Remove to regenerate."
echo "JWT_SECRET=$JWT_SECRET"
echo "ENCRYPTION_KEY=$ENCRYPTION_KEY"
} > "$AUTO_SECRETS_FILE"
fi
fi
# ---- Runtime security validation ----
MISSING_VARS=()
+22 -17
View File
@@ -1,44 +1,49 @@
# 安装与启动
LokiStack 面向 Linux 服务器交付:单二进制(内嵌前端、文档与落地页),或 Docker / Kubernetes 一键部署。按环境三选一。
## 环境要求
- 平台自身:任意 Linux / macOS(Go 1.24 构建或直接使用发布二进制),内存 ≥ 256MB
- 目标 Kubernetes 集群:≥ 1.20;或裸金属 Linux 主机(SSH 可达)
- 端口:平台默认 8080;Loki 默认 3100
- 平台自身:Linux x86_64 或 arm64,内存 ≥ 256MB
- 目标 Kubernetes 集群 ≥ 1.20;或裸金属 Linux 主机(SSH 可达)
## 必备环境变量
平台启动强制要求两个密钥(长度均需 ≥ 32 字符):
## 方式一:Kubernetes 一键部署
```bash
export JWT_SECRET=$(openssl rand -hex 32)
export ENCRYPTION_KEY=$(openssl rand -hex 32) # 凭证加密密钥,丢失将无法解密已存凭证
bash kubernetes/install.sh
```
## 方式一:开发模式
自动适配阿里云 ACK / 腾讯云 TKE / AWS EKS / 华为云 CCE / GCP GKE / 自建集群,部署到 `log` 命名空间,幂等可重复执行。常用变量:
```bash
./run.sh # 同时拉起前端(:3000)与后端(:8080),自动注入开发密钥
WITH_NODEPORT=1 bash kubernetes/install.sh # 同时开 NodePort(配合 Ingress)
STORAGE_CLASS=local-path bash kubernetes/install.sh # 手动指定 StorageClass
```
## 方式二:生产 Docker
## 方式二:Docker
```bash
make secrets # 生成 ./secrets/*.txt
docker compose -f docker-compose.prod.yml up -d
docker compose up -d
```
一条命令即可启动:未显式提供 `JWT_SECRET` / `ENCRYPTION_KEY` 时,容器自动生成随机密钥并持久化到数据卷(`$DATA_DIR/.secrets.env`,权限 0600),重启与升级保持不变。需要固定密钥或接入自有密钥管理时,再通过环境变量显式提供即可覆盖。
## 方式三:单二进制
从 Release 下载对应架构的包(Linux x86_64 / arm64):
```bash
bash build.sh # 产物 backend/bin/lokistack(前端已内嵌)
export JWT_SECRET=... ENCRYPTION_KEY=... DATA_DIR=/data
curl -LO https://gitea.91ai.io/rlwj-lab/LokiStack/releases/download/v2.0.0/lokistack-linux-amd64.tar.gz
tar xzf lokistack-linux-amd64.tar.gz && cd lokistack-linux-amd64
export DATA_DIR=/data # 密钥未设置时启动会自动生成并持久化到 $DATA_DIR/.secrets.env
./lokistack
```
首次启动会自动创建管理员账号,初始密码写入 `$DATA_DIR/initial-admin-password.txt`,请立即修改。
包内含二进制、用户手册(`/docs`)与落地页(`/homepage`),无需其它依赖;arm64 服务器换 `lokistack-linux-arm64.tar.gz`。
首次启动自动创建管理员账号,初始密码写入 `$DATA_DIR/initial-admin-password.txt`,请立即修改。
## 数据与升级
- 全部状态存储在 `$DATA_DIR/lokistack.json`(JSON 文件,无外部数据库依赖,单实例运行)
- 升级:替换二进制后重启即可;历史命名数据文件(opsxloki.json / lokideploy.json)会在启动时自动迁移
- 升级:替换二进制(或重新拉取镜像)后重启;历史命名数据文件会在启动时自动迁移