Docker | 第五章:構建自定義鏡像


前言

上一章節,主要是介紹了下Dockerfile的一些常用命令的說明。我們知道,利用Dockerfile可以構建一個新的鏡像,比如運行Java環境,就需要一個JDK環境的鏡像,但直接使用公共的鏡像時,一般上大小都比較大。所以本章節就主要結合Dockerfile文件及commit方式,構建屬於自己的鏡像,同時對鏡像進行壓縮和優化,同時也是對Dockerfile知識的一個實踐。

利用Dockerfile構建自定義鏡像

作為一個java后端開發,這里就直接以構建一個Oracle官方jre環境來示例。

選定基礎鏡像

由於在Linux中,JVM主要是調用系統的C語言庫,Oracle的官方JRE,使用的是libc,也就是glibc,這意味着你要運行任何Java程序,都需要先裝好glibc。所以我們直接去https://hub.docker.com找一個基於glibc的基礎鏡像(當然了,大家也可直接選定比如CensOS這些Linux的發行版本了)。

glibc

我們之類直接選擇默認排在第一個的alpine-glibc作為我們的基礎鏡像,比較這個大小也才12M左右呀!

題外話:大家作為實驗性質時,為了獲取更小的基礎鏡像,可以選擇alpine這個基礎鏡像,比較這個只有5M大小,夠精簡了!

alpine

准備JRE版本

這里我們直接去Oracle官網選擇jre版本,這里選擇的是jre-8u181-linux-x64版本(由於對linux命令不是很熟悉,為了不必要的時間浪費,這里直接下載了鏡像了,熟悉的各位可以直接使用wget進行下載的)。

jre版本

編寫Dockerfile

 # 基礎鏡像
 FROM frolvlad/alpine-glibc
 LABEL MAINTAINER oKong <499452441@qq.com>
 
 # 將JRE添加至鏡像中,add 命令在源文件為壓縮文件時,會自動解壓的
 ADD jre-8u181-linux-x64.tar.gz /opt/docker/java/jre8

# 設置JAVA環境變量
# 這里需要注意下,解壓后有個目錄的,為jre1.8.0_181,一開始沒注意,啟動時報了:exec: "java": executable file not found in $PATH: unknown 后才發現。
ENV JAVA_HOME /opt/docker/java/jre8/jre1.8.0_181
ENV CLASSPATH=$JAVA_HOME/bin
ENV PATH=.:$JAVA_HOME/bin:$PATH

# 這里無實際意義,只是在容器啟動時,輸出jre版本信息,驗證是否安裝成功
CMD ["java","-version"]

利用build命令,構建鏡像,同時指定tag

  docker build -t lqdev.cn/jre8:0.1 .

注意:后面有個.的。

Sending build context to Docker daemon  81.19MB
Step 1/7 : FROM frolvlad/alpine-glibc
 ---> d3bc626306a1
Step 2/7 : LABEL MAINTAINER oKong <499452441@qq.com>
 ---> Running in e788d29cd1e1
Removing intermediate container e788d29cd1e1
 ---> 5d95db4ae169
Step 3/7 : ADD jre-8u181-linux-x64.tar.gz /opt/docker/java/jre8
 ---> 0f4bb83df722
Step 4/7 : ENV JAVA_HOME /opt/docker/java/jre8/jre1.8.0_181
 ---> Running in 57a1e1ef00ed
Removing intermediate container 57a1e1ef00ed
 ---> 6f2b543a91b7
Step 5/7 : ENV PATH ${PATH}:${JAVA_HOME}/bin
 ---> Running in 2d75c88f97fb
Removing intermediate container 2d75c88f97fb
 ---> 92a7a0f9926c
Step 6/7 : WORKDIR /opt/docker/java/jre8/jre1.8.0_181
 ---> Running in 7b9a69efc980
Removing intermediate container 7b9a69efc980
 ---> 158c08c995c3
Step 7/7 : CMD ["java","-version"]
 ---> Running in 9ab517f8292a
