Trying to understand reading/writing files to volume from app in container

My app runs at the following location on the container

/home/unity/.config/unity3d/Lee/MyApp

Inside my app I can read/write files to that location just fine, but they’re not persisted, so I’m trying to create a volume that my app can reach to save/open files that stick around between instances.

I tried adding that path to a volume
docker-compose segment:

volumes:
- '/game-data:/data
- ‘/persistant:/home/unity/.config/unity3d/Lee/MyApp’

But when I try to save a file to /home/unity/.config/unity3d/Lee/MyApp I get:

UnauthorizedAccessException: Access to the path “/home/unity/.config/unity3d/Lee/MyApp/data.json” is denied.

If I remove the line with /persistent/ from my compose, and run the app:

Debug.Log(“/data exists? " + Directory.Exists(”/data")); //true
Debug.Log(Path.GetFullPath(“/data”)); //only shows /data

If I try to save my file to /data or ./data (which should be a volume defined in compose above?), it fails with an exception:

Could not find a part of the path “/data/data.json”

I can write data.json to /home/unity/mydir and read from it but if I try to make home/unity/mydir a volume i can no longer read/writeto it.

By default my code in my app saving to its local folder is here:

/home/unity/.config/unity3d/Lee/MyApp/

If I try to access a different folder like /data in code I get a access denied exception. I honestly don’t care where the files are stored I just want to be able to persist wherever I’m saving to, and each time the app opens, have access to that location. (From within my app running in the container)

This is my Dockerfile I pieced together, its probably terrible but works

FROM ubuntu:latest
RUN apt-get update -qq;
apt-get install -qq -y
zip
&& apt-get clean
&& rm -rf /var/lib/apt/lists/*
COPY headless.zip .
RUN unzip headless.zip
RUN useradd -ms /bin/bash unity
RUN chown unity:unity -R headless_server.x86_64
USER unity
RUN [“chmod”, “+x”, “/headless_server.x86_64”]
ENTRYPOINT [“/headless_server.x86_64”]

Can anyone explain what I need to do to either mount my directory where my app is as a volume I can access, or how to access the volume from my code if somewhere else, both ways I’ve tried are throwing exceptions.

When you do use bind-mounts (that is in fact what you actualy use), then you need to make sure the UID:GID of the host folder matches the UID:GID of the user that starts your containerized process.

Since you added the user “unity” in your Dockerfile, you could leverage user: in your docker-compose.yml to make docker replace the UID:GID of the “unity” user. The uid:gid injection will be always done for the first USER directive in the Dockerfile, see https://docs.docker.com/engine/reference/run/#user for further details.

On the other side: if you declare a named volume in your docker-compose.yml and use it as volume in your service instead, it should work out of the box.

update: fixed the link to docker run reference to point to the #user anchor.

1 Like

Thank you, a stupid period was needed in my compose for the original code above to work, I swear I tried every combination before I posted. I will use the user: way you mention instead though, thank you.

The period here was needed:

volumes:
- ‘./game-data:/home/unity/game-data’

I didn’t understand that was creating a bind mount, thought it was a volume called game-data on the container and thought game-data was relative to the container or something, not relative to the directory my dockerfile and project is in on the host machine. But after adding the period it created the folder in my project, and I can see that the file is in there on my machine, and not in the image, and my app accesses it through /home/unity/game-data without error now.

If the left hand side of the mapping starts with a host path, by convention it will use a bind-mount. In your original post you used an absolute path, in your last post you switched it to a relative path (relative to the compose file). You will not see it listed in docker volume ls

A named volume on the other hand needs to be declared specificly. Instead of a host path, the name of the named volume is on the left hand side of the mapping. Named volumes are listed in docker volume ls.

It’s better to actualy understand why it worked :slight_smile: I guess your host user and the container user by accident share the same UID…

1 Like

The left side is a path on the host. Without the “.” it was relative to the root.