FileNotFoundException。。没错、这篇还是从读取的文件找不到的问题开始,今天来个终极版( ̄∇ ̄)/
一开始我把要读取的文件放在了项目根路径,package就没把它打进去,显然是找不到的,于是我把这个JSON文件移到了resources中
此时可以看到,这个文件也打进了target中,这部分可以参考
【填坑向】Linux获取Java程序resource下的文件路径(这次的坑好像没填住……
之前的一篇的文章,那里有记录过获取路径失败的原因,这里就不重复赘述叻
今天这篇是有新发现!算是填上一篇文章的坑( ̄∇ ̄)/
在官网上了解到可以通过解包的方式,来读取jar包中的内容
官方地址:https://docs.spring.io/spring-boot/docs/2.3.12.RELEASE/reference/html/deployment.html#deployment
于是在本地的终端中对打好的jar包依次执行了这两行命令,运行无比顺滑然后我就也在Dockerfile中加了如下红框框内的两行
CMD ["jar","-xf","my-1.0.0-SNAPSHOT.jar"] CMD ["java","org.springframework.boot.loader.JarLauncher"]
推到服务器上。。。就是=[,,_,,]:3哭死在阿里云。。。
报找不到org.springframework.boot.loader.JarLauncher
找不到org.springframework.boot.loader.JarLauncher
最初单纯的俺一直觉得是没有填对路径,于是按照各种文章尝试:比如切换WORKDIR,改绝对路径、改相对路径。。。
服务器日志都是坚持告诉我:Could not find the main class: org.springframework.boot.loader.JarLauncher
即将哭死的我一不小心从旁边大佬处得知CMD指令只有最后一个有效。。。
WHAT?! RUN、CMD 和 ENTRYPOINT 指令都可以用来执行具体的命令RUN 指令是在 Docker 镜像构建时发挥作用, 可以使用多个该命令,且执行结果会记录到镜像中CMD 和 ENTYPOINT 指令是在容器启动时自动执行,均只有最后一个该指令有效,且均可以在 docker run 中被覆盖ENTRYPOINT 指令和 CMD 的区别在于使用 ENTRYPOINT 时 CMD 指令会被作为其默认参数,而用户也可以在启动容器时通过覆盖 CMD 指令来输入参数;此外, 这也意味着 ENTRYPOINT 指令的内容不易被用户命令覆盖。
好吧(谁让我不好好学docker=[,,_,,]:3)
怪不得看到很多案例使都是使用entrypoint.sh文件来执行多条脚本的,俺也来!
于是我在Dockerfile同级目录下新建了一个entrypoint.sh文件,把多条命令写在这个文件中
在Dockerfile中添加执行这个脚本的代码
ENTRYPOINT ["/app/docker/entrypoint.sh"]
又是一顿找不到。。。
no such file or directory
我们先来分析下这个异常记录📝,找不到文件?
我进入到了这个容器的终端中,使用find命令全局搜索🔍,仍然未找到,即不是路径的问题,在我看到ADD xxx.jar那句的时候,忽然意识到,并没有将这个文件复制进镜像,自然不会在启动后能找的到
但是对docker并不是很熟悉的我并不知道这个文件会在具体哪个路径下,算了,成年人不做选择!
全复制!加一行搞定(。・ω・。)ノ
COPY . /app/
就在我好不容易识别到了entrypoint.sh这个文件
它终于开始执行叻。。。。md
permission denied
caused: exec: "/app/docker/entrypoint.sh": permission denied: unknown
一顿搜索🔍主要有两种加权限的方法(如下图1、2)
我用的第二种
容器启动(。・ω・。)ノ
=[,,_,,]:3这个月都没今天哭的次数多、又又又又tmd报错叻!!!》〉冷静ing
算了继续刨错吧。。。
jar: command not found
又报了jar: command not found,明明以前java命令都是可以正常执行(_ _).。o○java命令可以正常执行,但是jar命令不行,这俩明明安装了JDK都会有的呀。。。
我抬头瞅了一眼运维同学提供的基础镜像,我又哭了
请问,这是只装了jre的意思吗?
运维同学:这个基础镜像只提供了运行jar包的基本环境哦,而且按照一般流程是只传jar包到服务器上的(运维同学表示这个锅我不背)
针对这个情况,目前想到的解决方案有两个
解决方案一
引用一个拥有完整JDK的基础镜像
解决方案二
放弃执行jar的解包命令,直接将要读取的文件跟jar包一起COPY到服务器上(这样可以不替换基础镜像,但是需要在代码中判断当前环境,根据不同环境选择不同的路径获取方式)
俺选了方案二,主要不想麻烦运维同学(我真体贴(*≧ω≦)ノ
但是我并不知道这些文件在启动起来的容器中的位置,由于之前用COPY . /app/把target中所有文件都复制了过去,所以我只需要在容器中看下,就知道这些文件的路径了,那么首先我需要把容器启动起来,于是把脚本文件里的代码替换成了单纯启动jar包的
java -server -Xms2048m -Xmx2048m -D java.security.egd=file:/dev./urandom -jar /app/ras-data-1.0.0-SNAPSHOT.jar
果然,容器正常启动了,进入容器后ls查看下,发现果然一句COPY . /app/复制进来了好多东西
再进入docker文件夹看到了我想要执行的脚本文件,但其实已经不重要了,因为俺选了方案二、=_=
然后进入classes文件夹看到了我想要拿路径的JSON文件。。。开心
所以我只需要在Dockerfile里加了如下这一行代码将JSON文件复制到jar包的同目录下
COPY ./target/classes/myJson.json /app/myJson.json
由于按此方案只有一条启动命令需要执行,所以就不需要entrypoint.sh这个脚本文件了,直接在Dockerfile里加即可(其实用的就是原来的启动命令)
ENTRYPOINT ["java","-server","-Xms2048m","-Xmx2048m","-D java.security.egd=file:/dev./urandom","-jar","/app/ras-data-1.0.0-SNAPSHOT.jar"]
Dockerfile成品图如下
启动成功!>> 终于填了之前耿耿于怀的坑坑、今天的花要撒满全世界!(。・ω・。)ノ🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