测试了好久,发现,单独读取dockerfile文件,然后上传,是无法构建成功的
构建的时候总会报无法找到dockerfile文件
Error response from daemon: Cannot locate specified Dockerfile: Dockerfile
查资料发现需要将dockerfile以及相关依赖文件打包成tar存档,才能正常读取并构建镜像
而使用 "github.com/docker/docker/pkg/archive"
库是无法正常创建所需的tar存档
需要自己手动打包成tar存档
如果大家有更好更优雅的方法,麻烦留言告知,万分感谢
打包tar存档的方法
打包文件夹中的文件
package main
import (
"archive/tar"
"fmt"
"io"
"os"
"path/filepath"
)
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
}
relPath, err := filepath.Rel(sourceDir, path)
if err != nil {
return err
}
header, err := tar.FileInfoHeader(info, relPath)
if err != nil {
return err
}
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 main() {
sourceDir := "path/to/source/directory" // 替换为要打包的文件夹路径
tarFilePath := "archive.tar" // 替换为要生成的.tar存档路径
if err := createTarArchiveDir(sourceDir, tarFilePath); err != nil {
fmt.Println("无法创建tar存档:", err)
return
}
fmt.Println("tar存档创建成功!")
}
特定文件打包的方法
package main
import (
"archive/tar"
"fmt"
"io"
"os"
)
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)
}
header := &tar.Header{
Name: sourceFile,
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() {
sourceFiles := []string{"path/to/file1.txt", "path/to/file2.txt"} // 替换为要打包的特定文件的路径
tarFilePath := "specific.tar" // 替换为要生成的.tar存档路径
if err := createTarArchiveFiles(sourceFiles, tarFilePath); err != nil {
fmt.Println("无法创建tar存档:", err)
return
}
fmt.Println("tar存档创建成功!")
}
整合完成构建镜像
package main
import (
"archive/tar"
"context"
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
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
}
relPath, err := filepath.Rel(sourceDir, path)
if err != nil {
return err
}
header, err := tar.FileInfoHeader(info, relPath)
if err != nil {
return err
}
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)
}
header := &tar.Header{
Name: sourceFile,
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
}
sourceFiles := []string{"aaa", "a.html"} // 替换为要打包的特定文件的路径
tarFilePath := "archive.tar" // 替换为要生成的.tar存档路径
// 对特定文件打包成tar存档
if err := createTarArchiveFiles(sourceFiles, tarFilePath); err != nil {
fmt.Println("无法创建tar存档:", err)
return
}
fmt.Println("tar存档创建成功!")
dockerBuildContext, err := os.Open("archive.tar")
defer dockerBuildContext.Close()
// 构建Docker镜像
buildOptions := types.ImageBuildOptions{
Dockerfile: "aaa",
Tags: []string{"a:v5"},
}
// 构建镜像
resp, err := cli.ImageBuild(context.Background(), dockerBuildContext, buildOptions)
if err != nil {
fmt.Println("无法构建Docker镜像:", err)
os.Exit(1)
}
defer resp.Body.Close()
// 解析构建过程中的输出日志并打印到控制台
// 这里只是一个简单的示例,实际应用中可能需要更多处理
fmt.Println("构建Docker镜像中...")
dec := json.NewDecoder(resp.Body)
for {
var v map[string]interface{}
if err := dec.Decode(&v); err != nil {
break
}
fmt.Println(v["stream"])
}
fmt.Println("Docker镜像构建成功!")
// 用完后删除tar存档
err = os.Remove("archive.tar")
if err != nil {
fmt.Println("无法删除文件:", err)
return
}
fmt.Println("文件删除成功!")
}