包管理、环境变量与日志
High Contrast
Dark Mode
Light Mode
Sepia
Forest
2 min read481 words

包管理、环境变量与日志

一台机器长期稳定,靠的不是"记忆",而是把依赖、配置和日志各放在标准位置。

三个最小规范

项目 规范 违反后果
包管理 记录安装来源与版本,关键包锁定版本 apt upgrade 意外升级,服务行为变化
环境变量 放进 systemd EnvironmentFile 或专用文件 服务读不到变量,或密钥暴露在进程列表
日志 区分 stdout/错误日志/访问日志,设置轮转 磁盘被日志撑满,关键错误淹没在噪声中

包管理实操

# 更新软件源(每次安装前)
sudo apt update
# 安装时记录版本
sudo apt install nginx=1.24.0-1~jammy
apt show nginx | grep Version    # 查看当前版本
# 锁定关键包版本(防止 apt upgrade 升级)
sudo apt-mark hold nginx postgresql-15
apt-mark showhold                # 查看已锁定的包
# 解除锁定
sudo apt-mark unhold nginx
# 查看已安装包
dpkg -l | grep nginx
dpkg -l | grep "^ii"             # 所有已安装包
# 查看某包从哪里安装(用于排查来源)
apt-cache policy nodejs

版本记录建议(写入运维手册或 README):

# /etc/myapp/package-versions.txt(手动维护)
nginx: 1.24.0-1~jammy
postgresql-15: 15.4-1.pgdg22.04+1
nodejs: 20.11.0

环境变量:正确的注入方式

为什么 .bashrc / export 对服务无效

graph TD A[你在 shell 中 export DB_HOST=...] --> B[只对当前 shell 会话有效] C[systemd 启动服务] --> D[独立于登录 shell 的进程] D --> E[不会继承 .bashrc 或手动 export 的变量] E --> F[服务读到空值或默认值,行为异常]

正确做法:EnvironmentFile

# /etc/myapp/myapp.env(权限 640,root:app 组)
DATABASE_URL=postgresql://app:pass@localhost:5432/myapp
REDIS_URL=redis://localhost:6379
APP_ENV=production
LOG_LEVEL=info
PORT=3000
# /etc/systemd/system/myapp.service
[Service]
EnvironmentFile=/etc/myapp/myapp.env
ExecStart=/usr/bin/node server.js

验证服务实际读到的环境变量

# 方法 1:查看进程环境(需要 root)
PID=$(systemctl show -p MainPID myapp | cut -d= -f2)
sudo cat /proc/$PID/environ | tr '\0' '\n' | grep -E "DATABASE|PORT|APP_ENV"
# 方法 2:在应用健康检查接口中输出 APP_ENV(开发时有用)
# 不要输出 DATABASE_URL 等敏感变量!
# 方法 3:用 systemctl show 查看加载的环境文件
systemctl show myapp | grep EnvironmentFiles

日志管理实操

三类日志及其位置

日志类型 推荐位置 查看方式
systemd 服务日志 journald(内存+磁盘) journalctl -u myapp
应用自定义日志 /var/log/myapp/app.log tail -f /var/log/myapp/app.log
Nginx 访问日志 /var/log/nginx/access.log tail -f /var/log/nginx/access.log
Nginx 错误日志 /var/log/nginx/error.log tail -f /var/log/nginx/error.log

journalctl 高频命令

journalctl -u myapp -f                     # 追踪实时日志
journalctl -u myapp -n 100 --no-pager      # 最后 100 行
journalctl -u myapp --since "30 min ago"   # 最近 30 分钟
journalctl -u myapp -b                     # 本次开机以来的日志
journalctl -u myapp -b -p err              # 本次开机的 ERROR 级别日志
journalctl --disk-usage                    # journal 磁盘占用
# 多服务同时查看(排查依赖关系)
journalctl -u myapp -u postgresql --since "10 min ago"

防止 journal 撑满磁盘

# 设置上限(写入 /etc/systemd/journald.conf)
sudo tee -a /etc/systemd/journald.conf <<'EOF'
[Journal]
SystemMaxUse=500M
MaxRetentionSec=30day
EOF
sudo systemctl restart systemd-journald

常见误区

误区 正确做法
把密钥写进 ExecStart 命令行参数 EnvironmentFile;命令行参数在 ps aux 中可见
export DB_HOST=... 写在 .bashrc 服务由 systemd 启动,不会读 .bashrc
apt upgrade 全量升级后服务行为异常 apt-mark hold 锁定关键服务,再升级
日志不轮转,半年后磁盘爆满 配置 logrotate 或限制 SystemMaxUse

本节执行清单

下一章网络、端口与远程访问——开始建立真正的网络排障能力。