Appearance
Go环境与基础语法
Go 常用于写运维工具、Exporter、控制器、命令行程序和 Kubernetes 相关组件。它编译成单个二进制文件,部署时不依赖目标机器上的解释器;标准库里自带 HTTP、JSON、并发、文件和系统命令能力,适合写长期维护的小工具。
Shell 适合直接串系统命令,Python 适合快速处理脚本和接口,Go 更适合做需要长期运行、并发处理、交付成二进制的工具。比如 Exporter、Webhook、Kubernetes Controller、批量巡检 Agent 这类程序,用 Go 会更自然。
一、Go 程序运行链路
Go 源码先通过 go build 编译成二进制文件,二进制再在目标机器运行。
和 Python 脚本不同,目标机器上通常不需要安装 Go 才能运行已经编译好的程序。目标机器只需要能执行这个二进制,并且系统架构匹配。
二、安装 Go
安装前先确认环境:
bash
go version
which goRocky / RHEL / CentOS 可以先用系统包:
bash
dnf install -y golang
go version
go env GOPATH GOROOT GOPROXYUbuntu / Debian:
bash
apt-get update
apt-get install -y golang-go
go version
go env GOPATH GOROOT GOPROXY系统仓库的 Go 版本可能偏旧。需要固定新版本时,通常用官方二进制包安装到 /usr/local/go,再把 /usr/local/go/bin 加入 PATH。
bash
# 先清理旧的官方安装目录,避免多个版本混在一起
rm -rf /usr/local/go
# go<version>.linux-amd64.tar.gz 按实际版本替换
tar -C /usr/local -xzf go<version>.linux-amd64.tar.gz
cat >/etc/profile.d/go.sh <<'EOF'
export PATH=/usr/local/go/bin:$PATH
EOF
source /etc/profile.d/go.sh
go versionWindows 上通常用官方安装包,装完后重新打开 PowerShell:
powershell
go version
go env GOPATH GOROOT GOPROXYGOROOT 是 Go 自身安装目录,GOPATH 是旧工作区和下载缓存相关目录。现在写项目主要用 Go Modules,不再把项目放进 GOPATH 下面。
三、配置模块代理
国内网络拉 Go 模块时经常慢或超时,可以配置 GOPROXY:
bash
go env -w GOPROXY=https://goproxy.cn,direct
go env GOPROXYdirect 表示代理找不到时直接访问原始仓库。公司内部私有模块还要配置 GOPRIVATE,避免私有模块路径被发到公共代理和校验服务。
bash
go env -w GOPRIVATE=git.example.com/*
go env GOPRIVATE常用相关变量:
| 变量 | 作用 |
|---|---|
GOPROXY | 模块下载代理 |
GOSUMDB | 模块校验数据库 |
GOPRIVATE | 私有模块匹配规则 |
GONOSUMDB | 不走公共校验数据库的模块 |
GO111MODULE | 模块模式开关,现代 Go 通常保持默认 |
排查模块下载问题时先看 go env。代理、私有仓库、认证、DNS 都可能影响 go mod tidy。
四、第一个 Go 项目
创建项目:
bash
mkdir -p ops-go-demo
cd ops-go-demo
# module 路径通常写成仓库路径,示例先用本地名字
go mod init example.com/ops-go-demomain.go:
go
package main
import "fmt"
func main() {
// main 是程序入口,go run 和编译后的二进制都会从这里开始执行
fmt.Println("hello go")
}运行:
bash
go run .编译:
bash
go build -o ops-go-demo .
./ops-go-demo项目目录:
text
ops-go-demo/
├── go.mod
├── main.go
└── ops-go-demogo.mod 记录模块名和依赖,main.go 是源码,ops-go-demo 是编译出来的二进制文件。
五、变量与类型
Go 是静态类型语言,变量有明确类型。编译阶段会检查类型错误。
go
package main
import "fmt"
func main() {
var service string = "nginx"
var port int = 80
var enabled bool = true
// := 是短变量声明,函数内部最常用
usage := 78.5
fmt.Println(service, port, enabled, usage)
}常见基础类型:
| 类型 | 示例 | 场景 |
|---|---|---|
string | "nginx" | 服务名、路径、日志文本 |
int | 80 | 端口、数量 |
float64 | 78.5 | 使用率、延迟 |
bool | true | 开关、检查结果 |
error | err | 错误返回 |
常量:
go
const defaultTimeout = 5
const appName = "ops-checker"Go 里未使用的变量会导致编译失败。这一点对脚本型思维不太一样,但能减少“写了但忘了用”的脏代码。
六、条件判断
Go 的 if 不需要括号,但代码块必须有 {}。
go
package main
import "fmt"
func main() {
cpuUsage := 82
if cpuUsage >= 90 {
fmt.Println("critical")
} else if cpuUsage >= 70 {
fmt.Println("warning")
} else {
fmt.Println("ok")
}
}if 可以带一个短语句,常用于错误处理:
go
if err := checkDisk("/"); err != nil {
fmt.Println("check failed:", err)
}这类写法让 err 的作用域限制在 if 语句里,避免后面误用。
七、循环
Go 只有 for,没有 while 关键字。
go
for i := 0; i < 3; i++ {
fmt.Println(i)
}类似 while:
go
retry := 0
for retry < 3 {
fmt.Println("retry", retry)
retry++
}遍历切片:
go
services := []string{"nginx", "mysql", "redis"}
for index, service := range services {
fmt.Println(index, service)
}只要值时可以用 _ 忽略索引:
go
for _, service := range services {
fmt.Println(service)
}八、函数
函数用 func 定义。参数和返回值都带类型。
go
func add(a int, b int) int {
return a + b
}连续同类型参数可以合并:
go
func add(a, b int) int {
return a + b
}Go 常见返回值是“结果 + 错误”:
go
package main
import (
"fmt"
"os"
)
func readConfig(path string) (string, error) {
data, err := os.ReadFile(path)
if err != nil {
return "", err
}
return string(data), nil
}
func main() {
content, err := readConfig("/etc/hosts")
if err != nil {
fmt.Println("read config failed:", err)
return
}
fmt.Println(content)
}nil 表示没有错误。Go 不用异常处理普通错误,函数调用方显式检查 err。
九、错误处理
创建错误:
go
import "errors"
func validatePort(port int) error {
if port < 1 || port > 65535 {
return errors.New("invalid port")
}
return nil
}带上下文的错误:
go
import "fmt"
func validatePort(port int) error {
if port < 1 || port > 65535 {
return fmt.Errorf("invalid port: %d", port)
}
return nil
}包装错误:
go
data, err := os.ReadFile("/etc/app.conf")
if err != nil {
return fmt.Errorf("read config: %w", err)
}%w 会保留原始错误,后面可以用 errors.Is 或 errors.As 判断错误类型。
十、格式化与检查
Go 官方工具链自带格式化:
bash
go fmt ./...检查和测试:
bash
go test ./...
go vet ./...编译 Linux 二进制:
bash
GOOS=linux GOARCH=amd64 go build -o bin/ops-checker .Go 的工具链比较统一。日常开发里 go fmt、go test、go mod tidy、go build 是最常用的几条命令。