1. 程式人生 > >理解docker部署springboot-容器記憶體優化的反思(五)

理解docker部署springboot-容器記憶體優化的反思(五)

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