I need build some Docker image directly from my Golang application. I spent some time on Google but I didn’t find any fully functional example of Goland code…
And then I had to write my own implementation of this functionality.
Here we go!
package main import ( "bufio" "context" "crypto/rand" "encoding/hex" "fmt" "io" "log" "os" "os/exec" "path/filepath" "time" "github.com/docker/docker/api/types" "github.com/docker/docker/client" ) func main() { if len(os.Args) != 3 { fmt.Println("bad num of arguments:\n\t1. = dir with image content\n\t2. = image name") os.Exit(0) } msg, err := buildImage(os.Args[1], os.Args[2]) if err != nil { log.Fatal(err) } fmt.Println(msg) } func createTar(srcDir, tarFIle string) error { /* #nosec */ c := exec.Command("tar", "-cf", tarFIle, "-C", srcDir, ".") if err := c.Run(); err != nil { return nil } return nil } func tempFileName(prefix, suffix string) (string, error) { randBytes := make([]byte, 16) if _, err := rand.Read(randBytes); err != nil { return "", err } return filepath.Join(os.TempDir(), prefix+hex.EncodeToString(randBytes)+suffix), nil } func buildImage(dir, name string) ([]string, error) { tarFile, err := tempFileName("docker-", ".image") if err != nil { return nil, err } defer os.Remove(tarFile) if err := createTar(dir, tarFile); err != nil { return nil, err } /* #nosec */ dockerFileTarReader, err := os.Open(tarFile) if err != nil { return nil, err } defer dockerFileTarReader.Close() cli, err := client.NewEnvClient() if err != nil { return nil, err } defer cli.Close() ctx, cancel := context.WithTimeout(context.Background(), time.Duration(300)*time.Second) defer cancel() buildArgs := make(map[string]*string) PWD, err := os.Getwd() if err != nil { return nil, err } defer os.Chdir(PWD) if err := os.Chdir(dir); err != nil { return nil, err } resp, err := cli.ImageBuild( ctx, dockerFileTarReader, types.ImageBuildOptions{ Dockerfile: "./Dockerfile", Tags: []string{name}, NoCache: true, Remove: true, BuildArgs: buildArgs, }) if err != nil { return nil, err } defer resp.Body.Close() var messages []string rd := bufio.NewReader(resp.Body) for { n, _, err := rd.ReadLine() if err != nil && err == io.EOF { break } else if err != nil { return messages, err } messages = append(messages, string(n)) } return messages, nil }