1. 程式人生 > >應用的容器化-docker打包spring boot映象

應用的容器化-docker打包spring boot映象

應用容器化

容器佔用資源少、部署快,每個應用可以被打包成一個容器映象,每個應用與容器間成一對一關係也使容器有更大優勢,使用容器可以在build或release 的階段,為應用建立容器映象,因為每個應用不需要與其餘的應用堆疊組合,也不依賴於生產環境基礎結構,這使得從研發到測試、生產能提供一致環境。類似地,容器比虛機輕量、更“透明”,這更便於監控和管理。

製作自己的映象

選擇適合你的方式來生成映象

  1. 通過 Dockerfile 來自動編譯生成映象,實現構建映象的需求。
    多用於使用者互動較少的時刻,比如軟體部署時無需輸入任何命令的應用。

  2. 通過容器內操作,並進行 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,然後就如圖中下方生成了映象。

  1. 使用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外掛安裝

  1. 在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映象,建立和啟動容器以及執行其它相關任務。

  2. 安裝外掛後,需要配置連線docker服務端
    從File->Settings->Build,Execution,Deployment->Docker開啟配置介面。
    點選+號新增一個docker配置,輸入Name和Engine API URL,URL是docker服務地址,需要docker開啟遠端連線功能

  3. 新增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

問題點:

  1. Alpine Linux使用了musl,可能和其他Linux發行版使用的glibc實現會有些不同。

  2. 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"]
  1. 使用別人已經制作好的映象 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
  1. 使用預設的映象。如果你不確認你使用哪個,version後面不加,應該就滿足你。它被設計為拋棄式throw away容器(掛載原始碼並啟動容器以啟動應用程式),又可以用作構建其他映像的基礎。
    你也可以加標籤tags jessie, sid, or stretch 。這些是Debian釋出的版本,用於宣告你用哪個基礎映象。

  2. -alpine這個映象是基於流行的 Alpine Linux專案。使用官方映象只有5MB大小。
    當希望映象儘可能小時,強烈推薦這個映象。
    為了減少映象大小,不推薦新增額外工具(如git、bash)包含進映象。使用這個映象作為基礎,在Docckerfile中新增所需的內容。

  3. 這個映像安裝了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方式是一樣的。

遇到問題整理

  1. -Dcom.sun.management.jmxremote.port=1332 java啟動引數,有這個啟動不起來。 提醒1332已被使用。
    暫時刪除該引數。
  2. 檔案傳成功到容器裡面了,但是java程式沒有啟動起來,登進容器可以手動啟起來? Error: Unable to access jarfile eurekaserver-0.0.1-SNAPSHOT.jar
    IDEA外掛斷開連線docker demon,重新連線,發現和之前不一樣,應該是成功了,spring boot啟動有個過程。注意檢視容器日誌即可。
    在這裡插入圖片描述