【Golang】golang使用三方SDK操作容器指南
大家好 我是寸鐵??
總結(jié)了一篇 golang使用三方SDK操作容器?
喜歡的小伙伴可以點(diǎn)點(diǎn)關(guān)注 ??
這應(yīng)該是目前全網(wǎng)最全golang使用三方SDK操作容器的指南了??
CreateConfig
主要是創(chuàng)建容器的配置信息,常用的字段
使用包如下:
"github.com/docker/docker/api/types"
配置創(chuàng)建Docker 容器的結(jié)構(gòu)體,具體字段的含義和用途如下:
1.Hostname
: 容器的主機(jī)名。
2.Domainname
: 容器的域名。
3.User
: 執(zhí)行容器內(nèi)命令的用戶,也支持指定用戶和用戶組。
4.AttachStdin
: 是否連接標(biāo)準(zhǔn)輸入,使得用戶可以與容器進(jìn)行交互。
5.AttachStdout
: 是否連接標(biāo)準(zhǔn)輸出。
6.AttachStderr
: 是否連接標(biāo)準(zhǔn)錯(cuò)誤輸出。
7.ExposedPorts
: 用于指定容器暴露的端口,是一個(gè) nat.PortSet
類型的字段。
8.Tty
: 是否將標(biāo)準(zhǔn)流連接到 tty(終端),包括標(biāo)準(zhǔn)輸入(如果它沒有關(guān)閉的話)。
9.OpenStdin
: 是否打開標(biāo)準(zhǔn)輸入。
10.StdinOnce
: 如果為 true,在第一個(gè)連接的客戶端斷開連接后關(guān)閉標(biāo)準(zhǔn)輸入。
11.Env
: 設(shè)置在容器中使用的環(huán)境變量的列表。
12.Cmd
: 在啟動容器時(shí)運(yùn)行的命令。
13.Healthcheck
: 描述容器健康狀況檢查的配置。
14.ArgsEscaped
: 如果為 true,表示命令已經(jīng)被轉(zhuǎn)義,即將其視為命令行(特定于 Windows)。
15.Image
: 由操作者傳遞的鏡像的名稱。
16.Volumes
: 用于指定容器使用的卷(掛載)的列表。
17.WorkingDir
: 容器中命令執(zhí)行的當(dāng)前目錄(PWD)。
18.Entrypoint
: 在啟動容器時(shí)運(yùn)行的入口點(diǎn)。
19.NetworkDisabled
: 是否禁用網(wǎng)絡(luò)。
20.MacAddress
: 容器的 MAC 地址。注意,此字段在 API 版本 v1.44 后已被廢棄,建議使用 EndpointSettings.MacAddress 替代。
21.OnBuild
:在 Dockerfile 中定義的 ONBUILD 元數(shù)據(jù)。這個(gè)字段用于保存在構(gòu)建鏡像時(shí)定義的 ONBUILD 指令,它們將在基礎(chǔ)鏡像的構(gòu)建過程中執(zhí)行。
22.Labels
:容器的標(biāo)簽列表。這個(gè)字段是一個(gè)映射,用于存儲容器的元數(shù)據(jù)信息,如作者、版本、描述等。標(biāo)簽可以用于組織和識別容器,也可以用于進(jìn)行元數(shù)據(jù)查詢。
23.StopSignal
:停止容器時(shí)發(fā)送的信號。這個(gè)字段指定了停止容器時(shí)使用的信號,例如 SIGTERM 或 SIGKILL。
24.StopTimeout
:停止容器的超時(shí)時(shí)間(以秒為單位)。這個(gè)字段指定了在發(fā)送停止信號后等待容器停止的時(shí)間。如果容器在超時(shí)時(shí)間內(nèi)未停止,則強(qiáng)制終止。
25.Shell
:用于 shell 形式的 RUN、CMD、ENTRYPOINT 的 shell。這個(gè)字段指定了容器內(nèi)部使用的 shell 解釋器,用于執(zhí)行 Dockerfile 中的命令。omitempty 表示如果字段為空,則在 JSON 輸出中省略該字段。
基本操作demo
package main
import (
"context"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
)
func main() {
// 初始化 Docker 客戶端
cli, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
panic(err)
}
//創(chuàng)建容器的配置信息
createConfig := &container.Config{
Image: "your_image_name",
// 可以根據(jù)需要配置其他容器參數(shù)
}
//停止容器的配置信息
stopConfig := container.StopOptions{}
//刪除容器的配置信息
removeOptions := types.ContainerRemoveOptions{
RemoveVolumes: true, // 刪除容器關(guān)聯(lián)的卷
Force: true, // 強(qiáng)制刪除容器
}
// 列出所有容器的列表
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
panic(err)
}
//操作每個(gè)容器的信息和容器的各種操作
for _, dockerContainer := range containers {
fmt.Printf("容器 ID:%s\n", dockerContainer.ID)
fmt.Printf("容器 名稱:%s\n", dockerContainer.Names)
// 在這里可以添加邏輯來判斷特定條件下的容器,并對其進(jìn)行操作
// 例如,暫停、刪除等操作
//容器的創(chuàng)建
//使用容器的名字創(chuàng)建容器,配置文件配置鏡像等等信息。
//創(chuàng)建容器的時(shí)候返回創(chuàng)建的容器ID
createID, err := cli.ContainerCreate(context.Background(), createConfig, nil, nil, nil, "my-container-18")
if err != nil {
panic(err)
}
fmt.Println("創(chuàng)建的容器ID為: ", createID)
//容器的刪除
err = cli.ContainerRemove(context.Background(), dockerContainer.ID, removeOptions)
if err != nil {
panic(err)
}
//容器的暫停
err = cli.ContainerPause(context.Background(), dockerContainer.ID)
if err != nil {
panic(err)
}
//容器的恢復(fù)
err = cli.ContainerUnpause(context.Background(), dockerContainer.ID)
if err != nil {
panic(err)
}
//容器的停止
err = cli.ContainerStop(context.Background(), dockerContainer.ID, stopConfig)
if err != nil {
panic(err)
}
//容器的重啟
err = cli.ContainerRestart(context.Background(), dockerContainer.ID, stopConfig)
if err != nil {
panic(err)
}
}
}
查找容器信息
cmd
對應(yīng)于cmd
的命令如下:
docker ps
類似于cmd
的方式,這里可以使用golang
程序拿到如下字段信息,查出當(dāng)前運(yùn)行的所有容器的信息。
實(shí)例
package main
import (
"context"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
/*
需求:
嘗試在golang中拉取鏡像、創(chuàng)建容器、刪除容器、停止容器、暫停容器、恢復(fù)容器、重啟容器。
運(yùn)行容器、怎么使用docker run去運(yùn)行一個(gè)容器、怎么使用docer build命令
看看其他在docker-cli中執(zhí)行的命令是否使用go程序也能夠正常執(zhí)行。
*/
func main() {
// 初始化 Docker 客戶端
cli, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
panic(err)
}
// 先得到列出所有容器的列表
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
panic(err)
}
// 對應(yīng)為docker ps -a 命令
// 再從列表中拿到信息
for _, container := range containers {
fmt.Printf("CONTAINER ID: %s\n", container.ID)
fmt.Printf("IMAGE: %s \n", container.Image)
fmt.Printf("COMMAND: %s \n", container.Command)
fmt.Printf("CREATED: %s \n", container.Created)
fmt.Printf("Status: %s \n", container.Status)
fmt.Printf("PORTS: %s \n", container.Ports)
fmt.Printf("NAMES:%s\n", container.Names)
}
}
運(yùn)行結(jié)果
遍歷容器,拿到容器的各種字段信息,與docker ps
命令的信息一致。
創(chuàng)建容器
cmd
運(yùn)行容器,一般是指定容器內(nèi)的端口和容器的名字(不能與之前的名字重復(fù))
--expose
:編輯容器內(nèi)的端口
--name
:編輯容器的名字
最后的my-golang-app
為鏡像源
docker run --expose 3888/tcp --name mycontainer-15 my-golang-app
結(jié)果如下:
實(shí)例
package main
import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
"io"
"log"
"os"
)
func main() {
ctx := context.Background()
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
log.Fatal(err)
}
//配置容器的各種信息,如鏡像源、容器內(nèi)的端口
containerConfig := &container.Config{
Image: "my-golang-app",
ExposedPorts: nat.PortSet{
"3889/tcp": {},
},
}
hostConfig := &container.HostConfig{}
networkingConfig := &network.NetworkingConfig{}
//創(chuàng)建容器
resp, err := cli.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, nil, "mycontainer-20")
if err != nil {
log.Fatal(err)
}
//啟動容器
if err := cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
log.Fatal(err)
}
//容器在后臺運(yùn)行
//fmt.Println("容器ID為: " , resp.ID)
// 獲取容器的日志
out, err := cli.ContainerLogs(ctx, resp.ID, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true})
if err != nil {
log.Fatal(err)
}
defer out.Close()
// 打印容器的日志到控制臺
go func() {
_, err := io.Copy(os.Stdout, out)
if err != nil && err != io.EOF {
log.Fatal(err)
}
}()
// 等待容器運(yùn)行完成
statusCh, errCh := cli.ContainerWait(ctx, resp.ID, container.WaitConditionNotRunning)
for {
select {
case err := <-errCh:
if err != nil {
log.Fatal(err)
}
case <-statusCh:
return
default:
// 如果沒有接收到任何數(shù)據(jù),則繼續(xù)等待
}
}
}
運(yùn)行結(jié)果
查看創(chuàng)建的容器的基本信息,如容器的端口和名字等等。
對照一下,兩種方式創(chuàng)建的結(jié)果都是一樣的。
程序中使用日志的方式打印出使用dockerfile
的go程序運(yùn)行的結(jié)果,但是打印一個(gè)數(shù)字后被阻塞了。
如果不使用上面程序的日志輸出,運(yùn)行時(shí)是以后臺的方式運(yùn)行的,也就不會直接把程序運(yùn)行的結(jié)果輸出來??梢韵葎?chuàng)建,再使用
Attach
方法進(jìn)入容器,就可以輸出程序的內(nèi)容了。具體見下面進(jìn)入容器部分。
刪除容器
cmd
docker rm -f 容器ID
查看結(jié)果如下:
實(shí)例
package main
import (
"context"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
func main() {
// 創(chuàng)建 Docker 客戶端
cli, err := client.NewEnvClient()
if err != nil {
panic(err)
}
// 定義要刪除的容器 ID
containerID := "d815a35c7822"
// 定義刪除容器時(shí)的選項(xiàng)
options := types.ContainerRemoveOptions{
Force: true, // 強(qiáng)制刪除容器
RemoveVolumes: true, // 刪除關(guān)聯(lián)的數(shù)據(jù)卷
RemoveLinks: false, // 不刪除關(guān)聯(lián)的鏈接
}
// 調(diào)用 ContainerRemove 方法刪除容器
err = cli.ContainerRemove(context.Background(), containerID, options)
if err != nil {
fmt.Printf("Failed to remove container: %v\n", err)
} else {
fmt.Println("Container removed successfully")
}
}
運(yùn)行結(jié)果
程序運(yùn)行結(jié)果如下:
刪除容器13
之前
容器13
成功刪除了
停止容器
cmd
docker stop 容器ID
停止容器前,狀態(tài)為Up
。
停止容器后,狀態(tài)為Exited
。
實(shí)例
package main
import (
"context"
"fmt"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
)
func main() {
// 創(chuàng)建 Docker 客戶端
cli, err := client.NewEnvClient()
if err != nil {
panic(err)
}
// 定義要停止的容器 ID
containerID := "b50423e8aade"
stopOptions := container.StopOptions{}
// 調(diào)用 ContainerStop 方法停止容器
err = cli.ContainerStop(context.Background(), containerID, stopOptions)
if err != nil {
fmt.Printf("Failed to stop container: %v\n", err)
} else {
fmt.Println("Container stopped successfully")
}
}
運(yùn)行結(jié)果
程序執(zhí)行結(jié)果如下:
檢查是否停止成功如下:
停止前
停止后
程序執(zhí)行結(jié)果與cmd停止命令一致。
重啟容器
cmd
docker restart 9ef8ae3b59d9
容器已停止:
重啟容器:
重啟容器后,容器的狀態(tài)如下:
實(shí)例
package main
import (
"context"
"fmt"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
)
func main() {
// 創(chuàng)建 Docker 客戶端
cli, err := client.NewEnvClient()
if err != nil {
panic(err)
}
// 定義要重啟的容器 ID
containerID := "746a98dfb20c"
topOptions := container.StopOptions{}
// 調(diào)用 ContainerRestart 方法重啟容器
err = cli.ContainerRestart(context.Background(), containerID, topOptions)
if err != nil {
panic(err)
}
fmt.Printf("Container %s has been restarted.\n", containerID)
}
運(yùn)行結(jié)果
重啟前:
重啟后:
運(yùn)行結(jié)果如下:
重啟完成,和cmd的執(zhí)行結(jié)果一致。
暫停容器
cmd
docker pause 容器ID
暫停容器前
暫停容器后
實(shí)例
package main
import (
"context"
"fmt"
"github.com/docker/docker/client"
)
func main() {
// 創(chuàng)建 Docker 客戶端
cli, err := client.NewEnvClient()
if err != nil {
panic(err)
}
// 定義要暫停的容器 ID
containerID := "e4d6650df3af"
// 暫停容器
err = cli.ContainerPause(context.Background(), containerID)
if err != nil {
fmt.Printf("Failed to pause container: %v\n", err)
} else {
fmt.Println("Container paused successfully")
}
}
運(yùn)行結(jié)果
暫停容器前:
暫停容器:
運(yùn)行結(jié)果如下:
恢復(fù)暫停
cmd
docker unpause 容器ID
恢復(fù)暫停前:
恢復(fù)暫停成功:
實(shí)例
package main
import (
"context"
"fmt"
"github.com/docker/docker/client"
)
func main() {
// 創(chuàng)建 Docker 客戶端
cli, err := client.NewEnvClient()
if err != nil {
panic(err)
}
// 定義要暫停的容器 ID
containerID := "e4d6650df3af"
// 暫停容器
err = cli.ContainerPause(context.Background(), containerID)
if err != nil {
fmt.Printf("Failed to pause container: %v\n", err)
} else {
fmt.Println("Container paused successfully")
}
}
運(yùn)行結(jié)果
恢復(fù)前:
恢復(fù)暫停:
運(yùn)行結(jié)果如下:
說明確實(shí)是恢復(fù)暫停成功了!
進(jìn)入容器
Attach
cmd
docker attach 容器ID
運(yùn)行結(jié)果如下:
退出容器,發(fā)現(xiàn)容器也停止掉了。
注意: 這種進(jìn)入容器的方式使用
exit
退出會把整個(gè)容器都停止掉。但是使用go的程序停止卻不會使得容器停止。
實(shí)例
要進(jìn)入容器,可以使用 Docker 客戶端的 ContainerAttach
方法。這個(gè)方法允許您連接到容器的標(biāo)準(zhǔn)輸入、輸出和錯(cuò)誤流,并與容器進(jìn)行交互。
package main
import (
"context"
"fmt"
"io"
"os"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
func main() {
// 創(chuàng)建 Docker 客戶端
cli, err := client.NewEnvClient()
if err != nil {
panic(err)
}
// 定義要進(jìn)入的容器 ID
containerID := "e4d6650df3af"
// 定義進(jìn)入容器時(shí)的選項(xiàng)
options := types.ContainerAttachOptions{
Stream: true,
Stdin: true,
Stdout: true,
Stderr: true,
}
// 調(diào)用 ContainerAttach 方法進(jìn)入容器
resp, err := cli.ContainerAttach(context.Background(), containerID, options)
if err != nil {
panic(err)
}
defer resp.Close()
// 將容器的標(biāo)準(zhǔn)輸入輸出連接到當(dāng)前進(jìn)程的標(biāo)準(zhǔn)輸入輸出
go io.Copy(os.Stdout, resp.Reader)
go io.Copy(resp.Conn, os.Stdin)
// 等待用戶輸入以繼續(xù)運(yùn)行
fmt.Println("Press enter to exit...")
fmt.Scanln()
}
運(yùn)行結(jié)果
運(yùn)行結(jié)果如下:
退出程序:
退出程序但是不會停止掉程序:
ExecAttach
cmd
docker exec -it mycontainer-18 bash
這樣的進(jìn)入容器是以命令行的方式進(jìn)入容器的,所以不會輸出程序的運(yùn)行結(jié)果,但是使用exit
退出程序不會關(guān)閉程序。
退出程序:
使用exit
退出程序,發(fā)現(xiàn)確實(shí)是沒有關(guān)閉程序。
實(shí)例
package main
import (
"context"
"fmt"
"io"
"os"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
func main() {
// 創(chuàng)建 Docker 客戶端
cli, err := client.NewEnvClient()
if err != nil {
panic(err)
}
// 定義要進(jìn)入的容器 ID
containerID := "e4d6650df3af"
// 定義要執(zhí)行的命令
cmd := []string{"sh"} // 這里可以根據(jù)需要修改為其他交互式 shell,如 bash
// 準(zhǔn)備執(zhí)行命令的選項(xiàng)
createResp, err := cli.ContainerExecCreate(context.Background(), containerID, types.ExecConfig{
Cmd: cmd,
AttachStdin: true,
AttachStdout: true,
AttachStderr: true,
Tty: true,
})
if err != nil {
panic(err)
}
// 連接到正在運(yùn)行的命令以進(jìn)行交互
resp, err := cli.ContainerExecAttach(context.Background(), createResp.ID, types.ExecStartCheck{
Tty: true,
})
if err != nil {
panic(err)
}
defer resp.Close()
// 將容器的標(biāo)準(zhǔn)輸入輸出連接到當(dāng)前進(jìn)程的標(biāo)準(zhǔn)輸入輸出
go func() {
if _, err := io.Copy(os.Stdout, resp.Reader); err != nil {
panic(err)
}
}()
go func() {
if _, err := io.Copy(resp.Conn, os.Stdin); err != nil {
panic(err)
}
}()
// 等待用戶輸入以繼續(xù)運(yùn)行
fmt.Println("Press enter to exit...")
fmt.Scanln()
}
運(yùn)行結(jié)果
以命令行的方式進(jìn)入容器進(jìn)行交互,和直接使用cmd
的方式是一樣的。
小結(jié)
以上兩種方式都可以進(jìn)入容器,需要結(jié)合具體使用場景進(jìn)行權(quán)衡。
- 其中一個(gè)是可以看到程序的執(zhí)行結(jié)果,但是退出會直接關(guān)閉掉容器。
- 另一個(gè)是以命令行的方式進(jìn)入容器進(jìn)行交互,退出不會直接關(guān)閉容器。
拉取鏡像
cmd
對應(yīng)到cmd
命令如下:
docker pull 鏡像名
如下:
docker pull nginx:latest
拉取結(jié)果如下:
實(shí)例
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
func main() {
// 創(chuàng)建 Docker 客戶端
cli, err := client.NewEnvClient()
if err != nil {
panic(err)
}
// 定義要拉取的鏡像的名稱和標(biāo)簽
imageName := "redis"
imageTag := "latest"
imageRef := imageName + ":" + imageTag
// 拉取鏡像
out, err := cli.ImagePull(context.Background(), imageRef, types.ImagePullOptions{})
if err != nil {
panic(err)
}
defer out.Close()
// 解析拉取鏡像的輸出
var pullResponse struct {
Status string `json:"status"`
}
if err := json.NewDecoder(out).Decode(&pullResponse); err != nil {
panic(err)
}
fmt.Printf("Pulling image %s: %s\n", imageRef, pullResponse.Status)
}
運(yùn)行結(jié)果
拉取鏡像成功,和cmd
拉取鏡像的方式一致。
拉取鏡像
cmd
對應(yīng)到cmd
命令如下:
docker pull 鏡像名
如下:
docker pull nginx:latest
拉取結(jié)果如下:
實(shí)例
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
func main() {
// 創(chuàng)建 Docker 客戶端
cli, err := client.NewEnvClient()
if err != nil {
panic(err)
}
// 定義要拉取的鏡像的名稱和標(biāo)簽
imageName := "redis"
imageTag := "latest"
imageRef := imageName + ":" + imageTag
// 拉取鏡像
out, err := cli.ImagePull(context.Background(), imageRef, types.ImagePullOptions{})
if err != nil {
panic(err)
}
defer out.Close()
// 解析拉取鏡像的輸出
var pullResponse struct {
Status string `json:"status"`
}
if err := json.NewDecoder(out).Decode(&pullResponse); err != nil {
panic(err)
}
fmt.Printf("Pulling image %s: %s\n", imageRef, pullResponse.Status)
}
運(yùn)行結(jié)果
拉取鏡像成功,和cmd
拉取鏡像的方式一致。
更新容器
應(yīng)用場景
- 動態(tài)調(diào)整資源限制: 您可能希望根據(jù)應(yīng)用程序的負(fù)載情況動態(tài)調(diào)整容器的資源限制,例如內(nèi)存限制、CPU 配額等。通過更新容器配置,您可以在不停止容器的情況下調(diào)整這些限制,從而使容器能夠適應(yīng)不同的負(fù)載。
- 修改網(wǎng)絡(luò)配置: 在某些情況下,您可能需要修改容器的網(wǎng)絡(luò)配置,例如更改容器的端口映射、連接到不同的網(wǎng)絡(luò)或修改容器的主機(jī)名等。通過更新容器配置,您可以實(shí)現(xiàn)這些網(wǎng)絡(luò)配置的變更,而無需重新創(chuàng)建容器。
- 更新掛載卷: 如果您使用了掛載卷來與容器共享數(shù)據(jù)或配置文件,可能會需要在運(yùn)行時(shí)更新掛載卷的配置。通過更新容器配置,您可以修改容器掛載的卷,例如更改卷的路徑或添加新的掛載卷。
- 應(yīng)用配置更改: 在某些情況下,您可能需要更新容器中運(yùn)行的應(yīng)用程序的配置。通過更新容器配置,您可以傳遞新的環(huán)境變量、更新容器的命令或參數(shù)等,從而修改容器中應(yīng)用程序的配置。
總的來說,ContainerUpdate
方法可以用于在容器運(yùn)行時(shí)對其進(jìn)行動態(tài)配置更改,而不需要停止和重新啟動容器。這種能力使得容器的管理更加靈活,并能夠在不中斷服務(wù)的情況下進(jìn)行必要的調(diào)整和更新。
cmd
docker update
命令用于更新一個(gè)正在運(yùn)行的容器的配置。它允許你修改容器的資源限制、重啟策略和其他配置選項(xiàng)。以下是docker update
命令的基本用法:
docker update 容器id/名字
實(shí)例
cli.ContainerUpdate
更新容器的資源限制、重啟策略和其他配置選項(xiàng),并不是更新容器的鏡像、端口之類的配置。其他暫無直接更新的API
。
采用:先刪除原有容器,再根據(jù)配置信息進(jìn)行重建的封裝函數(shù)。不過,這么做需要會影響容器內(nèi)正在運(yùn)行的服務(wù),需要考慮一下。
更新的結(jié)構(gòu)體如下:
updateConfig := container.UpdateConfig{
Resources: container.Resources{
Memory: 512000000, // 設(shè)置內(nèi)存限制為 512MB
NanoCPUs: 1000000000, // 設(shè)置 CPU 配額(以納秒為單位)
},
}
端口和掛載卷配置示例:
// 容器端口映射,鍵為容器端口,值為宿主機(jī)端口
portMapping := map[string]string{
"80/tcp": "8080",
}
// 容器掛載卷
volumeMounts := []mount.Mount{
{
Type: mount.TypeBind,
Source: "/host/path", // 宿主機(jī)路徑
Target: "/container/path", // 容器路徑
},
}
demo
package main
import (
"context"
"fmt"
"log"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
)
func main() {
// 創(chuàng)建 Docker 客戶端
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
log.Fatal(err)
}
// 容器ID,需要根據(jù)實(shí)際情況修改
containerID := "your_container_id_here"
// 配置更新
updateConfig := container.UpdateConfig{
Resources: container.Resources{
Memory: 512000000, // 設(shè)置內(nèi)存限制為 512MB
NanoCPUs: 1000000000, // 設(shè)置 CPU 配額(以納秒為單位)
},
}
// 執(zhí)行容器更新
err = updateContainer(cli, containerID, updateConfig)
if err != nil {
log.Fatal(err)
}
fmt.Println("容器配置已更新")
}
// updateContainer 函數(shù)用于更新容器的配置信息
func updateContainer(cli *client.Client, containerID string, updateConfig container.UpdateConfig) error {
ctx := context.Background()
// 執(zhí)行容器更新
_, err := cli.ContainerUpdate(ctx, containerID, updateConfig)
if err != nil {
return err
}
return nil
}
運(yùn)行結(jié)果
更新容器的內(nèi)存資源限制(單位bytes
)
運(yùn)行結(jié)果如下:
補(bǔ)充
還了解到一個(gè)方法:cli.ConfigUpdate()
,不過這個(gè)更新不是更新容器信息的,可更新的配置信息也非常少,基本與容器無關(guān)。
后面了解到,其實(shí)它主要用于更新 Docker Swarm
配置的信息。
在 Docker 中,Swarm 是 Docker 官方提供的用于容器編排
和集群管理
的工具。Swarm 允許您將多個(gè) Docker 主機(jī)組合成一個(gè)虛擬的、單一的 Docker 主機(jī)。Swarm 中有許多配置項(xiàng)可以控制集群的行為,例如服務(wù)配置、網(wǎng)絡(luò)配置、秘密配置等。
方法體如下:
// ConfigUpdate attempts to update a config
func (cli *Client) ConfigUpdate(ctx context.Context, id string, version swarm.Version, config swarm.ConfigSpec) error {
if err := cli.NewVersionError(ctx, "1.30", "config update"); err != nil {
return err
}
query := url.Values{}
query.Set("version", version.String())
resp, err := cli.post(ctx, "/configs/"+id+"/update", query, config, nil)
ensureReaderClosed(resp)
return err
}
待配置結(jié)構(gòu)體swarm.ConfigSpec
信息如下:
// ConfigSpec represents a config specification from a config in swarm
type ConfigSpec struct {
Annotations
Data []byte `json:",omitempty"`
// Templating controls whether and how to evaluate the config payload as
// a template. If it is not set, no templating is used.
Templating *Driver `json:",omitempty"`
}
Annotations
字段信息如下:
// Annotations represents how to describe an object.
type Annotations struct {
Name string `json:",omitempty"`
Labels map[string]string `json:"Labels"`
}
容器函數(shù)庫
將上面的各個(gè)函數(shù)集成到一個(gè)文件,形成一個(gè)函數(shù)庫,便于用戶使用和調(diào)用。
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
"github.com/opencontainers/image-spec/specs-go/v1"
"io"
"log"
"os"
)
func main() {
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
log.Fatal(err)
}
//查找容器信息
getInfoOptions := types.ContainerListOptions{}
getContainerInfo(cli, getInfoOptions)
//配置創(chuàng)建容器的屬性
containerConfig := &container.Config{
Image: "my-golang-app",
ExposedPorts: nat.PortSet{
"3889/tcp": {},
},
}
//配置容器主機(jī)的屬性
//主要用于配置容器的運(yùn)行環(huán)境和資源限制等主機(jī)級別的設(shè)置
//配置的是容器的主機(jī)配置,而不是宿主機(jī)(即物理計(jì)算機(jī)或虛擬機(jī))的主機(jī)配置。
hostConfig := &container.HostConfig{}
//主要用于配置容器的網(wǎng)絡(luò)連接和端口映射等網(wǎng)絡(luò)設(shè)置
networkingConfig := &network.NetworkingConfig{}
//主要用于指定容器的運(yùn)行平臺信息,以便 Docker 在部署時(shí)選擇合適的環(huán)境。
platformConfig := &v1.Platform{}
//創(chuàng)建的容器名字,唯一標(biāo)識
containerName := "mycontainer-30"
//調(diào)用createContainer創(chuàng)建容器并啟動
containerId, err := createContainer(cli, containerConfig, hostConfig, networkingConfig, platformConfig, containerName)
fmt.Printf("容器%s已創(chuàng)建好 ", containerId)
// 刪除容器是通過Id進(jìn)行刪除的,需要根據(jù)名字查找到容器Id
// 根據(jù)容器的名字查找出要刪除容器的Id
containerID, err := getContainerIDByName(cli, containerName)
if err != nil {
log.Fatal(err)
}
// 定義刪除容器時(shí)的選項(xiàng)
removeOptions := types.ContainerRemoveOptions{
Force: true, // 強(qiáng)制刪除容器
RemoveVolumes: true, // 刪除關(guān)聯(lián)的數(shù)據(jù)卷
RemoveLinks: false, // 不刪除關(guān)聯(lián)的鏈接
}
// 調(diào)用removeContainer刪除容器
removeContainer(cli, containerID, removeOptions)
//根據(jù)容器的新配置重新創(chuàng)建容器
reUpdateContainer(cli, removeOptions, containerConfig, hostConfig, networkingConfig, platformConfig, containerName)
// 停止容器
stopOptions := container.StopOptions{}
stopContainer(cli, containerID, stopOptions)
// 重啟容器
restartContainer(cli, containerID, stopOptions)
// 暫停容器
pauseContainer(cli, containerID)
// 恢復(fù)暫停
unpauseContainer(cli, containerID)
// 定義進(jìn)入容器時(shí)的選項(xiàng)
attachOptions := types.ContainerAttachOptions{
Stream: true,
Stdin: true,
Stdout: true,
Stderr: true,
}
attachContainer(cli, containerID, attachOptions)
// 定義以命令行進(jìn)入容器的選項(xiàng)
execAttachConfig := types.ExecConfig{
Cmd: []string{"sh"},
AttachStdin: true,
AttachStdout: true,
AttachStderr: true,
Tty: true,
}
execAttachCheck := types.ExecStartCheck{
Tty: true,
}
execAttachContainer(cli, containerID, execAttachConfig, execAttachCheck)
// 定義拉取鏡像的選項(xiàng)
// 定義要拉取的鏡像的名稱和標(biāo)簽
imageName := "redis"
imageTag := "latest"
imageRef := imageName + ":" + imageTag
imagePulloptions := types.ImagePullOptions{}
pullImage(cli, imageRef, imagePulloptions)
//獲取容器內(nèi)所有鏡像的信息
getImageOptions := types.ImageListOptions{}
err = getAllImagesInfo(cli, getImageOptions)
if err != nil {
log.Fatal(err)
}
// 定義更新容器的選項(xiàng)
// 更新容器配置信息
// 配置更新
updateConfig := container.UpdateConfig{
Resources: container.Resources{
// Minimum memory limit allowed is 6MB
// 單位為byte(字節(jié)數(shù))
Memory: 60000000,
MemorySwap: 60000000, //設(shè)置Memory小于交換內(nèi)存MemorySwap 需要同時(shí)配置MemorySwap
NanoCPUs: 1, // 設(shè)置 CPU 配額(以納秒為單位)范圍: 0.01 - 8.00
},
}
err = updateContainer(cli, containerID, updateConfig)
if err != nil {
log.Fatal(err)
}
}
/*
作用: 查找出容器的所有信息(容器ID、鏡像名、端口、運(yùn)行狀態(tài)等等)
*/
func getContainerInfo(cli *client.Client, getInfoOptions types.ContainerListOptions) {
// 先得到列出所有容器的列表
containers, err := cli.ContainerList(context.Background(), getInfoOptions)
if err != nil {
panic(err)
}
// 對應(yīng)為docker ps -a 命令
// 再從列表(map)中拿到信息
for _, container := range containers {
fmt.Printf("CONTAINER ID: %s\n", container.ID)
fmt.Printf("IMAGE: %s \n", container.Image)
fmt.Printf("COMMAND: %s \n", container.Command)
fmt.Printf("CREATED: %s \n", container.Created)
fmt.Printf("Status: %s \n", container.Status)
fmt.Printf("PORTS: %s \n", container.Ports)
fmt.Printf("NAMES:%s\n", container.Names)
}
}
/*
作用: 根據(jù)容器名字和配置的創(chuàng)建選項(xiàng)創(chuàng)建容器
*/
func createContainer(cli *client.Client, containerConfig *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platformConfig *v1.Platform, containerName string) (containerId string, err error) {
// 創(chuàng)建容器
resp, err := cli.ContainerCreate(context.Background(), containerConfig, hostConfig, networkingConfig, platformConfig, containerName)
if err != nil {
log.Fatal(err)
}
// 啟動容器
if err := cli.ContainerStart(context.Background(), resp.ID, types.ContainerStartOptions{}); err != nil {
log.Fatal(err)
}
//返回創(chuàng)建好的容器ID
return resp.ID, err
}
/*
作用: 根據(jù)容器ID和配置的刪除選項(xiàng)刪除容器
*/
func removeContainer(cli *client.Client, containerID string, removeOptions types.ContainerRemoveOptions) {
// 調(diào)用 ContainerRemove 方法刪除容器
err := cli.ContainerRemove(context.Background(), containerID, removeOptions)
if err != nil {
fmt.Printf("Failed to remove container: %v\n", err)
} else {
fmt.Println("Container removed successfully")
}
}
/*
作用: 根據(jù)容器ID和配置的停止選項(xiàng)停止容器
*/
func stopContainer(cli *client.Client, containerID string, stopOptions container.StopOptions) {
// 調(diào)用 ContainerStop 方法停止容器
err := cli.ContainerStop(context.Background(), containerID, stopOptions)
if err != nil {
fmt.Printf("Failed to stop container: %v\n", err)
} else {
fmt.Println("Container stopped successfully")
}
}
/*
作用: 根據(jù)容器ID和配置的停止選項(xiàng)重啟容器
*/
func restartContainer(cli *client.Client, containerID string, stopOptions container.StopOptions) {
// 調(diào)用 ContainerRestart 方法重啟容器
err := cli.ContainerRestart(context.Background(), containerID, stopOptions)
if err != nil {
panic(err)
}
fmt.Printf("Container %s has been restarted.\n", containerID)
}
/*
作用: 根據(jù)容器ID暫停容器
*/
func pauseContainer(cli *client.Client, containerID string) {
// 暫停容器
err := cli.ContainerPause(context.Background(), containerID)
if err != nil {
fmt.Printf("Failed to pause container: %v\n", err)
} else {
fmt.Println("Container paused successfully")
}
}
/*
作用: 根據(jù)容器ID恢復(fù)容器暫停
*/
func unpauseContainer(cli *client.Client, containerID string) {
// 恢復(fù)暫停
err := cli.ContainerUnpause(context.Background(), containerID)
if err != nil {
fmt.Printf("Failed to pause container: %v\n", err)
} else {
fmt.Println("Container paused successfully")
}
}
/*
作用: 根據(jù)容器ID和配置的進(jìn)入選項(xiàng)進(jìn)入容器內(nèi)部
*/
func attachContainer(cli *client.Client, containerID string, attachOptions types.ContainerAttachOptions) {
// 調(diào)用 ContainerAttach 方法進(jìn)入容器
resp, err := cli.ContainerAttach(context.Background(), containerID, attachOptions)
if err != nil {
panic(err)
}
defer resp.Close()
// 將容器的標(biāo)準(zhǔn)輸入輸出連接到當(dāng)前進(jìn)程的標(biāo)準(zhǔn)輸入輸出
go io.Copy(os.Stdout, resp.Reader)
go io.Copy(resp.Conn, os.Stdin)
// 等待用戶輸入以繼續(xù)運(yùn)行
fmt.Println("Press enter to exit...")
fmt.Scanln()
}
/*
作用: 通過容器ID配置的進(jìn)入選項(xiàng)以命令行的方式進(jìn)入容器內(nèi)部
*/
func execAttachContainer(cli *client.Client, containerID string, execAttachConfig types.ExecConfig, execAttachCheck types.ExecStartCheck) {
// 準(zhǔn)備執(zhí)行命令的選項(xiàng)
createResp, err := cli.ContainerExecCreate(context.Background(), containerID, execAttachConfig)
if err != nil {
panic(err)
}
// 連接到正在運(yùn)行的命令以進(jìn)行交互
resp, err := cli.ContainerExecAttach(context.Background(), createResp.ID, execAttachCheck)
if err != nil {
panic(err)
}
defer resp.Close()
// 將容器的標(biāo)準(zhǔn)輸入輸出連接到當(dāng)前進(jìn)程的標(biāo)準(zhǔn)輸入輸出
go func() {
if _, err := io.Copy(os.Stdout, resp.Reader); err != nil {
panic(err)
}
}()
go func() {
if _, err := io.Copy(resp.Conn, os.Stdin); err != nil {
panic(err)
}
}()
// 等待用戶輸入以繼續(xù)運(yùn)行
fmt.Println("Press enter to exit...")
fmt.Scanln()
}
/*
作用: 通過配置拉取的鏡像名和拉取選項(xiàng)拉取鏡像
*/
func pullImage(cli *client.Client, imageRef string, imagePulloptions types.ImagePullOptions) {
// 拉取鏡像
out, err := cli.ImagePull(context.Background(), imageRef, imagePulloptions)
if err != nil {
panic(err)
}
defer out.Close()
// 解析拉取鏡像的輸出
var pullResponse struct {
Status string `json:"status"`
}
if err := json.NewDecoder(out).Decode(&pullResponse); err != nil {
panic(err)
}
fmt.Printf("Pulling image %s: %s\n", imageRef, pullResponse.Status)
}
/*
作用: 通過容器ID和編寫的更新配置動態(tài)更新容器配置信息(主要是資源限制、重啟選項(xiàng))
*/
func updateContainer(cli *client.Client, containerID string, updateConfig container.UpdateConfig) error {
// 執(zhí)行容器更新
_, err := cli.ContainerUpdate(context.Background(), containerID, updateConfig)
if err != nil {
return err
}
fmt.Println("容器配置已更新")
return nil
}
/*
作用: 根據(jù)容器名字和容器的新配置創(chuàng)建容器,用于對容器的配置進(jìn)行靜態(tài)的修改。
*/
func reUpdateContainer(cli *client.Client, removeOptions types.ContainerRemoveOptions, containerConfig *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platformConfig *v1.Platform, containerName string) {
// 一開始調(diào)用函數(shù)時(shí)就要傳入創(chuàng)建、刪除容器的配置
//傳入要刪除的名字,得到要刪除的容器ID。
containerID, err := getContainerIDByName(cli, containerName)
if err != nil {
log.Fatal(err)
}
//刪除容器
removeContainer(cli, containerID, removeOptions)
//調(diào)用創(chuàng)建api,創(chuàng)建新的容器
containerId, err := createContainer(cli, containerConfig, hostConfig, networkingConfig, platformConfig, containerName)
fmt.Printf("容器%s已重新創(chuàng)建好 ", containerId)
}
/*
作用:通過容器名查找容器ID,常用于需要使用容器ID的容器操作
*/
func getContainerIDByName(cli *client.Client, containerName string) (string, error) {
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
return "", err
}
for _, container := range containers {
for _, name := range container.Names {
// 注意: 容器名字以 "/" 開頭,例如:你創(chuàng)建的名字為mycontainer-30 實(shí)際在容器中為"/mycontainer-30"
// 在查找時(shí)前面要拼接上一個(gè) /
if name == "/"+containerName {
return container.ID, nil
}
}
}
return "", fmt.Errorf("未找到容器名稱為 %s 的容器", containerName)
}
/*
作用: 獲取容器的所有鏡像信息(不包含鏡像的名字)
*/
func getAllImagesInfo(cli *client.Client, getImageOptions types.ImageListOptions) error {
// 調(diào)用 Docker API 獲取所有鏡像的摘要信息
images, err := cli.ImageList(context.Background(), getImageOptions)
if err != nil {
return err
}
// 打印每個(gè)鏡像的信息
for _, image := range images {
fmt.Printf("鏡像ID: %s\n", image.ID)
fmt.Printf("標(biāo)簽: %s\n", image.Labels["com.docker.compose.version"])
fmt.Printf("大小: %d bytes\n", image.Size)
fmt.Println("--------------")
}
return nil
}
往期好文??
保姆級教程
【保姆級教程】Windows11下go-zero的etcd安裝與初步使用
【保姆級教程】Windows11安裝go-zero代碼生成工具goctl、protoc、go-zero
【Go-Zero】手把手帶你在goland中創(chuàng)建api文件并設(shè)置高亮
報(bào)錯(cuò)解決
【Go-Zero】Error: user.api 27:9 syntax error: expected ‘:‘ | ‘IDENT‘ | ‘INT‘, got ‘(‘ 報(bào)錯(cuò)解決方案及api路由注意事項(xiàng)
【Go-Zero】Error: only one service expected goctl一鍵轉(zhuǎn)換生成rpc服務(wù)錯(cuò)誤解決方案
【Go-Zero】【error】 failed to initialize database, got error Error 1045 (28000):報(bào)錯(cuò)解決方案
【Go-Zero】Error 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: YES)報(bào)錯(cuò)解決方案
【Go-Zero】type mismatch for field “Auth.AccessSecret“, expect “string“, actual “number“報(bào)錯(cuò)解決方案
【Go-Zero】Error: user.api 30:2 syntax error: expected ‘)‘ | ‘KEY‘, got ‘IDENT‘報(bào)錯(cuò)解決方案
【Go-Zero】Windows啟動rpc服務(wù)報(bào)錯(cuò)panic:context deadline exceeded解決方案
Go面試向
【Go面試向】defer與time.sleep初探
【Go面試向】defer與return的執(zhí)行順序初探
【Go面試向】Go程序的執(zhí)行順序
【Go面試向】rune和byte類型的認(rèn)識與使用文章來源:http://www.zghlxwxcb.cn/news/detail-847712.html
【Go面試向】實(shí)現(xiàn)map穩(wěn)定的有序遍歷的方式文章來源地址http://www.zghlxwxcb.cn/news/detail-847712.html
到了這里,關(guān)于【Golang】golang使用三方SDK操作容器指南的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!