← Lesson 0002 教了你命令行基础。这节课把「会敲命令」升级到「能独立管理一台 Linux 服务器」——这是 DevOps 的日常。
Lesson 0002 讲了单文件权限。现在讲系统级的用户管理。
# 创建用户
sudo useradd -m -s /bin/bash deployer # -m=创建家目录 -s=指定shell
sudo passwd deployer # 设密码
# 查看用户信息
id deployer # uid, gid, groups
cat /etc/passwd | grep deployer # 用户数据库
# deployer:x:1001:1001::/home/deployer:/bin/bash
# ↑ ↑ ↑ ↑ ↑ ↑
# 用户名 密码 uid gid 家目录 shell
# 创建组 + 加人
sudo groupadd devops
sudo usermod -aG devops deployer # -a=追加 -G=附加组(不加-a会覆盖)
groups deployer # 验证
# 删除用户
sudo userdel -r deployer # -r=连家目录一起删
三张关键文件:
| 文件 | 内容 | 格式 |
|---|---|---|
/etc/passwd | 用户列表 | name:x:uid:gid:comment:home:shell |
/etc/shadow | 密码哈希 | 只有 root 可读 |
/etc/group | 组列表 | group:x:gid:members |
# 给 devops 组 sudo 权限(不用密码)
sudo visudo -f /etc/sudoers.d/devops # visudo 会做语法检查,永远用这个编辑
# 加一行:
%devops ALL=(ALL:ALL) NOPASSWD: ALL
# 解析:%组名 在哪台机器=(以谁的身份:以哪个组) 是否需要密码: 允许的命令
Lesson 0002 讲了 systemctl start/stop。现在写一个自定义 systemd 服务——把你的 Node.js 应用变成系统服务。
# /etc/systemd/system/myapp.service
sudo tee /etc/systemd/system/myapp.service << 'EOF'
[Unit]
Description=My Node.js Application
After=network.target # 网络就绪后再启动
[Service]
Type=simple
User=deployer
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/node server.js
Restart=on-failure # 崩溃后自动重启
RestartSec=5 # 等 5 秒再重启
Environment=NODE_ENV=production
EnvironmentFile=-/opt/myapp/.env # - 前缀 = 文件不存在也不报错
StandardOutput=journal # 日志进 journald
StandardError=journal
[Install]
WantedBy=multi-user.target # 多用户模式(正常启动)时启动
EOF
sudo systemctl daemon-reload # 重读所有 unit 文件
sudo systemctl enable --now myapp # 开机自启 + 立刻启动
sudo systemctl status myapp
journalctl -u myapp -f # 看日志
| Restart 策略 | 行为 |
|---|---|
no | 不重启(默认) |
on-failure | 退出码非 0 时重启(生产推荐) |
always | 任何退出都重启(包括正常退出) |
on-abnormal | 信号导致的退出才重启 |
# crontab 语法:分 时 日 月 星期 命令
# 编辑当前用户的 crontab
crontab -e
# 常用例子
0 2 * * * /opt/scripts/backup.sh # 每天凌晨 2 点备份
*/5 * * * * /opt/scripts/health-check.sh # 每 5 分钟健康检查
0 0 1 * * journalctl --vacuum-size=500M # 每月 1 号清理日志
@reboot /opt/scripts/startup.sh # 开机时执行
# 系统级 cron(更规范)
sudo tee /etc/cron.d/myapp << 'EOF'
# 分 时 日 月 星期 用户 命令
0 2 * * * deployer /opt/myapp/backup.sh
EOF
/usr/bin/docker 而不是 docker),或者在脚本开头 PATH=/usr/local/bin:/usr/bin:/bin。
日志不管理会撑爆磁盘。logrotate 自动轮转、压缩、删除旧日志。
# /etc/logrotate.d/myapp
sudo tee /etc/logrotate.d/myapp << 'EOF'
/var/log/myapp/*.log {
daily # 每天轮转
rotate 7 # 保留 7 个归档
compress # 压缩旧日志
delaycompress # 昨天的日志不压缩(可能还在写)
missingok # 文件不存在不报错
notifempty # 空的就不轮转
copytruncate # 复制后清空(不重开文件,适合不响应信号的程序)
}
EOF
# 测试配置
sudo logrotate -d /etc/logrotate.d/myapp # -d = dry run
# 手动执行
sudo logrotate -f /etc/logrotate.d/myapp
# Ubuntu 默认防火墙
sudo ufw status # 看状态
sudo ufw enable # 开启
sudo ufw default deny incoming # 默认拒绝入站
sudo ufw default allow outgoing # 默认允许出站
# 允许特定端口
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80,443/tcp # HTTP + HTTPS
sudo ufw allow from 10.0.0.0/24 # 允许整个子网
# 删除规则
sudo ufw status numbered
sudo ufw delete 3 # 删第 3 条
# 应用层防火墙
sudo ufw allow 'Nginx Full' # 用预定义的 profile
sudo ufw app list # 列出所有 profile
# 查看磁盘和分区
lsblk # 树状显示所有块设备
sudo fdisk -l # 详细分区表
# 挂载磁盘
sudo mkdir -p /data
sudo mount /dev/sdb1 /data
# 永久挂载:加到 /etc/fstab
echo "UUID=xxx-xxx /data ext4 defaults 0 2" | sudo tee -a /etc/fstab
# 查看 UUID
sudo blkid /dev/sdb1
任务:把你 Lesson 0004 写的 Shell 脚本变成一个 systemd 定时任务。
/tmp 写一个脚本 disk-monitor.sh:当磁盘使用超过 80% 时输出警告systemctl start 触发一次,用 journalctl 验证输出# 提示:systemd timer 替代 cron
# /etc/systemd/system/disk-monitor.service
# /etc/systemd/system/disk-monitor.timer
# timer 里 OnCalendar=hourly 表示每小时
# 然后 systemctl enable --now disk-monitor.timer
Lesson 0011:Linux 排错实战 →——出问题时你怎么找到根因?strace、lsof、tcpdump、性能分析。