理解docker部署springboot-容器記憶體優化的反思(五)
阿新 • • 發佈:2018-12-26
寫這篇部落格的目的可能反思多一些,前些日子一直想做docker記憶體的優化,沒有做成,一直困在這地方。經過大致這樣,我把jar和jdk做成一個映象之後,一個映象佔用記憶體大概181.8M,我虛機是2G的記憶體,除了其他程式佔用的之外,我就只能啟動5個映象,然後記憶體就沒了,但是我們在大部分講docker優點(原文)的地方都可以看到這個表格
其中最後一項說專案部署由虛機的幾十個變成容器的近千個,但是根據我實踐的情況來講這完全不可能啊,so,我的思路是我這個做映象的方式存在問題,不應該把記憶體佔用超過167M的jdk(我用的是網易蜂巢)打包到每一個映象中,而應該拆出來,然後就開始了我的花費大量實踐的探索之路。雖然現在看來這種思路可能有問題,但是這個過程還是要記錄一下的,首先用top去分析記憶體:
第一種方式:共享虛機環境內自身的jdk,以busybox作為基礎映象,畢竟busybox1.2也才不到兩M,jar+busybox一共也就22M多,先看dockerfile:
第二種方式:
第二種方式,這是在Stackoverflow上看到了方案。首先看下邊的映象檔案,我去,竟然用了Linux作為環境,這當然可以執行Java環境了,但是比網易蜂巢的jdk還要大,還怎麼優化,試了試放棄了
左圖是老的方式,新圖是新的方式,豁然開朗,jdk就是libraries,如何共享,顯然在新的方式是不可以的,如果這麼做了一致的執行環境,持續的部署和更輕鬆的遷移恐怕都沒有辦法做到,這可能就是固化思維吧,有時候解決不了的問題可以清空一下腦袋,換個方式去想問題沒準就會有不同的天地吧。但是既然這種方式不可以,那麼怎麼去解決記憶體佔用問題,我覺得還是應該有方案的,還是當行太淺啊,有知道的大神一定在評論裡提供一下
特性 | 容器 | 虛擬機器 |
---|---|---|
啟動 | 秒級 | 分鐘級 |
硬碟使用 | 一般為 MB |
一般為 GB |
效能 | 接近原生 | 弱於 |
系統支援量 | 單機支援上千個容器 | 一般幾十個 |
再看看佔用大戶都有誰,發現大部分都被jdk吃了[
[email protected] 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
下邊是執行容器的情況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
[[email protected] ~]# 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%的記憶體[[email protected] /]# 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,如何共享,顯然在新的方式是不可以的,如果這麼做了一致的執行環境,持續的部署和更輕鬆的遷移恐怕都沒有辦法做到,這可能就是固化思維吧,有時候解決不了的問題可以清空一下腦袋,換個方式去想問題沒準就會有不同的天地吧。但是既然這種方式不可以,那麼怎麼去解決記憶體佔用問題,我覺得還是應該有方案的,還是當行太淺啊,有知道的大神一定在評論裡提供一下