Removing intermediate container 9ab517f8292a
 ---> 9c8606ac315a
Successfully built 9c8606ac315a
Successfully tagged lqdev.cn/jre8:0.1

然后查看下鏡像列表,

  docker images

images

說明已經構建成功了,我們來運行下:

 docker run -it -d --name myfirstjre  lqdev.cn/jre8:0.1

查看下容器列表:

 docker ps -a

容器列表

由於Dockerfile中使用CMD命令覆蓋了原本的/bin/sh,容器已啟動就停止了。所以我們看下日志,就知道是否jre安裝成功。

docker logs -f c6873a97ff49

logs

輸出了版本信息了,說明已經安裝成功了。

實踐:運行SpringBoot的jar包

現在我們就可以基於這個jre鏡像進行實際的jar包部署了。

Dockerfile文件方式:

# 基於我們自定義構建的鏡像
FROM lqdev.cn/jre8:0.1

VOLUME /opt/tmp
# 這是jar 可自行選擇,這里直接使用了原先講解springboot十四章節:基於Docker部署時的jar包
ADD chapter-14-0.0.1-SNAPSHOT.jar app.jar

# -Djava.security.egd=file:/dev/./urandom 可解決tomcat可能啟動慢的問題
# 具體可查看:https://www.cnblogs.com/mightyvincent/p/7685310.html
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

# 對外端口
EXPOSE 8080

然后構建新鏡像,並運行,同時查看日志輸出

  docker run -it -d --name springboot  lqdev.cn/springboot:0.1

日志控制台:

控制台

運行的容器列表:

容器列表

說明我們已經成功了,jar也啟動了。現在訪問下部署的jar服務:

利用commit命令構建自定義鏡像

第三章講解Docker常用命令時,有說到,利用commit可從容器中構建一個新的鏡像。所以這里簡單講解下利用此命令進行自動鏡像的構建過程。

構建思路:我們啟動一個基礎鏡像,同時運行,然后我們進入容器,下載所需要的jre版本,並配置其環境變量。之后退出容器進行保存操作。這里就不直接下載了,我們直接拷貝jre到容器里

啟動基礎鏡像:

   docker run -it -d --name commitImages  frolvlad/alpine-glibc

拷貝jre到容器中。

docker cp /opt/docker/java/jre-8u181-linux-x64.tar.gz b0d354b9453a:/opt/docker/java/jre8

這里會提示,說目錄不存在,可利用exec命令,進入容器創建目錄下,這里就不演示了。

No such container:path: b0d354b9453a:/opt/docker/java

現在我們進入容器:

 docker exec -it b0d354b9453a /bin/sh

進入,/opt/docker/java/jre8目錄,進行常規linux下的jre安裝:

  cd /opt/docker/java/jre8
  # 解壓
  tar -xzvf jre-8u181-linux-x64.tar.gz
  # 配置環境變量,vi /etc/profile 末尾加入
  export JAVA_HOME=/opt/docker/java/jre8/jre1.8.0_181
  export CLASSPATH=$JAVA_HOME/bin
  export PATH=.:$JAVA_HOME/bin:$PATH
  # 生效配置
  source /etc/profile
  # 驗證是否成功
  java -version
  輸出:
  java version "1.8.0_181"
  Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
  Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
  # 這里有個坑,生效配置后退出容器后又失效了,搜索了后,把環境變量放在### ~/.bashrc 或者在~/.bashrc里面加一句source /etc/profile 但是還是未生效。。。。我放棄了。。 直接寫個sh腳本啟動 時加入吧。。
  
  

然后我們退出容器,利用commit命令進行構建新鏡像:

docker commit b0d354b9453a lqdev.cn/jre8:0.2

然后查看:

運行jar,驗證下是否正常,這里直接在啟動的時候拷貝jar到鏡像。

docker run -it -d -p 1234:8080 -v /opt/docker/java:/opt/docker/java/app.jar --name springboot2 lqdev.cn/jre8:0.2

