I have a local folder called images
that contains bunch of folders and files within. When I run the container I get the following error:
the command I execute: docker run -t -i file-uploader -token=abcdefgh
panic: failed Walk: Failed to walk directory: *fs.PathError lstat ./images/: no such file or directory
goroutine 1 [running]:
main.main()
/src/main.go:57 +0x357
Here is the Dockerfile
I created:
FROM golang:1.16
WORKDIR /src
COPY go.sum go.mod ./
RUN go mod download
COPY ./images/ images/
COPY . .
RUN CGO_ENABLED=0 go build -o /bin/app .
ENTRYPOINT ["/bin/app"]
FROM scratch
COPY --from=0 /bin/app /bin/app
ENTRYPOINT ["/bin/app"]
And, here is the code in the program:
var (
token = flag.String("token", "", "user's token for application")
rootpath = flag.String("rootpath", "./images/","folder path to be uploaded")
)
func main() {
flag.Parse()
if *token == "" {
log.Fatal(Red + "please provide a client token => -token={$token}")
}
tokenSource := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: *token})
oauthClient := oauth2.NewClient(context.TODO(), tokenSource)
client := putio.NewClient(oauthClient)
paths := make(chan string)
var wg = new(sync.WaitGroup)
for i := 0; i < 20; i++ {
wg.Add(1)
go worker(paths, wg, client)
}
if err := filepath.Walk(*rootpath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return fmt.Errorf("Failed to walk directory: %T %w", err, err)
}
if !info.IsDir() {
paths <- path
}
return nil
}); err != nil {
panic(fmt.Errorf("failed Walk: %w", err))
}
close(paths)
wg.Wait()
}
}
If flag is not provided, its default value is the folder itself which is ./images/
. When I run this normally like: go run main.go -token="abcde"
, it works properly. I did some changes on Dockerfile
. Some of the changes I made and tried again and again.:
- replacing
COPY . .
withCOPY ./images/ /images
. It should automatically creates a folder inside/src
like/src/images
and get the local folder from host and put into it. It didn’t work. - I also did try
COPY . .
, believing that it will copy everything from host into docker container. It didn’t work either. - I did put 2
COPY
command together. Didn’t work. COPY . ./
didn’t work either.
My structure of the project is as follows:
/file-uploader-cli
/images
Dockerfile
file-uploader-cli (binary)
go.mod with go.sum
main.go
How can I put /images
folder into container and run it properly?
Extra question: /images
folder is approx. 500 MB or something. Is it a good practice to put that folder into a container?
I guess it is possible to copy a folder like docker cp {$folder_name} ${container_id}:/{$path}
, but it must be a running container or something? I did try this using image_id
replacing the container_id
but I got an error like No such container:path: 12312312312:/
.
EDIT:
the problem is the scratch
image which was done in order to reduce the size. However, when I delete the scratch
thing, the size of the image became 1.1 GB. Any easier or convenient way to utilize the images
folder without having too much size?
2
Answers
You don’t need
images
when building your app, you need it when executing your app. Instead of addingimages
to the first image, add it to the final image:Or, if you want to provide images dynamically, you could mount it at runtime.
I also recommend removing docker containers automatically unless you actually want them sticking around. Otherwise you end up with lots and lots of
Exited
containers.I would also recommend you put your token in an environment variable so its not saved in bash history and docker runtime information.
I don’t usually containerize Go programs unless containers are a good fit for deployment and operations (eg kubernetes). Most languages like C/C++, Java, Erlang, Python, Javascript, all require significant runtime components provided by the filesystem – compiled ones are usually dynamically linked with shared libraries from the operating system, VM based languages like Java or Erlang require the VM to be installed and configured (and it will likely also have runtime dependencies), and interpreted languages like Python, Ruby, or Javascript require the entire interpreter runtime, as well as any shared libraries the language’s libraries are linked to.
Go is an exception to this though. Ignoring CGo (which I recommend avoiding whenever possible), Go binaries are statically linked and have minimal userspace runtime requirements. This is why a Go binary is one of the few things that can acutally work in a container built
FROM scratch
. The one exception to this, is that the Go program will need CA Certificates from the operating system to validate the certificates on HTTPS servers and other protocols secured with TLS.I recommend that you don’t dockerize the app unless docker is helping you distribute or operate it.
The problem is that the second build stage does not include the
images
directory. I don’t think you can use thescratch
base for this purpose, so we will have to change that. If you are concerned about image size, you should look into into alpine linux. I have converted your Dockerfile to use alpine.Note that I changed the app path in the second build stage to
/opt/app
. I did this because it would be odd to have an image folder under/bin
. And/opt
is a common place to store user applications.As for whether or not you should containerize your code, that is up to you. One of Go’s advantages is static compilation and easy cross-compiling. So you could distribute your binary (and images) as is.