go调用docker远程API(二)-docker API 的容器操作

1 获取容器列表

  • 语法
func (cli *Client) ContainerList(ctx context.Context, options ContainerListOptions) ([]Container, error)
  • 语法示例
containers, err := Cli.ContainerList(context.Background(), types.ContainerListOptions{All: true})
  • 完整示例
package main

import (
	"bufio"
	"context"
	"fmt"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
	"io"
	"log"
	"os"
)

func main() {
	cli, err := ConnectDocker()
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("docker 链接成功")
	}
	err = GetContainers(cli)
	if err != nil {
		fmt.Println(err)
	}
}

// ConnectDocker
// 链接docker
func ConnectDocker() (cli *client.Client, err error) {
	cli, err = client.NewClientWithOpts(client.WithAPIVersionNegotiation(), client.WithHost("tcp://10.10.239.32:2375"))
	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	return cli, nil
}

// GetContainers
// 获取容器列表
func GetContainers(cli *client.Client) error {
	//All-true相当于docker ps -a
	containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true})
	if err != nil {
		fmt.Println(err)
		return err
	}

	for _, container := range containers {
		fmt.Printf("%s %s\n", container.ID[:10], container.Image)
	}
	return nil
}
  • 输出
docker 链接成功
08d317f408 harbocto.boe.com.cn/public/redis:4   
c91fc7eeb1 harbocto.boe.com.cn/public/mysql:5.7 
48bcf68112 harbocto.boe.com.cn/crow/crow-qin    
381f5b2790 harbocto.boe.com.cn/magicube/ibex:0.3

2 查看指定容器信息

  • 查看方法
func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (ContainerJSON, error)

语法示例

	ctx := context.Background()
	containerJson, err := cli.ContainerInspect(ctx, containerId)
  • 返回结构体types.ContainerJSON
type ContainerJSON struct {
    *ContainerJSONBase
    Mounts          []MountPoint
    Config          *Config
    NetworkSettings *NetworkSettings
}
  • *ContainerJSONBase的内容
type ContainerJSONBase struct {
    ID              string `json:"Id"`
    Created         string
    Path            string
    Args            []string
    State           *ContainerState
    Image           string
    ResolvConfPath  string
    HostnamePath    string
    HostsPath       string
    LogPath         string
    Node            *ContainerNode `json:",omitempty"`
    Name            string
    RestartCount    int
    Driver          string
    Platform        string
    MountLabel      string
    ProcessLabel    string
    AppArmorProfile string
    ExecIDs         []string
    HostConfig      *HostConfig
    GraphDriver     GraphDriverData
    SizeRw          *int64 `json:",omitempty"`
    SizeRootFs      *int64 `json:",omitempty"`
}
  • 完整示例
package main

import (
	"context"
	"fmt"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
)

func main() {
	cli, err := ConnectDocker()
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("docker 链接成功")
	}

	containerId := "48bcf6811212"
	containerJson, err := GetContainer(cli, containerId)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("=======容器信息======\nID:%+v\name:%+v\n", containerJson.ID[:10], containerJson.Name)
}

func GetContainer(cli *client.Client, containerId string) (containerInfo types.ContainerJSON, err error) {
	ctx := context.Background()
	containerJson, err := cli.ContainerInspect(ctx, containerId)
	if err != nil {
		fmt.Println(err)
		return containerJson, err
	}
	return containerJson, nil
}
  • 打印结果
docker 链接成功
=======容器信息======   
ID:48bcf68112
ame:/crow-qin_crow_qin_1

3. 查看容器日志

  • 语法
func (cli *Client) ContainerLogs(ctx context.Context, container string, options ContainerLogsOptions) (io.ReadCloser, error)
  • 语法示例
ctx := context.Background()
	logs, err := Cli.ContainerLogs(ctx, containerId, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Follow: true, Tail: "200"})
  • 参数
    • ShowStdout:标准输出
    • ShowStderr:错误输出
    • Follow:
      • true:实时日志
      • false:当前日志
    • Tail:看结尾多少行,string类型,默认"all"
  • 完整示例
func main() {
	cli, err := ConnectDocker()
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("docker 链接成功")
	}

	err = containerLogs(cli, "48bcf68112")
	if err != nil {
		fmt.Println(err)
	}
}