然后進入容器運行下java 命令

# 進入容器
docker exec -it 583d0f387555 /bin/sh
# 生效配置
source etc/profile
# 運行jar
nohup java  -Djava.security.egd=file:/dev/./urandom -jar /opt/docker/java/app.jar >log.txt &

退出后,訪問宿主的1234端口服務,就能看見部署成功了:

新服務

其實比較好的做法是:創建一個sh腳本,腳本里設置了環境生效命令及java命令即可,大家可自行嘗試下,這里就不演示了。

鏡像文件壓縮技巧

上一章節,我們利用Dockerfilecommit的方式生成鏡像。現在我們看下,鏡像文件大小:

兩種方式,commit還多了80M多。這里我們本着精簡的原則,對鏡像大小進行優化下。

首先,鏡像文件是按鏡像層(Layers)進行疊加的。總的來說就是:每一條指令都會創建一個鏡像層,繼而會增加整體鏡像的大小。

選擇一個精簡的基礎鏡像

一個基礎鏡像的大小直接決定了新鏡像的大小,所以可以選擇盡量小的精簡的鏡像。本文就使用了alpine-glibc作為基礎鏡像,大小12.8M。

串聯RUN命令

多個RUN時,可通過 && 和 / 支持將命令串聯在一起

# 舉例
RUN yum -y install java-1.7.0-openjdk-devel && yum clean all

很多鏡像大部分都是通過此方式進行RUN方式編寫的。官網:https://hub.docker.com/里面的大部分鏡像都是如下寫法

刪除多余文件及命令安裝包等

比如jre包中就有很多的文檔及說明文件是非必要的,這些就可以刪除了。以下只是個參考,大家可以自行刪減,可以在Dockerfile編寫時,解壓后,使用RUN命令進行操作也可以直接把壓縮包里刪除后在拷貝:

rm -rf COPYRIGHT LICENSE README release THIRDPARTYLICENSEREADME-JAVAFX.txtTHIRDPARTYLICENSEREADME.txt Welcome.html
#刪除其他無用文件
rm -rf     lib/plugin.jar \
           lib/ext/jfxrt.jar \
           bin/javaws \
           lib/javaws.jar \
           lib/desktop \
           plugin \
           lib/deploy* \
           lib/*javafx* \
           lib/*jfx* \
           lib/amd64/libdecora_sse.so \
           lib/amd64/libprism_*.so \
           lib/amd64/libfxplugins.so \
           lib/amd64/libglass.so \
           lib/amd64/libgstreamer-lite.so \
           lib/amd64/libjavafx*.so \
           lib/amd64/libjfx*.so

對比下,確實少了很多了。

當然對於大小不關心的,也就無需理會了,畢竟現在存儲空間都很大的,也就可能傳輸的時候慢點,哈哈~

參考資料

鏡像優化的大家可看看以下幾篇文章或者自行搜索下相關資料:

  1. https://blog.csdn.net/qq_36763896/article/details/53293088
  2. https://my.oschina.net/shyloveliyi/blog/1627020
  3. https://blog.csdn.net/chenyufeng1991/article/details/78766123

總結

本章節主要是介紹如何利用Dockerfile或者commit方式構建自定義鏡像。通過這兩種方式,我們就能根據自己的實際業務需要進行個性化改造、優化,最終構建一個通用鏡像。在構建自己的鏡像時,盡量還是選擇自己熟悉的、穩定的基礎環境鏡像進行構建,畢竟出了問題找起來也熟門熟路點。通常,運維部門或者實施部門,制定的鏡像屬於資產,一般不會上送至Docker遠程倉庫的,有了鏡像,我們就需要有個地方去存儲。下一章節,就重點講解下如何構建私有倉庫,管理自己的鏡像文件!

最后

若文中有錯誤或者遺漏之處,還望指出,共同進步!

老生常談

  • 個人QQ:499452441
  • 微信公眾號:lqdevOps

公眾號

個人博客:http://blog.lqdev.cn


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM