原文位址:http://blog.jboost.cn/2019/07/17/docerk-5.html
擷取鏡像的途徑有兩個,一是從鏡像倉庫擷取,如官方的Docker Hub,二是自定義。上文已經介紹如何從鏡像倉庫擷取鏡像,本文基于一個Springboot項目,來介紹自定義一個鏡像的基本流程。
1. 定制鏡像的本質
我們知道鏡像是分層存儲的,鏡像的建構也是一層一層進行的,一層建構完後,就變為隻讀,在其上再建構下一層。是以定制鏡像,實際上就是定義每一層要幹的事,比如執行某個指令,設定一個環境變量,聲明一個暴露端口等等。然後在建構時,按照各層的定義,一層一層地完成建構,最終形成一個包含這些層的鏡像。
2. Dockerfile檔案
Docker中定義各層要幹的事的檔案叫Dockerfile,它是一個文本檔案,包含了一條條的指令,每一條指令對應一層鏡像,指令的内容就描述了這一層該如何建構。如下示例了一個非常簡單的Dockerfile,
FROM nginx
RUN echo '<h1>Hello jboost!</h1>' > /usr/share/nginx/html/index.html
我們定制鏡像,必須要以某一個鏡像為基礎,在其上建構自己需要的層,如上示例中,我們是以nginx鏡像為基礎,然後在第二層定制了我們自己的内容——修改index.html的内容為
<h1>Hello jboost!</h1>
,這樣運作容器打開nginx首頁時就不會顯示預設的頁面内容了。
上面示例中接觸了Dockerfile的兩個指令
- FROM:FROM指令指定基礎鏡像,每一個定制鏡像必須要有一個基礎鏡像,是以必須要有一條FROM指令,并且是Dockerfile的第一條指令
- RUN:RUN指令指定需要執行的指令,後面接的指令就像是shell腳本一樣可執行
Dockerfile還提供了許多其它指令,後續我們再集中介紹,本文隻對接觸到的指令做簡單說明。
3. 自定義一個鏡像
這部分以一個Springboot項目為基礎,介紹自定義一個鏡像涉及的基本環節。項目位址為:https://github.com/ronwxy/swagger-register ,該項目是一個Swagger API文檔注冊服務,其它項目可将Swagger API資訊注冊到該服務,進行統一檢視與管理。
3.1 定義Dockerfile檔案
首先,我們在項目的根目錄下建立一個Dockerfile檔案(檔案名就叫Dockerfile),其内容為:
FROM openjdk:8-jdk-alpine
ENV PROFILE=dev
RUN mkdir /app /logs
COPY ./target/swagger-register-1.0.0-SNAPSHOT.jar /app/app.jar
WORKDIR /app
VOLUME /register-data
EXPOSE 11090
CMD ["java", "-Dspring.profiles.active=${PROFILE}", "-jar", "app.jar"]
從上往下依次介紹如下
- 第一行:FORM openjdk:8-jdk-alpine, 表示以
這個鏡像為基礎鏡像,因為這是一個Springboot項目是以必須要有jdk支援,我們在定制鏡像時,可以找一個最适合的鏡像作為基礎鏡像。openjdk:8-jdk-alpine
- 第二行:ENV PROFILE=dev, 定義了一個環境變量,這個環境變量可以在後面被引用
- 第三行:RUN mkdir /app /logs,通過mkdir指令建立了兩個目錄,用來儲存jar執行檔案及日志
- 第四行:COPY ./target/swagger-register-1.0.0-SNAPSHOT.jar /app/app.jar 将target目錄下的jar包複制到/app目錄下,并且進行重命名
- 第五行:WORKDIR /app, 指定工作目錄為/app,後面各層的目前目錄就是指定的工作目錄
- 第六行:VOLUME /register-data, 定義一個匿名資料卷,前面說過寫操作不要直接在容器内進行,而要改為寫挂載的資料卷目錄,這個定義可在運作容器時通過 -v 來覆寫。
- 第七行:EXPOSE 11090, 聲明了運作容器時提供的服務端口,也僅僅是個聲明而已,隻是告訴使用的人要映射這個端口,通過 -p 可映射端口。
- 第八行:CMD [“java”, “-Dspring.profiles.active=${PROFILE}”, “-jar”, “app.jar”], 指定了容器啟動指令,因為是一個Springboot項目,是以就是一個java -jar的執行指令,容器啟動的時候就會執行該指令來運作Springboot服務,這裡引用了第二行定義的環境變量PROFILE
3.2 配置maven插件
定義好Dockerfile後,為了友善建構鏡像,我們可以借助maven的dockerfile插件
dockerfile-maven-plugin
,在pom.xml的build部分加入配置如下
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- Docker maven plugin -->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.10</version>
<configuration>
<repository>${docker.image.prefix}/${project.artifactId}</repository>
<buildArgs>
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
<!-- Docker maven plugin -->
</plugins>
</build>
repository指定了鏡像的名稱,
docker.image.prefix
需要properties部分進行定義,我這裡是
springboot
。
3.3 建構鏡像
下載下傳源碼:https://github.com/ronwxy/swagger-register.git ,然後在項目的根目錄下執行如下指令(前提是本地已經裝好了docker與maven及jdk)
mvn clean package -Dmaven.test.skip=true dockerfile:build
該指令首先會執行
mvn clean package -Dmaven.test.skip=true
對項目進行打包,生成./target/swagger-register-1.0.0-SNAPSHOT.jar檔案,然後基于目前目錄下的Dockerfile檔案進行建構,如下圖所示
由上圖可看出,該鏡像建構分八步(對應Dockerfile的八行指令),每一步生成一個鏡像層,每一層都有唯一的ID。由圖中也可以看出,除了COPY之類的指令外,每一層的建構實際上是先基于上一層啟動一個容器,然後執行該層定義的操作,再移除這個容器來實作的,如第八步中
Step 8/8 : CMD ["java", "-Dspring.profiles.active=${PROFILE}", "-jar", "app.jar"]
[INFO]
[INFO] ---> Running in f4acd0b53bca
[INFO] Removing intermediate container f4acd0b53bca
[INFO] ---> a9ee579f2d62
先啟動一個ID為f4acd0b53bca的容器,在其中執行CMD所定義的指令,然後再移除容器f4acd0b53bca,最後生成ID為a9ee579f2d62的鏡像。
建構完後,我們就可以在本地鏡像中通過
docker iamges
看到我們定制的鏡像了,如圖
圖中springboot/swagger-register鏡像即為我們剛剛建構好的定制鏡像。
3.4 啟動容器
我們可以通過以下指令來啟動一個剛才定制鏡像的容器
docker run -d --name swagger-register -p 11090:11090 -v /home/jenkins/swagger-register/register-data:/register-data -v /home/jenkins/swagger-register/logs:/logs --restart=always springboot/swagger-register:latest
其中:
- -d 表示以背景程序方式運作
- –name 指定容器名稱
- -p 指定端口映射,左邊為主控端端口,右邊為容器服務端口
- -v 指定資料卷挂載,左邊為主控端目錄,右邊為容器目錄
- –restart=always 表示在docker啟動時自動啟動該容器
關于容器相關的内容後面詳細介紹,這裡不展開說明了。啟動容器後, 我們就可以浏覽器打開位址 http://主控端ip:11090/doc.html 來通路服務了(打開頁面後内容是空的,因為沒有任何服務注冊Swagger API, 相關内容可參考 swagger api文檔集中化注冊管理)
4. 總結
本文介紹了一個基于Springboot項目的Docker鏡像定制及使用過程,對鏡像的建構過程,及Dockerfile的基本指令以及容器的運作做了基本介紹。後續會對Dockerfile的其它指令及Dockerfile的一些最佳實踐進行更為詳細的介紹,歡迎關注。
我的個人部落格位址:http://blog.jboost.cn
我的微信公衆号:jboost-ksxy (一個不隻有技術幹貨的公衆号,歡迎關注,及時擷取更新内容)
—————————————————————————————————————————————————————