前面几节我们学习了 mongodb 的一些基本操作,上一节我们又用 springboot 整合 mongodb 完成了一个小 demo,这节我们将从基础开始把这个 springboot 项目部署到 docker 环境。
我们都知道java项目需要依赖 jre 环境,如果你的镜像直接添加一个jdk进去,这也是完全可以的,但是有一个问题就是,这样可能会使得你的镜像非常大,但是这其实是完全没必要的。
了解过的人都知道,docker 镜像是分层构建的,怎么描述呢?通常一个 docker 镜像可以分为 系统层、环境层、应用层。比如这里的系统层指的就是我们依赖的操作系统,我这里是centos7,环境层指的是运行java依赖的jre环境,应用层就值得是我们自己的应用(jar包)文件。
为了使我们的镜像可以比较小,各层都采用基础镜像完成构建。当然精简的镜像好处就是体积小,但也有缺点,比如我们常用的一些 linux 工具没有安装,使得我们在进入到容器内部排查问题就有些不方便了。
这里我们系统层采用 alpine 作为基础镜像,alpine 是一个轻量级的linux系统,镜像大小5M左右。我们直接使用 alpine 作为基础层镜像,这里不用特殊处理。
环境层这里采用 jdk8 来构建,我们对其做适当精简。
首先下载 jdk8
下载完成以后解压文件并删除不分不需要的文件
mkdir -p /usr/local/shell/docker
tar -zxvf jdk-8u333-linux-x64.tar.gz
cd jdk1.8.0_333/
mv jre/ ..
cd jre/
rm -rf ./lib/plugin.jar \
./lib/ext/jfxrt.jar \
./bin/javaws \
./lib/javaws.jar \
./lib/desktop \
./plugin \
./lib/deploy* \
./lib/*javafx* \
./lib/*jfx* \
./lib/amd64/libdecora_sse.so \
./lib/amd64/libprism_*.so \
./lib/amd64/libfxplugins.so \
./lib/amd64/libglass.so \
./lib/amd64/libgstreamer-lite.so \
./lib/amd64/libjavafx*.so \
./lib/amd64/libjfx*.so
cd /usr/local/shell/docker
cat >> Dockerfile <<EOF
# 以alpine为基础镜像
FROM docker.io/jeanblanchard/alpine-glibc
# 把jre添加进去
ADD jre /usr/local/
# 设置环境变量
ENV JAVA_HOME /usr/local/jre
ENV PATH ${PATH}:${JAVA_HOME}/bin
CMD ["java", "-version"]
EOF
# 构建镜像
docker build -t jre-env/jre:v1 .
基础镜像构建完成,通过 docker iamges 查看,我们新构建的镜像大小为 137M。
docker 镜像的构建都是基于 Dockerfile 描述文件,
项目添加 Dockerfile。
# 使用我们上面构建的环境镜像作为基础镜像
FROM jre-env/jre:v1
# 维护者信息
MAINTAINER hxj
# 设置字符编码
ENV LANG C.UTF-8
# 设置alpine时区
ENV TIMEZONE Asia/Shanghai
# 添加应用 这里相当于把应用添加进来并重命名
ADD spring-mongo-1.0.jar spring-mongo.jar
# 启动应用
ENTRYPOINT ["java -jar spring-mongo.jar"]
由于我本地没有安装docker,把 Dockerfile 文件和 spring-mongo-1.0.jar,文件拷贝到 images 下 构建应用镜像。
docker build -t spring-mongo .
查看镜像,发现我们构建的镜像已经在我们本地镜像仓库了。
docker images
镜像构建完成,那我们试试把应用跑起来:
docker run -itd -p 80:8080 spring-mongo
# 查看运行中的镜像
docker ps
不幸的是,这里面并没有我们刚刚启动的 spring-mongo,我开始发现,事情并没有我想象的name简单。
# 查看容器日志
docker logs bf3b671ed5f97d95efc16bd57caf0db10b9d673f2bc6ac7b08ed77f497f2df6f(容器id)
这是什么鬼,完全不认识好吗!百度了下,musl libc 和 glibc 之间的差异
,不明觉厉的样子,解决起来好像还挺麻烦,既然这样,干脆换个基础镜像好了。于是在 dockerhup 找到了这个镜像 frolvlad/alpine-glibc
,那我就重新构建,只需要修改 Dockerfile 中的基础镜像:
cd /usr/local/shell/docker
cat >> Dockerfile <<EOF
# 以frolvlad/alpine-glibc为基础镜像
FROM frolvlad/alpine-glibc
# 把jre添加进去
ADD jre /usr/local/
# 设置环境变量
ENV JAVA_HOME /usr/local/jre
ENV PATH ${PATH}:${JAVA_HOME}/bin
CMD ["java", "-version"]
EOF
# 构建镜像
docker build -t jre-env/jre:v1 .
然后重新构建应用镜像,构建完成以后在此运行,刚才的问题还是存在!!! 好吧,我承认我可耻的屈服了。直接使用 java8 做基础镜像,这回不会有问题了吧。修改应用层 Dockerfile
# 使用java:8-jre作为基础镜像
FROM java:8-jre
# 维护者信息
MAINTAINER hxj
# 设置字符编码
ENV LANG C.UTF-8
# 设置alpine时区
ENV TIMEZONE Asia/Shanghai
# 添加应用 这里相当于把应用添加进来并重命名
ADD spring-mongo-1.0.jar spring-mongo.jar
# 启动应用
ENTRYPOINT ["java" ,"-jar", "spring-mongo.jar"]
构建应用镜像
docker build -t spring-mongo .
运行
docker run -itd -p 80:8080 spring-mongo
查看运行中容器:
docker ps
oh mygod!终于跑起来了,迫不及待拿出 postman 请求了下接口,发现不通,telnet 主机 80
,果然不通,怀疑是防火墙的问题
查看防火墙
systemctl status firewalld.service
# 发现有个绿色的 active 字样,果然防火墙是开着的
# 这里为了简单,直接关闭防火墙
systemctl stop firewalld.service
# 再次查看防火墙状态 disavtive ,说明防火墙已关闭
systemctl status firewalld.service
# 最后禁止防火墙启动,一劳永逸
systemctl disable firewalld.service
再次 telnei 主机 80
,瞬间就连上了,拿出 postman,果然拿到了我们想要的数据
至此,我们的 springboot 应用就成功部署到 docker 上了。虽然过程不是那么的顺利,虽然我们的镜像有一点肥胖,但是我们最终还是达成了我们的目的。
至于这个肥胖的镜像,以后有时间再尝试给他减肥吧。今天的内容就到这里了,我们下节见。