首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用io阅读器客户端

如何使用io阅读器客户端
EN

Stack Overflow用户
提问于 2022-04-05 06:09:50
回答 1查看 128关注 0票数 1

我希望使用在容器中运行的go代码将压缩文件从主机复制到容器。安装程序在安装了docker.sock的容器中运行go代码。其想法是将zip文件从主机复制到运行go代码的容器。路径参数位于主机上。在主机命令行上,如下所示

代码语言:javascript
运行
复制
docker cp hostFile.zip myContainer:/tmp/

码头-客户端CopyToContainer的文档看起来

代码语言:javascript
运行
复制
func (cli *Client) CopyToContainer(ctx context.Context, containerID, dstPath string, content io.Reader, options types.CopyToContainerOptions) error

如何创建content io.Reader参数?

代码语言:javascript
运行
复制
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
    panic(err)
}

// TODO
// reader := io.Reader()
// reader := file.NewReader()
// tar.NewReader()

cli.CopyToContainer(context.Background(), containerID, dst, reader, types.CopyToContainerOptions{
    AllowOverwriteDirWithFile: true,
    CopyUIDGID:                true,
})
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-04-05 11:46:49

实现io.Reader的东西种类繁多。在这种情况下,通常的方法是使用os.Open打开一个文件,然后生成的*os.File指针是一个io.Reader

但是,正如您在注释中所指出的,这只会帮助您从“本地”文件系统中读取和写入内容。访问主机的Docker套接字是非常强大的,但它不能直接让您对主机文件系统进行读写访问。( @mkopriva在一条评论中指出,使用docker run -v /host/path:/container/path绑定挂载启动容器要简单得多,并且避免了我将要讨论的大量安全问题。)

您需要做的是启动第二个容器,绑定-挂载您需要的内容,并从容器中读取文件。听起来像是在尝试将它写到本地文件系统中,这简化了一些事情。在容器内的docker exec shell提示符中,您可能会执行以下操作

代码语言:javascript
运行
复制
docker run --rm -v /:/host busybox cat /host/some/path/hostFile.zip \
  > /tmp/hostFile.zip 

在Go中,它涉及更多,但仍然非常可行(未经测试,没有进口)

代码语言:javascript
运行
复制
ctx := context.Background()
cid, err := client.ContainerCreate(
  ctx,
  &container.Config{
    Image: "docker.io/library/busybox:latest",
    Cmd: strslice.StrSlice{"cat", "/host/etc/shadow"},
  },
  &container.HostConfig{
    Mounts: []mount.Mount{
      {
        Type: mount.TypeBind,
        Source: "/",
        Target: "/host",
      },
    },
  },
  nil,
  nil,
  ""
)
if err != nil {
  return err
}

defer client.ContainerRemove(ctx, cid.ID, &types.ContainerRemoveOptions{})

rawLogs, err := client.ContainerLogs(
  ctx,
  cid.ID, 
  types.ContainerLogsOptions{ShowStdout: true},
)
if err != nil {
  return err
}
defer rawLogs.close()

go func() {
  of, err := os.Create("/tmp/host-shadow")
  if err != nil {
    panic(err)
  }
  defer of.Close()

  _ = stdcopy.StdCopy(of, io.Discard, rawLogs)
}()

done, cerr := client.ContainerWait(ctx, cid.ID, container. WaitConditionNotRunning)
for {
  select {
    case err := <-cerr:
      return err
    case waited := <-done:
      if waited.Error != nil {
        return errors.New(waited.Error.Message)
      } else if waited.StatusCode != 0 {
        return fmt.Errorf("cat container exited with status code %v", waited.StatusCode)
      } else {
        return nil
      }
  }
}

正如我在前面所暗示并在代码中显示的那样,这种方法绕过了主机上的所有控件;我决定返回主机的/etc/shadow加密密码文件,因为我可以,没有什么可以阻止我使用基本相同的方法选择根密码来编写它。所有者、权限和其他任何事情都无关紧要: Docker守护进程作为root运行,大多数容器默认以root形式运行(如果没有,您可以显式地请求它)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71746994

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档