There is a specific technical argument that the Dockerfile should be in the project root and named exactly Dockerfile, and I'd go with this approach as a default.
When you build a Docker image, you send Docker a directory tree called the build context. You can't access any files outside the build context at all; depending on the version of Docker, COPY ../../../build.gradle ./ will either result in a specific error or attempt to copy it out of the context root directory instead. This means that the build context directory must be the project root (or a parent directory).
You also need to tell Docker where the Dockerfile is. Its default value is Dockerfile, with no extension, in the root directory of the build context. You can specify other paths or filenames, but if you use that default name then you can omit the option entirely.
# In the project root docker build . # Not in the project root docker build . -f src/main/docker/Dockerfile
Docker Compose has an even shorter syntax if you're using only default settings:
services: in-the-project-root: build: . not-in-the-project-root: build: context: . dockerfile: src/main/docker/Dockerfile
The other argument here is that the left-hand side of COPY is always relative to the build-context directory, not the Dockerfile location. In these last examples where the build context is several directories above the location of the Dockerfile, COPY ./build.gradle ./ will be the build context directory. Putting the Dockerfile somewhere else can be counterintuitive.
As I've shown, it's definitely possible to put the Dockerfile somewhere else or to name it something else. But you'll have the least friction with Docker tooling if it's exactly in the project root and if it's named exactly Dockerfile.