FAQ-17:在 Ubuntu 上安装 Go

预计阅读时间:14 分钟

📖 目录

问题速查表

问题解决章节
安装官方预编译二进制(推荐)方式一:安装官方二进制(推荐)
想要最简便的安装方式方式二:使用 Snap
需要从源码编译 Go方式三:使用 Git 手动安装(适合开发者)
go: command not found错误一:go: command not found
GOPATH 目录写入权限不足错误二:permission denied 写入 GOPATH
GOPATH 是什么?需要配置吗?错误三:GOPATH 是什么?需要配置吗?
下载模块超时或缓慢错误四:下载模块超时

Go(Golang)是云原生基础设施最常用的语言之一。Docker、Kubernetes、Terraform、Prometheus 等核心项目都用 Go 编写。Go 编译出的是静态链接的单一二进制文件,部署极其方便,非常适合 CLI 工具、微服务和系统级程序的开发。本文提供多种安装方式,并附带完整的环境配置和常见问题排查。

安装方法

方式一:安装官方二进制(推荐)

Go 官方提供了预编译的二进制包,这是最直接、最可控的安装方式。

# 下载最新版本(访问 https://go.dev/dl/ 获取最新版本号)
wget https://go.dev/dl/go1.22.5.linux-amd64.tar.gz

# 解压到 /usr/local(先清理旧版本)
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.22.5.linux-amd64.tar.gz

# 将 Go 加入 PATH(编辑 ~/.bashrc 或 ~/.profile)
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
echo 'export GOPATH=$HOME/go' >> ~/.bashrc
echo 'export PATH=$PATH:$GOPATH/bin' >> ~/.bashrc

# 重新加载 shell 配置
source ~/.bashrc

# 验证
go version

方式二:使用 Snap

Snap 提供了最简便的安装方式,但版本更新可能稍有滞后。

# 安装 Go
sudo snap install go --classic

# 验证
go version

# 查看安装路径
which go

方式三:使用 Git 手动安装(适合开发者)

如果你需要从源码编译 Go 本身(例如参与 Go 语言开发),可以克隆官方仓库。

# 安装编译依赖
sudo apt install -y git gcc make

# 克隆 Go 源码
git clone https://go.googlesource.com/go
cd go

# 编译(需要已安装的 Go 来编译新版本,称为 bootstrap)
cd src
./make.bash

# 安装编译好的 Go
sudo cp -R ../bin /usr/local/go/bin
sudo cp -R ../pkg /usr/local/go/pkg

# 验证
go version

版本管理

如果你需要在多个 Go 版本之间切换,可以使用 gvm(Go Version Manager)或手动管理。

# 查看当前安装的 Go 版本
go version

# 下载新版本(覆盖安装)
# 访问 https://go.dev/dl/ 获取版本号
wget https://go.dev/dl/go1.21.13.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.21.13.linux-amd64.tar.gz

# 使用 gvm 管理多版本(可选)
bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)
gvm install go1.22.5
gvm use go1.22.5 --default

在 Go 项目中,可以通过 go.mod 文件的 go 指令声明所需的最低 Go 版本,确保团队成员使用一致的版本。

Go 环境验证

安装后先执行 go env 确认关键配置,常见的环境问题大多集中在这几个字段:

$ go env
GOROOT=/usr/local/go          # Go 安装目录(官方二进制默认)
GOPATH=/root/go               # 工作区:源码/缓存/编译产物
GOBIN=                        # 空=go install 产物放到 $GOPATH/bin
GOPROXY=https://proxy.golang.org,direct  # 模块下载源
GO111MODULE=on                # 模块模式(1.16+ 默认开启)

# 快速自检三步
go version                     # 版本
go env GOPATH                  # 工作区路径
go install golang.org/x/tools/gopls@latest  # 装一个工具验证 go install 可用

GOPATH vs Go Modules:Go 1.11+ 引入模块模式后,项目不再强制放在 $GOPATH/src 下,任何目录都可以建 go.mod 独立开发。若发现"import 报 cannot find package",多半是模块模式未开启(GO111MODULE=off)或依赖未下载(go mod tidy)。

GOPROXY 配置:国内网络推荐使用镜像加速,避免下载超时:

go env -w GOPROXY=https://goproxy.cn,direct
go env -w GOSUMDB=sum.golang.org   # 保持校验和验证

常见错误

错误一:go: command not found

