feat: 新增 Docker 缓存清理独立脚本

- 新增 docker-cache-cleanup.sh:支持多种清理模式(默认/激进/保守/完全)
- 自动检测运行环境:通过 curl ip.sb 获取公网 IP 匹配服务器列表
- 清理内容:dangling 镜像、测试镜像、构建缓存
- deploy-ai.sh 改为调用独立清理脚本
- 更新 README.md 和 deploy-ai-readme.md 文档
- sites-manage-local.sh 新增 gitea 站点支持(端口 6182)
This commit is contained in:
aiyimickey 2026-07-08 16:58:58 +08:00
parent cb9fc42097
commit eb6182f222
5 changed files with 306 additions and 67 deletions

View File

@ -15,6 +15,7 @@
| `deploy-monitor.sh` | 独立部署 monitor-ai 告警监控 | 云端 | | `deploy-monitor.sh` | 独立部署 monitor-ai 告警监控 | 云端 |
| `edit-site-cc.sh` | www.tlyq.cc 官网内容管理 | 云端 | | `edit-site-cc.sh` | www.tlyq.cc 官网内容管理 | 云端 |
| `check-compliance.sh` | D1-D8 合规检查LESSONS-LEARNED 自动化) | 本地 | | `check-compliance.sh` | D1-D8 合规检查LESSONS-LEARNED 自动化) | 本地 |
| `docker-cache-cleanup.sh` | Docker 缓存清理(构建缓存、悬空镜像、测试镜像) | 本地/云端 |
### 备份与恢复(`backup/` 目录) ### 备份与恢复(`backup/` 目录)
@ -101,6 +102,40 @@ bash scripts/backup/restore.sh --local --full ... # 本地灾难恢复(新服
> 详细文档见 [backup/README.md](backup/README.md) > 详细文档见 [backup/README.md](backup/README.md)
## docker-cache-cleanup.sh — Docker 缓存清理
自动检测运行环境:通过 `curl ip.sb` 获取当前公网 IP与生产环境服务器 IP 列表匹配。
- 在生产服务器上运行:直接执行 Docker 命令
- 在本地运行:通过 SSH 连接服务器执行
```bash
bash scripts/docker-cache-cleanup.sh # 默认:保留 3 小时内的缓存
bash scripts/docker-cache-cleanup.sh --aggressive # 激进:保留 1 小时内
bash scripts/docker-cache-cleanup.sh --conservative # 保守:保留 6 小时内
bash scripts/docker-cache-cleanup.sh --full # 完全:删除所有缓存
```
清理内容:
- **dangling 镜像**:无标签或未被引用的中间层
- **测试镜像**:以 `test-` 开头的镜像
- **构建缓存**:根据模式保留不同时长
- **磁盘紧张处理**:使用率 > 85% 时自动深度清理
配置:在脚本开头的 `PRODUCTION_SERVER_IPS` 数组中添加/删除服务器 IP。
```bash
PRODUCTION_SERVER_IPS=(
"43.133.38.210" # txjp (腾讯云北京)
# "159.75.83.209" # tgz (腾讯云广州)
)
```
定时清理(可选):
```bash
# 每天凌晨 3 点执行保守清理
ssh txjp "crontab -l 2>/dev/null; echo '0 3 * * * /root/docker/scripts/docker-cache-cleanup.sh --conservative' | crontab -"
```
## 备份存储路径 ## 备份存储路径
| 位置 | 路径 | | 位置 | 路径 |

View File