// ConnectDocker
// 链接docker
func ConnectDocker() (cli *client.Client, err error) {
	cli, err = client.NewClientWithOpts(client.WithAPIVersionNegotiation(), client.WithHost("tcp://10.10.239.32:2375"))
	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	return cli, nil
}

//containerLogs
//获取容器日志
func containerLogs(cli *client.Client, containerId string) error {
	ctx := context.Background()
	logs, err := cli.ContainerLogs(ctx, containerId, types.ContainerLogsOptions{ShowStdout: true, Follow: true, ShowStderr: true})
	if err != nil {
		fmt.Println(err)
		return err
	}
	_, err = io.Copy(os.Stdout, logs)
	if err != nil {
		fmt.Println(err)
		return err
	}
	return nil
}

4 创建容器

4.1 简单使用

4.1.1 语法

  • ContainerCreate() 函数
func (cli *Client) ContainerCreate(ctx context.Context, config *Config, hostConfig *HostConfig, networkingConfig *NetworkingConfig, platform *Platform, containerName string) (CreateResponse, error)
  • 结构体 *container.Config

关于container的设置在此结构体

type Config struct {
    Hostname        string
    Domainname      string
    User            string
    AttachStdin     bool
    AttachStdout    bool
    AttachStderr    bool
    ExposedPorts    PortSet `json:",omitempty"`
    Tty             bool
    OpenStdin       bool
    StdinOnce       bool
    Env             []string
    Cmd             StrSlice
    Healthcheck     *HealthConfig `json:",omitempty"`
    ArgsEscaped     bool          `json:",omitempty"`
    Image           string
    Volumes         map[string]struct{}
    WorkingDir      string
    Entrypoint      StrSlice
    NetworkDisabled bool   `json:",omitempty"`
    MacAddress      string `json:",omitempty"`
    OnBuild         []string
    Labels          map[string]string
    StopSignal      string            `json:",omitempty"`
    StopTimeout     *int              `json:",omitempty"`
    Shell           StrSlice `json:",omitempty"`
}
  • 结构体**container.HostConfig

宿主机相关配置,在这个结构体中。

type HostConfig struct {
    Binds           []string
    ContainerIDFile string
    LogConfig       LogConfig
    NetworkMode     NetworkMode
    PortBindings    PortMap
    RestartPolicy   RestartPolicy
    AutoRemove      bool
    VolumeDriver    string
    VolumesFrom     []string
    ConsoleSize     [2]uint
    CapAdd          StrSlice
    CapDrop         StrSlice
    CgroupnsMode    CgroupnsMode
    DNS             []string `json:"Dns"`
    DNSOptions      []string `json:"DnsOptions"`
    DNSSearch       []string `json:"DnsSearch"`
    ExtraHosts      []string
    GroupAdd        []string
    IpcMode         IpcMode
    Cgroup          CgroupSpec
    Links           []string
    OomScoreAdj     int
    PidMode         PidMode
    Privileged      bool
    PublishAllPorts bool
    ReadonlyRootfs  bool
    SecurityOpt     []string
    StorageOpt      map[string]string `json:",omitempty"`
    Tmpfs           map[string]string `json:",omitempty"`
    UTSMode         UTSMode
    UsernsMode      UsernsMode
    ShmSize         int64
    Sysctls         map[string]string `json:",omitempty"`
    Runtime         string            `json:",omitempty"`
    Isolation       Isolation
    Resources
    Mounts        []Mount `json:",omitempty"`
    MaskedPaths   []string
    ReadonlyPaths []string
    Init          *bool `json:",omitempty"`
}
  • *network.NetworkingConfig
type NetworkingConfig struct {
    EndpointsConfig map[string]*EndpointSettings
}

4.1.2 完整示例

package main

import (
	"context"
	"fmt"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/network"
	"github.com/docker/docker/client"
)

func main() {
	cli, err := ConnectDocker()
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("docker 链接成功")
	}

	config := &container.Config{
		Image: "harbocto.boe.com.cn/crow/crow-qin",
		Tty:   true,
	}

	//创建容器
	containerId, err := CreateContainer(cli, config, nil, nil, "crow-test")
	if err != nil {
		fmt.Println(err)
	}
	//验证(用前文写的查找函数验证)
	containerInfo, err := GetContainer(cli, containerId)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("成功创建容器%q,状态为:%q", containerInfo.ID[:10], containerInfo.State.Status)
}