Go 的可执行文件不在系统 PATH 中。确认 /usr/local/go/bin 已加入 PATH:

# 检查 PATH
echo $PATH | tr ':' '\n' | grep go

# 如果没有,手动添加
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc

# 验证
go version

错误二:permission denied 写入 GOPATH

Go 在下载模块和编译时需要写入 $GOPATH(默认为 ~/go)。如果该目录权限有问题:

# 确认 GOPATH 目录存在且可写
ls -la ~/go
mkdir -p ~/go
chmod -R u+w ~/go

错误三:GOPATH 是什么?需要配置吗?

Go 模块在 1.16+ 版本后已不需要设置 GOPATH 来存放项目代码。模块代码可以存放在任意目录,使用 go mod init 初始化即可。GOPATH 现在主要用于存放下载的模块缓存和编译产物。

# 查看 Go 环境配置
go env GOPATH GOROOT GOMODCACHE

# 清理模块缓存(磁盘空间不足时有用)
go clean -modcache

错误四:下载模块超时

国内网络环境下,Go 模块代理可能连接缓慢:

# 设置国内镜像代理
go env -w GOPROXY=https://goproxy.cn,direct

# 验证设置
go env GOPROXY

# 如果需要绕过代理
go env -w GOPROXY=off

错误五:go vet 或编译报错——缺少 C 编译器

某些 CGO 包(如 sqlite3)需要 C 编译器:

# 安装 gcc 和相关工具
sudo apt install -y gcc libc6-dev

# 禁用 CGO 编译纯 Go 项目(可选)
CGO_ENABLED=0 go build -o myapp

真实案例

案例 A:go install 装好的工具命令找不到

用户执行 go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest 成功,但运行 golangci-lint 却提示 command not found。

# 报错
golangci-lint: command not found

# 排查:go install 的产物在哪
go env GOBIN        # 为空
go env GOPATH       # /root/go
# 产物实际在 $GOPATH/bin(GOBIN 为空时的默认位置)
ls /root/go/bin/    # golangci-lint 存在

# 修复:把 GOBIN 加入 PATH
echo 'export PATH=$PATH:$(go env GOPATH)/bin' >> ~/.bashrc
source ~/.bashrc

# 验证
which golangci-lint

根因:GOBIN 未设置时工具装到 $GOPATH/bin,而该目录不在 PATH;验证which golangci-lint 输出实际路径,新开终端也正常。

案例 B:GO111MODULE 旧项目 import 报错

# 报错
cannot find package "github.com/gin-gonic/gin" in any of:
        /usr/local/go/src/github.com/gin-gonic/gin (from $GOROOT)
        /root/go/src/github.com/gin-gonic/gin (from $GOPATH)

# 排查:项目没有 go.mod(还是 GOPATH 时代的项目)
ls go.mod    # No such file

# 修复:初始化模块并拉取依赖
go mod init myapp
go get github.com/gin-gonic/gin
go mod tidy

# 验证
go build ./...    # 编译通过

根因:项目停留在 GOPATH 模式(GO111MODULE=off 或无 go.mod);修复go mod init 迁移到模块模式;验证go build 成功,go.mod 已生成并记录依赖版本。

案例 C:GOPROXY 未设置导致国内环境依赖下载超时

现象:执行 go get github.com/gin-gonic/gin 卡住很久后报 dial tcp: lookup proxy.golang.org: no such host

# 默认代理 proxy.golang.org 在国内不可达
$ go env GOPROXY
https://proxy.golang.org,direct

# 设置国内代理
$ go env -w GOPROXY=https://goproxy.cn,direct
$ go env GOPROXY
https://goproxy.cn,direct

# 重新拉取依赖
$ go get github.com/gin-gonic/gin    # 秒级完成

根因:Go 模块默认通过 proxy.golang.org 下载依赖,该服务在国内访问不稳定。

修复go env -w GOPROXY=https://goproxy.cn,direct 设置国内镜像代理。direct 表示代理不存在时直接从源站下载。

验证安装

# 查看版本
go version

# 查看环境配置
go env

# 创建测试项目
mkdir ~/hello && cd ~/hello
go mod init hello

# 创建 main.go
cat > main.go << 'GOEOF'
package main

import "fmt"

func main() {
    fmt.Println("Hello from Go!")
}
GOEOF

# 编译并运行
go run main.go

# 编译为独立二进制文件
go build -o hello ./main.go
./hello

