Home > Software design >  Docker does not copy executable if I bind a volume to it
Docker does not copy executable if I bind a volume to it

Time:07-30

I'm trying to dockerize an application that downlaods youtube livestreams automagically. I wan't to store the outputs on my drive which is connected and mounted in my RaspberryPi which is also running Docker (in rootless mode). That's why I want the docker container to use a volume on my drive.

When I start the docker container with -v /dir-to-drive:/app it says:

docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "./ytarchiver": stat ./ytarchiver: no such file or directory: unknown.
ERRO[0002] error waiting for container: context canceled

But when I create an volume with docker volume create and bind it -v volume:/app it does work.

This is my dockerfile:

FROM golang:1.16 AS build-env

WORKDIR /go/src

COPY . .

RUN go build -o ytarchiver

WORKDIR /app

RUN apt-get -y update
RUN apt-get install -y ffmpeg

FROM golang:1.16

WORKDIR /app

VOLUME /app

COPY --from=build-env /go/src/ytarchiver ./

ENTRYPOINT ["./ytarchiver"]

CodePudding user response:

Anything you mount with docker run -v will hide anything that was in the image. This means you do not typically want to mount volumes over the directories that contain your application code or your compiled application.

In the case of a (compiled) Go application, things are simpler than in other interpreted languages (Python, Javascript, ...): you only need to COPY the compiled binary from the build stage, and since it's only the one binary, you can put it into a normal binary directory like /usr/local/bin. So I might rewrite this Dockerfile as:

# (This is your existing build stage)
FROM golang:1.16 AS build-env
WORKDIR /go/src
COPY . .
RUN go build -o ytarchiver

FROM ubuntu # do not need the Go toolchain

# If you need ffmpeg or other external tools, they need to be
# installed in the final image
RUN apt-get update \
 && DEBIAN_FRONTEND=noninteractive \
    apt-get install --no-install-recommends --assume-yes \
      ffmpeg

# Copy _only_ the built binary, into a directory on $PATH
COPY --from=build-env /go/src/ytarchiver /usr/local/bin/

# Set up the data directory
VOLUME /data

# Explain how to run the container
WORKDIR /data
CMD ["ytarchiver"]

You should be able to use either a bind mount or a named volume here.

docker run -v "$PWD/ytarchiver-data:/data" my/ytarchiver

docker volume create ytadata
docker run -v ytadata:/data my/ytarchiver

In your original form, you're putting your application in the /app directory and then mounting a volume over it, which hides the copy of the binary in the image. This apparently works with a named volume, since Docker copies the contents of images into named volumes – but only the very first time you use the volume, only if the volume is actually empty, and only with Docker named volumes and not any other kind of storage. If you run the container a second time with a modified application, there will be an old copy in the named volume and that will take precedence.

  • Related