【云原生】利用 docker api 管理容器

目的

对容器进行管理

方案

使用 docker 官方sdk 对docker进行操作,操作依赖docker socket

官方sdk 参考 : https://docs.docker.com/engine/api/sdk/

准备工作

为了方便调试,打开docker socket 的2375端口

部分代码

定义一个docker client ,连接 docker socket

client.go

go 复制代码
package dockermgr

import (
	"context"
	"github.com/docker/docker/client"
	"log"
	"net"
)

func DockerClient(apiVersion string) *client.Client {
	if apiVersion == "" {
		apiVersion = "1.39"
	}
	dockerClient, err := client.NewClientWithOpts(
		//client.WithHost("tcp://192.168.124.84:2375"),
		client.WithDialContext(func(_ context.Context, _, _ string) (net.Conn, error) {
			return net.Dial("unix", "/var/run/docker.sock")
		}),
		client.WithVersion(apiVersion))
	if err != nil {
		log.Fatal(err)
	}
	ping, err := dockerClient.Ping(context.Background())
	//}))
	if err != nil {
		log.Fatal(err)
	}
	log.Println(ping.APIVersion)
	return dockerClient
}

container.go

主要用来管理容器

这里定义了一个ClientAPI的结构体以及一个ClientAPIer的接口

go 复制代码
package dockermgr

import (
	"context"
	"errors"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/api/types/network"
	"github.com/docker/docker/client"
	"io"
	"net/http"
	"os"
	"strings"
)

var c *ClientAPI

type ClientAPI struct {
	DockerCli *client.Client
	Ctx       context.Context
}

