赞
踩
golang docker sdk 需要和安装的docker api version相兼容。一般我们只需要注意docker api version就可以了.
docker version
查看本地docker api version
go get github.com/docker/docker/client
拉取docker client sdk
go 代码中得创一个docker client。后面和docker 所有操作都走这个client,你甚至能创几个来自不同机器的client,在程序内控制几台机器的docker
import (
"github.com/docker/docker/client"
"log"
)
var cli *client.Client
func init() {
var err error
cli, err = client.NewClientWithOpts(client.WithVersion("1.39"), client.WithAPIVersionNegotiation())//初始化一个本地的docker client,我docker version 命令行输出中api version 是1.39所以这里是1.39
if err != nil {
log.Fatalln("init docker client failed " + err.Error())
}
}
简单的创建个debian镜像的容器
type Container struct {
Id string
}
//指定工作目录(如果没有指定,你容器的默认目录绝对路径为/),Cmd是你容器启动时的命令,我这里启动的是我自己一个简单的echo服务,这里你可以替换成你自己的。
//HostConfig 这里如果你没什么额外操作直接nil,这里我是将容器的container 的/root目录与宿主机当前目录下的container目录链接了一起。就可以启动一个纯debian镜像的容器,在里面跑我宿主机上的程序
//Tty选项 如果容器启动的程序没有标准输出输入直接写入到文件的话,可以不写默认是false。如果启动tty,attchstdin/stderr/stdout这三个选项根据自身需求打开
func NewContainerWithLink(container_name, docker_filepath, host_path string) (*Container, error) {
resp, err := cli.ContainerCreate(context.Background(), &container.Config{Image: "debian", WorkingDir: "/root", Cmd: []string{"./child"}, Tty: true, AttachStdout: true, AttachStderr: true}, &container.HostConfig{Mounts: []mount.Mount{mount.Mount{Type: mount.TypeBind, Source: host_path, Target: docker_filepath, BindOptions: &mount.BindOptions{CreateMountpoint: true}}}}, nil, nil, container_name)
// return nil, err
if err == nil {
return &Container{Id: resp.ID}, nil
}
return nil, err
}
容器启动
func (s *Container) Run() error { err := cli.ContainerStart(context.Background(), s.Id, container.StartOptions{}) if err != nil { return err } //attach 能将容器的实时stdin,stdout,stderr暴露出来,上面创建时你开了stdin的话就能通过暴露出来的Conn给把数据写入容器 hresp, err := cli.ContainerAttach(context.Background(), s.Id, container.AttachOptions{Stream: true, Stdout: true, Stderr: true}) if err != nil { return err } go func() { _, err2 := io.Copy(os.Stdout, hresp.Conn) if err2 != nil { fmt.Fprintln(os.Stderr, err2.Error()) } }() // var resp io.ReadCloser return nil }
容器停止
func (s *Container) Stop() error {
return cli.ContainerStop(context.Background(), s.Id, container.StopOptions{Signal: "SIGQUIT"})
}
容器单独执行另外的命令
func (s *Container) Exec(cmd string, args ...string) error {
cmds := make([]string, 1+len(args))
cmds[0] = cmd
if len(args) > 0 {
copy(cmds[1:], args)
}
ex, err := cli.ContainerExecCreate(context.Background(), s.Id, types.ExecConfig{Tty: true, AttachStdout: true, AttachStderr: true, Detach: true, Cmd: cmds})
if err == nil {
err = cli.ContainerExecStart(context.Background(), ex.ID, types.ExecStartCheck{Detach: true, Tty: true})
}
return err
}
删除容器
func (s *Container) Close() error {
err := s.Stop()
if err == nil {
err = cli.ContainerRemove(context.Background(), s.Id, container.RemoveOptions{})
}
return err
}
完整demo代码
package main import ( "context" "fmt" "io" "log" "os" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/mount" "github.com/docker/docker/client" ) var ( cli *client.Client ) func init() { var err error cli, err = client.NewClientWithOpts(client.WithVersion("1.39"), client.WithAPIVersionNegotiation()) if err != nil { log.Fatalln("init docker client failed " + err.Error()) } } type Container struct { Id string } func NewContainerWithLink(container_name, docker_filepath, host_path string) (*Container, error) { resp, err := cli.ContainerCreate(context.Background(), &container.Config{Image: "debian", WorkingDir: "/root", Cmd: []string{"./child"}, Tty: true, AttachStdout: true, AttachStderr: true}, &container.HostConfig{Mounts: []mount.Mount{mount.Mount{Type: mount.TypeBind, Source: host_path, Target: docker_filepath, BindOptions: &mount.BindOptions{CreateMountpoint: true}}}}, nil, nil, container_name) // return nil, err if err == nil { return &Container{Id: resp.ID}, nil } return nil, err } func (s *Container) Stop() error { return cli.ContainerStop(context.Background(), s.Id, container.StopOptions{Signal: "SIGQUIT"}) } func (s *Container) Close() error { err := s.Stop() if err == nil { err = cli.ContainerRemove(context.Background(), s.Id, container.RemoveOptions{}) } return err } func (s *Container) Run() error { err := cli.ContainerStart(context.Background(), s.Id, container.StartOptions{}) if err != nil { return err } hresp, err := cli.ContainerAttach(context.Background(), s.Id, container.AttachOptions{Stream: true, Stdout: true, Stderr: true}) if err != nil { return err } go func() { _, err2 := io.Copy(os.Stdout, hresp.Conn) if err2 != nil { fmt.Fprintln(os.Stderr, err2.Error()) } }() // var resp io.ReadCloser return nil } func (s *Container) Exec(cmd string, args ...string) error { cmds := make([]string, 1+len(args)) cmds[0] = cmd if len(args) > 0 { copy(cmds[1:], args) } ex, err := cli.ContainerExecCreate(context.Background(), s.Id, types.ExecConfig{Tty: true, AttachStdout: true, AttachStderr: true, Detach: true, Cmd: cmds}) if err == nil { err = cli.ContainerExecStart(context.Background(), ex.ID, types.ExecStartCheck{Detach: true, Tty: true}) if err == nil { var r io.ReadCloser r, err = cli.ContainerLogs(context.Background(), s.Id, container.LogsOptions{ShowStdout: true}) if err == nil { _, err = io.Copy(os.Stdout, r) if err == io.EOF { err = nil } } } } return err }
这里容器客户端基本功能结构体就已经构建好了,测试main函数由你自行编写,边学边写效率才能更高,不然一切都是纸上谈兵。运行目录下container目录与容器/root目录相关联。测试程序自行拷贝到container 目录下即可。
我自己的demo 效果
如果你使用的是linux包管理工具安装的docker,你需要找到启动你docker服务的地方,一般是走systemd管理的。直接systemctl status docker
就可以看见docker.service文件位置在哪里,默认是监听unix socket docker.sock来访问的。默认配置启动命令那里参数应该是/..../dockerd -H fd://
你在后面加一个-H tcp://你要监听的ip地址:端口号
。然后systemctl daemon-reload
,docker sdk在使用client.NewClientWithOpts
函数时,里面是加一个client.WithHost
函数就行了,地址短口填对
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。