正确使用Go DockerSDK(gomod)
正确使用Go DockerSDK(gomod)
1. 背景
1.1 go语言特性: 标准导入路径(canonical import path)
Go 1.4 introduces an annotation for package clauses in Go source that identify a canonical import path for the package. If an import is attempted using a path that is not canonical, the go command will refuse to compile the importing package.
go1.4 引入了一个特性,在package后可以使用注释声明导入这个包的标准路径, 叫做canonical import path。如果导入某个包的路径与这个canonical import path不同,则go命令会拒绝编译该包。
例如:
package pdf // import "rsc.io/pdf"
1.2 docker项目更名
docker详细开发现状参见: docker开发现状
这里要了解的是,docker曾在2017年将项目迁移到github.com/moby/moby
1.3 docker项目的依赖管理方式
go语言在1.11版本时发布了gomod特性来管理依赖,非常好用,但也有一些用起来不方便的地方,例如必须依赖于tag来管理版本。
docker未使用gomod管理依赖,使用的方法是在vendor中明细每个依赖的commit记录:
例如docker/cli/vendor.conf中导入了github.com/docker/docker的commit记录,这使得github.com/docker/docker即使没有发布更新的release记录,也能进行更新。
github.com/docker/docker a09e6e323e55e1a9b21df9c2c555f5668df3ac9b
github.com/docker/docker-credential-helpers 54f0238b6bf101fc3ad3b34114cb5520beb562f5 # v0.6.3
github.com/docker/go d30aec9fd63c35133f8f79c3412ad91a3b08be06 # Contains a customized version of canonical/json and is used by Notary. The package is periodically rebased on current Go versions.
2. 目的: 使用最新版本的docker
3. 问题与原因
3.1 docker/docker版本过低
根据官方库的指导,应该使用import github.com/docker/docker/client
,而github.com/moby/moby/client是不存在的
3.2 Sirupsen/logrus更名冲突
go: finding github.com/docker/libtrust latest
go: finding github.com/vbatts/tar-split/tar/storage latest
go: finding github.com/vbatts/tar-split/tar/asm latest
go: finding github.com/vbatts/tar-split/tar latest
go: extracting github.com/Sirupsen/logrus v1.4.2
go: finding github.com/opencontainers/runtime-spec/specs-go latest
go: finding github.com/docker/distribution/digest latest
go: finding github.com/docker/docker/errdefs latest
go: github.com/Sirupsen/logrus@v1.4.2: parsing go.mod: unexpected module path "github.com/sirupsen/logrus"
go: error loading module requirements
4. 解决方案
因为历史原因,docker仓库从github.com/docker/docker更换到github.com/moby/moby, 而github.com/docker/docker已于release1.13.1停止更新,因此我们的项目中如果import path是github.com/docker/docker, 是只能获取到v1.13.1的。
而docker又不愿意更换import path, 所以才有此问题。(docker使用的custom import path)
参考这个issue, https://github.com/golang/go/issues/28489, 可以在gomod中替换仓库地址而不更改import path
在go.mod文件中添加replace语句
require (
github.com/docker/docker v1.13.1
)
replace github.com/docker/docker => github.com/docker/engine v19.03.5
// 使用具体commit亦可
// replace github.com/docker/docker => github.com/docker/engine v0.0.0-20191113042239-ea84732a7725
其中docker-engine的最新版本可以在此地址查询:https://github.com/docker/engine/releases,但是这里不能使用latest,只能使用固定版本号
如果有多个docker库时,需要注意每个库版本的对应关系。例如docker/cli调用了docker/docker库,他们的对应关系可以在docker/cli/vendor.conf中查询到。我们可以如此调用:
require (
github.com/docker/cli v0.0.0-20191220145525-ba63a92655c0
github.com/docker/docker v1.13.1
github.com/docker/swarmkit v1.12.0 // indirect
)
replace github.com/docker/cli => github.com/docker/cli v0.0.0-20191220145525-ba63a92655c0
replace github.com/docker/docker => github.com/docker/docker v0.7.3-0.20191025225506-a09e6e323e55
replace github.com/docker/swarmkit => github.com/docker/swarmkit v1.12.1-0.20190717134425-7dded76ec532
当然直接在require语句中写清楚commit记录也是可以的。
也可以使用在docker/engine中查询到tag记录,执行go mod tidy来获取对应的commit记录 require ( github.com/docker/docker v19.03.12 )
例如使用以上语句声明docker版本,执行go mod tidy命令时,会自动替换成commit时间-hash的形式。
$ go mod tidy
go: downloading github.com/docker/docker v0.0.0-20200618181300-9dc6525e6118