@ -43,7 +43,7 @@ bash scripts/deploy-ai.sh [选项]
5. **依赖安装**:服务器 `npm install --prefer-offline` 5. **依赖安装**:服务器 `npm install --prefer-offline`
6. **环境变量**:写入生产环境所需的环境变量到 `.env` 6. **环境变量**:写入生产环境所需的环境变量到 `.env`
7. **构建**:服务器 `npm run build` 7. **构建**:服务器 `npm run build`
8. **清理**:删除 Alpine musl 残留sharp、swc 8. **清理**:删除 Alpine musl 残留sharp、swc,清理 Docker 构建缓存(调用 `docker-cache-cleanup.sh`
9. **重启容器**`docker compose up -d` + `docker compose restart` 9. **重启容器**`docker compose up -d` + `docker compose restart`
10. **快照保存**:保存本次源码 MD5 用于下次比对 10. **快照保存**:保存本次源码 MD5 用于下次比对

View File

@ -16,6 +16,11 @@
# 不使用 set -e改用显式错误处理避免管道命令导致意外退出 # 不使用 set -e改用显式错误处理避免管道命令导致意外退出
# ============================================================
# 脚本目录
# ============================================================
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# ============================================================ # ============================================================
# 颜色和日志 # 颜色和日志
# ============================================================ # ============================================================
@ -684,28 +689,9 @@ EOF
echo 'shared 符号链接已恢复' echo 'shared 符号链接已恢复'
fi" fi"
# 7. 清理构建产生的悬空镜像和缓存(根据磁盘使用率动态调整 # 7. 清理构建产生的悬空镜像和缓存(调用独立清理脚本
log "清理构建缓存..." log "清理构建缓存..."
# 清理悬空镜像(无标签或未被引用的中间层) bash "${SCRIPT_DIR}/docker-cache-cleanup.sh" --default
ssh txjp "docker image prune -f 2>/dev/null" || warn "docker image prune 失败"
# 根据磁盘使用率动态调整构建缓存清理策略
DISK_USAGE=$(ssh txjp "df / --output=pcent | tail -1 | tr -d ' %'" 2>/dev/null || echo "50")
if [ "$DISK_USAGE" -gt 95 ]; then
warn "磁盘使用率 ${DISK_USAGE}%,执行紧急清理"
ssh txjp "docker builder prune -f 2>/dev/null || true"
# 截断容器日志(占磁盘大户)
ssh txjp "truncate -s 0 /var/lib/docker/containers/\$(docker inspect --format '{{.Id}}' ${CONTAINER} 2>/dev/null)/\*-json.log 2>/dev/null || true"
elif [ "$DISK_USAGE" -gt 85 ]; then
info "磁盘使用率 ${DISK_USAGE}%执行激进清理6小时"
ssh txjp "docker builder prune -f --filter 'until=6h' 2>/dev/null || true"
elif [ "$DISK_USAGE" -gt 70 ]; then
info "磁盘使用率 ${DISK_USAGE}%执行正常清理24小时"
ssh txjp "docker builder prune -f --filter 'until=24h' 2>/dev/null || true"
else
info "磁盘使用率 ${DISK_USAGE}%执行保守清理48小时"
ssh txjp "docker builder prune -f --filter 'until=48h' 2>/dev/null || true"
fi
# 8. 保存快照 # 8. 保存快照
ssh txjp "mkdir -p ${SNAPSHOT_DIR} && echo '$local_md5' > ${SNAPSHOT_FILE}" ssh txjp "mkdir -p ${SNAPSHOT_DIR} && echo '$local_md5' > ${SNAPSHOT_FILE}"

200
docker-cache-cleanup.sh Executable file
View File

@ -0,0 +1,200 @@
#!/bin/bash
# Docker 缓存清理脚本
# 用法:
# ./docker-cache-cleanup.sh # 默认清理(保留 3 小时内的缓存)
# ./docker-cache-cleanup.sh --aggressive # 激进清理(保留 1 小时内)
# ./docker-cache-cleanup.sh --conservative # 保守清理(保留 6 小时内)
# ./docker-cache-cleanup.sh --full # 完全清理(删除所有缓存)
set -euo pipefail
# ============================================================
# 配置
# ============================================================
REMOTE_HOST="${REMOTE_HOST:-txjp}"
CLEANUP_MODE="${1:---default}"
RETENTION_HOURS=3 # 默认保留 3 小时
# 生产环境服务器 IP 列表(用于判断是否在服务器本地运行)
# 新增服务器时,只需在此添加 IP 地址即可
PRODUCTION_SERVER_IPS=(
"43.133.38.210" # txjp (腾讯云北京)
# "159.75.83.209" # tgz (腾讯云广州) - 如需添加
# "10.0.0.1" # 其他服务器 - 如需添加
)
# 检测运行环境:
# 通过 curl ip.sb 获取当前公网 IP与生产环境服务器 IP 列表匹配
IS_LOCAL=false
# 获取当前公网 IP
CURRENT_IP=$(curl -s --connect-timeout 5 ip.sb 2>/dev/null || echo "")
if [ -n "$CURRENT_IP" ]; then
# 遍历生产环境服务器 IP 列表,检查是否匹配
for SERVER_IP in "${PRODUCTION_SERVER_IPS[@]}"; do
if [ "$CURRENT_IP" = "$SERVER_IP" ]; then
IS_LOCAL=true
break
fi
done
fi
# 如果是本地运行,不需要 SSH
if [ "$IS_LOCAL" = true ]; then
REMOTE_HOST=""
fi
# 颜色
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# ============================================================
# 日志函数
# ============================================================
log() { echo -e "${GREEN}[$(date '+%H:%M:%S')]${NC} $*"; }
warn() { echo -e "${YELLOW}[$(date '+%H:%M:%S')] WARNING:${NC} $*"; }
error() { echo -e "${RED}[$(date '+%H:%M:%S')] ERROR:${NC} $*" >&2; }
# ============================================================
# 清理模式设置
# ============================================================
case "$CLEANUP_MODE" in
--aggressive)
RETENTION_HOURS=1
log "激进清理模式:保留 ${RETENTION_HOURS} 小时内的缓存"
;;
--conservative)
RETENTION_HOURS=6
log "保守清理模式:保留 ${RETENTION_HOURS} 小时内的缓存"
;;
--full)
log "完全清理模式:删除所有缓存"
RETENTION_HOURS=0
;;
*)
log "默认清理模式:保留 ${RETENTION_HOURS} 小时内的缓存"
;;
esac
# ============================================================
# 辅助函数
# ============================================================
# 执行命令(根据是否本地决定是否使用 SSH
run_cmd() {
if [ "$IS_LOCAL" = true ]; then
eval "$@"
else
ssh "$REMOTE_HOST" "$@"
fi
}
# 获取磁盘使用率
get_disk_usage() {
run_cmd "df / --output=pcent | tail -1 | tr -d ' %'" 2>/dev/null || echo "0"
}
# 获取构建缓存大小
get_cache_size() {
run_cmd "docker system df --format '{{.Size}}' 2>/dev/null | head -1" || echo "0"
}
# 获取镜像数量
get_image_count() {
run_cmd "docker images -q 2>/dev/null | wc -l" || echo "0"
}
# ============================================================
# 清理函数
# ============================================================
# 清理 dangling 镜像(无标签或未被引用的中间层)
cleanup_dangling_images() {
log "清理 dangling 镜像..."
run_cmd "docker image prune -f 2>/dev/null" || warn "docker image prune 失败"
}
# 清理测试镜像(以 test- 开头的镜像)
cleanup_test_images() {
log "清理测试镜像..."
local test_images=$(run_cmd "docker images --format '{{.Repository}}:{{.Tag}}' | grep -E '^test-' 2>/dev/null" || true)
if [ -n "$test_images" ]; then
echo "$test_images" | while read -r img; do
log " 删除: $img"
done
run_cmd "docker images --format '{{.Repository}}:{{.Tag}}' | grep -E '^test-' | xargs -r docker rmi -f 2>/dev/null" || true
else
log " 无测试镜像"
fi
}
# 清理构建缓存
cleanup_build_cache() {
if [ "$RETENTION_HOURS" -eq 0 ]; then
log "清理所有构建缓存..."
run_cmd "docker builder prune -af 2>/dev/null" || warn "docker builder prune 失败"
else
log "清理 ${RETENTION_HOURS} 小时前的构建缓存..."
run_cmd "docker builder prune -f --filter 'until=${RETENTION_HOURS}h' 2>/dev/null" || warn "docker builder prune 失败"
fi
}
# 根据磁盘使用率决定是否需要深度清理
cleanup_by_disk_usage() {
local DISK_USAGE=$(get_disk_usage)
log "当前磁盘使用率: ${DISK_USAGE}%"
if [ "$DISK_USAGE" -gt 85 ]; then
warn "磁盘使用率 ${DISK_USAGE}% > 85%,执行深度清理"
# 清理所有构建缓存
run_cmd "docker builder prune -af 2>/dev/null" || true
# 清理容器日志
log "截断容器日志..."
run_cmd "truncate -s 0 /var/lib/docker/containers/\$(docker ps -q)/\*-json.log 2>/dev/null" || true
elif [ "$DISK_USAGE" -gt 75 ]; then
cleanup_build_cache
else
log "磁盘使用率正常,仅执行常规清理"
cleanup_build_cache
fi
}
# ============================================================
# 打印清理结果
# ============================================================
print_result() {
local DISK_AFTER=$(get_disk_usage)
local CACHE_AFTER=$(get_cache_size)
local IMAGE_AFTER=$(get_image_count)
echo ""
log "========== 清理完成 =========="
log "磁盘使用率: ${DISK_AFTER}%"
log "构建缓存大小: ${CACHE_AFTER}"
log "镜像数量: ${IMAGE_AFTER}"
}
# ============================================================
# 主函数
# ============================================================
main() {
local DISK_BEFORE=$(get_disk_usage)
local CACHE_BEFORE=$(get_cache_size)
local IMAGE_BEFORE=$(get_image_count)
echo ""
log "========== Docker 缓存清理 =========="
log "清理前 - 磁盘使用率: ${DISK_BEFORE}%, 缓存大小: ${CACHE_BEFORE}, 镜像数量: ${IMAGE_BEFORE}"
echo ""
# 执行清理
cleanup_dangling_images
cleanup_test_images
cleanup_by_disk_usage
# 打印结果
print_result
}
# 执行主函数
main "$@"