// CreateContainer
// 创建容器
func CreateContainer(cli *client.Client, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (containerId string, err error) {
	ctx := context.Background()

	//创建容器
	resp, err := cli.ContainerCreate(ctx, config, hostConfig, networkingConfig, nil, containerName)
	if err != nil {
		fmt.Println(err.Error())
	}
	return resp.ID, nil
}
  • 输出
docker 链接成功
成功创建容器"c13a3deefb",状态为:"created"

4.2 端口映射

4.2.1 语法

  • 容器内端口 container.Config.ExposedPorts
    • 上文已经知道 container.Config是容器的配置,它的成员 ExposedPorts即是容器内部监听的端口。
    • ExposedPorts的类型是nat.PortSet
    • nat.PortSet的类型如下
      type PortSet map[Port]struct{}
      
    • 语法示例
      config := &container.Config{
      	Image: "harbocto.boe.com.cn/crow/crow-qin",
      	Tty:   true,
      	ExposedPorts: nat.PortSet{  //这里是容器内端口设置
      		"1840": struct{}{},
      	},
      }
      
  • 绑定容器外端口 container.HostConfig.PortBindings
    • 上文已经知道 container.HostConfig是宿主机的配置
    • 它的成员 PortBindings绑定容器内外端口。
    • ExposedPorts的类型是nat.PortMap
    • nat.PortMap的类型如下
      type PortMap map[Port][]PortBinding
      
    • PortBinding的类型如下
    type PortBinding struct {
        HostIP   string `json:"HostIp"`
        HostPort string
    }
    
    • 语法示例
    	hostConfig := &container.HostConfig{
      	PortBindings: nat.PortMap{
      		"1840": []nat.PortBinding{  //容器内端口
      			{
      				HostIP:   "0.0.0.0",
      				HostPort: "1841",  //容器外端口
      			},
      		},
      	},
      }
    

4.2.2 完整示例

func main() {
	cli, err := ConnectDocker()
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("docker 链接成功")
	}

	//创建容器
	//protMap := nat.PortSet{}
	config := &container.Config{
		Image: "harbocto.boe.com.cn/crow/crow-qin",
		Tty:   true,
		ExposedPorts: nat.PortSet{
			"1840": struct{}{},
		},
	}
	hostConfig := &container.HostConfig{
		PortBindings: nat.PortMap{
			"1840": []nat.PortBinding{
				{
					HostIP:   "0.0.0.0",
					HostPort: "1841",
				},
			},
		},
	}
	containerId, err := CreateContainer(cli, config, hostConfig, nil, "crow-qin-test")

	err = StartContainer(cli, containerId)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(containerId)

}

