第一次批量接手新服务器的时候,我还在逐台手工敲命令。几十台机器从配置 yum 源、装基础工具、调内核参数到加固 SSH,每台至少折腾二十多分钟,错一台还容易埋隐患。后来我干脆把整套初始化流程整理成一个 CentOS 7 初始化脚本,新机器到手跑一遍,几分钟就能交付,输出日志一目了然。这篇文章就把这个脚本的设计思路、完整代码和踩过的坑一块儿分享出来,尤其是新手做运维或者自己折腾服务器的人,可以直接拿过去改改就用。
1. CentOS 7 初始化脚本到底在解决什么问题
先别急着看代码,我们得把问题聊透。很多人觉得初始化就是装个系统然后配个 IP,真正上过生产环境的人才知道,新机器落地这半小时能决定后面三个月省不省心。
1.1 手动初始化新机器的三个痛点
第一个痛点是重复劳动。公司采购一批服务器,硬件配置一致,装完 CentOS 7 之后要做的事情几乎完全一样:配源、装 epel、关 SELinux、设时区、调内核参数、建部署用户、加固 SSH、装 JDK、装 Docker。这些操作单看都不难,但一台一台手动敲,几十台下来既无聊又容易出错。
第二个痛点是顺序错乱。初始化各步骤之间是有依赖关系的,比如先配好 yum 源才能装软件包,先建好用户才能配置 sshd 的登录策略,先放通防火墙端口才能安全地修改 SSH 端口。手工执行时一旦打乱顺序,轻则某一步失败,重则把机器搞到连不上,只能让机房同事帮忙重启或者走 IPMI。
第三个痛点是配置漂移。三个人分别初始化三台机器,每个人的习惯不一样,有人顺手把 SSH 端口改成 2222,有人忘了关 SELinux,有人装了 Docker 但没设开机自启。半年后排查问题的时候,你会发现每台机器都是独一无二的“雪花服务器”,维护成本直线上升。
1.2 脚本设计必须死磕的四个原则
写初始化脚本不是把命令堆在一起就完事,我在实践中总结出四个核心原则。
第一是幂等性。脚本要有本事重复执行而不出乱子。比如创建用户之前先检查用户是否存在,安装软件之前先检查是否已安装,备份配置文件时加时间戳避免覆盖上一次的备份。做不到幂等,脚本跑第二遍就会报一堆错,运维同事会想骂人。
第二是可追溯性。脚本的每一步操作都要有日志输出,最好能落盘到 /var/log 下面。你想想,中午跑完脚本,晚上发现某台机器配置不对,如果没有日志,你根本不知道当时执行到哪一步、有没有报错。我习惯用一个 LOG_FILE 变量统一记录,并在关键步骤前后打点。
第三是模块化。每个功能点封装成独立函数,比如 set_yum_repo()、disable_selinux()、config_sshd()。这样做的好处是脚本可以按需裁剪,你不需要装 Docker 的公司注释掉对应函数就行,别人接手你的脚本也能一眼看懂整体流程。
第四是可配置性。把容易变化的参数抽到脚本头部集中管理,比如 SSH 端口、部署用户名、时区、需要安装的软件列表。改参数不用在代码里到处翻,改头部几行就行,配合配置漂移问题也能更快收敛。
1.3 脚本整体架构:从入口到出口的阶段划分
我习惯把初始化脚本分成四个阶段。前置检查阶段负责确认执行者是 root、机器能联网、系统版本符合预期。系统基础配置阶段负责 yum 源、epel、基础工具、SELinux、防火墙、时区。安全与账号阶段负责创建用户、配置 sudo、加固 SSH。应用安装阶段按需装 JDK、Docker、Git 等。最后统一打印执行总结,耗时情况一目了然。
这种分层的结构让我在不同项目里复用时特别舒服。新项目如果只要基础环境,后面两个阶段直接注释掉;如果是内网服务器,软件源配置改成公司私有镜像源即可。整个脚本像搭积木,而不是一盘散沙。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 初始化脚本的核心模块与关键参数设计
下面把各个模块逐个拆开讲。每个模块我都会说明为什么这么写、关键点在哪里、有哪些地方容易出问题。
2.1 软件源配置:决定后续能不能顺利装包
CentOS 7 的默认源指向 mirror.centos.org,但这个官方源体系已经进入维护末期,新装完的系统直接 yum 安装经常超时。所以脚本第一步就是切换软件源。我在大多数场景下会优先选择阿里云源,或者直接改用 vault.centos.org 这个归档源,具体看你公司的网络策略。
切换源之前一定要先做备份,把原始 .repo 文件移到带时间戳的备份目录,万一新源有问题还能回滚。然后下载新源文件,这里有个小坑:阿里云的 Centos-7.repo 文件里用到了 $releasever 变量,在 CentOS 7 上解析成 7 是没问题的,但如果你后面挂了 epel 源,epel.repo 里的 $releasever 也要确认能解析正确,否则会出现 baseurl 指向不存在的路径。
EPEL 源是安装很多额外软件包的前提,比如 htop、jq、python-pip 这些都不在默认源里。安装 epel-release 之后同样建议把 mirrorlist 注释掉,直接改用 baseurl 指向镜像地址,速度会快很多。
2.2 安全与访问控制:SELinux、防火墙与 SSH
SELinux 是初始化阶段绕不开的话题。很多应用在 CentOS 7 上装完跑不起来,排查半天发现是 SELinux 在拦。我在生产环境里偏向两种处理方式,要么直接关闭,要么保持 enforcing 但为应用写专门的策略。对于绝大多数中小团队,直接在初始化时关闭 SELinux 更省心。脚本里用 setenforce 0 临时关闭,再用 sed 修改 /etc/selinux/config 让重启后也保持关闭。
防火墙这里要分情况。如果服务器前面还有云安全组或者硬件防火墙,那么本机 firewalld 可以直接关闭,减少一层干扰。如果没有外部防护,则至少要放通 SSH 端口和业务端口。脚本里我做成一个变量,由使用者决定是 disable 还是手动加端口。
SSH 加固是安全重点。我会把 PermitRootLogin 设为 no,关闭 root 密码登录,开启 PubkeyAuthentication,设置 MaxAuthTries 为 3。但这里务必注意顺序:如果没有把公钥提前写入目标机器的 authorized_keys,一下子把密码登录关掉,密码登录又只允许 root 的话,你就进不去了。所以脚本里要先创建部署用户、生成或分发密钥,再改 sshd_config,最后 systemctl reload sshd,而不是 restart,reload 不会断开现有连接,这个细节能救命。
2.3 时间、内核参数与文件描述符限制
系统时间不同步会引发很多莫名其妙的问题,最典型的是 https 证书校验失败、日志时间错乱、定时任务执行时间偏差。脚本里我直接强制设置时区为 Asia/Shanghai,并安装 chrony 做时间同步。很多刚接触服务器的人容易忽略这一步,等业务侧反馈时间不对再来处理就很被动。
内核参数优化这块,每个公司的诉求不一样,我给出的是比较通用的模板。fs.file-max 提高全局限定,net.core.somaxconn 增大 accept 队列长度,net.ipv4.ip_local_port_range 扩大本地端口范围,net.ipv4.tcp_tw_reuse 开启 TIME_WAIT 复用,vm.swappiness 调低减少交换分区使用。这些参数可以通过 /etc/sysctl.d/99-custom.conf 来配置,用 sysctl --system 生效,不要直接改 /etc/sysctl.conf,文件被覆盖的风险更小。
文件描述符限制同样重要。高并发服务要同时打开大量文件,系统默认的 1024 肯定不够。我在 /etc/security/limits.d/20-nofile.conf 里统一设置 nofile 和 nproc,注意 nproc 不要覆盖过猛,太高的 nproc 在某些内核和 systemd 版本下会引发无法登录的问题,建议软硬限制都设为 65535 即可满足绝大多数场景。
2.4 基础工具与常用软件安装
基础工具列表我固定为 vim、wget、curl、git、net-tools、lsof、tree、psmisc、unzip、zip、tcpdump、telnet、bind-utils、yum-utils。net-tools 提供 ifconfig 和 netstat,虽然新习惯是 ip 命令,但排查问题的时候很多老哥们还是顺手敲 netstat;bind-utils 提供 dig 和 nslookup。
JDK 的安装我建议用 tar 包解压,放到 /usr/local/java,再通过 /etc/profile.d/java.sh 设置 JAVA_HOME 和 PATH,这样比直接用 yum 装 openjdk 更可控。Docker 这块要特别留意版本,CentOS 7 的内核和较新的 containerd 之间有过兼容性问题,我已经不只一次遇到 docker-ce 最新版在 CentOS 7.9 上启动失败的案例。脚本里我会固定安装 docker-ce-20.10.x 版本,并锁定版本号,而不是用 latest。
3. 完整脚本实现与关键参数说明
这节把完整脚本拆分出来讲。我会先给脚本骨架,再给每个核心函数的具体实现,最后把几个关键参数的选择依据说清楚。
3.1 脚本骨架与公共函数
脚本开头先定义变量和公共函数,包括日志打印、备份函数、root 检查。日志函数用了 tee 同时输出到终端和文件,颜色也做了区分,这样执行的时候既能实时看到进度,事后也有完整日志可以回溯。
bash复制#!/bin/bash
# =====================================================
# CentOS 7 初始化脚本
# 适用环境:新装 CentOS 7 系列
# 使用方式:bash centos7_init.sh
# =====================================================
set -e # 任何命令出错立即退出
set -u # 使用未定义变量时退出
# ================= 可配置参数 =================
SSH_PORT=22
DEPLOY_USER="deploy"
TIMEZONE="Asia/Shanghai"
INSTALL_DOCKER="yes"
INSTALL_JDK="yes"
LOG_FILE="/var/log/centos7_init_$(date +%Y%m%d_%H%M%S).log"
COLOR_RED='\033[0;31m'
COLOR_GREEN='\033[0;32m'
COLOR_YELLOW='\033[0;33m'
COLOR_NONE='\033[0m'
log_info() {
echo -e "${COLOR_GREEN}[INFO]${COLOR_NONE} $(date '+%Y-%m-%d %H:%M:%S') $*" | tee -a "$LOG_FILE"
}
log_warn() {
echo -e "${COLOR_YELLOW}[WARN]${COLOR_NONE} $(date '+%Y-%m-%d %H:%M:%S') $*" | tee -a "$LOG_FILE"
}
log_error() {
echo -e "${COLOR_RED}[ERROR]${COLOR_NONE} $(date '+%Y-%m-%d %H:%M:%S') $*" | tee -a "$LOG_FILE"
}
check_root() {
if [[ $EUID -ne 0 ]]; then
log_error "请使用 root 权限执行本脚本"
exit 1
fi
}
backup_file() {
local file_path="$1"
if [[ -f "$file_path" ]]; then
cp "$file_path" "${file_path}.bak_$(date +%Y%m%d%H%M%S)"
log_info "已备份 $file_path"
fi
}
set -e 和 set -u 很多人一开始不习惯,但运行初始化脚本时它们能第一时间暴露问题。没有 set -e,中途某条命令失败脚本还会继续往下跑,最后机器处于半初始化状态,反而不如不跑。需要注意 set -e 有个副作用,比如管道命令中前面失败也会触发退出,所以条件判断的地方我会刻意规避,比如用 if 进行命令检查而不是直接把命令放在顶层。
3.2 核心功能模块完整代码
下面这段是脚本中几个关键模块的实现。软件源配置、SELinux 关闭、SSH 加固、内核参数设置、用户创建这五个函数我都贴出来了,应用安装部分因为版本差异大,已经封装成独立函数,方便按项目修改。
bash复制# ================= 软件源配置 =================
set_yum_repo() {
log_info "开始配置 yum 源"
local backup_dir="/etc/yum.repos.d/backup_$(date +%Y%m%d%H%M%S)"
mkdir -p "$backup_dir"
mv /etc/yum.repos.d/*.repo "$backup_dir/" 2>/dev/null || true
# 以阿里云源为例,如公司有内网源请替换为内网地址
wget -O /etc/yum.repos.d/CentOS-Base.repo \
https://mirrors.aliyun.com/repo/Centos-7.repo || {
log_error "下载阿里云源失败,尝试使用 vault 源"
cat > /etc/yum.repos.d/CentOS-Base.repo <<'EOF'
[base]
name=CentOS-7 - Base
baseurl=https://vault.centos.org/7.9.2009/os/x86_64/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
[updates]
name=CentOS-7 - Updates
baseurl=https://vault.centos.org/7.9.2009/updates/x86_64/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
[extras]
name=CentOS-7 - Extras
baseurl=https://vault.centos.org/7.9.2009/extras/x86_64/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
EOF
}
# 安装 epel 源
yum install -y epel-release || {
log_warn "yum 安装 epel-release 失败,尝试 rpm 方式"
rpm -Uvh https://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm || true
}
# 清理缓存并重建
yum clean all
yum makecache
log_info "yum 源配置完成"
}
# ================= 关闭 SELinux =================
disable_selinux() {
log_info "关闭 SELinux"
if [[ -f /etc/selinux/config ]]; then
backup_file /etc/selinux/config
setenforce 0 2>/dev/null || true
sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
sed -i 's/^SELINUX=permissive/SELINUX=disabled/' /etc/selinux/config
fi
if getenforce | grep -qi "enforcing"; then
log_warn "SELinux 当前仍为 enforcing,请重启后确认"
else
log_info "SELinux 已关闭"
fi
}
# ================= 时间同步 =================
set_time_and_date() {
log_info "设置时区为 $TIMEZONE"
timedatectl set-timezone "$TIMEZONE"
yum install -y chrony
systemctl enable --now chronyd
chronyc sources -v
timedatectl status
}
# ================= 内核参数优化 =================
set_sysctl_config() {
log_info "优化内核参数"
backup_file /etc/sysctl.d/99-custom.conf
cat > /etc/sysctl.d/99-custom.conf <<'EOF'
fs.file-max = 6553560
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 10000 65000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
vm.swappiness = 10
EOF
sysctl --system
}
# ================= 创建用户 =================
create_deploy_user() {
if id "$DEPLOY_USER" &>/dev/null; then
log_warn "用户 $DEPLOY_USER 已存在,跳过创建"
return
fi
log_info "创建部署用户 $DEPLOY_USER"
useradd "$DEPLOY_USER"
echo "$DEPLOY_USER:ChangeMe123!" | chpasswd
# 加入 wheel 组并配置免密 sudo
usermod -aG wheel "$DEPLOY_USER"
echo "$DEPLOY_USER ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/"$DEPLOY_USER"
chmod 440 /etc/sudoers.d/"$DEPLOY_USER"
}
这里你可能会问为什么要创建带密码的部署用户,而且密码还写在脚本里。实际上密码是临时密码,脚本跑完应当立即通知相关同事修改,或者后续统一交给配置管理工具分发密钥。生产环境更合适的做法是直接配置 SSH 公钥,脚本里通过参数传入公钥内容,写入用户家目录下的 authorized_keys。
3.3 SSH 加固和防火墙处理
SSH 加固脚本需要单独拿出来讲,因为这里翻车率最高。先备份 sshd_config,然后用 sed 修改关键项,最后 reload 服务。注意我用的是 reload 而不是 restart,这么做的原因是 reload 不会把当前连接全部断掉,即使配置有问题,你还有一条活路可以抢救。
bash复制config_sshd() {
log_info "配置 SSH 安全策略"
backup_file /etc/ssh/sshd_config
# 设置 SSH 端口
sed -i "s/^#Port 22/Port $SSH_PORT/" /etc/ssh/sshd_config
sed -i "s/^Port 22/Port $SSH_PORT/" /etc/ssh/sshd_config
# 禁止 root 密码登录,但允许公钥登录
sed -i "s/^#PermitRootLogin yes/PermitRootLogin no/" /etc/ssh/sshd_config
sed -i "s/^PermitRootLogin yes/PermitRootLogin no/" /etc/ssh/sshd_config
sed -i "s/^#PubkeyAuthentication yes/PubkeyAuthentication yes/" /etc/ssh/sshd_config
sed -i "s/^#PasswordAuthentication yes/PasswordAuthentication no/" /etc/ssh/sshd_config
sed -i "s/^PasswordAuthentication yes/PasswordAuthentication no/" /etc/ssh/sshd_config
echo "MaxAuthTries 3" >> /etc/ssh/sshd_config
echo "ClientAliveInterval 60" >> /etc/ssh/sshd_config
echo "ClientAliveCountMax 3" >> /etc/ssh/sshd_config
# 不要在这里 restart,先用 reload 验证
sshd -t && systemctl reload sshd
log_info "SSH 配置已生效,新端口为 $SSH_PORT"
}
这里有一个非常关键的经验:如果改了 SSH 端口,一定要先把新端口加入防火墙策略,再 reload sshd,否则下次连接会直接超时。防火墙处理我写成单独函数,放在 config_sshd 前面执行。
bash复制config_firewall() {
log_info "配置防火墙"
# 如果机器前面有安全组/硬件防火墙,这里可以直接关闭本机 firewalld
# systemctl disable --now firewalld
# return
# 如果没有外部防护,至少放通 SSH 端口
systemctl enable --now firewalld
firewall-cmd --permanent --add-port=${SSH_PORT}/tcp
firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --permanent --add-port=443/tcp
firewall-cmd --reload
}
3.4 应用安装模块
JDK 和 Docker 我单独拆了函数。JDK 用 tar 包解压避免 yum 源里 openjdk 版本太老;Docker 则固定版本,避免最新版和 CentOS 7 的内核兼容性翻车。
bash复制install_jdk() {
local java_version="8u202-linux-x64"
local java_home="/usr/local/java"
log_info "安装 JDK $java_version"
mkdir -p "$java_home"
# 假设包已经下载到 /data/packages/,或者用 wget 拉一个内网地址
wget -P /data/packages/ http://你的内网镜像服务器/jdk-${java_version}.tar.gz
tar -zxf /data/packages/jdk-${java_version}.tar.gz -C "$java_home" --strip-components=1
cat > /etc/profile.d/java.sh <<EOF
export JAVA_HOME=$java_home
export PATH=\$JAVA_HOME/bin:\$PATH
EOF
source /etc/profile.d/java.sh
java -version
}
install_docker() {
log_info "安装 Docker 20.10.x"
yum install -y yum-utils
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -o /etc/yum.repos.d/docker-ce.repo
sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
yum install -y docker-ce-20.10.24 docker-ce-cli-20.10.24 containerd.io
systemctl enable --now docker
docker version
}
JDK 的安装路径和内网源地址需要根据公司环境改,脚本里写成内网地址是因为我在公司内部就是这样干的。如果你在云上,直接从华为云等公开源拉取也可以,重点是不要下载一个损坏的包就往下走。
3.5 主流程入口
主流程函数按顺序调用上面这些模块。因为脚本追求模块化,主流程读起来非常清晰。
bash复制main() {
check_root
log_info "开始 CentOS 7 初始化"
set_yum_repo
install_base_tools
disable_selinux
set_time_and_date
set_sysctl_config
set_limits_config
create_deploy_user
config_firewall
config_sshd
if [[ "$INSTALL_JDK" == "yes" ]]; then
install_jdk
fi
if [[ "$INSTALL_DOCKER" == "yes" ]]; then
install_docker
fi
log_info "初始化全部完成,日志文件:$LOG_FILE"
log_warn "注意:请及时修改部署用户临时密码,并按需配置 SSH 公钥"
}
main "$@"
有些公司希望初始化后自动重启,可以在脚本最后加一个判断,但我不推荐自动化脚本里直接 reboot,风险太大,应该是人工确认后再重启。
4. 实际执行中的常见问题与排查技巧
脚本写得好不好,拉到真实环境跑一遍才知道。这里把我实际执行初始化脚本时遇到的经典问题整理出来,有些坑真的很隐蔽。
4.1 软件源失效导致 yum 安装大面积失败
有段时间阿里云源在国内某些网络环境下访问不稳定,脚本里 wget 下载 CentOS-Base.repo 直接超时,后面所有 yum install 全部失败。后来我在脚本里加了两个处理。第一,wget 命令加超时参数 --timeout=20 --tries=3,不要让它无限等下去。第二,下载失败后自动切换 vault 源策略,保证脚本不会因为一个源失败而全盘崩溃。
另外要注意 vault.centos.org 的仓库里没有 7.9.2009 之外的目录,如果你用 $releasever 变量,在 CentOS 7 上解析成 7 是找不到目录的。所以 vault 源必须写死 7.9.2009,这个细节我踩过一次,yum 一直报 404 还以为是网络问题。
4.2 SSH 加固后把自己锁在外面
这个问题的经典程度不用多说。我后来给自己定了几条规矩。第一,在脚本里改 sshd_config 之前先备份,并把备份文件名加上时间戳,方便快速回滚。第二,使用 reload 而不是 restart,reload 不强制断开已有连接。第三,如果修改 SSH 端口,必须在同一会话里先测试新端口是否可连,再退出现有会话。
有一次我在脚本里先关了密码登录,再去部署公钥,顺序反了,导致机器彻底失联。现在我在创建用户模块里就默认写入公钥,只有公钥写入成功后才允许关闭密码登录。这个顺序问题在文档里很少被强调,但实际运维中真的能坑到人。
4.3 脚本重复执行时幂等性不足
第一次写脚本时,创建用户那步没有做存在性判断,结果初始化脚本跑第二遍直接 useradd 报错,但因为 set -e 的存在,脚本当场退出,后续所有操作全部中断。后来我把幂等性检查补齐了,核心函数里都加了 if 判断,比如用户存在就跳过、软件已安装就跳过、备份文件存在就跳过。这一轮补丁之后,脚本重复执行可以安心很多。
内核参数和 limits 配置这类文件写入操作,重复执行会覆盖成同样的内容,其实没有副作用,但配置文件备份越来越多,所以备份目录要定期清理,或者只保留最近 5 份。
4.4 常见问题速查表
| 问题现象 | 可能原因 | 处理方法 |
|---|---|---|
| yum install 报 Could not resolve host | DNS 未配置 | 检查 /etc/resolv.conf,脚本开头加入 DNS 检查 |
| yum 报 Cannot find a valid baseurl | 源地址失效 | 切换到 vault.centos.org 或内网镜像源 |
| 修改 SSH 端口后连接超时 | 防火墙未放行新端口 | 通过 VNC/IPMI 登录,放行端口或回滚配置 |
| 脚本执行到一半中断 | 某条命令失败,set -e 生效 | 查看 LOG_FILE,定位最后成功执行的步骤 |
| 用户密码登录失败 | PasswordAuthentication 已关闭但公钥未配置 | 用运维账号进入,写入公钥或开启密码登录 |
| chronyc sources 一直无输出 | 公网 NTP 端口被防火墙拦截 | 检查 outbound 123/udp 或使用内网 NTP 服务器 |
| 时间同步后业务时间仍不准 | 时区配置错误或 tzdata 未更新 | timedatectl set-timezone 重置,再重启 chronyd |
5. 从初始化脚本走向自动化运维
初始化脚本只是第一步,真正要让服务器管理省心,还得靠自动化和配置管理工具沉淀。脚本里积累的这些模块,后来我迁移到了 Ansible 的 role 里,通过 inventory 分组控制哪些机器装 Docker、哪些机器装 JDK,比每台机器手工跑脚本更可控。
如果你团队只有几台机器,这个脚本完全够用。如果机器数量上到几十台,建议在脚本外面包一层批量执行工具,比如 pssh、ansible ad-hoc,或者用 Jenkins pipeline 在交付时自动触发。脚本本身已经模块化,迁移到 Ansible role 时只需要把函数体改写成 task,成本很低。
我个人的操作习惯是:新机器装完系统,先跑脚本完成基础初始化,再根据业务角色补装应用。每次新环境需要不同配置,我会复制脚本再改头部参数,而不是直接在公用脚本上不断堆功能。脚本文件本身我也会放到 git 仓库里管理,每次变更都有记录,方便排查问题。
最后再分享一个小技巧,脚本执行前先在测试机跑一遍,确认没有报错再批量上生产机器。遇到环境差异导致的问题,优先在测试机复现,别在生产机器上反复试错。这个习惯帮我避开了不少麻烦,也建议你从第一次使用初始化脚本开始就保持。
