應用的容器化-docker打包spring boot映象
應用容器化
容器佔用資源少、部署快,每個應用可以被打包成一個容器映象,每個應用與容器間成一對一關係也使容器有更大優勢,使用容器可以在build或release 的階段,為應用建立容器映象,因為每個應用不需要與其餘的應用堆疊組合,也不依賴於生產環境基礎結構,這使得從研發到測試、生產能提供一致環境。類似地,容器比虛機輕量、更“透明”,這更便於監控和管理。
製作自己的映象
選擇適合你的方式來生成映象
-
通過 Dockerfile 來自動編譯生成映象,實現構建映象的需求。
多用於使用者互動較少的時刻,比如軟體部署時無需輸入任何命令的應用。 -
通過容器內操作,並進行 Commit 來實現打包生成映象。
用於使用者互動較多、安裝過程中配置較多的應用。
如何拆分現有的應用,來實現打包。Docker 容器化的應用應當是功能最小化的應用。這裡的拆分並不是指將每個軟體拆分成為一個容器,而是強調實現功能最小化。
一般來說,你可以將應用拆分成為 2-3 個容器, 2 個容器的情況下,是資料儲存和應用程式各自一個容器。對於部分應用,可能還有快取系統,同樣也要單獨放置在一個容器內。這樣的結構下,在你需要擴容時,就比較容易,根據你的需要,可以隨時擴容快取系統或應用程式。
Dockerfile 打包
Dockerfile 就是宣告應用環境和應用本身。Docker 需要更專注於它本身作為容器的技術。完成無狀態化應用和寫完 Dockerfile 之後,這個程式就可以被打報成 Docker image 了,放到一個 Docker Host 上執行起來就得到了無狀態的應用容器,也就完成了把應用裝容器的過程。
docker打包springboot專案成映象
FROM openjdk:8-alpine
VOLUME /tmp
ARG JAR_FILE=target/gs-spring-boot-docker-0.1.0.jar
ADD ${JAR_FILE} app.jar
ENV JAVA_OPTS=""
ENTRYPOINT exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar
應用程式的jar檔案(檔名為app.jar)被新增到容器中,執行 ENTRYPOINT
我們增加了一個VOLUME指向”/tmp”,因為那是Spring Boot應用程式為Tomcat建立的預設工作目錄。作用是在你的主機”/var/lib/docker”目錄下建立一個臨時的檔案,並且連結到容器中的”/tmp”目錄。對於簡單程式這一步是可選的,但是對於其他想要真實寫入檔案系統的Spring Boot應用程式又是必選的。
我們增加了一個指向”/dev/urandom”的Tomcat系統屬性來縮小Tomcat的啟動時間。
可以看到在左上叫有個執行的標記,很對,這個就是用來在IDEA構建jar包到映象,然後放到Docker中執行的按鈕。
如上圖 我們只需要建立對應的Dockerfile檔案,IDEA就會提醒上圖中的選擇供我們操作,我們選擇編輯xxx/Dockerfile,填寫image tag資訊,然後run,然後就如圖中下方生成了映象。
- 使用docker-maven-plugin外掛,在pom.xml中配置外掛,完成自動化的映象生成上線。
TODO 未測試
docker-maven-plugin 介紹
在我們持續整合過程中,專案工程一般使用 Maven 編譯打包,然後生成映象,通過映象上線,能夠大大提供上線效率,同時能夠快速動態擴容,快速回滾,著實很方便。docker-maven-plugin 外掛就是為了幫助我們在Maven工程中,通過簡單的配置,自動生成映象並推送到倉庫中。
然後在ternimal中執行 mvn clean package -DskipTests=true docker:build命令,打包專案並構建映象,命令執行完畢可以看到
IDEA使用Docker外掛
IDEA Docker外掛安裝
-
在IntelliJ IDEA中安裝Docker integration外掛
This plugin lets you download and build Docker images, create and start Docker containers, and carry out other related tasks.
這個外掛可以下載構建Docker映象,建立和啟動容器以及執行其它相關任務。 -
安裝外掛後,需要配置連線docker服務端
從File->Settings->Build,Execution,Deployment->Docker開啟配置介面。
點選+號新增一個docker配置,輸入Name和Engine API URL,URL是docker服務地址,需要docker開啟遠端連線功能。 -
新增Docker的選單視窗
IDEA頂部工具欄的View–>Tool Windows–>Docker
完成點選左下角的小視窗圖示放大即可看到Docker的選單工具欄
外掛的基本操作
主要包含了containers和images,裡面是一些已經存在的容器和映象,下面是一些基本操作:
- 拉取映象
如果要拉取映象,直接在images上右擊pull images然後填寫Repository即可。
例如,填寫如下 地址,即下載nginx
hub.c.163.com/library/nginx
- 建立映象容器執行
在需要跑的映象上右擊建立容器,這個時候也可看到映象的ID和Tag,如下圖
配置相應的埠繫結等資訊即可啟動即可,在建立的容器上右擊選擇inspect可以檢視相應容器的詳細資訊,也可以啟動或者停止容器。
至此,我們已經可以使用docker命令,直接把我們生成的spring boot手動利用docker命令打包到docker容器中,並直接執行。
關於2375埠
為了實現叢集管理,Docker提供了遠端管理介面。Docker Daemon作為守護程序,執行在後臺,可以執行傳送到管理介面上的Docker命令。
**啟動Docker Daemon時,加入-H 0.0.0.0:2375,Docker Daemon就可以接收遠端的Docker Client傳送的指令。**注意,Docker是把2375埠作為非加密埠暴露出來,一般是用在測試環境中。此時,沒有任何加密和認證過程,只要知道Docker主機的IP,任何人都可以管理這臺主機上的容器和映象。
通過遠端管理的方式,向Docker主機發送命令。
docker -H 192.168.0.10:2375 info
Linux下開啟2375埠
Windows開啟2375埠
在windows下設定docker直接使用gui介面來設定就可以了
右鍵啟動欄的docker小圖示,點選settings>general
設定啟用localhost的2375埠來執行docker
Expose daemon on tcp://localhost:2375 without TLS
基礎映象 Commit 生成映象
除了通過 Dockerfile 來打包生成映象外,也可以通過 Docker Commit 來生成映象。通過 Commit 打包的映象多是由於應用本身在部署時有大量的互動內容,無法通過命令來指定。
容器ID 35f1c2ae1f7e 則
將容器打包成映象執行命令 docker commit 35f1c2ae1f7e mynewimage就將容器35f1c2ae1f7e打包為新的映象mynewimage了
Docker映象大小問題
基本的構建方式,就是依賴各種資源的傳統方式構建,分層較多,一個容器至少在600M左右,但是各方的依賴工具都很全面,對於除錯,以及內部操作都 相對簡單方便。
Docker 容器應該只包含一個程序以及用於執行這個程序所需的最少的檔案,你不需要整個作業系統。
“distroless”映象只包含應用程式及其執行時依賴項,不包含程式包管理器、shell 以及在標準 Linux 發行版中可以找到的任何其他程式。
這個未包含額外程式的映象會多小呢?
$ docker images | grep node-distroless
node-distroless 7b4db3b7f1e5 76.7MB
僅僅76.76MB!
比前一個映象少了600MB!
需要注意的是,我們不應該在生產環境中附加到容器中進行除錯,而應依靠正確的日誌和監控。
如果我們既希望能除錯,又關心尺寸大小,又該怎麼辦?
使用Alpine作為更小的基礎映象
一個基於musl libc[3]和busybox[4]、面向安全的輕量級Linux發行版。
換言之,它是一個尺寸更小、更安全的Linux發行版。
Alpine基礎映象
Alpine基礎映象是基於muslc的,這是一個C的替代標準庫。
但是,多數Linux發行版,比如Ubuntu、Debian及CentOS都是基於glibc的。這兩個庫照理應該實現了相同的介面。
不過,它們的目標不同:
- glibc最常用,速度更快
- muslc佔用空間更少,以安全為核心
在編譯應用程式時,多數情況下是使用某個libc來編譯的。如果想在其他libc中使用,只能重新編譯。
Alpine Linux是一個面向安全的輕型的Linux發行版。
Alpine Linux採用了 musl libc 和 busybox以減小系統的體積和執行時資源消耗。
在保持瘦身的同時,Alpine Linux還提供了自己的包管理工具apk。
關鍵的是,相比於其他Linux的Docker映象,它的容量非常小,僅僅只有5MB。
問題點:
-
Alpine Linux使用了musl,可能和其他Linux發行版使用的glibc實現會有些不同。
-
musl實現的DNS服務不會使用resolv.conf檔案中的search和domain兩個配置,通過DNS來進行服務發現時需要注意。
原生基礎映象非常適合用於測試和開發。
它的尺寸比較大,不過用起來就像你主機上安裝的Ubuntu一樣。並且,你能訪問該作業系統裡有的所有二進位制程式。
Alpine製作JDK8映象
FROM alpine:edge
LABEL maintainer="mritd <[email protected]>"
ENV JAVA_HOME /usr/lib/jvm/java-1.8-openjdk
ENV PATH $PATH:/usr/lib/jvm/java-1.8-openjdk/jre/bin:/usr/lib/jvm/java-1.8-openjdk/bin
ENV JAVA_VERSION 8u144
ENV JAVA_ALPINE_VERSION 8.144.01-r0
RUN apk add --update bash curl tar wget ca-certificates unzip \
openjdk8=${JAVA_ALPINE_VERSION} font-adobe-100dpi ttf-dejavu fontconfig \
&& rm -rf /var/cache/apk/* \
CMD ["bash"]
- 使用別人已經制作好的映象 alpine jdk8
進入阿里雲映象中心https://dev.aliyun.com/search.html
找到JAVA相關,點選進去
This image is officially deprecated in favor of the openjdk image, and will receive no further updates after 2016-12-31 (Dec 31, 2016). Please adjust your usage accordingly.
此映像被正式棄用,而支援openjdk映像,並且在2016-12-31(2016年12月31日)之後將不會接收到進一步的更新。請相應地調整您的使用情況。
openjdk:<version>
openjdk:<version>-alpine
openjdk:<version>-slim
-
使用預設的映象。如果你不確認你使用哪個,version後面不加,應該就滿足你。它被設計為拋棄式throw away容器(掛載原始碼並啟動容器以啟動應用程式),又可以用作構建其他映像的基礎。
你也可以加標籤tags jessie, sid, or stretch 。這些是Debian釋出的版本,用於宣告你用哪個基礎映象。 -
-alpine這個映象是基於流行的 Alpine Linux專案。使用官方映象只有5MB大小。
當希望映象儘可能小時,強烈推薦這個映象。
為了減少映象大小,不推薦新增額外工具(如git、bash)包含進映象。使用這個映象作為基礎,在Docckerfile中新增所需的內容。 -
這個映像安裝了OpenJDK -headless的包,因此缺少了許多與UI相關的Java庫和預設標籤中包含的一些普通包。它只包含執行Java所需的最小包。百度關鍵字 “java headless”
version 就是你的jdk的版本,8就填8。
根據上面資訊,我們使用openjdk-8-jdk-alpine的話,docker 命令應該如下:
docker pull openjdk:8-alpine
這個應該是官方 最精簡的 jdk8 docker映象。
openjdk-8-jdk-alpine容器問題整理
基於已有映象,dockr命令直接打包jar檔案到容器中並執行
基於有時候沒有開啟遠端服務,也可把jar上傳至伺服器,然後編寫指令碼進行執行,這裡簡單示例下,正常部署時,正常是通過jenkins打包,然後編寫打包後事件,執行指令碼即可。
-v 你宿主機的目錄/檔案
windows環境下,你使用絕對路徑,系統會提醒,講你用到的碟符共享。(其實就是windows共享給Docker宿主Linux,Docker才能訪問,copy它需要的檔案給容器中。)
如果你執行Docker在linux主機下,應該不存在此問題。
-w 你容器主機目錄/檔案(也可以-v中用冒號直接隔開即可)
–name 指定新生成的容器名
docker run -d -p 1234:11111 -v D:\bat\eurekaserver-0.0.1-SNAPSHOT.jar:/usr/eurekaserver-0.0.1-SNAPSHOT.jar --name SpringbootByJar3 openjdk:8-alpine java -server -jar -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=127.0.0.1 /usr/eurekaserver-0.0.1-SNAPSHOT.jar --spring.config.location=eurekaserver.properties
如果需要copy整個目錄的檔案到容器中呢?
如下 -v 填目錄 冒號後面是目標目錄,測試通過。
docker run -d -p 1234:11111 -v D:\bat\:/usr/test --name SpringbootByJar3 openjdk:8-alpine java -server -jar -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=127.0.0.1 /usr/test/eurekaserver-0.0.1-SNAPSHOT.jar --spring.config.location=eurekaserver.properties
其實就是把jar拷貝從宿主中拷貝到容器中,然後執行java命令進行啟動。和原來的執行jar方式是一樣的。
遇到問題整理
- -Dcom.sun.management.jmxremote.port=1332 java啟動引數,有這個啟動不起來。 提醒1332已被使用。
暫時刪除該引數。 - 檔案傳成功到容器裡面了,但是java程式沒有啟動起來,登進容器可以手動啟起來? Error: Unable to access jarfile eurekaserver-0.0.1-SNAPSHOT.jar
IDEA外掛斷開連線docker demon,重新連線,發現和之前不一樣,應該是成功了,spring boot啟動有個過程。注意檢視容器日誌即可。