// CreateContainer
// 创建容器
func CreateContainer(cli *client.Client, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (containerId string, err error) {
	ctx := context.Background()
	//创建容器
	resp, err := cli.ContainerCreate(ctx, config, hostConfig, networkingConfig, nil, containerName)
	if err != nil {
		fmt.Println(err.Error())
	}
	return resp.ID, nil

}

// StartContainer
// 启动容器
func StartContainer(cli *client.Client, containerId string) error {
	ctx := context.Background()
	err := cli.ContainerStart(ctx, containerId, types.ContainerStartOptions{})
	if err != nil {
		fmt.Println(err)
		return err
	}
	return nil
}

4.3 挂载本机目录/文件

4.3.1 语法

  • 指明容器内目录 container.Config.Volumes
    • 类型:
      Volumes         map[string]struct{}
      
    • 语法示例
      config := &container.Config{
      	Image: "harbocto.boe.com.cn/crow/crow-qin",
      	Tty:   true,
      	Volumes: map[string]struct{}{
      		"/test01": {},
      	},
      }
      
  • 容器内外路径网绑定 container.HostConfig.Binds
    • 类型:[]string
    • 语法示例
      hostConfig := &container.HostConfig{
      	Binds: []string{"/tmp/liuBei.txt:/liuBei.txt"},
      }
      
  • 注意
    • 如果只有 container.Config.ExposedPorts,容器内目录将挂载到docker的默认位置(docker目录的 /volumes下)
    • 如果写了container.HostConfig.PortBindings,则 container.Config.ExposedPorts实际可以不写

4.3.2 完整代码

func main() {
	cli, err := ConnectDocker()
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("docker 链接成功")
	}

	//创建容器
	//protMap := nat.PortSet{}

	config := &container.Config{
		Image: "harbocto.boe.com.cn/crow/crow-qin",
		Tty:   true,
		Volumes: map[string]struct{}{ //如上文,本代码这里实际可以省略
			"/test01": {},
		},
	}
	hostConfig := &container.HostConfig{
		Binds: []string{"/tmp/test01:/test01"},
	}
	containerId, err := CreateContainer(cli, config, hostConfig, nil, "crow-qin-test")

	err = StartContainer(cli, containerId)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(containerId)
}
// CreateContainer
// 创建容器
func CreateContainer(cli *client.Client, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (containerId string, err error) {
	ctx := context.Background()
	//创建容器
	resp, err := cli.ContainerCreate(ctx, config, hostConfig, networkingConfig, nil, containerName)
	if err != nil {
		fmt.Println(err.Error())
	}
	return resp.ID, nil

}

// StartContainer
// 启动容器
func StartContainer(cli *client.Client, containerId string) error {
	ctx := context.Background()
	err := cli.ContainerStart(ctx, containerId, types.ContainerStartOptions{})
	if err != nil {
		fmt.Println(err)
		return err
	}
	return nil
}

5. 启动容器

  • 语法
func (cli *Client) ContainerStart(ctx context.Context, containerID string, options ContainerStartOptions) error
  • 语法示例
	ctx := context.Background()
	err := cli.ContainerStart(ctx, containerId, types.ContainerStartOptions{})
  • 完整示例
package main

import (
	"context"
	"fmt"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
)

func main() {
	cli, err := ConnectDocker()
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("docker 链接成功")
	}

	containerId := "c13a3deefb"
	err = StartContainer(cli, containerId)
	if err != nil {
		fmt.Println(err)
	}
	//验证(用前文写的查找函数验证)
	containerInfo, err := GetContainer(cli, containerId)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("成功启动容器%q\n状态为:%q", containerInfo.ID[:10], containerInfo.State.Status)
}

//StartContainer
// 启动容器
func StartContainer(cli *client.Client, containerId string) error {
	ctx := context.Background()
	err := cli.ContainerStart(ctx, containerId, types.ContainerStartOptions{})
	if err != nil {
		fmt.Println(err)
		return err
	}
	return nil
}
  • 输出
docker 链接成功
成功启动容器"c13a3deefb"
状态为:"running"  

如上可见,我们刚才创建的容器状态从created变为running

6 停止容器

  • 语法
func (cli *Client) ContainerStart(ctx context.Context, containerID string, options ContainerStartOptions) error
  • 语法示例
ctx := context.Background()
err := cli.ContainerStart(ctx, containerId, types.ContainerStartOptions{})
  • 完整示例
package main

import (
	"context"
	"fmt"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/client"
)

func main() {
	cli, err := ConnectDocker()
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("docker 链接成功")
	}

	containerId := "c13a3deefba9"
	err = StopContainer(cli, containerId)
	if err != nil {
		fmt.Println(err)
	}
	//验证(用前文写的查找函数验证)
	containerInfo, err := GetContainer(cli, containerId)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("成功停止容器%q\n状态为:%q", containerInfo.ID[:10], containerInfo.State.Status)
}

// StopContainer
// 停止容器
func StopContainer(cli *client.Client, containerId string) error {
	ctx := context.Background()
	err := cli.ContainerStop(ctx, containerId, container.StopOptions{})
	if err != nil {
		fmt.Println(err)
		return err
	}
	return nil
}

7 删除(已停止的)容器

  • 语法
func (cli *Client) ContainerRemove(ctx context.Context, containerID string, options ContainerRemoveOptions) error
  • 语法示例
	ctx := context.Background()
	err := cli.ContainerRemove(ctx, containerId, types.ContainerRemoveOptions{})
  • 完整示例
package main

import (
	"context"
	"fmt"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
)

