go通过docker sdk复制文件到容器中
第一步:需要先判断容器中的文件夹是否存在
第二步:将需要拷贝的文件打包成tar存档
第三步:读取打包的tar存档,然后拷贝到容器中
package main
import (
"archive/tar"
"context"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"unicode"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
// 判断文件夹是否存在
func checkFolderExistenceInContainer(cli *client.Client, containerID, folderPath string) (bool, error) {
ctx := context.Background()
// 创建一个容器内执行的命令
cmd := []string{"sh", "-c", fmt.Sprintf("test -e %s > /dev/null && echo $?", folderPath)}
// 创建一个容器执行请求
createResp, err := cli.ContainerExecCreate(ctx, containerID, types.ExecConfig{
AttachStdout: true,
AttachStderr: true,
Cmd: cmd,
})
if err != nil {
fmt.Println(err.Error())
return false, err
}
// 执行命令并获取输出
resp, err := cli.ContainerExecAttach(ctx, createResp.ID, types.ExecStartCheck{})
if err != nil {
return false, err
}
defer resp.Close()
// 读取命令输出
output, err := io.ReadAll(resp.Reader)
if err != nil {
return false, err
}
// 去除不可见字符串
cleanedStr := strings.Map(func(r rune) rune {
// 使用unicode.IsGraphic函数判断字符是否为可见字符
if unicode.IsGraphic(r) {
return r
}
return -1 // 返回-1表示删除该字符
}, string(output))
// 判断文件夹是否存在
// 此处假设如果文件夹存在,Shell命令返回值为0
return cleanedStr == "0", nil
}
// 打包文件夹中的文件
func createTarArchiveDir(sourceDir, tarFilePath string) error {
tarFile, err := os.Create(tarFilePath)
if err != nil {
return fmt.Errorf("无法创建tar存档文件: %w", err)
}
defer tarFile.Close()
tw := tar.NewWriter(tarFile)
defer tw.Close()
return filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 如果当前路径是源文件夹,则跳过
if path == sourceDir {
return nil
}
relPath, err := filepath.Rel(sourceDir, path)
if err != nil {
return err
}
// 如果需要修改名称,需要加上这段
// 在创建tar.Header之前修改文件名
newFilename := "new_" + relPath
header, err := tar.FileInfoHeader(info, relPath)
if err != nil {
return err
}
//需要修改名称,则需要加上这段
// 将新的文件名设置为tar.Header的Name字段
header.Name = newFilename
if err := tw.WriteHeader(header); err != nil {
return err
}
if !info.Mode().IsRegular() {
return nil
}
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(tw, file)
return err
})
}
// 打包特定文件
func createTarArchiveFiles(sourceFiles []string, tarFilePath string) error {
tarFile, err := os.Create(tarFilePath)
if err != nil {
return fmt.Errorf("无法创建tar存档文件: %w", err)
}
defer tarFile.Close()
tw := tar.NewWriter(tarFile)
defer tw.Close()
for _, sourceFile := range sourceFiles {
file, err := os.Open(sourceFile)
if err != nil {
return fmt.Errorf("无法打开文件 %s: %w", sourceFile, err)
}
defer file.Close()
stat, err := file.Stat()
if err != nil {
return fmt.Errorf("无法获取文件信息 %s: %w", sourceFile, err)
}
// 这里可以修改拷贝到容器中文件的文件名
newName := "c" + filepath.Base(sourceFile)
header := &tar.Header{
Name: newName,
Mode: int64(stat.Mode().Perm()),
Size: stat.Size(),
}
if err := tw.WriteHeader(header); err != nil {
return fmt.Errorf("无法写入tar头部信息 %s: %w", sourceFile, err)
}
_, err = io.Copy(tw, file)
if err != nil {
return fmt.Errorf("无法将文件内容写入tar存档 %s: %w", sourceFile, err)
}
}
return nil
}
func main() {
// 设置远程Docker守护进程的地址(包括协议和端口号)
remoteDockerHost := "tcp://10.0.0.12:2376"
// 创建Docker客户端并指定远程Docker守护进程地址
cli, err := client.NewClientWithOpts(
client.WithHost(remoteDockerHost),
// client.WithVersion("1.41"),
client.WithAPIVersionNegotiation(),
)
if err != nil {
fmt.Println("创建容器失败:", err)
return
}
containerID := "nginx" // 要复制文件的容器ID
sourceFiles := []string{"a.html"} // 替换为要打包的特定文件的路径
tarFilePath := "test.tar" // 替换为要生成的.tar存档路径
destFilePath := "/usr/share/nginx/html" // 容器中的目标文件夹路径
//判断目标文件夹路径是否存在
exists, err := checkFolderExistenceInContainer(cli, containerID, destFilePath)
if err != nil {
fmt.Printf("检查文件夹存在性时发生错误:%v\n", err)
return
}
if exists {
err = createTarArchiveFiles(sourceFiles, tarFilePath)
// err = createTarArchiveDir("test", "test.tar")
if err != nil {
fmt.Println("创建tar存档失败:", err)
return
}
srcFile, err := os.Open("test.tar")
if err != nil {
fmt.Println("文件打开失败:", err)
return
}
err = cli.CopyToContainer(context.Background(), containerID, destFilePath, srcFile, types.CopyToContainerOptions{
AllowOverwriteDirWithFile: true,
})
if err != nil {
fmt.Println("复制文件失败:", err.Error())
return
}
fmt.Println("文件拷贝成功!")
err = os.Remove("test.tar")
if err != nil {
fmt.Println("无法删除文件:", err)
return
}
fmt.Println("缓存文件删除成功!")
} else {
fmt.Printf("文件夹 %s 不存在于容器 %s 内\n", destFilePath, containerID)
}
}
本文来自博客园,作者:厚礼蝎,转载请注明原文链接:https://www.cnblogs.com/guangdelw/p/17567860.html