Docker Go SDK 入门(一)

如果你从未接触过Docker或Go,但却很感兴趣,这篇文章或许可以帮助你

这篇文章可能需要你

  • 使用过Docker、Dockerfile,或阅读过Docker官方文档

最近在使用docker的SDK做一个项目,但官方的文档遵循了Go社区的经典原则,只给出了几个example

image-20220330142012483

如果你想做的事情不在这个列表内,那么很遗憾,你就没有代码可以抄了,自己研究吧。

这片文章会描述我在这段时间内对docker SDK for Go 的探索,不涉及你能在官方文档中找到的基础知识

先来从简单的例子开始(不包含在官方的example中的例子)

  • 像平常那样,用DockerFile完成一次简单的部署
func DeployWithDockerFile(username, repoName string) {
  f, err := NewTarArchiveFromPath(download.GetRepoDir(username, repoName))
  if err != nil {
    panic(err)
  }
  
  build, err := cli.ImageBuild(ctx, f, types.ImageBuildOptions{
    Dockerfile: "Dockerfile",
  })
  if err != nil {
    panic(err)
  }
  
  all, err := io.ReadAll(build.Body)
  if err != nil {
    panic(err)
  }
  
  fmt.Println("resp:", string(all))
}
复制代码

在上面这段代码中,做了如下几件事

  • 将要部署的项目压缩成一个tar文件
  • 调用cli.ImageBuild
  • 处理cli.ImageBuild的返回值,他是一个ImageBuildResponse

cli

首先,如果你阅读过了官方文档,你一定知道这个cli是什么,以及他是怎么运作的:

Go社区很喜欢用这种缩写作为变量的名字,如果在Java社区中,我想它可能会叫做DockerClient

扫描二维码关注公众号,回复: 13773496 查看本文章
cli, _ = client.NewClientWithOpts(client.FromEnv,client.WithAPIVersionNegotiation())
复制代码

使用这种方式对其进行初始化,点开源码发现

client, err := defaultHTTPClient(DefaultDockerHost)
...
func defaultHTTPClient(host string) (*http.Client, error) {
  ...
  return &http.Client{
    Transport:     transport,
    CheckRedirect: CheckRedirect,
  }, nil
}
复制代码

这居然就是个普通的HTTPClient,用于和docker的daemon线程进行交互,所以这个go sdk实际上就是帮你封装了一层,具体做的事情和自己封装http.Client去使用API没有任何区别,不过有了这层封装,代码写起来还是方便了很多

ImageBuild()

这个函数需要传入三个参数,这个SDK中的大部分函数都是按照这个模式设计的

首先是恒古不变的context,文档中没有特殊要求,给他传一个emptyContext就可以了,如果你对context感到陌生,也不要紧,他只是Go中对于协程控制的一部分,可以很方便的在父子协程中通信,使用这个SDK对于它基本上是无感知的,只需要把它传进去就好

第二个参数通常用来定位你的项目/容器/镜像,在这里他接受一个tar文件,作为你的当前操作目录,在其他的函数中,这一项可能要传入容器id/镜像id等等。在Docker中涉及文件传输的部分,经常会使用tar这种格式

第三个参数通常是当前操作的options,这个options中的选项即是官方文档中API reference的各种参数,比如这里的dockerfile参数,他需要指定Dockerfile在你项目中的相对路径

这个函数返回一个Response,可以将其理解为精简的httpResponse,里面包含着docker返回的信息,但根据返回结果来看它应该是http2.0的stream

将项目打包成Image后,需要将其Run成Container,在这个过程中绑定端口

docker run -p 8000:9000 demo
复制代码

他的实现如下

func StartFromImage(username, repoName string) {
   var resp, err = cli.ContainerCreate(ctx, &container.Config{
      Image: imageName,
   }, &container.HostConfig{
      PortBindings: nat.PortMap{"9000/tcp": []nat.PortBinding{{
         HostIP:   "0.0.0.0",
         HostPort: "8000",
      }}},
   }, nil, nil, "name")
   cID := resp.ID
   if err := cli.ContainerStart(ctx, cID, types.ContainerStartOptions{}); err != nil {
      ...
   }
    ...
}
复制代码

ContainerCreate

在Docker API中,创建容器和启动容器是两个操作,其中需要注意在调用ContainerCreate绑定端口时,需设置PortBindings

他是一个nat.PortMap类型

// PortMap is a collection of PortBinding indexed by Port
type PortMap map[Port][]PortBinding
复制代码

这里的Port是string类型,map的value是一个PortBinding的数组

特别注意:这里的port是端口号/协议的组合,形如8080/tcp,9000/udp,而后面PortBinding中则是普通的端口号和Host地址

ContainerStart

相当于docker start,但只接受容器的id,不支持tag作为参数

至此,完成了基本的由Dockerfile创建镜像,再创建容器,运行容器的过程

猜你喜欢

转载自juejin.im/post/7083493035949965348