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.