“环境变量”这个词,有经验的开发同学对它一定很熟悉了,它提供给软件工程以高灵活性、高扩展性,大到操作系统,小到某个项目,都有它的影子,它的表现方式有很多。

微服务应用提倡将配置存储在环境变量中,任何从开发环境切换到生产环境时需要修改的东西都从代码抽取到环境变量里。但是在实际开发中,如果同一台机器运行多个项目,在操作系统中设置环境变量容易冲突,不实用,就会有了从 .env 文件中读取配置, 然后存储到程序的环境变量中。一个项目对应一个 .env 文件,在代码中读取 .env 文件的方式也非常方便。

很多大型项目会使用环境变量进行配置,作为配置选项的环境变量大大简化了应用程序的部署。这些在云基础设施中也很常见,一个大型项目中通常会配备一个提供环境变量配置服务的配置平台,包括 AB 平台也可以看作是此类的一个例子。

百度百科上的定义,环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:临时文件夹位置和系统文件夹位置等。环境变量是在操作系统中一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息。

那么在 Go 中,环境变量通常是什么表现形式呢?有两种很常见,分别是 Go 开发必需的环境变量、普通环境变量


Go 开发必需的环境变量

开发 Go,必须在安装 Go 语言开发工具后,再配置 Go 语言自带的开发所必需的环境变量,才算搭建好了基本的 Go 开发环境,进行接下来的 Go 项目管理和开发。

可以使用以下命令查看系统中的Golang环境变量,

// 打印 Go 所有默认的环境变量
$ go env
GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/shouyuan/Library/Caches/go-build"
GOENV="/Users/shouyuan/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/shouyuan/workspace/project/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/shouyuan/workspace/project/go"
GOPRIVATE=""
GOPROXY="https://goproxy.cn,direct"
GOROOT="/opt/homebrew/Cellar/go@1.16/1.16.15/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/homebrew/Cellar/go@1.16/1.16.15/libexec/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.16.15"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/yy/5wksklpj00j341q9w0r3jhxh0000gn/T/go-build2304754593=/tmp/go-build -gno-record-gcc-switches -fno-common"

// 打印某个环境变量的值
$ go env GOPATH
/Users/shouyuan/workspace/project/go
$ go env GOPATH GOROOT
/Users/shouyuan/workspace/project/go
/opt/homebrew/Cellar/go@1.16/1.16.15/libexec

环境变量的设置,会影响我们开发和编译项目的过程与结果,所以还是很有必要了解一下的。虽然常常需要我们配置的环境变量就那么几个,但 Go 语言提供了很多默认的环境变量,让我们可以自由地定制开发和编译器行为。上面这些环境变量中,有些伴随着 Go 一起出现在人们面前,比如 GOPATH;而有些则是随着 Go 语言的发展逐步出现,甚至不同 Go 版本同一名字的环境变量意义也会有不同,比如 GO111MODULE;有些环境变量我们可以永远都不会用到,大概了解一下就可以了。

通用的

GCCGO
GOARCH
GOBIN
GOCACHE
GOFLAGS
GOOS
GOPATH
GOPROXY
GOPRIVATE
GO111MODULE
GORACE
GOROOT
GOTMPDIR

和 cgo 一起使用的

CC
CGO_ENABLED
CGO_CFLAGS
CGO_CFLAGS_ALLOW
CGO_CFLAGS_DISALLOW
CGO_CPPFLAGS, CGO_CPPFLAGS_ALLOW, CGO_CPPFLAGS_DISALLOW
CGO_CXXFLAGS, CGO_CXXFLAGS_ALLOW, CGO_CXXFLAGS_DISALLOW
CGO_FFLAGS, CGO_FFLAGS_ALLOW, CGO_FFLAGS_DISALLOW
CGO_LDFLAGS, CGO_LDFLAGS_ALLOW, CGO_LDFLAGS_DISALLOW
CXX
PKG_CONFIG
AR

和系统架构体系相关的

GOARM
GO386
GOMIPS
GOMIPS64