# 交叉编译(编译为 ARM64 架构)
GOOS=linux GOARCH=arm64 go build -o hello-arm64 ./main.go

# 清理
rm -f hello hello-arm64
cd ~ && rm -rf ~/hello

案例 D:go build 报 no required module provides package

项目依赖一个内部包,执行 go buildno required module provides package

# 报错
no required module provides package mycompany.com/internal/pkg:
        mycompany.com/internal/pkg imported by myapp
        to add it: go get mycompany.com/internal/pkg

# 排查:go.mod 中没有声明该依赖
cat go.mod | grep mycompany
# 无输出

# 修复:添加私有仓库配置
go env -w GOPRIVATE=mycompany.com/*
go env -w GONOSUMDB=mycompany.com/*
go env -w GONOPROXY=mycompany.com/*

# 配置 git 凭证(私有仓库需要认证)
git config --global url."git@github.com:mycompany/".insteadOf "https://github.com/mycompany/"

# 拉取依赖
go get mycompany.com/internal/pkg
go mod tidy

# 验证
go build ./...

根因:Go 模块默认通过公共代理下载,私有仓库需要配置 GOPRIVATE 和认证方式;修复:设置 GOPRIVATE 跳过代理和校验,并配置 Git 凭证;预防:团队文档中记录私有仓库配置步骤。

案例 E:交叉编译报 CGO_ENABLED=1 错误

执行 GOOS=linux GOARCH=arm64 go build 报错找不到 C 编译器,原因是启用了 CGO 但缺少目标架构的交叉编译工具链。

# 报错(真实输出:找不到目标架构的 C 交叉编译器)
$ CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build -o myapp
# exec: "aarch64-linux-gnu-gcc": executable file not found in $PATH

# 原因:CGO_ENABLED=1 时需要目标架构的 C 交叉编译器
# 解决方案一:禁用 CGO(纯 Go 项目推荐)
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o myapp-arm64

# 解决方案二:安装交叉编译工具链
sudo apt install -y gcc-aarch64-linux-gnu
CC=aarch64-linux-gnu-gcc CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build -o myapp-arm64

# 解决方案三:使用 Docker 交叉编译
docker run --rm -v "$PWD":/work -w /work golang:1.22 \
  GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o myapp-arm64 .

# 验证
file myapp-arm64    # ELF 64-bit LSB executable, ARM aarch64

根因:CGO 启用时 Go 需要调用 C 编译器,交叉编译需要对应架构的交叉编译器;修复:纯 Go 项目禁用 CGO(CGO_ENABLED=0),需要 CGO 则安装交叉编译工具链。

版本管理详解

gvm 完整使用指南

gvm(Go Version Manager)是 Go 的多版本管理工具,类似于 nvm 之于 Node.js:

# 安装 gvm
bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)

# 重新加载 shell
source ~/.bashrc

# 查看已安装版本
gvm list
# gvm
#    go1.21.13
#    go1.22.5
# => go1.22.6
#    stable

# 安装指定版本
gvm install go1.22.6
gvm install go1.21.13

# 切换版本
gvm use go1.21.13
gvm use go1.22.6 --default   # 设为默认

# 使用 stable 通道自动安装最新稳定版
gvm install stable
gvm use stable --default

# 卸载版本
gvm uninstall go1.21.13

# 查看远程可用版本
gvm listall | grep "1.22"

# 注意:gvm 会覆盖 GOROOT,切换版本后检查环境
go env GOROOT
go version

手动管理多版本

如果不想安装额外工具,可以手动管理多个 Go 版本:

# 下载多个版本
wget https://go.dev/dl/go1.21.13.linux-amd64.tar.gz
wget https://go.dev/dl/go1.22.6.linux-amd64.tar.gz

# 解压到不同目录
sudo tar -C /usr/local -xzf go1.21.13.linux-amd64.tar.gz
sudo mv /usr/local/go /usr/local/go1.21.13

sudo tar -C /usr/local -xzf go1.22.6.linux-amd64.tar.gz
sudo mv /usr/local/go /usr/local/go1.22.6

# 创建切换脚本
cat > ~/go-switch.sh << 'EOF'
#!/bin/bash
VERSION=${1:-"1.22.6"}
sudo rm -rf /usr/local/go
sudo ln -s /usr/local/go${VERSION} /usr/local/go
go version
EOF
chmod +x ~/go-switch.sh

# 使用
~/go-switch.sh 1.21.13   # 切到 1.21.13
~/go-switch.sh 1.22.6    # 切到 1.22.6

go.mod 中的版本约束

# go.mod 中声明最低 Go 版本
module myapp

go 1.21    # 最低要求 Go 1.21

# go.sum 校验和(提交到 Git,确保依赖完整性)
# go.sum 由 go mod tidy 生成,不要手动修改

# 查看模块可用版本
go list -m -versions github.com/gin-gonic/gin
# github.com/gin-gonic/gin v1.7.0 v1.7.1 ... v1.9.1

# 升级依赖到最新版
go get -u github.com/gin-gonic/gin@latest

# 升级所有直接依赖
go get -u

# 降级依赖
go get github.com/gin-gonic/gin@v1.9.0

# 查看可升级的依赖
go list -m -u all

# tidy:清理不需要的依赖,添加缺少的依赖
go mod tidy

# vendor:将依赖复制到 vendor 目录(离线构建)
go mod vendor
go build -mod=vendor ./...

GOPROXY 镜像对比

# 国内常用镜像
go env -w GOPROXY=https://goproxy.cn,direct          # 七牛云(推荐)
go env -w GOPROXY=https://goproxy.io,direct          # goproxy.io
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy # 阿里云

# 自建代理(企业内网)
# 使用 go module 镜像工具:goproxy
go install github.com/goproxyio/goproxy@latest
goproxy -listen=:8080 -cache-dir=/tmp/goproxy-cache

# 各代理特点
# goproxy.cn:   国内最稳定,七牛云维护,同步速度快
# goproxy.io:   国际版,国内可用但速度略慢
# 阿里云镜像:   需要阿里云内网访问权限

故障排查决策树

当 Go 环境出现问题时,按以下流程排查:

问题:go: command not found
├── which go 有输出?
│   ├── 是 → PATH 正常,检查是否被覆盖:type go
│   └── 否 → 查找安装位置:
│       ├── ls /usr/local/go/bin/go /snap/bin/go 2>/dev/null
│       │   ├── 有 → 加入 PATH
│       │   └── 无 → 未安装:选择安装方式
│       └── gvm 环境?
│           ├── gvm list 查看已安装版本
│           ├── gvm use  激活
│           └── source ~/.bashrc 重新加载 gvm 初始化

问题:go build 报 "cannot find package"
├── 检查模块模式:go env GO111MODULE
│   ├── off → 设置开启:go env -w GO111MODULE=on
│   └── on → 继续排查
├── 检查 go.mod 是否存在
│   ├── 不存在 → 初始化:go mod init myapp
│   └── 存在 → 继续排查
├── 检查依赖是否下载:go mod download
│   ├── 失败 → 检查 GOPROXY:go env GOPROXY
│   │   └── 设置国内代理:go env -w GOPROXY=https://goproxy.cn,direct
│   └── 成功 → 检查包名拼写和版本

问题:go install 工具命令找不到
├── 检查 GOBIN:go env GOBIN
│   ├── 为空 → 工具在 $(go env GOPATH)/bin
│   ├── 有值 → 工具在 $GOBIN
│   └── 修复:echo 'export PATH=$PATH:$(go env GOPATH)/bin' >> ~/.bashrc
└── 验证:which 

问题:go mod tidy 报错
├── 检查网络:go env GOPROXY
│   └── 设置代理:go env -w GOPROXY=https://goproxy.cn,direct
├── 检查 go.mod 语法:cat go.mod
│   └── 修复语法错误(缺少 module 声明等)
└── 检查版本约束冲突
    └── 调整 go.mod 中的 require 版本

问题:交叉编译报错
├── CGO_ENABLED=1 时缺少交叉编译器
│   └── 禁用 CGO:CGO_ENABLED=0 go build
├── 目标平台不支持
│   └── 检查 GOOS/GOARCH 组合是否有效
└── Docker 交叉编译
    └── 使用官方 golang 镜像构建

生产环境配置建议

  • 使用 Go Modules 锁定依赖:所有项目都应使用 go.modgo.sum,CI 中用 go mod verify 校验依赖完整性。
  • 设置国内镜像代理:生产环境部署时配置 GOPROXY=https://goproxy.cn,direct,加速构建过程。
  • 使用多阶段 Docker 构建:builder 阶段编译,runtime 阶段只复制二进制文件,镜像体积可从 800MB+ 降到 10MB 以下。
  • 启用 go vet 和 staticcheck:CI 中加入 go vet ./...staticcheck ./... 作为代码质量卡点。
  • 使用 race detector 检测并发问题:测试时开启 go test -race ./...,检测数据竞争。
  • 保持 Go 版本更新:Go 小版本更新通常包含安全修复,建议至少保持在最新两个小版本。生产环境可锁定版本:go env -w GOVERSION=go1.22.6
  • 善用交叉编译准备部署:在开发机上交叉编译出 ARM64 二进制,直接部署到 ARM 服务器,无需在目标机器上安装 Go 环境。
  • 使用 go generate 管理代码生成:在代码中用 //go:generate 注释声明需要生成的代码,统一代码生成流程。

案例 F:go mod tidy 报 "go.sum has unexpected contents"

执行 go mod tidy 报错 go.sum has unexpected contents,怀疑 go.sum 被篡改。

# 报错
go: go.sum has unexpected contents
go: updates to go.sum needed

# 排查:go.sum 文件内容异常
head -5 go.sum
# 内容看起来正常

# 可能原因:go.sum 与 go.mod 不同步
# (有人手动修改了 go.mod 但没更新 go.sum)

# 修复:删除 go.sum 重新生成
rm go.sum
go mod tidy

# 或直接更新
go mod download all

# 验证
go mod verify    # 校验通过
go build ./...   # 编译通过

根因go.sumgo.mod 不同步(可能是手动编辑或分支合并冲突导致);修复:删除 go.sum 后执行 go mod tidy 重新生成。

案例 G:32 位系统无法运行 64 位 Go 程序

在 32 位系统上运行 64 位交叉编译出的测试/二进制,报 exec format error。

# 报错(真实输出:架构不匹配,内核拒绝加载)
bash: ./myapp: cannot execute binary file: Exec format error

# 排查:检查系统架构
uname -m    # i686(32位)

# 原因:Go 1.22 起官方不再提供 32 位安装包(amd64 二进制无法在 i386 上运行)

# 修复:改用 64 位系统编译/运行,或在 64 位机器上交叉编译
GOOS=linux GOARCH=amd64 go build -o myapp ./...

# 或安装 64 位 Go(如果系统支持)
wget https://go.dev/dl/go1.22.6.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.22.6.linux-amd64.tar.gz

# 验证
go env GOARCH    # amd64

根因:Go 1.21+ 不再支持 32 位架构,在 32 位系统上运行测试需要交叉编译为 64 位;修复:设置 GOARCH=amd64 交叉编译。

最佳实践

  • 使用 Go Modules:所有 Go 项目都应使用模块管理依赖,在项目根目录运行 go mod init 初始化。
  • 设置国内镜像代理:在国内网络环境下,配置 GOPROXY=https://goproxy.cn,direct 可以显著加速依赖下载。
  • 使用 go vet 检查代码:在提交代码前运行 go vet ./... 检查潜在错误,比编译器更严格。
  • 保持 Go 版本更新:Go 的小版本更新通常包含安全修复和性能改进,建议至少保持在最新的两个小版本。
  • 善用交叉编译:Go 的交叉编译非常方便,可以在 x86 机器上编译出 ARM64 二进制,适合为不同架构的服务器准备部署文件。

延伸阅读

案例 H:go workspace 模式与模块模式冲突

现象:在 monorepo 项目中执行 go build ./... 报错 no required module provides package,但依赖已下载:

# 报错
no required module provides package mycompany.com/internal/pkg:
        mycompany.com/internal/pkg imported by myapp
        to add it: go get mycompany.com/internal/pkg

# 检查 go.work 文件
$ cat go.work
go 1.22

use (
    ./app1
    ./app2
)

排查过程

# 检查 go.work 模式是否启用
$ go env GOWORK
auto

# 尝试关闭 workspace 模式
$ GOWORK=off go build ./...
# 成功

根因:go.work 文件中 use 的模块路径与实际目录结构不匹配,导致 workspace 模式下依赖解析失败。

修复

# 修正 go.work 中的模块路径
cat > go.work << 'EOF'
go 1.22

use (
    ./app1
    ./app2
    ./shared
)
EOF

# 同步依赖
go work sync

# 验证
go build ./...

预防:使用 go workspace 前确保所有模块路径正确。团队协作时将 go.work 提交到 Git,确保所有人使用相同的 workspace 配置。

↑ 回到顶部