I am working on an application in spring boot in which photos will be uploaded to the server and then read from the server using the url. The application is on the docker and tomcat server. From what I have learned the best way would be to store photos on docker volume using the host. So using the docker-compose.yml file I create the volume and give the path to the host. File fragment:
version: '3.8'
services:
my-app:
image: app
environment:
- _JAVA_OPTIONS=-Xmx512m -Xms256m
- SPRING_PROFILES_ACTIVE=prod,api-docs
.
.
.
ports:
- 8085:8085
networks:
default:
ipv4_address: 172.19.0.2
volumes:
- ./var/home/my-app:/var/lib/docker/containers/docker_my-app //"path to the host:path to the docker container"
From what I read on the Docker website there, this is how you should create a path to the host where the photos will be stored, i.e. on the left the path to the host, and on the right the path to the container. The problem is that no path is created or is, but I can’t find it. I also have a method that runs every time it checks to see if a path exists:
@PostConstruct
public void init() {
if (!Files.exists(Paths.get("./var/home/my-app"))) {
try {
Files.createDirectory(root);
} catch (IOException e) {
throw new StorageException("Error initializing directory: " + e.getMessage());
}
}
And this throws that path does not exists.
So, I have questions:
- Am I creating a good path to the host?
- Or should the path to the host be different?
- If host will be with read write permissions should I add something in docker-compose.yml file?
Edit
So to specify my problem. I wanto save files in volume host and then gets image by URL e.g. localhost:8080/image/12/picture.png
I have to specify path where the files are ulpoded. Method init() checks if path exists and then a path is assigned to the variable root where the files should be saved.
@PostConstruct
public void init() {
if (isProd) {
root = Paths.get("./var/home/my-app");
} else {
root = Paths.get("./uploads");
}
if (!Files.exists(root)) {
try {
Files.createDirectory(root);
} catch (IOException e) {
throw new StorageException("Error initializing directory: " + e.getMessage());
}
}
}
And then I saved files like this:
Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING); //filePath: ./upluads/image/12/picture.png
filePath should contains path to host and unique folders for each photo with id in the name.
2
Answers
You’re currently mounting the folder
/var/home/my-app
from your host machine to the folder/var/lib/docker/containers/docker_my-app
inside the container.As your application is running inside a container the method you’ve written
creates the directory structure
/var/home/my-app
inside the container filesystem.If your Java code is written to save data under the folder
/var/home/my-app
you should create your volume in the following way:Assuming your check-method is inside your Spring application, i.e., inside the my-app container, you need to check for the
folder, instead of the
folder:
On the first use of the volume-folder, the respective folder on the host should be created (as you are using the short-notation for the volume definition).
The folder that should be created would be alongside your docker-compose.yml file, named var/home/my-app
To be able to create subfolders based on the provided url, for instance
localhost:8080/image/12/picture.png
, you need to define the endpoint/image/{id}/{image_name}
where theid
is a path variable andimage_name
is a path variable.Similarly, your POST request that you use to upload the file needs to have
id
path variable, which you translate to a folder name in your code, and create it if it is not present.Regarding your third question:
That depends on whether you defined a user to isolate your container.
Have a look here: https://docs.docker.com/engine/security/userns-remap/
Unless you did something like this, your process inside the container is running as root and can then write on your host regardless of missing permissions.
Edit to clarify the folders that are created due to the line in docker-compose.yml:
As you correctly commented on this line,
the ./var/home/my-app is the path on your host machine.
Since it starts with a ‘.’ it is a relative path and will start at the current location where the docker-compose.yml file is located.
The second part: /var/lib/docker/containers/docker_my-app is the path inside the container, which gets mapped to the folder on your host.
This is an absolute path, since it starts with ‘/’.
Anything that your application places in this folder (/var/lib/docker/containers/docker_my-app) will be accessible on your host machine (so outside of your docker container) in the other folder (./var/home/my-app).
They are the same space on your hard drive, once accessed from inside the container and once accessed from the host.
In you application that runs in the docker-container, you exclusively use the path: /var/lib/docker/containers/docker_my-app.
Outside of the container, so on your host, you exclusively use the path ./var/home/my-app.
Suppose on your host the docker-compose.yml file is located in the folder:
Then you will find the contents of the shared folder under
If you want to have files from your host accessible inside the docker-container, you need to put them in this directory.
Then, from inside the docker-container, you access these files by navigating to :