在Linux运维领域,Go语言正逐渐成为自动化脚本的首选——它编译后生成单一可执行文件,部署简单,并发处理能力强。今天我们就以CentOS系统为例,从环境搭建到实战脚本,再到生产级服务部署,完整走一遍流程。

1. 环境准备:安装Go语言
在CentOS上安装Go并不复杂。用wget下载最新版Go压缩包(例如go1.20.linux-amd64.tar.gz),解压到/usr/local目录,然后配置环境变量。编辑~/.bash_profile,加入以下两行:
export GOPATH=$HOME/go
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
保存后执行source ~/.bash_profile让配置生效,最后用go version确认安装成功。整个过程不超过五分钟。
2. 编写常见运维脚本
下面我们直接从三个最常用的场景入手:定时巡检、日志清理、服务监控与自动重启。这些代码拿来就能用,但建议根据实际环境调整路径和周期。
2.1 定时系统巡检(磁盘使用率)
通过time.Ticker实现周期性任务,核心逻辑是用os/exec包执行df -h命令,然后筛选出包含/dev/的行——这些通常是实际挂载的设备。示例代码如下,每5分钟输出一次磁盘状态:
package main
import (
"fmt"
"os/exec"
"strings"
"time"
)
func checkDiskUsage() {
cmd := exec.Command("df", "-h")
output, err := cmd.Output()
if err != nil {
fmt.Printf("执行df命令失败: %v\n", err)
return
}
lines := strings.Split(string(output), "\n")
for _, line := range lines {
if strings.Contains(line, "/dev/") {
fmt.Println("磁盘状态:", line)
}
}
}
func main() {
ticker := time.NewTicker(5 * time.Minute)
defer ticker.Stop()
checkDiskUsage() // 立即执行一次
for range ticker.C {
checkDiskUsage()
}
}
当然,实际运维中你可以把输出写入日志或推送到监控平台,这个框架可以很灵活地扩展。
2.2 自动化日志清理
日志文件日积月累会吃掉大量磁盘空间。这里用filepath.Walk遍历指定目录(比如/var/log/myapp),结合time.Now()计算文件的最后修改时间,删除超过7天的.log文件。配合time.Ticker实现每日自动清理:
package main
import (
"fmt"
"os"
"path/filepath"
"time"
)
func cleanupLogs(logDir string, maxAgeDays int) {
now := time.Now()
cutoff := now.AddDate(0, 0, -maxAgeDays)
filepath.Walk(logDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return nil
}
if !info.IsDir() && filepath.Ext(path) == ".log" && info.ModTime().Before(cutoff) {
if err := os.Remove(path); err == nil {
fmt.Printf("已删除过期日志: %s\n", path)
}
}
return nil
})
}
func main() {
for range time.NewTicker(24 * time.Hour).C {
cleanupLogs("/var/log/myapp", 7)
}
}
注意这里的AddDate(0, 0, -maxAgeDays)简洁地算出了7天前的截止时间,比手动计算秒数要优雅得多。
2.3 服务状态监控与自动重启
生产环境中服务意外设掉是家常便饭。通过systemctl is-active命令检查服务状态,如果返回不是active,就调用systemctl start重启。这里设置每30秒检查一次:
package main
import (
"fmt"
"os/exec"
"strings"
"time"
)
func isServiceRunning(serviceName string) bool {
cmd := exec.Command("systemctl", "is-active", serviceName)
output, err := cmd.Output()
return err == nil && strings.TrimSpace(string(output)) == "active"
}
func startService(serviceName string) {
cmd := exec.Command("systemctl", "start", serviceName)
if err := cmd.Run(); err != nil {
fmt.Printf("启动服务 %s 失败: %v\n", serviceName, err)
} else {
fmt.Printf("已启动服务: %s\n", serviceName)
}
}
func monitorService(serviceName string) {
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
for range ticker.C {
if !isServiceRunning(serviceName) {
fmt.Printf("服务 %s 未运行,尝试重启...\n", serviceName)
startService(serviceName)
}
}
}
func main() {
monitorService("myweb") // 替换为目标服务名
}
这种模式特别适合那些没有自带高可用机制的服务,用Go写一个轻量级守护进程,比用shell脚本更可控。
3. 部署与管理:从脚本到生产级服务
脚本写好了,怎么让它稳定运行?这里提供两种方案:systemd和Supervisor。前者是CentOS原生推荐,后者则更灵活。
3.1 构建Go应用
将脚本编译为可执行文件:
go build -o cleanup-logs cleanup-logs.go
chmod +x cleanup-logs
编译后只有一个二进制文件,复制到目标机器的/usr/local/bin或自定义路径即可。
3.2 注册为Systemd服务
创建服务文件/etc/systemd/system/cleanup-logs.service:
[Unit]
Description=Daily Log Cleanup Service
After=network.target
[Service]
Type=simple
ExecStart=/path/to/cleanup-logs
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
然后依次执行:
systemctl daemon-reload
systemctl enable cleanup-logs
systemctl start cleanup-logs
用systemctl status cleanup-logs查看状态,确保一切正常。这样服务就能随系统启动自动运行,且崩溃后自动重启。
3.3 部署优化:使用Supervisor守护进程
虽然systemd已经够用,但Supervisor在某些场景下更友好——比如需要更细粒度的进程控制、日志管理或Web管理界面。先安装:
yum install epel-release -y
yum install supervisor -y
systemctl start supervisord
systemctl enable supervisord
在/etc/supervisord.d/下创建配置cleanup-logs.conf:
[program:cleanup-logs]
command=/path/to/cleanup-logs
autostart=true
autorestart=true
stderr_logfile=/var/log/cleanup-logs.err.log
stdout_logfile=/var/log/cleanup-logs.out.log
然后执行supervisorctl reread和supervisorctl update使配置生效。用supervisorctl status可以看到进程状态。两种方式二选一即可,个人更推荐systemd原生方案,少装一个依赖。
4. 关键注意事项
- 错误处理与日志记录:脚本中每个
if err != nil都不应该被忽略。生产环境中建议使用log包或第三方库(如logrus、zap)输出结构化日志,方便后续和ELK等日志系统对接。 - 性能优化:如果要对成百上千台服务器执行SSH操作,Go的
goroutine和channel是天生优势。配合golang.org/x/crypto/ssh库可以实现无密码批量执行命令,效率远超shell循环。 - 安全实践:硬编码密码是运维大忌。敏感信息应通过环境变量或配置文件(推荐
viper库)管理。另外定期更新Go版本,及时修复已知安全漏洞。
从零搭建到生产部署,这条路径经过多次验证,稳定可靠。如果你正打算用Go替代旧的shell脚本或Python脚本,不妨从这三个小工具开始试点。
