// createAndExtractImage creates a docker container based on the option's image with containerName. // It will then insepct the container and image and then attempt to extract the image to // option's destination path. If the destination path is empty it will write to a temp directory // and update the option's destination path with a /var/tmp directory. /var/tmp is used to // try and ensure it is a non-in-memory tmpfs. func (i *defaultImageInspector) createAndExtractImage(client *docker.Client, containerName string) (*docker.Image, error) { container, err := client.CreateContainer(docker.CreateContainerOptions{ Name: containerName, Config: &docker.Config{ Image: i.opts.Image, // For security purpose we don't define any entrypoint and command Entrypoint: []string{""}, Cmd: []string{""}, }, }) if err != nil { return nil, fmt.Errorf("Unable to create docker container: %v\n", err) } // delete the container when we are done extracting it defer func() { client.RemoveContainer(docker.RemoveContainerOptions{ ID: container.ID, }) }() containerMetadata, err := client.InspectContainer(container.ID) if err != nil { return nil, fmt.Errorf("Unable to get docker container information: %v\n", err) } imageMetadata, err := client.InspectImage(containerMetadata.Image) if err != nil { return imageMetadata, fmt.Errorf("Unable to get docker image information: %v\n", err) } if i.opts.DstPath, err = createOutputDir(i.opts.DstPath, "image-inspector-"); err != nil { return imageMetadata, err } reader, writer := io.Pipe() // handle closing the reader/writer in the method that creates them defer writer.Close() defer reader.Close() log.Printf("Extracting image %s to %s", i.opts.Image, i.opts.DstPath) // start the copy function first which will block after the first write while waiting for // the reader to read. errorChannel := make(chan error) go func() { errorChannel <- client.CopyFromContainer(docker.CopyFromContainerOptions{ Container: container.ID, OutputStream: writer, Resource: "/", }) }() // block on handling the reads here so we ensure both the write and the reader are finished // (read waits until an EOF or error occurs). handleTarStream(reader, i.opts.DstPath) // capture any error from the copy, ensures both the handleTarStream and CopyFromContainer // are done. err = <-errorChannel if err != nil { return imageMetadata, fmt.Errorf("Unable to extract container: %v\n", err) } return imageMetadata, nil }