专用的

GCCGOTOOLDIR
GOROOT_FINAL
GO_EXTLINK_ENABLED
GIT_ALLOW_PROTOCOL

其他

GOEXE
GOHOSTARCH
GOHOSTOS
GOMOD
GOTOOLDIR

注意:Go 提供的 Windows 安装包(.msi 后缀)安装完成后,会自动配置几个常用的环境变量。

记录几个常见的(GOROOT、GOPATH、GOBIN、GOOS、GOARCH、GOPROXY、GOPRIVATE、GO111MODULE)

GOROOT

GOROOT 表示 Go 语言的安装目录,

在 Windows 中,GOROOT 的默认值是 C:/go,在 Mac 或 Linux 中 GOROOT 的默认值是 usr/loca/go,如果将 Go 安装在其他目录中,而需要将 GOROOT 的值修改为对应的目录。

GOROOT/bin 则包含 Go 为我们提供的工具链,因此,应该将 GOROOT/bin 配置到环境变量 PATH 中,方便我们在全局中使用Go工具链。

// Mac 上通过 brew install go 安装之后,找到对应的安装目录设置即可
export GOROOT=/opt/homebrew/Cellar/go/1.18/libexec
export PATH=$PATH:$GOROOT/bin

GOPATH

GOPATH 用于指定我们的工作空间(workspace),用来存放源代码、测试文件、库静态文件、可执行文件。注意,GOPATH 的值不能和 GOROOT 相同。

类 Unix (Mac OS 或 Linux)操作系统中, GOPATH 的默认值是 $home/go。而在 Windows 中 GOPATH 的默认值则为 %USERPROFILE%\go (比如在 Admin 用户,其值为 C:\Users\Admin\go)。

我们可以通过修改GOPATH来更换工作区,

export GOPATH=$HOME/workspace/project/go

也可以在 GOPATH 中设置多个工作区,不过当我们使用 go get 命令去获取远程库的时候,一般会安装到第一个工作区当中。

export GOPATH=$HOME/workspace/project/go;$HOME/go

按照早期的 Go 开发规范和工程(包)组织规则,GOPATH 目录下一般会有三个子目录,分别是 src、pkg、bin,后来 go module 包管理方法(计划写一篇文章专门来总结)出现后,弱化了这种组织规则。其中,src 目录存在开发的源代码文件,其下面对应的目录称为包,pkg 存放编译后的库静态文件,bin 存放源代码编译后的可执行文件。

GOBIN

GOBIN 表示程序编译后二进制命令的安装目录。

当使用 go install 命令编译和打包应用程序时,该命令会将编译后二进制程序打包 GOBIN 目录,一般我们将 GOBIN 设置为 GOPATH/bin 目录。

export GOBIN=$GOPATH/bin

GOOS 和 GOARCH

学习这两个环境变量的用法,就得了解什么是交叉编译_满守园的博客-CSDN博客

在其他编程语言中进行交叉编译可能要借助第三方工具,但在 Go 语言进行交叉编译非常简单,最简单只需要设置 GOOS 和 GOARCH 这两个环境变量就可以了。

GOOS 的默认值是我们当前的操作系统,比如 Windows、Linux,注意 Mac 操作的上的值是darwin。 GOARCH 则表示 CPU 架构,如 386、amd64、arm等。

GOOS 和 GOARCH 的值成对出现,而且只能是下面列表对应的值。

$GOOS	    $GOARCH
android	    arm
darwin	    386
darwin	    amd64
darwin	    arm
darwin	    arm64
dragonfly   amd64
freebsd	    386
freebsd	    amd64
freebsd	    arm
linux	    386
linux	    amd64
linux	    arm
linux	    arm64
linux	    ppc64
linux	    ppc64le
linux	    mips
linux	    mipsle
linux	    mips64
linux	    mips64le
linux	    s390x
netbsd	    386
netbsd	    amd64
netbsd	    arm
openbsd	    386
openbsd	    amd64
openbsd	    arm
plan9	    386
plan9	    amd64
solaris	    amd64
windows	    386
windows	    amd64

