<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          為了實現(xiàn)CI/CD,先來定制一個Docker鏡像【實戰(zhàn)精華篇】

          共 9437字,需瀏覽 19分鐘

           ·

          2022-07-31 17:15

          背景

          計劃把手頭的項目逐步改造為基于Docker容器的方式發(fā)布,同時,項目中已經采用了云廠商提供的CI/CD自動化發(fā)布流水線。因此,為配合CI/CD操作,需要先針對項目構建一些發(fā)布的腳本,通過腳本來操作Docker鏡像定制、Docker的啟動和停止。

          在閱讀和實踐本篇文章之前,如果你還未搭建Docker的環(huán)境,可參考上篇文章《Linux安裝Docker完整教程》,先把整個環(huán)境搭建起來,同時熟悉一下Docker的基本操作命令。

          這篇文章就配合具體的實踐案例來為大家講講如何定制一個Docker鏡像,并通過腳本來執(zhí)行鏡像的構建、項目的發(fā)布、容器的啟動與停止等。

          什么是Dockerfile?

          Dockerfile是一個用來構建鏡像的文本文件,文本內容包含了一條條構建鏡像所需的指令和說明。常見的指令比如有:FROM、RUN、ADD、COPY、CMD、ENV等。

          在鏡像構建時,需要注意的一點是:鏡像的構建是一層層構建的,前一層是后一層的基礎。每一層構建完就不會再發(fā)生改變,后一層上的任何改變只發(fā)生在自己這一層。

          像上面提到的指令,每一次操作都會構建一層。比如刪除前一層的文件,在最終容器運行時,雖然看不到這個文件,但是實際上該文件會一直跟隨鏡像。因此,在構建鏡像時,需要額外小心,每一層盡量只包含該層需要添加的東西,任何額外的東西應該在該層構建結束前清理掉。

          另外,為了減少構建層的數(shù)量,在編寫Dockerfile文件時盡量將多層的指令合并成一層執(zhí)行,比如兩個RUN命令可以通過&&將其合并成一條。

          不建議的鏡像制作方式

          制作Docker鏡像通常有兩種方式:基于docker commit和基于Dockerfile的形式。

          Docker提供了一個 docker commit 命令,可以將容器的存儲層保存下來成為鏡像。換句話說,就是在原有鏡像的基礎上,再疊加上容器的存儲層,并構成新的鏡像。后續(xù)運行這個新鏡像時,就會擁有原有容器最后的文件變化。

          docker commit的方式除了學習之外,還可以用于一些特殊的場景,比如被入侵后保存現(xiàn)場等。但是不要使用 docker commit 定制鏡像,定制鏡像應該使用 Dockerfile 來完成。

          這是因為在使用docker commit制作鏡像時,除了我們想要修改的內容(文件)之外,該命令還會修改一些其他的文件,而且所有對鏡像的操作都是黑箱操作,生成的鏡像也被稱為黑箱鏡像

          除了制作鏡像的人知道執(zhí)行過什么命令、怎么生成的鏡像,別人根本無從得知。即使制作鏡像的人,一段時間后可能也無法記清具體的操作。這種黑箱鏡像的維護工作是非常痛苦的。

          另外,如果使用 docker commit 制作鏡像,以及后期修改的話,每一次修改都會讓鏡像更加臃腫一次,所刪除的上一層的東西并不會丟失,會一直如影隨形的跟著這個鏡像,即使根本無法訪問到。這會讓鏡像更加臃腫。

          因此,這里我們不采用 docker commit 的方式制作鏡像,如果大家感興趣的話,可以在網絡上查詢一下該方式的制作流程。本文重點介紹基于 Dockerfile 的方式來制作鏡像,下面就以實例展示一下如何構建一個Docker鏡像。

          Dockerfile指令編寫

          在/opt目錄下創(chuàng)建一個業(yè)務目錄/opt/channel/docker(這里部署的項目為渠道項目,取名channel),在該目錄下存放Dockerfile、待發(fā)布的jar包等資源文件。

          cd /opt/channel/docker
          $ touch Dockerfile

          上述指令先進入/opt/channel/docker目錄、創(chuàng)建了一個空的Dockerfile(文本)文件。

          編輯Dockerfile內容如下:

          FROM java:8
          COPY ./hqy-service-channel.jar ./app.jar
          ENV spring.profiles.active prod
          EXPOSE 8190
          ENTRYPOINT ["java""-jar","-Duser.timezone=GMT+08""./app.jar"]

          Dockerfile中涉及到FROM、COPY、ENV、EXPOSE、ENTRYPOINT五個指令,下面逐一講解。

          FROM指令

          所謂制作鏡像,就是在已經存在的鏡像的基礎上進行定制。基礎鏡像是必須指定的,而 FROM 就是指定基礎鏡像,因此一個 DockerfileFROM 是必備的指令,并且必須是第一條指令。

          這里的FROM java:8,也就是采用openjdk在Docker鏡像源中的鏡像,版本為8。可以通過search命令查看一下這個鏡像:

          [docker]# docker search java
          NAME                                 DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
          node                                 Node.js is a JavaScript-based platform for s…   11734     [OK]
          tomcat                               Apache Tomcat is an open source implementati…   3368      [OK]
          openjdk                              "Vanilla" builds of OpenJDK (an open-source …   3362      [OK]
          java                                 DEPRECATED; use "openjdk" (or other JDK impl…   1976      [OK]

          第4個name為java的便是,為了方便后面操作,這里直接將鏡像pull到本地。

          docker pull java:8

          查看本地pull之后,本地的鏡像列表:

          [root@iZ2zehx0enix3i0aiea7p0Z docker]# docker images
          REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
          java         8         d23bdf5b1b1b   5 years ago     643MB

          后續(xù)執(zhí)行鏡像制作時便以該鏡像為基礎進行構建。

          COPY指令

          COPY,復制指令,從上下文目錄中復制文件或者目錄到容器里指定路徑。

          COPY ./hqy-service-channel.jar ./app.jar

          其中第一個參數(shù)為源文件路徑,第二個參數(shù)為容器內目標文件路徑。這里是將當前目錄下的Spring Boot項目jar包hqy-service-channel.jar,復制到容器內并命名為app.jar。在執(zhí)行創(chuàng)建鏡像命令之前,需要把項目jar包放到Dockerfile同級目錄下。

          ENV指令

          ENV指令,用于設置環(huán)境變量,定義了環(huán)境變量,那么在后續(xù)的指令中,就可以使用這個環(huán)境變量。

          基本格式為:

          ENV <key> <value>
          ENV <key1>=<value1> <key2>=<value2>...

          第一個參數(shù)為變量key,第二個參數(shù)為變量值,這里用于設置SpringBoot項目的配置文件的profile為prod(生產配置文件)。

          EXPOSE指令

          EXPOSE指令,僅僅只是聲明端口。作用是幫助鏡像使用者理解這個鏡像服務的守護端口,以方便配置映射。另外,在運行時使用隨機端口映射時,也就是 docker run -P 時,會自動隨機映射 EXPOSE 的端口。

          基本格式:

          EXPOSE <端口1> [<端口2>...]

          這里采用了8190端口。

          ENTRYPOINT指令

          ENTRYPOINT指令,類似于CMD指令,但其不會被docker run的命令行參數(shù)指定的指令所覆蓋,而且這些命令行參數(shù)會被當作參數(shù)送給 ENTRYPOINT指令指定的程序。在執(zhí)行docker run時可以指定ENTRYPOINT運行所需的參數(shù)。

          ENTRYPOINT ["<executeable>","<param1>","<param2>",...]

          這里使用ENTRYPOINT指令來執(zhí)行jar -jar啟動SpringBoot項目。

          RUN指令

          RUN指令雖然在實例中沒用到,但也是非常常見的一個指令,于執(zhí)行后面跟著的命令行命令,有以下兩種格式。

          shell 格式:

          RUN <命令行命令>
          # <命令行命令> 等同于,在終端操作的 shell 命令。

          exec格式:

          RUN ["可執(zhí)行文件""參數(shù)1""參數(shù)2"]
          # 例如:
          # RUN ["./test.php", "dev", "offline"] 等價于 RUN ./test.php dev offline

          經過上述一系列的操作,Dockerfile文件編寫完畢。在構建命令時值得注意的是:按照Docker最佳實踐的要求,容器不應該向其存儲層內寫入任何數(shù)據,容器存儲層要保持無狀態(tài)化。所有的文件寫入操作,都應該使用數(shù)據卷(Volume)、或者綁定宿主目錄,在這些位置的讀寫會跳過容器存儲層,直接對宿主(或網絡存儲)發(fā)生讀寫,其性能和穩(wěn)定性更高。

          構建鏡像

          上面準備好了Dockerfile文件,再把對應的jar包放在指定的位置,可在Dockerfile文件的目錄執(zhí)行構建命令,比如:

          docker build -t channel .

          其中-t channel指定了構建鏡像的名稱,當然也可以同時指定版本編號-t channel:v1。后面的“.”指的是當前目錄。

          執(zhí)行效果如下:

          [docker]# docker build -t channel .
          Sending build context to Docker daemon  82.31MB
          Step 1/5 : FROM java:8
           ---> d23bdf5b1b1b
          Step 2/5 : COPY ./hqy-service-channel.jar ./app.jar
           ---> 10cb376c7572
          Step 3/5 : ENV spring.profiles.active test
           ---> Running in ca70651b21b6
          Removing intermediate container ca70651b21b6
           ---> ec420f94df51
          Step 4/5 : EXPOSE 8190
           ---> Running in 318e718d552a
          Removing intermediate container 318e718d552a
           ---> 6746bad4a990
          Step 5/5 : ENTRYPOINT ["java""-jar","-Duser.timezone=GMT+08""./app.jar"]
           ---> Running in 135de4d42ec8
          Removing intermediate container 135de4d42ec8
           ---> 1720afb4fec7
          Successfully built 1720afb4fec7
          Successfully tagged channel:latest

          執(zhí)行docker images可查看到鏡像構建完畢:

          [docker]# docker images
          REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
          channel      latest    1720afb4fec7   51 seconds ago   725MB
          java         8         d23bdf5b1b1b   5 years ago      643MB

          后續(xù)便可以通過docker run命令來啟動容器了。

          這里為了方便CI/CD操作,我們可以通過腳本來完成整個容器停止、容器移除、鏡像的移除、鏡像的重新制作以及容器的重新啟動,這樣CI/CD的系統(tǒng)只用調用對應的腳本即可。

          示例腳本start.sh如下:

          #!/bin/bash
          # 停止容器
          docker stop channel
          echo "停止容器success!"
          # 移除容器
          docker rm channel
          echo "移除容器success!"
          # 移除鏡像
          docker rmi channel
          echo "移除鏡像success!"
          # 制作鏡像
          docker build -t channel /opt/channel/docker/
          echo "制作鏡像success!"
          # 啟動容器
          docker run -d --name channel -p 8190:8190 -v /opt/channel/logs/:/opt/channel/logs/ channel channel:latest
          echo "啟動success!"

          執(zhí)行上述腳本之后,查看容器執(zhí)行結果:

          [bin]# docker ps
          CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                    NAMES
          e9eff75cdb6f   channel   "java -jar -Duser.ti…"   30 seconds ago   Up 28 seconds   0.0.0.0:8190->8190/tcp   channel

          可以看到容器已經成功啟動。當重新構建新的jar包時,只需對目錄中的jar包進行替換,然后再執(zhí)行一遍start.sh命令即可。

          小結

          本文帶大家以具體的實例演示了如何制作Docker鏡像,在制作Docker鏡像過程中需要注意的事項,以及制作之后用于CI/CD的腳本編寫。大家可參考以上實例,根據自己的業(yè)務場景所需進行對應的改造。


          Linux安裝Docker完整教程

          2022-07-28

          CAS+失敗重試方式實現(xiàn)數(shù)據庫的原子性更新

          2022-07-27

          面試被問Linux 命令su和sudo的區(qū)別?

          2022-07-26

          到底如何保證線程安全,你真的清楚嗎?(干貨推薦)

          2022-07-25

          4種 Redis 集群方案介紹+優(yōu)缺點對比

          2022-07-24

          2.2w Star,這是一款什么樣的Nginx可視化配置神器?

          2022-07-23





          如果你覺得這篇文章不錯,那么,下篇通常會更好。備注“公眾號”添加微信好友(微信號:zhuan2quan)

          ▲ 按關注”程序新視界“,洞察技術內幕
          瀏覽 53
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91欧美| 一区二区三区日本黄色电影 | 亚洲第一免费视频 | 青青草成人免费观看 | 欧美成人毛片AAAAAA |