public File convert(MultipartFile multipartFile) {
byte[] bytes;
try {
bytes = multipartFile.getBytes();
try (FileOutputStream fos = new FileOutputStream("files/" + multipartFile.getOriginalFilename())) {
fos.write(bytes);
}
} catch(IOException e) {
System.out.println("Exception when converting multipart file to array of bytes");
System.out.println(e.getCause());
System.out.println(e.getMessage());
}
return new File("files/" + multipartFile.getOriginalFilename());
}
У меня есть этот метод, который преобразует MultipartFile в файл (из пакета .io). files/ — это каталог внутри базового каталога моего проекта. На моем локальном компьютере все работает нормально (ubuntu 22), но когда я запускаю приложение в контейнере докеров и вызываю этот метод, он выдает IOException:
file-exchange-web-1 | Exception when converting multipart file to array of bytes
file-exchange-web-1 | null
file-exchange-web-1 | files/zip.png (No such file or directory)
Вот что происходит, когда я пытаюсь получить доступ к этому файлу:
file-exchange-web-1 | java.io.FileNotFoundException: file [/apps/files/zip.png] cannot be resolved in the file system for checking its content length
Вот мой докер-файл:
FROM openjdk:21-slim
WORKDIR /apps
ARG JAR_FILE
COPY target/${JAR_FILE} /apps/app.jar
COPY /entrypoint.sh /apps/entrypoint.sh
RUN adduser --system servuser
RUN chmod +x /apps/entrypoint.sh
RUN chown -R servuser /apps
USER servuser
EXPOSE 8080 8080
CMD ["/apps/entrypoint.sh"]
Я понимаю, что dockerfile меняет рабочий каталог на /apps и меняет путь, но я не совсем понимаю, что именно делает WORKDIR: где он создает каталог /apps, в каком каталоге в контейнере находится мое приложение и т. д. Я также слышал об использовании System.getProperty("user.dir"); но я не совсем понимаю, где в контейнере находится мое приложение, поэтому для меня это не имеет особого смысла. Я погуглил концепцию точных каталогов, которая помещает приложение в контейнер, но не нашел ничего, что могло бы мне помочь.
Отредактировано*
Изменение файла Docker решило мою проблему:
ОТ openjdk:21-slim
РАБОЧИЙ ПАРАМЕТР/приложения ARG JAR_FILE КОПИРОВАТЬ target/${JAR_FILE} /apps/app.jar КОПИРУЙТЕ /entrypoint.sh /apps/entrypoint.sh.
RUN adduser --системный серверный пользователь ЗАПУСК chmod +x /apps/entrypoint.sh ЗАПУСТИТЬ chown -R сервер/приложения ЗАПУСК файлов mkdir
Пользователь root РАЗВЕРНУТЬ 8080 8080 CMD ["/apps/entrypoint.sh"]
Я предполагаю, что проблема в том, что каталог файлов не существует в контейнере Docker.
Вы были правы, я забыл это создать. Спасибо :)
Вы устанавливаете WORKDIR
при создании образа докера, и это гарантирует, что все команды RUN
используют один и тот же путь.
Должен быть создан файл под корнем, т. е. /apps
, но когда вы действительно запускаете образ докера, вам также необходимо указать /apps
как ваш рабочий каталог, используя опцию -w
.
Способ устранения таких проблем: docker run -it --entrypoint=/bin/bash
и вы можете посмотреть структуру каталогов вашего изображения и то, что там существует.
Большое спасибо, я понял, что проблема в том, что я не создал каталог файлов в apps/. Я добавил эти две команды RUN mkdir files USER root, и теперь у меня все работает нормально.
docker run -w
и WORKDIR
оба устанавливают одно и то же: текущий каталог в контейнере. IME нужен довольно редко docker run -w
.
Я думаю, что WORKDIR предназначен только для того, чтобы использовать файл Docker. Вы можете определить путь, распечатав текущий каталог, например
new File(".")