在导出的golang变量中说明的正在运行的Docker容器的最新列表

时间:2018-10-15 12:33:22

标签: docker go goroutine docker-api

我试图使用Docker的Golang SDK来维护一个切片变量,该变量与本地Docker实例上当前正在运行的容器一起使用。该切片是从包中导出的,我想用它来填充网页。

我真的不习惯使用goroutine和通道,这就是为什么我想知道是否为我的问题找到了一个好的解决方案。

我有一个docker软件包,如下所示。

https://play.golang.org/p/eMmqkMezXZn

它有一个Running变量,包含正在运行的容器的当前状态。

var Running []types.Container

我使用reload函数将运行中的容器加载到Running变量中。

// Reload the list of running containers
func reload() error {
    ...
    Running, err = cli.ContainerList(context.Background(), types.ContainerListOptions{
        All: false,
    })
    ...
}

然后我从init函数开始一个goroutine,以监听Docker事件并相应地触发reload函数。

func init() {
    ...
    // Listen for docker events
    go listen()
    ...
}

// Listen for docker events
func listen() {
    filter := filters.NewArgs()
    filter.Add("type", "container")
    filter.Add("event", "start")
    filter.Add("event", "die")

    msg, errChan := cli.Events(context.Background(), types.EventsOptions{
        Filters: filter,
    })

    for {
        select {
        case err := <-errChan:
            panic(err)
        case <-msg:
            fmt.Println("reloading")
            reload()
        }
    }
}

我的问题是,从goroutine内部更新变量(就同步而言)是否合适?也许有一种更清洁的方式来实现我要构建的东西?

更新

我在这里真正关心的并不是缓存。它更多的是隐藏来自Docker SDK的侦听和更新过程的“复杂性”。我想提供类似索引的内容,以方便最终用户循环并显示当前正在运行的容器。

我知道线程程序中的数据争用问题,但我没有意识到我实际上是在并发上下文中进行操作(以前我从未在Go中编写并发程序)。

我实际上需要重新考虑该解决方案,以使其更加惯用。据我所知,这里有两个选择:要么用互斥锁保护变量,要么重新考虑设计以集成通道。

对我而言,最重要的是隐藏或封装所使用的同步方法,以便程序包用户不必担心共享状态如何受到保护。

您有什么建议吗?

非常感谢您的帮助, Loric

1 个答案:

答案 0 :(得分:0)

否,这不是习惯用法。在两个goroutine之间共享Running变量。您可以通过在运行main函数的例程和以listen开始的go函数之间共享它来实现此目的,这会生成另一个goroutine。

为什么,是因为它以

中断
  

请勿通过共享内存进行通信;而是通过共享内存   沟通。 ¹

因此,API的设计需要更改才能变得惯用;您需要删除Running变量并将其替换为什么?这取决于您要实现的目标。如果您由于需要经常调用cli.ContainerList而试图对其进行缓存,而这可能很昂贵,则应该实现一个在每个cli.Events上都无效的缓存。

你的动机是什么?