运行时环境:Python、Node、Go、Java

“本地能跑、服务器报错”的事故里,一大半是运行时版本不一致引起的。发行版自带的 Python 与 Node 往往版本偏旧,直接 apt install python3 上生产很快就会撞上语法或依赖不兼容。本章按语言给出可复制的安装方式、依赖锁定做法与产物目录规范。

各语言的推荐安装方式

语言推荐方式关键命令不适合的方式
Pythonpyenv 管版本 + venv 管依赖pyenv install 3.12.6用系统 Python 装业务依赖
Nodenvm 管版本 + pnpm/npm 管依赖nvm install 20apt install nodejs 得到旧版本
Go官方 tar 包解压到 /usr/local/gotar -C /usr/local -xzf go*.tar.gz发行版包(版本落后、路径混乱)
JavaSDKMAN 装 JDK/Maven/Gradlesdk install java 21.0.5-tem手工解压多版本互相干扰

Python:pyenv + venv

# 1) 编译 Python 需要的系统库,缺一个就会编译失败
sudo apt -y install make build-essential libssl-dev zlib1g-dev libbz2-dev \
  libreadline-dev libsqlite3-dev libffi-dev liblzma-dev libncursesw5-dev tk-dev

# 2) 安装 pyenv 并写入 shell 初始化(追加三行到 ~/.bashrc)
curl -fsSL https://pyenv.run | bash
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
exec "$SHELL" -l

pyenv install 3.12.6 && pyenv global 3.12.6
pyenv versions && python -V
# 4) 每个项目一个虚拟环境,依赖不互相污染
cd ~/apps/myapi && python -m venv .venv && source .venv/bin/activate
python -m pip install -U pip

# 生产用 lock 文件安装,保证可复现
pip install pip-tools && pip-compile requirements.in -o requirements.txt && pip-sync requirements.txt
deactivate
依赖管理工具锁定文件特点建议
pip + requirements.txtrequirements.txt最简单,版本约束靠手写小项目够用,pip freeze 结果要人工清理
pip-toolsrequirements.inrequirements.txt分离直接依赖与全部锁定传统项目的稳妥选择
Poetrypoetry.lock依赖与打包一体需要发布包时好用
uvuv.lock极快,兼容 pip 生态新项目优先

Node:nvm + pnpm

# 国内网络慢就先用镜像
export NVM_NODEJS_ORG_MIRROR=https://npmmirror.com/mirrors/node
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
exec "$SHELL" -l

nvm install 20 && nvm alias default 20 && node -v && npm -v

# corepack 随 Node 自带,启用 pnpm 最省事
corepack enable && corepack prepare pnpm@9 --activate && pnpm -v

# 严格按锁定文件安装,绝不在服务器上更新依赖
pnpm install --frozen-lockfile     # 等价于 npm ci

npm install 会按 package.json 重算依赖树并可能改写 package-lock.jsonnpm cipnpm install --frozen-lockfile 严格按锁文件安装,不一致时直接报错,生产构建必须用后者

Go:官方 tar 与交叉编译

# 1) 安装官方工具链
wget https://go.dev/dl/go1.23.2.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.23.2.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
exec "$SHELL" -l && go version

# 2) 国内代理与模块缓存(缓存放数据盘,别挤占系统盘)
go env -w GOPROXY=https://goproxy.cn,direct
go env -w GOMODCACHE=/data/go/pkg/mod

# 3) 安装小工具:go install 是 Go 特有的一行式安装
go install github.com/air-verse/air@latest
# 4) 交叉编译:CGO_ENABLED=0 才能产出静态二进制
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
  go build -trimpath -ldflags "-s -w -X main.version=1.4.0" -o bin/app ./cmd/app

# 部署时只需要传这一个文件,服务器上不用装 Go
scp bin/app prod:~/apps/myapp/app
ssh prod 'chmod +x ~/apps/myapp/app && ~/apps/myapp/app -v'

Go 的最大优势就在这里:一个静态二进制就是全部产物,不会有“官方镜像里缺 so 库”的问题。

Java:SDKMAN 管理版本

curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"

sdk install java 21.0.5-tem
sdk install maven && sdk install gradle
java -version && mvn -v

用完整 JDK 而不是 JRE,是为了保留 jcmdjstack 这些排障工具;容器里再换 eclipse-temurin:21-jre 精简体积即可。

构建产物目录规范

目录内容是否入库
~/apps/<name>/releases/<时间戳>每次发布的产物不入库,服务器保留最近 3~5 个
~/apps/<name>/current指向当前生效版本的软链不入库,切换靠改软链
~/apps/<name>/shared/.env环境配置与密钥不入库,权限 600
/srv/www/<name>前端静态产物不入库,由构建流程覆盖
/data/<name>数据库文件、上传文件绝不入库,单独备份
/var/log/<name>应用日志不入库,配 logrotate

releases + current 软链是零停机发布与秒级回滚的基础,第 10 章会展开。

验证方法

python -V && pip -V && node -v && pnpm -v && go version && java -version
python -c "import sys; print(sys.executable)"   # 期望 .venv/bin/python
pip check && pnpm list --depth 0 >/dev/null && echo deps-ok
file bin/app && ldd bin/app                     # 期望 statically linked
./bin/app --version

常见坑

现象做法
用系统 Python 装业务依赖与系统工具冲突,升级即翻车venv 隔离,系统 Python 只给系统用
服务器上 npm install依赖漂移,锁文件被改写npm ci / pnpm install --frozen-lockfile
在服务器上构建内存吃满、磁盘被依赖撑爆本地或 CI 构建,只上传产物
Go 忘了 CGO_ENABLED=0二进制依赖服务器 glibc 版本交叉编译时显式关闭 CGO
多版本共存无切换机制不同项目互相踩版本用 pyenv/nvm/SDKMAN 统一管理

小结:运行时版本必须由版本管理工具锁定,Python 用 pyenv + venv、Node 用 nvm + pnpm、Go 用官方 tar 加交叉编译、Java 用 SDKMAN;依赖一律按锁定文件安装,生产构建不更新依赖;产物按 releases/current/shared 规范存放,Go 这类静态二进制可以直接跑,环境问题一次解决到位。

笔记加载中…