v 0.0.1
parent
ac6d641f17
commit
9556a30747
2
.env
2
.env
|
|
@ -10,5 +10,3 @@ AI_MODEL=deepseek-chat
|
||||||
AI_TEMPERATURE=0.2
|
AI_TEMPERATURE=0.2
|
||||||
|
|
||||||
PORT=8770
|
PORT=8770
|
||||||
PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
|
|
||||||
BASE_IMAGE=docker.1ms.run/library/python:3.12-slim
|
|
||||||
|
|
|
||||||
11
.env.example
11
.env.example
|
|
@ -26,10 +26,13 @@ HOST_PORT=8770
|
||||||
# 周期/周次/入库时间等日期按此时区计算,别留 UTC,否则整体差 8 小时
|
# 周期/周次/入库时间等日期按此时区计算,别留 UTC,否则整体差 8 小时
|
||||||
TZ=Asia/Shanghai
|
TZ=Asia/Shanghai
|
||||||
|
|
||||||
# ---- 国内网络加速(构建镜像用,deploy.sh 首次 up 时自动探测并写回这里)----
|
# ---- 国内网络加速(只在构建镜像时用到)----
|
||||||
# 国内直连 docker.io / pypi.org 基本超时,deploy.sh 会先探一个能真拉下镜像的加速站。
|
# 基础镜像:优先用本地已有的镜像,脚本不会联网去试各种加速站。
|
||||||
# 手工钉死(推荐内网环境写死,省掉每次探测):
|
# 先在机器上准备好 python:3.12-slim(docker pull / 内网仓库 / docker load)即可;
|
||||||
# BASE_IMAGE=docker.1ms.run/library/python:3.12-slim
|
# 本地是别的名字或别的 tag,就在下面钉死。别把某台机器上的前缀提交进仓库,换台机器就找不到了。
|
||||||
|
# BASE_IMAGE=python:3.12-slim
|
||||||
|
# pip 源:构建时在容器里装依赖,容器不认宿主机的代理,只能换源;
|
||||||
|
# ./deploy.sh 会在容器里真访问一次挑可用的(默认清华源),想固定就取消注释:
|
||||||
# PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
|
# PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
|
||||||
# 关掉自动探测(源已在上面配好,或机器能直连官方源):CN_MIRROR=0 ./deploy.sh up
|
# 关掉自动探测(源已在上面配好,或机器能直连官方源):CN_MIRROR=0 ./deploy.sh up
|
||||||
# 跳过构建、直接用本地已有镜像(离线机器上 docker load 完之后用):NO_BUILD=1 ./deploy.sh up
|
# 跳过构建、直接用本地已有镜像(离线机器上 docker load 完之后用):NO_BUILD=1 ./deploy.sh up
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@
|
||||||
# 镜像里只有依赖和代码,数据库/附件都在 data/,靠 bind mount 挂进来。
|
# 镜像里只有依赖和代码,数据库/附件都在 data/,靠 bind mount 挂进来。
|
||||||
# data/ 已被 .dockerignore 排除,不会把本机 board.db 打进镜像。
|
# data/ 已被 .dockerignore 排除,不会把本机 board.db 打进镜像。
|
||||||
#
|
#
|
||||||
# 基础镜像。国内直连 docker.io 会在 load metadata 阶段 TLS 超时,所以支持换仓库前缀:
|
# 基础镜像。国内直连 docker.io 会在 load metadata 阶段 TLS 超时,所以支持指成本地已有的镜像:
|
||||||
# docker build --build-arg BASE_IMAGE=docker.1ms.run/library/python:3.12-slim .
|
# docker pull python:3.12-slim && docker build --build-arg BASE_IMAGE=python:3.12-slim .
|
||||||
# ./deploy.sh up 会自动探测可用加速站并把结果写进 .env,正常情况下不用手工传。
|
# ./deploy.sh 会优先用本地已有的同名镜像,不会去联网试各种加速站。
|
||||||
ARG BASE_IMAGE=python:3.12-slim
|
ARG BASE_IMAGE=python:3.12-slim
|
||||||
FROM ${BASE_IMAGE}
|
FROM ${BASE_IMAGE}
|
||||||
|
|
||||||
|
|
|
||||||
20
README.md
20
README.md
|
|
@ -110,7 +110,7 @@ cd /path/to/unis_manager
|
||||||
|---|---|
|
|---|---|
|
||||||
| `Dockerfile` | 运行镜像:装依赖 + 拷 `app/ web/ scripts/`;启动时先跑 `init_db.py`(幂等)再起 uvicorn |
|
| `Dockerfile` | 运行镜像:装依赖 + 拷 `app/ web/ scripts/`;启动时先跑 `init_db.py`(幂等)再起 uvicorn |
|
||||||
| `docker-compose.yml` | 编排:`./data` 挂进容器存数据库、`HOST_PORT` 控对外端口、`restart: unless-stopped` 随 Docker 自启 |
|
| `docker-compose.yml` | 编排:`./data` 挂进容器存数据库、`HOST_PORT` 控对外端口、`restart: unless-stopped` 随 Docker 自启 |
|
||||||
| `deploy.sh` | 命令封装:`up` / `update` / `restart` / `down` / `logs` / `status` / `backup` / `mirror`,顺带检查 docker 是否在跑、`.env` 与 `data/` 是否存在,并在构建前探测国内可用源 |
|
| `deploy.sh` | 命令封装:`up` / `update` / `restart` / `down` / `logs` / `status` / `backup` / `mirror`,顺带检查 docker 是否在跑、`.env` 与 `data/` 是否存在,并在构建前定好基础镜像与 pip 源 |
|
||||||
| `.dockerignore` | 保证 `data/`、`.env`、`.git` 不会被烤进镜像 |
|
| `.dockerignore` | 保证 `data/`、`.env`、`.git` 不会被烤进镜像 |
|
||||||
|
|
||||||
| 场景 | 命令 |
|
| 场景 | 命令 |
|
||||||
|
|
@ -131,21 +131,27 @@ cd /path/to/unis_manager
|
||||||
|
|
||||||
| 卡在哪 | 典型报错 | 治法 |
|
| 卡在哪 | 典型报错 | 治法 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| ① 守护进程拉基础镜像 | `failed to resolve source metadata for docker.io/library/python:3.12-slim: ... TLS handshake timeout` | 换仓库前缀 `BASE_IMAGE`(走加速站,或给守护进程配 registry-mirrors) |
|
| ① 守护进程拉基础镜像 | `failed to resolve source metadata for docker.io/library/python:3.12-slim: ... TLS handshake timeout` | 用本地已有的镜像(`BASE_IMAGE=` 指定),或先 `docker pull` / 给守护进程配 registry-mirrors |
|
||||||
| ② 构建容器里装依赖 | `[4/8] RUN pip install ... -i https://pypi.org/simple` 非零退出 | 换 pip 源 `PIP_INDEX_URL`(清华 / 阿里 / 腾讯) |
|
| ② 构建容器里装依赖 | `[4/8] RUN pip install ... -i https://pypi.org/simple` 非零退出 | 换 pip 源 `PIP_INDEX_URL`(清华 / 阿里 / 腾讯) |
|
||||||
|
|
||||||
`./deploy.sh up` 在构建前会自动把两道源都探出来(判据是真的 `docker pull`、是在容器里 `urlopen`,不信宿主机 curl,也不信 `docker manifest inspect` 的假 `denied`),结果写进 `.env`,下次以及裸跑 compose 都复用:
|
`./deploy.sh up` 构建前把这两道都定下来,原则是**能本地解决就不联网**:
|
||||||
|
|
||||||
|
- 基础镜像只看本地有没有:`BASE_IMAGE` 指定的镜像在本地 → 直接用;只有同名 tag(如 `python:3.12-slim`)→ 也用(仓库前缀只是当初从哪儿拉的,镜像是同一份)。本地确实没有才试拉一次(守护进程配的 registry-mirrors 在这一步生效),还拉不到就**直接报错停下**并打印补救命令——不去逐个试加速站,那种循环只会白等几分钟。
|
||||||
|
- pip 源:在构建用的容器里真 `urlopen` 一次逐个试(容器网络 = 构建网络,比宿主机 curl 准),默认清华源。
|
||||||
|
- 定下来的值只 export 给本次构建,**不写回 `.env`**(`.env` 在 git 里,把某台机器的地址带到另一台机器正是故障源)。
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./deploy.sh up # 自动探测 → 写 .env → 构建 → 等健康检查
|
./deploy.sh up # 定源(本地有镜像就不联网)→ 构建 → 等健康检查
|
||||||
./deploy.sh mirror # 只想重探一遍源(不会冲掉 .env 里手工钉死的 BASE_IMAGE)
|
./deploy.sh mirror # 重探一次 pip 源,并打印可写进 .env 的两行
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **别把某台机器上的 `BASE_IMAGE` 前缀提交进仓库。** 换机器后那个前缀对应的镜像本地不存在,构建就会卡在 `load metadata`;这行留空或写裸 `python:3.12-slim`,让每台机器自己的镜像说了算。
|
||||||
|
|
||||||
不想用脚本,等价的两条 build-arg:
|
不想用脚本,等价的两条 build-arg:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose build \
|
docker compose build \
|
||||||
--build-arg BASE_IMAGE=docker.1ms.run/library/python:3.12-slim \
|
--build-arg BASE_IMAGE=python:3.12-slim \
|
||||||
--build-arg PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
|
--build-arg PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
@ -154,7 +160,7 @@ docker compose up -d
|
||||||
|
|
||||||
- **基础镜像拉成功 ≠ 构建能过**:`docker pull` 只治①,容器里的 `pip install` 照旧撞 pypi.org,必须另外给②换源。
|
- **基础镜像拉成功 ≠ 构建能过**:`docker pull` 只治①,容器里的 `pip install` 照旧撞 pypi.org,必须另外给②换源。
|
||||||
- **shell 里的 `HTTP(S)_PROXY` 对构建没用**:Docker 守护进程和构建容器都不读宿主机的代理变量。要走代理得在 Docker Desktop → Settings → Resources → Proxies 里配 `http://host.docker.internal:7897`(端口换成你本机代理的)。
|
- **shell 里的 `HTTP(S)_PROXY` 对构建没用**:Docker 守护进程和构建容器都不读宿主机的代理变量。要走代理得在 Docker Desktop → Settings → Resources → Proxies 里配 `http://host.docker.internal:7897`(端口换成你本机代理的)。
|
||||||
- **境外机器 / 内网有自建源**:`CN_MIRROR=0 ./deploy.sh up` 关掉探测,源完全由 `.env` 说了算。
|
- **境外机器 / 内网有自建源**:`CN_MIRROR=0 ./deploy.sh up` 跳过 pip 探测,源完全由 `.env` 说了算。
|
||||||
- **目标机完全不能上网**:走离线路。`docker save -o unis-board.tar unis-board:latest` → 拷过去 `docker load -i unis-board.tar` → `NO_BUILD=1 ./deploy.sh up`(跳过构建直接用本地镜像)。
|
- **目标机完全不能上网**:走离线路。`docker save -o unis-board.tar unis-board:latest` → 拷过去 `docker load -i unis-board.tar` → `NO_BUILD=1 ./deploy.sh up`(跳过构建直接用本地镜像)。
|
||||||
- 构建失败时脚本会自己打印一份排查清单(`deploy.sh` 的 `build_hint`),照抄命令即可。
|
- 构建失败时脚本会自己打印一份排查清单(`deploy.sh` 的 `build_hint`),照抄命令即可。
|
||||||
|
|
||||||
|
|
|
||||||
109
deploy.sh
109
deploy.sh
|
|
@ -7,7 +7,7 @@
|
||||||
# ./deploy.sh logs 跟踪日志(Ctrl+C 退出)
|
# ./deploy.sh logs 跟踪日志(Ctrl+C 退出)
|
||||||
# ./deploy.sh backup 导出数据库快照(部署到新机器时带走数据)
|
# ./deploy.sh backup 导出数据库快照(部署到新机器时带走数据)
|
||||||
# ./deploy.sh status 容器状态 + 健康检查 + 访问地址
|
# ./deploy.sh status 容器状态 + 健康检查 + 访问地址
|
||||||
# ./deploy.sh mirror 重新探测国内加速源(基础镜像 + pip 源)并写进 .env
|
# ./deploy.sh mirror 重新探测可用的 pip 源(基础镜像只认本地已有的,不去试加速站)
|
||||||
# 环境变量:CN_MIRROR=0 跳过加速探测;NO_BUILD=1 不构建、直接用本地镜像
|
# 环境变量:CN_MIRROR=0 跳过加速探测;NO_BUILD=1 不构建、直接用本地镜像
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
cd "$(dirname "$0")"
|
cd "$(dirname "$0")"
|
||||||
|
|
@ -37,26 +37,19 @@ URL="http://127.0.0.1:${HOST_PORT}"
|
||||||
# ---------- 0.5 通用小工具(供后面读写 .env、探测、加超时用)----------
|
# ---------- 0.5 通用小工具(供后面读写 .env、探测、加超时用)----------
|
||||||
env_get() { { [ -f .env ] && sed -n "s/^$1=//p" .env | tail -1; } || true; }
|
env_get() { { [ -f .env ] && sed -n "s/^$1=//p" .env | tail -1; } || true; }
|
||||||
|
|
||||||
# 覆盖式写回 .env(没有这个键就追加)
|
|
||||||
env_set() {
|
|
||||||
awk -v k="$1" -v v="$2" 'BEGIN{hit=0} index($0,k"=")==1{print k"="v; hit=1; next} {print} END{if(!hit)print k"="v}' .env > .env.tmp && mv .env.tmp .env
|
|
||||||
}
|
|
||||||
|
|
||||||
# 站点可达?能握手且不是 5xx 就算数(401/403 只是不允许匿名列表)
|
|
||||||
http_ok() {
|
|
||||||
local code
|
|
||||||
code="$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 3 --max-time "${2:-8}" "$1" 2>/dev/null || true)"
|
|
||||||
case "$code" in 000|"") return 1 ;; 5*) return 1 ;; *) return 0 ;; esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# with_timeout 秒 命令…(macOS 没有 timeout 命令,自己搭一个,防止探测卡死)
|
# with_timeout 秒 命令…(macOS 没有 timeout 命令,自己搭一个,防止探测卡死)
|
||||||
with_timeout() {
|
with_timeout() {
|
||||||
local t="$1" rc=0 pid wpid; shift
|
local t="$1" rc=0; shift
|
||||||
"$@" >/dev/null 2>&1 & pid=$!
|
# 整个动作丢进子 shell 并把它的 stderr 关掉:否则后台任务被 kill 时
|
||||||
( sleep "$t"; kill "$pid" 2>/dev/null ) >/dev/null 2>&1 & wpid=$!
|
# bash 会往终端插一行「已终止」,看着像脚本自己挂了。
|
||||||
|
( "$@" >/dev/null 2>&1 &
|
||||||
|
pid=$!
|
||||||
|
( sleep "$t"; kill "$pid" 2>/dev/null ) >/dev/null 2>&1 &
|
||||||
|
wpid=$!
|
||||||
wait "$pid" || rc=$?
|
wait "$pid" || rc=$?
|
||||||
kill "$wpid" 2>/dev/null || true; wait "$wpid" 2>/dev/null || true
|
kill "$wpid" 2>/dev/null || true
|
||||||
return "$rc"
|
wait "$wpid" 2>/dev/null || true
|
||||||
|
exit "$rc" ) 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
# ---------- 1. 国内加速:基础镜像 + pip 源 ----------
|
# ---------- 1. 国内加速:基础镜像 + pip 源 ----------
|
||||||
|
|
@ -65,63 +58,56 @@ with_timeout() {
|
||||||
# 并写回 .env —— 之后裸跑 docker compose up -d --build 用的也是同一套配置。
|
# 并写回 .env —— 之后裸跑 docker compose up -d --build 用的也是同一套配置。
|
||||||
|
|
||||||
BASE_IMAGE="${BASE_IMAGE:-$(env_get BASE_IMAGE)}"
|
BASE_IMAGE="${BASE_IMAGE:-$(env_get BASE_IMAGE)}"
|
||||||
BASE_IMAGE="${BASE_IMAGE:-python:3.12-slim}" # 想换加速站就写进 .env,例:docker.1ms.run/library/python:3.12-slim
|
BASE_IMAGE="${BASE_IMAGE:-python:3.12-slim}" # 本地有哪个 python 镜像就用哪个;内网自建仓库才需要在这里钉死
|
||||||
BASE_TAG="${BASE_TAG:-${BASE_IMAGE##*/}}" # 加速站上的固定路径是 library/<BASE_TAG>
|
|
||||||
MIRROR_HOSTS="${MIRROR_HOSTS:-docker.1ms.run docker.m.daocloud.io docker.1panel.live docker.xuanyuan.me}"
|
|
||||||
PIP_URLS="${PIP_URLS:-https://pypi.tuna.tsinghua.edu.cn/simple https://mirrors.aliyun.com/pypi/simple https://mirrors.cloud.tencent.com/pypi/simple https://pypi.org/simple}"
|
PIP_URLS="${PIP_URLS:-https://pypi.tuna.tsinghua.edu.cn/simple https://mirrors.aliyun.com/pypi/simple https://mirrors.cloud.tencent.com/pypi/simple https://pypi.org/simple}"
|
||||||
|
|
||||||
configure_mirror() {
|
configure_mirror() {
|
||||||
local force="${1:-}" host url ref tag pip_picked=0 base_picked=0
|
local force="${1:-}" url tag
|
||||||
PIP_INDEX_URL="${PIP_INDEX_URL:-$(env_get PIP_INDEX_URL)}"
|
PIP_INDEX_URL="${PIP_INDEX_URL:-$(env_get PIP_INDEX_URL)}"
|
||||||
if [ "$force" = "--force" ]; then
|
if [ "$force" = "--force" ]; then
|
||||||
PIP_INDEX_URL=""
|
PIP_INDEX_URL=""
|
||||||
# 手工钉死过的基础镜像不冲掉,只重探 pip 源
|
# 手工钉死过的基础镜像不冲掉,只重探 pip 源
|
||||||
if [ -z "$(env_get BASE_IMAGE)" ]; then BASE_IMAGE="python:3.12-slim"; fi # .env 里钉死过的基础镜像不冲掉
|
# .env 里钉死过的基础镜像不冲掉,--force 只重探 pip 源
|
||||||
|
if [ -z "$(env_get BASE_IMAGE)" ]; then BASE_IMAGE="python:3.12-slim"; fi
|
||||||
fi
|
fi
|
||||||
BASE_IMAGE="${BASE_IMAGE:-python:3.12-slim}"
|
BASE_IMAGE="${BASE_IMAGE:-python:3.12-slim}"
|
||||||
|
|
||||||
if [ "${CN_MIRROR:-1}" = "0" ] || [ "${NO_BUILD:-0}" = "1" ]; then
|
if [ "${CN_MIRROR:-1}" = "0" ] || [ "${NO_BUILD:-0}" = "1" ]; then
|
||||||
export BASE_IMAGE PIP_INDEX_URL
|
export BASE_IMAGE PIP_INDEX_URL
|
||||||
echo "==> 跳过加速探测(CN_MIRROR=0 或 NO_BUILD=1):${BASE_IMAGE:-官方 python} / ${PIP_INDEX_URL:-官方 pypi}"
|
echo "==> 跳过源探测(CN_MIRROR=0 或 NO_BUILD=1):${BASE_IMAGE:-官方 python} / ${PIP_INDEX_URL:-官方 pypi}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 基础镜像的判据是「Docker 守护进程能不能拿到它」,不是宿主机 curl 能不能通:
|
# 基础镜像只用「本地有没有」做判据,不去逐个试加速站(试一圈要几分钟,而且多半全挂)。
|
||||||
# 宿主机 curl 走 HTTP_PROXY,守护进程和构建容器都不认 shell 的代理变量。
|
# 判据也不看宿主机 curl:宿主机走 HTTP_PROXY,守护进程和构建容器都不认 shell 的代理变量。
|
||||||
tag="${BASE_IMAGE##*/}"
|
tag="${BASE_IMAGE##*/}" # 纯 tag,例 python:3.12-slim
|
||||||
if docker image inspect "$BASE_IMAGE" >/dev/null 2>&1; then
|
if docker image inspect "$BASE_IMAGE" >/dev/null 2>&1; then
|
||||||
echo "==> 基础镜像本地已有,不联网:$BASE_IMAGE"
|
echo "==> 基础镜像本地已有,不联网:$BASE_IMAGE"
|
||||||
|
elif docker image inspect "$tag" >/dev/null 2>&1; then
|
||||||
|
# 本地已有同名 tag 就直接用。镜像内容是同一份,仓库前缀只是「当初从哪儿拉的」,
|
||||||
|
# 换台机器还抱着旧前缀去联网拉,反而会把一次本来能成的构建搞挂。
|
||||||
|
echo "==> 本地已有 ${tag},直接用它(忽略 .env 里的仓库前缀)"
|
||||||
|
BASE_IMAGE="$tag"
|
||||||
elif with_timeout 25 docker pull --quiet "$BASE_IMAGE"; then
|
elif with_timeout 25 docker pull --quiet "$BASE_IMAGE"; then
|
||||||
echo "==> 基础镜像可从当前配置源拉取:$BASE_IMAGE"
|
echo "==> 基础镜像已从当前配置的源拉取:$BASE_IMAGE"
|
||||||
else
|
else
|
||||||
echo " $BASE_IMAGE 守护进程侧拉不到,开始找加速站"
|
echo "!! 本地没有 ${BASE_IMAGE},25 秒内也没拉到;这一步过不去,构建必然失败,先解决基础镜像:" >&2
|
||||||
for host in $MIRROR_HOSTS; do
|
echo " 1) 本地有别的 python 镜像 → 指定它:BASE_IMAGE=$(docker images --format '{{.Repository}}:{{.Tag}}' | grep -m1 python || echo python:3.12-slim) ./deploy.sh up" >&2
|
||||||
ref="$host/library/$tag"
|
echo " 2) 手工拉一次(守护进程配的 registry-mirrors 在这一步生效):docker pull $tag" >&2
|
||||||
echo -n "==> 测试加速站 $host "
|
echo " 3) 机器不能上网 → 从别处拷:docker save -o py.tar $tag && scp py.tar 目标机 && docker load -i py.tar" >&2
|
||||||
if with_timeout 120 docker pull --quiet "$ref"; then
|
echo " 4) 已经构建过本项目镜像 → 跳过构建直接起:NO_BUILD=1 ./deploy.sh up" >&2
|
||||||
BASE_IMAGE="$ref"; base_picked=1; echo " 可用"; break
|
return 1
|
||||||
else
|
|
||||||
echo " 不可用"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "$base_picked" = 0 ]; then
|
|
||||||
echo "!! 所有加速站都拉不到 $tag;可以先在服务器上手拉,再 ./deploy.sh up(本地有就不会再联网):" >&2
|
|
||||||
echo " docker pull docker.1ms.run/library/$tag && docker tag docker.1ms.run/library/$tag $BASE_IMAGE" >&2
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# pip 源:装依赖是在构建容器里发生的,容器不继承 shell 的代理,
|
# pip 源:装依赖是在构建容器里发生的,容器不继承宿主机的代理,
|
||||||
# 所以拿刚选好的基础镜像真跑一次访问探测,比在宿主机上 curl 靠谱。
|
# 所以拿刚定下的基础镜像(此时必然已在本地)真跑一次访问探测,比宿主机 curl 靠谱。
|
||||||
if [ -n "${PIP_INDEX_URL:-}" ]; then
|
if [ -n "${PIP_INDEX_URL:-}" ]; then
|
||||||
echo "==> pip 源(沿用已有配置):$PIP_INDEX_URL"
|
echo "==> pip 源(沿用已有配置):$PIP_INDEX_URL"
|
||||||
else
|
else
|
||||||
docker image inspect "$BASE_IMAGE" >/dev/null 2>&1 \
|
|
||||||
|| with_timeout 120 docker pull --quiet "$BASE_IMAGE" \
|
|
||||||
|| BASE_IMAGE="$(docker images --format '{{.Repository}}:{{.Tag}}' | grep -m1 '^python:3' || true)"
|
|
||||||
for url in $PIP_URLS; do
|
for url in $PIP_URLS; do
|
||||||
if [ -n "${BASE_IMAGE:-}" ] && with_timeout 40 docker run --rm --entrypoint python "$BASE_IMAGE" \
|
if with_timeout 40 docker run --rm --entrypoint python "$BASE_IMAGE" \
|
||||||
-c "import sys,urllib.request;urllib.request.urlopen(sys.argv[1],timeout=8)" "$url/"; then
|
-c "import sys,urllib.request;urllib.request.urlopen(sys.argv[1],timeout=8)" "$url/"; then
|
||||||
PIP_INDEX_URL="$url"; pip_picked=1; break
|
PIP_INDEX_URL="$url"; break
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [ -z "${PIP_INDEX_URL:-}" ]; then
|
if [ -z "${PIP_INDEX_URL:-}" ]; then
|
||||||
|
|
@ -131,9 +117,9 @@ configure_mirror() {
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 探出来的结果落盘,下次(以及裸 compose 命令)直接复用
|
# 只 export 给本次构建,故意不写回 .env —— .env 在 git 里,把这台机器探到的
|
||||||
if [ "$pip_picked" = 1 ]; then env_set PIP_INDEX_URL "$PIP_INDEX_URL"; fi
|
# 加速站带到另一台机器上,正是那边拉不到镜像的原因。
|
||||||
if [ "$base_picked" = 1 ]; then env_set BASE_IMAGE "$BASE_IMAGE"; fi
|
# 想固定就在 .env 里手工写 BASE_IMAGE= / PIP_INDEX_URL= 两行(裸 compose 命令也吃这两个值)。
|
||||||
export BASE_IMAGE PIP_INDEX_URL
|
export BASE_IMAGE PIP_INDEX_URL
|
||||||
echo "==> 本次构建用:基础镜像 $BASE_IMAGE | pip 源 $PIP_INDEX_URL"
|
echo "==> 本次构建用:基础镜像 $BASE_IMAGE | pip 源 $PIP_INDEX_URL"
|
||||||
}
|
}
|
||||||
|
|
@ -143,16 +129,16 @@ build_hint() {
|
||||||
if [ -n "${HTTPS_PROXY:-}${HTTP_PROXY:-}${https_proxy:-}${http_proxy:-}" ]; then
|
if [ -n "${HTTPS_PROXY:-}${HTTP_PROXY:-}${https_proxy:-}${http_proxy:-}" ]; then
|
||||||
echo "!! 注意:当前 shell 配了 HTTP(S)_PROXY,但 Docker 守护进程不认 shell 环境变量。" >&2
|
echo "!! 注意:当前 shell 配了 HTTP(S)_PROXY,但 Docker 守护进程不认 shell 环境变量。" >&2
|
||||||
echo " 要用代理出网,得在 Docker Desktop → Settings → Resources → Proxies 里配" >&2
|
echo " 要用代理出网,得在 Docker Desktop → Settings → Resources → Proxies 里配" >&2
|
||||||
echo " http://host.docker.internal:7897(端口换成你本机代理的),否则只能走加速站。" >&2
|
echo " http://host.docker.internal:7897(端口换成你本机代理的),否则构建期出不了网。" >&2
|
||||||
fi
|
fi
|
||||||
cat >&2 <<'HINT'
|
cat >&2 <<'HINT'
|
||||||
!! 构建失败。国内环境最常见的两个原因:
|
!! 构建失败。国内环境最常见的两个原因:
|
||||||
1) 基础镜像拉不到(failed to resolve source metadata / TLS handshake timeout)
|
1) 基础镜像拉不到(failed to resolve source metadata / TLS handshake timeout)
|
||||||
./deploy.sh mirror # 重跑自动探测
|
docker images | grep python # 看看本地有哪个可用
|
||||||
BASE_IMAGE=docker.1ms.run/library/python:3.12-slim ./deploy.sh up # 手工指定加速站
|
BASE_IMAGE=python:3.12-slim ./deploy.sh up # 显式指定本地已有的镜像
|
||||||
也可以给 Docker 守护进程配 registry-mirrors(Docker Desktop → Settings → Docker Engine):
|
docker pull python:3.12-slim # 或手工拉一次
|
||||||
{ "registry-mirrors": ["https://docker.1ms.run"] }
|
也可以给 Docker 守护进程配 registry-mirrors(服务器改 /etc/docker/daemon.json,
|
||||||
保存并重启 Docker 后,把 .env 里的 BASE_IMAGE 那行删掉再 ./deploy.sh up
|
桌面端 Settings → Docker Engine),保存并重启 Docker 后再 ./deploy.sh up
|
||||||
2) pip 装依赖超时
|
2) pip 装依赖超时
|
||||||
PIP_INDEX_URL=https://mirrors.aliyun.com/pypi/simple ./deploy.sh up
|
PIP_INDEX_URL=https://mirrors.aliyun.com/pypi/simple ./deploy.sh up
|
||||||
完全不能上网的机器:在能上网的机器上构建后拷镜像过去
|
完全不能上网的机器:在能上网的机器上构建后拷镜像过去
|
||||||
|
|
@ -184,7 +170,7 @@ wait_ready() {
|
||||||
echo -n "."
|
echo -n "."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
echo; echo "!! 等待超时(当前状态:$state),执行 ./deploy.sh logs 看原因" >&2
|
echo; echo "!! 等待超时(当前状态:${state}),执行 ./deploy.sh logs 看原因" >&2
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -253,8 +239,9 @@ PYEOF
|
||||||
mirror)
|
mirror)
|
||||||
prepare
|
prepare
|
||||||
configure_mirror --force
|
configure_mirror --force
|
||||||
echo "==> 已写入 .env 的配置:"
|
echo "==> 想让以后的构建固定用这组源,把下面两行写进 .env 即可(不写也行):"
|
||||||
grep -E '^(BASE_IMAGE|PIP_INDEX_URL)=' .env 2>/dev/null || echo " (无:说明用的是默认源或 CN_MIRROR=0)"
|
echo " BASE_IMAGE=${BASE_IMAGE:-python:3.12-slim}"
|
||||||
|
if [ -n "${PIP_INDEX_URL:-}" ]; then echo " PIP_INDEX_URL=$PIP_INDEX_URL"; fi
|
||||||
;;
|
;;
|
||||||
status)
|
status)
|
||||||
"${COMPOSE[@]}" ps
|
"${COMPOSE[@]}" ps
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue