写这篇博客的目的可能反思多一些,前些日子一直想做docker内存的优化,没有做成,一直困在这地方。经过大致这样,我把jar和jdk做成一个镜像之后,一个镜像占用内存大概181.8M,我虚机是2G的内存,除了其他程序占用的之外,我就只能启动5个镜像,然后内存就没了,但是我们在大部分讲docker优点(原文)的地方都可以看到这个表格
特性 |
容器 |
虚拟机 |
启动 |
秒级 |
分钟级 |
硬盘使用 |
一般为 MB |
一般为 GB |
性能 |
接近原生 |
弱于 |
系统支持量 |
单机支持上千个容器 |
一般几十个 |
其中最后一项说项目部署由虚机的几十个变成容器的近千个,但是根据我实践的情况来讲这完全不可能啊,so,我的思路是我这个做镜像的方式存在问题,不应该把内存占用超过167M的jdk(我用的是网易蜂巢)打包到每一个镜像中,而应该拆出来,然后就开始了我的花费大量实践的探索之路。虽然现在看来这种思路可能有问题,但是这个过程还是要记录一下的,首先用top去分析内存:
[root@iZwz9cps5bpzjurg8m4ax0Z springboot-docker-test]# top -c
top - 16:08:02 up 27 days, 6 min, 1 user, load average: 0.00, 0.01, 0.05
Tasks: 142 total, 3 running, 130 sleeping, 2 stopped, 7 zombie
Cpu(s): 0.7%us, 0.0%sy, 0.0%ni, 99.0%id, 0.3%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 2054828k total, 1988716k used, 66112k free, 11800k buffers
Swap: 0k total, 0k used, 0k free, 338960k cached
再看看占用大户都有谁,发现大部分都被jdk吃了
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
5418 root 20 0 100m 4468 3448 S 0.3 0.2 0:00.79 sshd
8619 root 20 0 2501m 173m 5516 S 0.3 8.7 23:59.20 java
16133 root 20 0 136m 7664 2820 S 0.3 0.4 14:33.93 AliYunDun
27526 root 20 0 920m 35m 7860 S 0.3 1.8 0:56.58 docker
30089 root 20 0 2397m 152m 7048 S 0.3 7.6 1:30.27 java
30318 root 20 0 2396m 145m 6804 S 0.3 7.3 1:29.71 java
下边是运行容器的情况
[root@iZwz9cps5bpzjurg8m4ax0Z ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c9a5e263b5e7 txxs/springbootdocker:1.1 "java -jar /app.jar" 7 days ago Up 7 days 0.0.0.0:8087->8080/tcp cranky_kalam
1b962162184d centos "/bin/bash" 7 days ago Up 7 days logs
b4697ffe4dc2 txxs/springbootdocker:1.1 "java -jar /app.jar" 7 days ago Up 7 days 0.0.0.0:8085->8080/tcp nostalgic_mcnulty
91f942bad2a3 txxs/springbootdocker:1.1 "java -jar /app.jar" 7 days ago Up 7 days 0.0.0.0:8084->8080/tcp loving_sinoussi
c55e17c2a024 txxs/springbootdocker:1.0 "java -jar /app.jar" 7 days ago Up 7 days 0.0.0.0:8083->8080/tcp evil_bhabha
91f92f6b3545 txxs/springbootdocker:1.0 "java -jar /app.jar" 7 days ago Up 7 days 0.0.0.0:8082->8080/tcp insane_mahavira
14a8a7b0df84 txxs/springbootdocker:1.0 "java -jar /app.jar" 7 days ago Up 7 days 0.0.0.0:8081->8080/tcp sleepy_liskov
812b841b5422 daocloud.io/mysql "docker-entrypoint.sh" 4 weeks ago Up 7 days 0.0.0.0:3308->3306/tcp mysql-slave
33225198ecc3 daocloud.io/mysql "docker-entrypoint.sh" 4 weeks ago Up 7 days 0.0.0.0:3307->3306/tcp mysql-master
将所有的springboot的Java项目删除完之后的内存占用情况为45.1%,说明6个springboot的应用占了51.7%的内存
[root@iZwz9cps5bpzjurg8m4ax0Z /]# top -c
top - 16:14:08 up 33 days, 12 min, 1 user, load average: 0.00, 0.01, 0.05
Tasks: 105 total, 3 running, 95 sleeping, 0 stopped, 7 zombie
Cpu(s): 0.3%us, 0.0%sy, 0.0%ni, 99.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 2054828k total, 926004k used, 1128824k free, 54224k buffers
Swap: 0k total, 0k used, 0k free, 129484k cached
顺着这个思路下去自然就会想到把jdk拿出来做共享的jdk,而不是每个里边都有一个,这样应该会节省大量内存,毕竟一个项目的jar才不到20M。
第一种方式:共享虚机环境内自身的jdk,以busybox作为基础镜像,毕竟busybox1.2也才不到两M,jar+busybox一共也就22M多,先看dockerfile:
FROM busybox:latest
RUN mkdir /share
RUN mkdir /share/jdk
ENV JAVA_HOME /share/jdk
ENV PATH $JAVA_HOME/bin:$PATH
ENV CLASSPATH .:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ADD syway-0.0.1-SNAPSHOT.jar app.jar
CMD ["java","-jar","/app.jar"]
构建启动执行以下命令:
docker build -t txxs/springbootdocker:1.2 .
docker run -d -v /jcommon/compile/jdk8/jdk1.8.0_131/:/share/jdk -p 8081:8080 txxs/springbootdocker:1.2
镜像构建完成之后可以通过docker inspect imageID 查看images内的环境变量
"Env": [
"PATH=/share/jdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"JAVA_HOME=/share/jdk",
"CLASSPATH=.:/share/jdk/lib/dt.jar:/share/jdk/lib/tools.jar"
],
启动容器失败,为啥呢,没法执行Java命令,想想也是做的镜像只有一个jar和busybox,不知道Java命令是啥,那就
第二种方式:
第二种方式,这是在 Stackoverflow
上看到了方案。首先看下边的镜像文件,我去,竟然用了Linux作为环境,这当然可以运行Java环境了,但是比网易蜂巢的jdk还要大,还怎么优化,试了试放弃了
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \
&& gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
&& grep " node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum -c - \
&& tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 \
&& rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs
还试了一些其他方案,但是都没有成功,在Google、bing、百度各种找也没找着现成的方式,我觉得应该还是还是可以解决的,我也没有深入研究这块,如果有哪位大神知道可以提供一下方案。但是这个思路是对的吗,直到我到下边这两个图
左图是老的方式,新图是新的方式,豁然开朗,jdk就是libraries,如何共享,显然在新的方式是不可以的,如果这么做了一致的运行环境,持续的部署和更轻松的迁移恐怕都没有办法做到,这可能就是固化思维吧,有时候解决不了的问题可以清空一下脑袋,换个方式去想问题没准就会有不同的天地吧。但是既然这种方式不可以,那么怎么去解决内存占用问题,我觉得还是应该有方案的,还是当行太浅啊,有知道的大神一定在评论里提供一下