type ClientAPIer interface {
	Stop(containerId string, timeout int) error
	Restart(containerId string, timeout int) error
	PullImage(imageUrl string) error
	Create(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (string, error)
	Start(containerId string, startOpts types.ContainerStartOptions) error
	EnsureImageExist(image string) (bool, error)
	CreateNetwork(containerName string) (string, error)
	ConnectNetwork(networkId string, containerId string) error
	RemoveImage(imageId string, removeOpt types.ImageRemoveOptions) error
	Status(containerId string) (*types.Container, error)
	Inspect(containerId string) (*types.ContainerJSON, error)
	Stats(containerId string, stream bool) (*types.ContainerStats, error)
	RemoveContainer(containerId string, removeVolumes bool) error
	RemoveNetwork(networkId string) error
	Exec(containerId string, cmd []string) error
	EnsureNetworkExist(networkName string) (string, error)
	FindContainer(containerName string) (string, error)
	IsImageUsed(imageID string) (bool, error)
	ContainerLogs(writer http.ResponseWriter, containerId string, follow bool, since string, tail string, until string) error
	ExportImage(imageId string) (io.ReadCloser, error)
	ImportImage(savePath string, repo string, tag string) error
	ImageInfo(imageId string) (*types.ImageInspect, error)
}

func GetContainerAPIer() ClientAPIer {
	return c
}

func NewContainerMgr(apiVersion string) ClientAPIer {
	return &ClientAPI{
		DockerCli: DockerClient(apiVersion),
		Ctx:       context.Background(),
	}
}

func (c *ClientAPI) Create(config *container.Config, hostConfig *container.HostConfig, networkConfig *network.NetworkingConfig, containerName string) (string, error) {
	//var networkConfig *network.NetworkingConfig

	rspBody, err := c.DockerCli.ContainerCreate(c.Ctx, config, hostConfig, networkConfig, nil, containerName)
	if err != nil {
		return "", err
	}
	return rspBody.ID, nil
}

func (c *ClientAPI) Start(containerId string, startOpts types.ContainerStartOptions) error {
	err := c.DockerCli.ContainerStart(c.Ctx, containerId, startOpts)
	if err != nil {
		return err
	}
	return nil
}

func (c *ClientAPI) Status(containerId string) (*types.Container, error) {
	var args = filters.NewArgs()
	args.Add("id", containerId)
	containerInfo, err := c.DockerCli.ContainerList(c.Ctx, types.ContainerListOptions{
		All:     true,
		Filters: args})

	if err != nil {
		return nil, err
	}
	if len(containerInfo) > 0 {
		return &containerInfo[0], nil
	}
	return nil, errors.New("not found container")
}

func (c *ClientAPI) Inspect(containerId string) (*types.ContainerJSON, error) {
	containerInpsect, err := c.DockerCli.ContainerInspect(c.Ctx, containerId)
	if err != nil {
		return nil, err
	}
	return &containerInpsect, nil
}

func (c *ClientAPI) Stats(containerId string, stream bool) (*types.ContainerStats, error) {
	containerStats, err := c.DockerCli.ContainerStats(c.Ctx, containerId, stream)
	if err != nil {
		return nil, err
	}
	return &containerStats, nil
}

func (c *ClientAPI) Stop(containerId string, timeout int) error {
	if timeout == 0 {
		timeout = 10
	}
	options := container.StopOptions{
		Signal:  "",
		Timeout: &timeout,
	}

	err := c.DockerCli.ContainerStop(c.Ctx, containerId, options)

	if err != nil {
		return err
	}
	return nil
}

func (c *ClientAPI) Restart(containerId string, timeout int) error {
	if timeout == 0 {
		timeout = 10
	}
	options := container.StopOptions{
		Signal:  "",
		Timeout: &timeout,
	}

	err := c.DockerCli.ContainerRestart(c.Ctx, containerId, options)

	if err != nil {
		return err
	}
	return nil
}

func (c *ClientAPI) RemoveContainer(containerId string, removeVolumes bool) error {
	//var duration = 10 * time.Second

	err := c.DockerCli.ContainerRemove(c.Ctx, containerId, types.ContainerRemoveOptions{RemoveVolumes: removeVolumes})

	if err != nil {
		return err
	}
	return nil
}

func (c *ClientAPI) Exec(containerId string, cmd []string) error {
	execId, err := c.DockerCli.ContainerExecCreate(c.Ctx, containerId, types.ExecConfig{
		Cmd: cmd,
	})
	if err != nil {
		return err
	}
	//err = c.DockerCli.ContainerExecStart(c.Ctx, execId.ID, types.ExecStartCheck{
	//	Detach: false,
	//	Tty:    false,
	//})
	//if err != nil {
	//	return err
	//}
	resp, err := c.DockerCli.ContainerExecAttach(c.Ctx, execId.ID, types.ExecStartCheck{
		Detach: false,
		Tty:    false,
	})
	defer resp.Close()
	io.Copy(os.Stdout, resp.Reader)
	if err != nil {
		return err
	}

	return nil
}

func (c *ClientAPI) FindContainer(containerName string) (string, error) {
	var args = filters.NewArgs()
	args.Add("name", containerName)
	containerInfos, err := c.DockerCli.ContainerList(c.Ctx, types.ContainerListOptions{
		All:     true,
		Filters: args})

	if err != nil {
		return "", err
	}
	if len(containerInfos) > 0 {
		for i, ci := range containerInfos {
			if strings.TrimLeft(ci.Names[0], "/") == containerName {
				return containerInfos[i].ID, nil
			}
		}
	}
	return "", nil
}

func (c *ClientAPI) ContainerLogs(writer http.ResponseWriter, containerId string, follow bool, since string, tail string, until string) error {
	options := types.ContainerLogsOptions{
		ShowStdout: true,
		ShowStderr: true,
		Since:      since,
		Until:      until,
		Timestamps: false,
		Follow:     follow,
		Tail:       tail,
		Details:    false,
	}
	responseBody, err := c.DockerCli.ContainerLogs(c.Ctx, containerId, options)
	if err != nil {
		return err
	}
	defer responseBody.Close()

	writer.Header().Add("Content-Type", "application/octet-stream")
	writer.WriteHeader(200)
	_, err = io.Copy(writer, responseBody)
	return err
}

其他更多的代码内容,请参考我的github

我的Github

相关推荐
我不会起名字32232 分钟前
节点 NotReady:kubelet 与容器运行时的 4 步排查
云原生·kubernetes·kubelet·排查
说实话起个名字真难啊1 小时前
实战docker部署dify及注意点
运维·docker·容器
闲云自留地2 小时前
K8s Service 全解:服务发现、四种类型、会话保持、金丝雀发布一篇通
容器·kubernetes·服务发现
分布式存储与RustFS2 小时前
GPU 在空转等数据?PyTorch 训练集进 RustFS 的三种接法
云原生·开源·对象存储·分布式存储·s3·rustfs·性能基准
choumin3 小时前
C++ 标准容器为什么不能存引用
c++·容器·引用类型
Starry-sky(jing)4 小时前
crane 下载镜像:不连接 Docker,3 步准备并校验 ARM64 离线包
运维·docker·arm64·crane
时间售卖铺5 小时前
MySQL 备份
运维·数据库·mysql·云原生
FungLeo5 小时前
成为全栈·Go 后端篇·用 Go 重写分层架构:领域包、装配根与最小抽象
golang·go·领域驱动设计·gorm·分层架构·成为全栈
对象存储与RustFS5 小时前
GPU 在空转等数据?PyTorch 训练集进 RustFS 的三种接法
后端·docker·云原生
我不会起名字3226 小时前
Go 服务升级 Go 1.2x 后 P99 变差:GMP 调度相关的 3 个变化
golang·go·gmp·调度·gomaxprocs