skip to Main Content

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


  1. 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

    @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());
            } 
    }
    

    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:

    volumes:
       - /var/home/my-app:/var/home/my-app
    
    Login or Signup to reply.
  2. Assuming your check-method is inside your Spring application, i.e., inside the my-app container, you need to check for the

    /var/lib/docker/containers/docker_my-app
    

    folder, instead of the

    ./var/home/my-app
    

    folder:

    @PostConstruct
    public void init() {
      if (!Files.exists(Paths.get("/var/lib/docker/containers/docker_my-app"))) {
        try {
            Files.createDirectory(root);
        } catch (IOException e) {
            throw new StorageException("Error initializing directory: " + e.getMessage());
        } 
    }
    

    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 the id is a path variable and image_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:

    If host will be with read write permissions should I add something in docker-compose.yml file?

    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:

     - ./var/home/my-app:/var/lib/docker/containers/docker_my-app  //"path to the host:path to the docker container"
    

    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:

    /home/thortiede/docker/docker-compose.yml
    

    Then you will find the contents of the shared folder under

    /home/thortiede/docker/var/home/my-app
    

    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 :

    /var/lib/docker/containers/docker_my-app
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search