func main() {
	cli, err := ConnectDocker()
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("docker 链接成功")
	}

	containerId := "c13a3deefba9"
	err = DeleteContainer(cli, containerId)
	if err != nil {
		fmt.Println(err)
	}

	//验证(用前文写的查找函数验证)
	b, err := CheckContainer(cli, containerId)
	if err != nil {
		fmt.Println(err)
	}
	if b == false {
		fmt.Println("删除成功")
	} else {
		fmt.Println("删除失败")
	}
}

// DeleteContainer
// 删除已停止容器
func DeleteContainer(cli *client.Client, containerId string) error {
	ctx := context.Background()
	err := cli.ContainerRemove(ctx, containerId, types.ContainerRemoveOptions{})
	if err != nil {
		fmt.Println(err)
		return err
	}
	return nil
}
// CheckContainer
// 获取容器信息
func CheckContainer(cli *client.Client, containerId string) (result bool, err error) {
	ctx := context.Background()
	containerJson, err := cli.ContainerInspect(ctx, containerId)
	if err != nil {
		fmt.Println(err)
		return false, err
	}
	if containerJson.ContainerJSONBase == nil {
		return false,nil
	}
	fmt.Println(containerJson)
	return true, nil
}

8 进入容器执行命令

本文仅演示示例,实际应用参见本人文档《gin框架使用websocket实现进入容器内部执行命令》

8.1 语法

  • 创建配置

说明:创建一个新的exec配置来运行exec进程。

func (cli *Client) ContainerExecCreate(ctx context.Context, container string, config ExecConfig) (IDResponse, error)

语法示例

	ir, err := dockerCli.ContainerExecCreate(ctx, containerId, types.ExecConfig{
		AttachStdin:  true,
		AttachStdout: true,
		AttachStderr: true,
		Cmd:          []string{"/bin/sh"},
		Tty:          true,
	})
  • 将链接附加到exec进程

语法

func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, config ExecStartCheck) (HijackedResponse, error)

语法示例

hr, err := cli.ContainerExecAttach(ctx, ir.ID, types.ExecStartCheck{Detach: false, Tty: true})
  • 命令传入
_, err = hr.Conn.Write([]byte("ls\r"))

8.2 完整示例

  • 代码
package main

import (
	"bufio"
	"context"
	"fmt"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
	"io"
	"log"
	"os"
)


func main() {
	cli,err := ConnectDocker()
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("docker 链接成功")
	}
	//GetContainers()
	err = ExecContainer(cli,"48bcf68112")
	if err != nil {
		fmt.Println(err)
	}

}

// ConnectDocker
// 链接docker
func ConnectDocker() (cli *client.Client,err error)  {
	cli, err = client.NewClientWithOpts(client.WithAPIVersionNegotiation(), client.WithHost("tcp://10.10.239.32:2375"))
	if err != nil {
		fmt.Println(err)
		return nil,err
	}
	
	return cli,nil
}



func ExecContainer(cli *client.Client, containerId string) error {

	ctx := context.Background()
	//创建进程
	ir, err := cli.ContainerExecCreate(ctx, containerId, types.ExecConfig{
		AttachStdin:  true,
		AttachStdout: true,
		AttachStderr: true,
		Cmd:          []string{"/bin/sh"},
		Tty:          true,
	})
	if err != nil {
		return err
	}

	// 将链接附加到exec进程
	hr, err := cli.ContainerExecAttach(ctx, ir.ID, types.ExecStartCheck{Detach: false, Tty: true})
	if err != nil {
		return err
	}
	// 关闭链接和读取器
	defer hr.Close()

	// 输入一条命令
	_, err = hr.Conn.Write([]byte("echo liuBei > xiShu.txt\r"))
	if err != nil {
		return err
	}
	//输入第二条命令
	_, err = hr.Conn.Write([]byte("cat xiShu.txt\r"))
	if err != nil {
		return err
	}

	//输出
	scanner := bufio.NewScanner(hr.Conn)
	for scanner.Scan() {
		fmt.Println(scanner.Text())
		if err != nil {
			log.Println("写入错误", err)
			continue
		}
	}

	return nil
}

  • 结果输出
docker 链接成功
/ # echo liuBei > xiShu.txt
/ # cat xiShu.txt
liuBei

在这里插入图片描述

posted on 2023-04-03 09:32  运维开发玄德公  阅读(432)  评论(0编辑  收藏  举报  来源

导航