编译在 64 位 Linux 系统上运行的程序,

$ GOOS=linux GOARCH=amd64 go build main.go

编译 arm 架构 Android系统上运行的程序,

$ GOOS=android GOARCH=arm GOARM=7 go build main.go

GOPROXY

从 Go 1.11 版本开始,官方支持了 go module 包依赖管理工具。不仅如此, Go 1.11 还新增了 GOPROXY 环境变量。如果设置了该变量,下载源代码时将会通过这个环境变量设置的代理地址。Go modules 的扶正是在 Go 1.13 发布中开发者能直接感觉到的最大变化,GOPROXY 环境变量在 Go 1.13 中的用法也发生了一些变化,具体参见https://golang.org/doc/go1.13

goproxy.io 提供了一个开源的解决方案允许开发者一键构建自己的 GOPROXY 代理服务,同时也提供了公用的代理服务 https://goproxy.io,参见Goproxy.io Enterprise 企业版本功能介绍;七牛云也出了个国内代理 goproxy.cn 方便国内用户更快的访问,参见Goproxy.cngoproxy.cn - 为中国 Go 语言开发者量身打造的模块代理

没有用 GOPROXY 环境变量的表现,

$ go get -u -v golang.org/x/tools/go/packages
package golang.org/x/tools/go/packages: unrecognized import path "golang.org/x/tools/go/packages" (https fetch: Get https://golang.org/x/tools/go/packages?go-get=1: dial tcp 216.239.37.1:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.)

使用 GOPROXY 变量后,可以正常拉取程序包,golang 的 goproxy 配置方法参见golang的goproxy配置 - Go语言中文网 - Golang中文社区

$ go env -w GO111MODULE=on
$ go env -w GOPROXY=https://goproxy.cn,direct
$ go get -u -v github.com/securego/gosec/cmd/gosec

GOPRIVATE

go get 通过代理服务拉取私有仓库(企业内部 module 或托管站点上的 private 库),而代理服务不可能访问到私有仓库,会出现了 404 错误。Go1.13 版本提供了一个方便的解决方案:GOPRIVATE 环境变量。

eg.

export GOPRIVATE=*.corp.example.com,rsc.io/private

参见 GOPRIVATE 环境变量GOLANG 环境几个重要的env配置参数解析一文说清GO环境变量

GO111MODULE

Golang 官方建议是一个项目一个 GOPATH,但是由于麻烦,很多人都不这么做,在 Go 1.11 中推出了 go modules 来解决依赖管理的问题,GO111MODULE 正是控制 go modules 的开关,在 Go 1.13 中也进行了功能升级, 具体参见https://golang.org/doc/go1.13go语言:环境变量GOPROXY和GO111MODULE设置

普通环境变量

环境变量是系统级的键-值对,正在运行的进程可以访问它。这些通常用于使同一程序在不同的部署环境(例如 PROD、DEV 或 TEST)中表现不同。在环境中存储配置是 twelve-factor 应用程序的原理之一,它使应用程序具有可移植性。如何在 Go 程序代码中设置、获取以及列出环境变量,也是非常重要的一环。

目前 Go 中有下面几种在代码里边访问环境变量的方式,

1. 使用内置标准库 os 包

Go by Example 中文版: 环境变量

Go获取与设置环境变量的方法详解_Golang_脚本之家

Golang获取系统环境变量及godotenv库使用 - 人艰不拆_zmc - 博客园

2. 使用第三方包(GoDotEnvViper

比较出众的有两种,包括ViperGoDotEnv,这两种方式受众相当的广泛,生产环境建议还是使用vipergodotenv。ViperGithub的star最多,文档更加全面,GoDotEnv次之。另外还有两个比较小众轻量级的,包括gonfiggo-akka。轮子还是很多的,按照各自实际情况挑选吧。

详解 Go 中的环境变量

Environment variables in Golang | LoginRadius Blog​​​​​​​

Have Fun

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