View File

@ -38,10 +38,9 @@ MONITOR_PORT=6181
WWW_CC_PORT=5173 WWW_CC_PORT=5173
CLOUD_CC_PORT=5174 CLOUD_CC_PORT=5174
TOKEN_CC_PORT=5175 TOKEN_CC_PORT=5175
GITEA_PORT=3000 GITEA_PORT=6182
is_port() { lsof -i :"$1" >/dev/null 2>&1; } is_port() { lsof -i :"$1" >/dev/null 2>&1; }
is_running() { docker ps --format '{{.Names}}' 2>/dev/null | grep -q "^$1$"; }
# 检查 Docker 服务是否运行 # 检查 Docker 服务是否运行
check_docker() { check_docker() {
@ -56,16 +55,21 @@ check_docker() {
# ============================================================ # ============================================================
docker_start() { docker_start() {
local name=$1 dir=$2 local name=$1 dir=$2
if is_running $name; then if [ "$(cd "$dir" && docker compose ps -q --status running 2>/dev/null)" ]; then
warn "$name 已在运行" warn "$name 已在运行"
else else
log "启动 $name..." log "启动 $name..."
cd "$dir" && docker compose up -d 2>/dev/null && log "$name 已启动" || err "$name 启动失败" cd "$dir" && docker compose up -d 2>/dev/null || { err "$name 启动失败"; return 1; }
for i in $(seq 1 30); do
[ "$(cd "$dir" && docker compose ps -q --status running 2>/dev/null)" ] && { log "$name 已启动"; return 0; }
sleep 1
done
err "$name 启动异常(可能处于重启循环,请检查 docker compose logs"
fi fi
} }
docker_stop() { docker_stop() {
local name=$1 dir=$2 local name=$1 dir=$2
if is_running $name; then if [ "$(cd "$dir" && docker compose ps -q --status running --status restarting 2>/dev/null)" ]; then
log "停止 $name..." log "停止 $name..."
cd "$dir" && docker compose down 2>/dev/null && log "$name 已停止" || err "$name 停止失败" cd "$dir" && docker compose down 2>/dev/null && log "$name 已停止" || err "$name 停止失败"
else else
@ -102,28 +106,28 @@ node_stop() {
start_all() { start_all() {
for name in "$@"; do for name in "$@"; do
case $name in case $name in
www-cc) docker_start www-local "$BASE_DIR/www-cc" ;; www-cc) docker_start www-cc "$BASE_DIR/cc-site/www-cc" ;;
cloud-cc) docker_start cloud-cc "$BASE_DIR/cloud-cc" ;; cloud-cc) docker_start cloud-cc "$BASE_DIR/cc-site/cloud-cc" ;;
token-cc) docker_start token-cc "$BASE_DIR/token-cc" ;; token-cc) docker_start token-cc "$BASE_DIR/cc-site/token-cc" ;;
www-ai) docker_start www-local-ai "$BASE_DIR/www-ai" ;; www-ai) docker_start www-ai "$BASE_DIR/www-ai" ;;
cloud-ai) docker_start cloud-ai "$BASE_DIR/cloud-ai" ;; cloud-ai) docker_start cloud-ai "$BASE_DIR/cloud-ai" ;;
token-ai) docker_start token-ai "$BASE_DIR/token-ai" ;; token-ai) docker_start token-ai "$BASE_DIR/token-ai" ;;
issue) node_start issue-ai "$ISSUE_DIR" $ISSUE_PORT "/tmp/issue-ai-dev.log" issue) node_start issue "$ISSUE_DIR" $ISSUE_PORT "/tmp/issue-ai-dev.log"
if ! is_port $ASSETS_PORT; then if ! is_port $ASSETS_PORT; then
node_start assets-ai "$ASSETS_DIR" $ASSETS_PORT "/tmp/assets-ai-dev.log" node_start assets "$ASSETS_DIR" $ASSETS_PORT "/tmp/assets-ai-dev.log"
warn "已自动启动 assets-aiissue 依赖 assets API" warn "已自动启动 assets-aiissue 依赖 assets API"
fi ;; fi ;;
assets) node_start assets-ai "$ASSETS_DIR" $ASSETS_PORT "/tmp/assets-ai-dev.log" ;; assets) node_start assets "$ASSETS_DIR" $ASSETS_PORT "/tmp/assets-ai-dev.log" ;;
ldap) docker_start lldap "$LDAP_DIR" ldap) docker_start ldap "$LDAP_DIR"
if is_port $LDAP_WEB_PORT; then if is_port $LDAP_WEB_PORT; then
log "LLDAP Web UI: http://127.0.0.1:$LDAP_WEB_PORT" log "LLDAP Web UI: http://127.0.0.1:$LDAP_WEB_PORT"
fi ;; fi ;;
oa) node_start oa-ai "$OA_DIR" $OA_PORT "/tmp/oa-ai-dev.log" ;; oa) node_start oa "$OA_DIR" $OA_PORT "/tmp/oa-ai-dev.log" ;;
sso) docker_start authelia "$SSO_DIR" ;; sso) docker_start sso "$SSO_DIR" ;;
gitea) docker_start gitea-ai "$GITEA_DIR" ;; gitea) docker_start gitea "$GITEA_DIR" ;;
monitor) node_start monitor-ai "$MONITOR_DIR" $MONITOR_PORT "/tmp/monitor-ai-dev.log" ;; monitor) node_start monitor "$MONITOR_DIR" $MONITOR_PORT "/tmp/monitor-ai-dev.log" ;;
cc) start_all www-cc cloud-cc token-cc ;; cc) start_all www-cc cloud-cc token-cc ;;
ai) start_all ldap www-ai cloud-ai token-ai issue assets oa sso gitea monitor ;; ai) start_all www-ai cloud-ai token-ai issue assets ldap oa sso monitor gitea ;;
all) start_all cc ai ;; all) start_all cc ai ;;
*) err "未知站点: $name" ;; *) err "未知站点: $name" ;;
esac esac
@ -133,21 +137,21 @@ start_all() {
stop_all() { stop_all() {
for name in "$@"; do for name in "$@"; do
case $name in case $name in
www-cc) docker_stop www-local "$BASE_DIR/www-cc" ;; www-cc) docker_stop www-cc "$BASE_DIR/cc-site/www-cc" ;;
cloud-cc) docker_stop cloud-cc "$BASE_DIR/cloud-cc" ;; cloud-cc) docker_stop cloud-cc "$BASE_DIR/cc-site/cloud-cc" ;;
token-cc) docker_stop token-cc "$BASE_DIR/token-cc" ;; token-cc) docker_stop token-cc "$BASE_DIR/cc-site/token-cc" ;;
www-ai) docker_stop www-local-ai "$BASE_DIR/www-ai" ;; www-ai) docker_stop www-ai "$BASE_DIR/www-ai" ;;
cloud-ai) docker_stop cloud-ai "$BASE_DIR/cloud-ai" ;; cloud-ai) docker_stop cloud-ai "$BASE_DIR/cloud-ai" ;;
token-ai) docker_stop token-ai "$BASE_DIR/token-ai" ;; token-ai) docker_stop token-ai "$BASE_DIR/token-ai" ;;
issue) node_stop issue-ai $ISSUE_PORT ;; issue) node_stop issue $ISSUE_PORT ;;
assets) node_stop assets-ai $ASSETS_PORT ;; assets) node_stop assets $ASSETS_PORT ;;
ldap) docker_stop lldap "$LDAP_DIR" ;; ldap) docker_stop ldap "$LDAP_DIR" ;;
oa) node_stop oa-ai $OA_PORT ;; oa) node_stop oa $OA_PORT ;;
sso) docker_stop authelia "$SSO_DIR" ;; sso) docker_stop sso "$SSO_DIR" ;;
gitea) docker_stop gitea-ai "$GITEA_DIR" ;; gitea) docker_stop gitea "$GITEA_DIR" ;;
monitor) node_stop monitor-ai $MONITOR_PORT ;; monitor) node_stop monitor $MONITOR_PORT ;;
cc) stop_all www-cc cloud-cc token-cc ;; cc) stop_all www-cc cloud-cc token-cc ;;
ai) stop_all ldap www-ai cloud-ai token-ai issue assets oa sso gitea monitor ;; ai) stop_all www-ai cloud-ai token-ai issue assets ldap oa sso monitor gitea ;;
all) stop_all cc ai ;; all) stop_all cc ai ;;
*) err "未知站点: $name" ;; *) err "未知站点: $name" ;;
esac esac
@ -170,9 +174,9 @@ show_status() {
local expanded=() local expanded=()
for t in "${targets[@]}"; do for t in "${targets[@]}"; do
case $t in case $t in
all) eval "expanded=(www-cc cloud-cc token-cc ldap www-ai cloud-ai token-ai issue assets oa sso gitea monitor)" ;; all) eval "expanded=(www-cc cloud-cc token-cc www-ai cloud-ai token-ai issue assets ldap oa sso monitor gitea)" ;;
cc) eval "expanded=(\${expanded[@]} www-cc cloud-cc token-cc)" ;; cc) eval "expanded=(\${expanded[@]} www-cc cloud-cc token-cc)" ;;
ai) eval "expanded=(\${expanded[@]} ldap www-ai cloud-ai token-ai issue assets oa sso gitea monitor)" ;; ai) eval "expanded=(\${expanded[@]} www-ai cloud-ai token-ai issue assets ldap oa sso monitor gitea)" ;;
*) expanded+=($t) ;; *) expanded+=($t) ;;
esac esac
done done
@ -203,17 +207,31 @@ show_status() {
} }
local running=0 local running=0
for name in "${expanded[@]}"; do
local port=$(get_port $name) # 按 cc/ai 分组输出
_status_group() {
local label=$1; shift
local group=() gname n
for gname in "$@"; do
for n in "${expanded[@]}"; do
[ "$n" = "$gname" ] && group+=("$n") && break
done
done
[ ${#group[@]} -eq 0 ] && return
printf " ${CYAN}%s站点:${NC}\n" "$label"
for gname in "${group[@]}"; do
local port=$(get_port $gname)
if [ -n "$port" ] && is_port $port; then if [ -n "$port" ] && is_port $port; then
printf " ${GREEN}${NC} %-12s 运行中 (port %d)\n" "$name" $port printf " ${GREEN}${NC} %-12s 运行中 (port %d)\n" "$gname" $port
running=$((running + 1)) running=$((running + 1))
else else
printf " ${RED}${NC} %-12s 未运行\n" "$name" printf " ${RED}${NC} %-12s 未运行\n" "$gname"
fi fi
done done
echo "" echo ""
}
_status_group "cc " www-cc cloud-cc token-cc
_status_group "ai " www-ai cloud-ai token-ai issue assets ldap oa sso monitor gitea
printf "${CYAN}=========================================${NC}\n" printf "${CYAN}=========================================${NC}\n"
printf "${CYAN} 访问地址${NC}\n" printf "${CYAN} 访问地址${NC}\n"
printf "${CYAN}=========================================${NC}\n" printf "${CYAN}=========================================${NC}\n"
@ -227,13 +245,13 @@ show_status() {
echo " www-ai http://127.0.0.1:6173" echo " www-ai http://127.0.0.1:6173"
echo " cloud-ai http://127.0.0.1:6174" echo " cloud-ai http://127.0.0.1:6174"
echo " token-ai http://127.0.0.1:6175" echo " token-ai http://127.0.0.1:6175"
echo " issue http://127.0.0.1:$ISSUE_PORT"
echo " assets http://127.0.0.1:$ASSETS_PORT"
echo " ldap http://127.0.0.1:$LDAP_WEB_PORT (LLDAP Web UI)" echo " ldap http://127.0.0.1:$LDAP_WEB_PORT (LLDAP Web UI)"
echo " oa http://127.0.0.1:$OA_PORT" echo " oa http://127.0.0.1:$OA_PORT"
echo " sso http://127.0.0.1:$SSO_PORT (Authelia OIDC)" echo " sso http://127.0.0.1:$SSO_PORT (Authelia OIDC)"
echo " issue http://127.0.0.1:$ISSUE_PORT"
echo " assets http://127.0.0.1:$ASSETS_PORT"
echo " gitea http://127.0.0.1:$GITEA_PORT"
echo " monitor http://127.0.0.1:$MONITOR_PORT" echo " monitor http://127.0.0.1:$MONITOR_PORT"
echo " gitea http://127.0.0.1:$GITEA_PORT"
echo "" echo ""
} }