回顾
项目已开源:基于 Golang 的 容器管理系统
- 「容器管理系统」1. 开篇:框架选型和环境搭建
- 「容器管理系统」开发篇:1. 初始化配置和日志监控
- 「容器管理系统」开发篇:2. 封装gin统一返回JSON
- 「容器管理系统」开发篇:3. JWT(JSON Web Token)的应用
- 「容器管理系统」开发篇:4. Gin 如何优雅的使用 struct 的 tag 标签
- 「容器管理系统」开发篇:5. 如何实现 RBAC 权限管理(一)
- 「容器管理系统」开发篇:5. 如何实现 RBAC 权限管理(二)
- 「容器管理系统」开发篇:6. 如何在项目中集成 casbin 策略授权库?
- 「容器管理系统」开发篇:7. 初识 ETCD
什么是 docker ?
Docker
是一种轻量级的虚拟化技术,同时是一个开源的应用容器运行环境搭建平台,可以让开发者以便捷方式打包应用到一个可移植的容器中,然后安装至任何运行Linux
或Windows
等系统的服务器上。相较于传统虚拟机,Docker
容器提供轻量化的虚拟化方式、安装便捷、启停速度快。
docker 的特点
Docker容器具有以下三大特点:
- 轻量化:一台主机上运行的多个
Docker
容器可以共享主机操作系统内核;启动迅速,只需占用很少的计算和内存资源。 - 标准开放:
Docker
容器基于开放式标准,能够在所有主流Linux
版本、Microsoft Windows
以及包括VM
、裸机服务器
和云
在内的任何基础设施
上运行。 - 安全可靠:
Docker
赋予应用的隔离性不仅限于彼此隔离,还独立于底层的基础设施。Docker
默认提供最强的隔离,因此应用出现问题,也只是单个容器的问题,而不会波及到整台主机。
为什么用 docker ?
虚拟机(Virtual Machine
,简称VM
)的发展,减轻了企业对硬件资源的依赖,它将一台物理设备虚拟为多个逻辑设备,每个逻辑设备可运行不同的操作系统,并且应用程序都可以在相互独立的空间内运行而互不影响,从而显著提高设备的工作效率。然而,传统VM需要安装操作系统才能执行应用程序,占用系统资源过多。多数情况下,用户只需要运行简单的应用程序,采用VM技术操作繁琐且造成资源浪费。倘若需要迁移应用服务程序,则需迁移整个VM,因此企业迫切需要轻量级的虚拟化技术。
使用 docker 有什么好处?
容器,就是一种轻量级的虚拟化技术,目的和虚拟机一样,都是为了创造"隔离环境
"。但是它不像VM采用操作系统级的资源隔离,容器采用的是进程级的系统隔离。Docker作为创建容器的主流工具,近年来迅速发展,它的优势在于:
可以让开发者将企业需要的各种应用及应用依赖文件封装在
Docker
镜像文件中,然后在任何物理设备(Linux设备或Window设备等)上安装运行
实现虚拟化,让应用程序彻底脱离
底层设备,可以在物理机之间灵活迁移
部署,使运维工程师摆脱了繁琐
的环境部署,极大的提高了工作效率,同时减少了部署过程中的潜在风险
。
golang 如何操作 docker ?
golang
可以通过 docker sdk
来操作 docker
。
- 安装
docker sdk
包
go
go get github.com/docker/docker
封装 docker sdk
包
- 初始化 docker client
go
import (
"context"
"github.com/docker/docker/client"
)
type DockerClient struct {
Client *client.Client
Ctx context.Context
}
- 获取容器列表
go
// ContainerList 获取全部容器列表(含未运行)
func (d *DockerClient) ContainerList() (containerList []types.Container, err error) {
containerList, err = d.Client.ContainerList(d.Ctx, types.ContainerListOptions{
All: true,
})
return
}
这里面有个需要注意的地方:
ContainerListOptions
中的All
参数,如果All
参数设置以为true
,则是获取运行中和未运行的全部容器数据,默认不设置,则是获取运行中的容器数据
- 停止指定容器
go
// ContainerStop 停止指定容器
func (d *DockerClient) ContainerStop(ID string) error {
err := d.Client.ContainerStop(d.Ctx, ID, container.StopOptions{})
return err
}
- 获取指定容器日志
go
// ContainerLogs 获取指定容器日志
func (d *DockerClient) ContainerLogs(ID string) (string, error) {
options := types.ContainerLogsOptions{ShowStdout: true}
out, err := d.Client.ContainerLogs(d.Ctx, ID, options)
defer func(out io.ReadCloser) {
err := out.Close()
if err != nil {
panic(err)
}
}(out)
// 从 io.ReadCloser 解析数据
buf := new(bytes.Buffer)
buf.ReadFrom(out)
return buf.String(), err
}
这里
sdk
返回是一个io.ReadCloser
接口,如果需要得到数据,需要进行解析
- 创建容器
go
// ContainerCreate 创建容器
func (d *DockerClient) ContainerCreate(
options *container.Config,
hostOptions *container.HostConfig,
networkingOptions *network.NetworkingConfig,
platform *specs.Platform,
name string,
) (cont string, err error) {
resp, err := d.Client.ContainerCreate(d.Ctx, options, hostOptions, networkingOptions, platform, name)
if err != nil {
return "", err
}
return resp.ID, nil
}
这里主要注意的是:
options
,hostOptions
这两个结构体,常用的创建参数,这两个里面基本上可以满足,封装阶段咱们这里不详细讲述
- 运行指定容器
go
// ContainerStart 启动指定容器
func (d *DockerClient) ContainerStart(ID string) error {
err := d.Client.ContainerStart(d.Ctx, ID, types.ContainerStartOptions{})
if err != nil {
return err
}
return nil
}
接口调用封装的 sdk
包
这里着重讲解创建容器,其他方法
sdk
直接的调用即可
- 创建容器
go
func ContainerCreate(c *gin.Context) {
var params common.ContainerCreateRequest
if err := c.ShouldBindJSON(¶ms); err != nil {
response.Error(c, constant.ErrorParams, err, constant.ErrorMsg[constant.ErrorParams])
return
}
// 配置要启动的容器
containerOptions := &container.Config{
Image: params.Image,
Cmd: params.Cmd,
}
// 主机配置
hostOptions := &container.HostConfig{
// 将容器的80端口映射到宿主机的8080端口
PortBindings: nat.PortMap{
nat.Port(params.LocalProt + "/tcp"): []nat.PortBinding{
{
HostIP: params.HostIP,
HostPort: params.HostPort,
},
},
},
RestartPolicy: container.RestartPolicy{
Name: params.PolicyName,
},
}
id, err := dockerClient.ContainerCreate(containerOptions, hostOptions, nil, nil, params.ContainerName)
if err != nil {
response.Error(c, constant.ErrorCreateContainer, err, constant.ErrorMsg[constant.ErrorCreateContainer])
return
}
response.OK(c, id, constant.ErrorMsg[constant.Success])
}
container.Config
容器的配置
go
// Config 包含有关容器的配置数据。
// 它应该只包含有关容器的可移植信息。
// 在这里,"可移植"的意思是"独立于我们运行的主机"。
// 不可移植的信息 *should* 出现在 HostConfig 中。
// 添加到此结构的所有字段都必须标记为 "omiteempty" 才能继续获取
// 来自旧的 "v1Compatibility" 配置的可预测散列。
type Config struct {
Hostname string // 主机名
Domainname string // 域名
User string // 将在容器内运行命令的用户,还支持User:group
AttachStdin bool // 附加标准输入,实现用户交互
AttachStdout bool // 附加标准输出
AttachStderr bool // 附加标准误差
ExposedPorts nat.PortSet `json:",omitempty"` //暴露端口列表
Tty bool // 将标准流附加到Tty,如果Tty未关闭,则包括stdin。
OpenStdin bool // Open stdin
StdinOnce bool // 如果为true,请在连接的1个客户端断开连接后关闭stdin。
Env []string // 要在容器中设置的环境变量列表
Cmd strslice.StrSlice // 启动容器时要运行的命令
// Healthcheck 描述了如何检查容器是否健康
Healthcheck *HealthConfig `json:",omitempty"`
// ArgsEscaped True,如果命令已转义(意味着将其视为命令行)(特定于Windows)。
ArgsEscaped bool `json:",omitempty"`
Image string // 操作传递的镜像的名称(例如,可以是符号)
Volumes map[string]struct{} // 用于容器的卷(装载)列表
WorkingDir string // 将启动命令中的当前目录(PWD)
Entrypoint strslice.StrSlice // 启动容器时要运行的入口点
NetworkDisabled bool `json:",omitempty"` // 已禁用网络
MacAddress string `json:",omitempty"` // 容器的Mac地址
OnBuild []string // image Dockerfile上定义的OnBuild元数据
Labels map[string]string // 设置到此容器的标签列表
StopSignal string `json:",omitempty"` // 停止容器的信号
StopTimeout *int `json:",omitempty"` // 停止容器的超时(秒)
// Shell 表示RUN的Shell形式,CMD,ENTRYPOINT
Shell strslice.StrSlice `json:",omitempty"`
}
container.HostConfig
主机配置
go
// HostConfig 容器的不可移植的 Config 结构。
// 在这里,"不可移植"的意思是"依赖于我们运行的主机"。
// 可移植信息 *should* 出现在配置中。
type HostConfig struct {
// 适用于所有平台
Binds []string // 此容器的卷绑定列表
ContainerIDFile string // 写入containerId的文件(路径)
LogConfig LogConfig // 此容器的日志配置
NetworkMode NetworkMode // 用于容器的网络模式
PortBindings nat.PortMap // 暴露端口(容器)和主机之间的端口映射
RestartPolicy RestartPolicy // 用于容器的重新启动策略
AutoRemove bool // 退出时自动删除容器
VolumeDriver string // 用于装载卷的卷驱动程序的名称
VolumesFrom []string // 从其他容器获取的卷列表
ConsoleSize [2]uint // 初始控制台尺寸(高度、宽度)
// 适用于 UNIX 平台
CapAdd strslice.StrSlice // 要添加到容器的内核功能列表
CapDrop strslice.StrSlice // 要从容器中删除的内核功能列表
CgroupnsMode CgroupnsMode // 用于容器的Cgroup命名空间模式
DNS []string `json:"Dns"` // 要查找的DNS服务器列表
DNSOptions []string `json:"DnsOptions"` // 要查找的DNS选项列表
DNSSearch []string `json:"DnsSearch"` // 要查找的DNS搜索列表
ExtraHosts []string // 额外主机列表
GroupAdd []string // 容器进程将作为其运行的其他组的列表
IpcMode IpcMode // 用于容器的IPC命名空间
Cgroup CgroupSpec // 用于容器的Cgroup
Links []string // 链接列表(名称:alias form)
OomScoreAdj int // OOM-killing的容器偏好
PidMode PidMode // 用于容器的PID命名空间
Privileged bool // 容器是否处于特权模式
PublishAllPorts bool // docker是否应该发布容器的所有暴露端口
ReadonlyRootfs bool // 容器根文件系统是只读的吗
SecurityOpt []string // 用于自定义MLS系统(如SELinux)标签的字符串值列表。
StorageOpt map[string]string `json:",omitempty"` // 每个容器的存储驱动程序选项。
Tmpfs map[string]string `json:",omitempty"` // 用于集装箱的tmpfs(支架)列表
UTSMode UTSMode // 用于容器的UTS命名空间
UsernsMode UsernsMode // 用于容器的用户命名空间
ShmSize int64 // shm内存使用总量
Sysctls map[string]string `json:",omitempty"` // 用于容器的命名空间sysctl列表
Runtime string `json:",omitempty"` // 与此容器一起使用的运行时
// 适用于 Windows 平台
Isolation Isolation // 容器的隔离技术(例如默认、hyperv)
// 包含容器的资源(cgroup、ulimit)
Resources
// 安装容器使用的规格
Mounts []mount.Mount `json:",omitempty"`
// MaskedPaths是容器内要屏蔽的路径列表(这将覆盖默认路径集)
MaskedPaths []string
// ReadonlyPaths是要在容器内设置为只读的路径列表(这将覆盖默认路径集)
ReadonlyPaths []string
// 在容器内运行自定义init,如果为null,则使用守护进程的配置设置
Init *bool `json:",omitempty"`
}
network.NetworkingConfig
网络配置
go
// NetworkingConfig
// 表示容器每个接口的网络配置携带"docker run"和"docker network connect"命令中指定的网络配置
type NetworkingConfig struct {
EndpointsConfig map[string]*EndpointSettings // 每个连接网络的端点配置
}
go
// EndpointSettings 存储网络端点详细信息
type EndpointSettings struct {
// Configurations
IPAMConfig *EndpointIPAMConfig
Links []string
Aliases []string
// 操作数据
NetworkID string
EndpointID string
Gateway string
IPAddress string
IPPrefixLen int
IPv6Gateway string
GlobalIPv6Address string
GlobalIPv6PrefixLen int
MacAddress string
DriverOpts map[string]string
}
go
// EndpointIPAMConfig 表示终结点的IPAM配置
type EndpointIPAMConfig struct {
IPv4Address string `json:",omitempty"`
IPv6Address string `json:",omitempty"`
LinkLocalIPs []string `json:",omitempty"`
}
specs.Platform
镜像配置
go
// Platform 配置镜像运行参数
type Platform struct {
// Architecture 指定CPU体系结构
// `amd64` or `ppc64`.
Architecture string `json:"architecture"`
// OS 指定操作系统,例如"linux"或"windows"。
OS string `json:"os"`
// OSVersion 指定操作系统版本的可选字段,例如在Windows"10.0.14393.1066"上。
OSVersion string `json:"os.version,omitempty"`
// OSFeatures 是一个可选字段,用于指定字符串数组,每个字符串都列出所需的操作系统功能
// (例如,在Windows"win32k"上)。
OSFeatures []string `json:"os.features,omitempty"`
// Variant 是指定CPU变体的可选字段,例如"v7",用于在体系结构为"arm"时指定 ARMv7。
Variant string `json:"variant,omitempty"`
}
golang
操作 docker
的前置条件
注意:
docker sdk
对golang
是有版本要求的
就项目而言:
docker sdk
使用的 tag 版本为:v23.0.3+incompatible
docker engine
:24.0.6
docker client
:4.24.0 (122432)
golang
版本:1.21.3
golang 1.18
以下使用遇到问题的请看:「容器管理系统」 2. 版本问题记录
结束语
- 简述了
docker
的发展史 docker
的特点docker
的好处golang
如何操作docker
docker sdk
的使用docker
的前置使用条件