Docker知識點總結

一. 什么是Docker

????????在docker的官方之什么是docker中提到了一句話:“當今各大組織或者團體的創新都源于軟件(例如OA、ERP等),其實很多公司都是軟件公司"。用戶量的激增導致了并發、指數級增加的數據、應用的可靠性等問題,單體應用已經應對不了這些問題,于是誕生了分布式、集群、微服務、邊緣計算等各種名詞、架構風格和滿足這種架構風格的各種框架,那我們接下來跟大家談談這些技術名詞。

? ? ???? 分布式:將一個復雜的應用按照模塊進行拆分,每個拆分的模塊做成一個應用,分開部署,分開運行,各個模塊之間通過webservice、http rest、rpc的方式進行調用。但是分布式系統中面臨著很多棘手的問題:1. 如果某一個應用crash掉了,會導致調用該模塊的其他模塊也無法正常工作;2. 因為網絡抖動或者硬件的問題導致數據的一致性問題(即分布式事務問題);3. 運維和硬件成本的急劇上升。

? ? ????集群:集群是指將某一個應用或者某個模塊部署在多臺機器上(這些機器上跑的代碼是相同的),然后通過負載均衡的方式讓每個應用都能處理請求,即使某一個應用宕掉了,其他的應用一樣可以處理請求,集群是為了解決我們上面提到的分布式應用中的第一個問題,但是集群也面臨著諸多的問題:1. 運維和硬件成本的急劇增加;2. 實現集群勢必會引入第三方的插件,那么第三方插件如何去保障其穩定運行;

? ? ? ? ? 微服務:微服務只是一種架構風格,最早是由Martin Fowler(博客點擊這里)提出,他對微服務的解釋是:In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies(簡而言之,微服務是一種架構的風格,將每一個單獨的應用來作為一個服務套件,每一個服務套件運行在其獨立的進程當中,使用輕量級的方式相互調用,通常采用HTTP的方式。這些個服務是要建立在業務能力和自動化獨立部署的基礎上的。這些服務間應該以一種去中心化的方式運行,而且這些服務可以使用不同的語言、不同的存儲機制來實現)。我用自己的話來表達一下,所謂的微服務就是將一個可以獨立部署、業務能力獨立的應用,應用之間耦合度盡量降低(只能盡量降低,不可能實現絕對的解耦),盡可能的去中心化。微服務也同樣的面臨著諸多的問題:1. 分布式事務問題;2. 運維和硬件成本急劇上升。

? ? ? ? 邊緣計算:首先跟大家說一下,為什么要在這里提到邊緣計算呢?因為本文講的是docker, docker中提到了邊緣計算。所謂的邊緣計算是指在接近數據源的地方進行數據的處理,而不是將數據集中到一起進行處理,邊緣計算可以實現數據的實時分析,將有價值的數據過濾后丟給云端。下面給一張圖方便大家的理解:

我們在回到本節標題“什么是docker”,我們在介紹完上面這些名詞后,會發現無論當今所流行的不論是分布式、集群還是微服務都面臨著一個問題:運維和硬件成本的急劇上升。那么docker的出現就是為了解決這個問題:解決運維和硬件成本的問題。

  提到這里結合自己的工作經歷跟大家講解一下我以前在某家公司是如何解決這個問題的,我們公司購買一臺服務器,然后在服務器上虛擬出多個計算機,然后在虛擬的機器上部署我們的應用,所謂虛擬機是借助于一些軟件虛擬出一臺和我們的物理機一樣的機器,也有CPU、內存、硬盤、光驅等。雖然我們可以在一臺真實的物理機上虛擬出多臺機器,但是每個機器上其實都是有一套完整的操作系統,那么多臺虛擬機上就有多套操作系統,這些操作系統也是要消耗物理機的資源的,那么如何解決這個問題呢?這同樣回到我們該節的主題“什么是docker”。

二. Docker的優點

其實這個問題,我們在第一節“什么是docker”這個章節已經給出了答案。在本節我們會給出系統的總結:

2.1 資源的復用

? ? ? 上節筆者說到我們公司在解決運維和機器成本問題的時候說到,通過傳統的虛擬機的方式每一臺虛擬機都有一套完整的操作系統,那么我們能不能就使用一個操作系統,每個隔離的進程只運行我們的應用和所依賴的第三方軟件,docker恰恰可以解決這個問題。

2.2 一致的環境

? ? ? 我相信做過開發的朋友都有這樣的經歷,我們在本地開發一個應用,尤其是分布式應用,我們需要在本地安裝多臺虛擬機,在本地測試各種功能完好。接著修改各種參數后辛辛苦苦部署到測試機上后,測試的同事經過緊張、嚴謹的測試,一切都那么的prefect。當我們高高興興的修改完各種參數后部署到生產環境,我嘞個擦,各種問題都出現。開發人員經常掛在嘴邊的幾句話“昨天我跑著還是好好的呀”,“測試的時候還是好好的呀”,導致開發人員說這些話的原因是因為開發、測試、生產環境的不一致所導致的。docker也可以解決這個問題,docker的鏡像提供了除內核以外完整運行環境,確保的環境的一致性。

2.3 啟動速度更快

? ? ? 以往的虛擬機的方式啟動的時候需要的時間會很長,因為要啟動操作系統,可能需要幾分鐘甚至更長。但是docker啟動只需要幾秒、幾毫秒。

2.4 應用的遷移

? ? ? 給朋友舉個例子,以前你的應用部署在阿里云上,那么那天你的領導需要將應用簽署到騰訊云上,使用docker的話,會變得非常的簡單。

三. Docker的安裝

Docker安裝步驟的官網地址:https://docs.docker.com/install/linux/docker-ce/ubuntu/

3.1配置倉庫

yum install -y yum-utils \

? device-mapper-persistent-data \

? lvm2

3.2 開始安裝

配置docker的下載源

yum-config-manager \

?? --add-repo \

?? http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

安裝docker

yum -y install docker-ce docker-ce-cli containerd.io

3.3? 驗證docker是否安裝成功

docker -v ? ? ? #查看docker的版本信息

docker info ? ? #查看docker的基本信息,例如多少鏡像,多少個容器等

docker help ?? #查看docker命令

四. docker鏡像與容器

docker的鏡像與容器是docker中兩個至關重要的概念,首先給各位讀者解釋一下這兩個概念。鏡像,我們從字面意思上看,鏡子里成像,我們人站在鏡子面前,在鏡子中會呈現一個完整的我們(包括我們的著裝、表情、發型等等)。那么在軟件領域的鏡像是指對數據按照一定的格式的一個完整的拷貝;容器是鏡像運行時的實體,比如說鏡像是個類,當沒有被加載的時候,它是存放在我們的硬盤上的,而容器是對象,對象只有在程序運行的時候才會被創建,并且一個類可以創建N多個對象,對應到我們的鏡像與容器,一個鏡像可以用于創建多個容器,每個容器運行在各自的namespace中間。

鏡像是對文件的副本,能被特定的軟件或者硬件鎖識別。

在本節我們粗略的說一下鏡像,重點在于講解容器,因為容器一定要用到鏡像,所有我們又不得不提,會有專門的篇章來介紹鏡像。

4.1 鏡像倉庫的配置

所謂的鏡像倉庫就是鏡像集中存放的位置,docker默認的鏡像倉庫地址是 https://hub.docker.com,由于該地址服務器不在內地,訪問的速度可能會有一定的影響。所以我們會經常將docker默認的鏡像倉庫換成阿里巴巴或者163的鏡像倉庫地址,以便加快我們的訪問速度,本小節我們以阿里巴巴的鏡像倉庫為例為大家講解。

A. 注冊阿里云賬戶,地址為:https://account.aliyun.com/login/login.htm

B.進入到阿里云控制臺,選擇“容器鏡像服務”

C.進入到“鏡像加速器”,在右側會出現“加速器地址”以及如何配置加速器地址

D. 在 /etc/docker/目錄下是沒有 daemon.json文件的,所有你要進入到 /etc/docker/ 目錄下執行 touch? daemon.json? 命令創建 daemon.json文件,如下圖所示:

E.在新創建的daemon.json文件中加入如下內容

{

? "registry-mirrors": ["https://zbhswmwr.mirror.aliyuncs.com"]

}

F.執行如下命令

sudo systemctl daemon-reload ? ? ? ? ? ? ? ?? #重新加載守護進程

sudo systemctl restart docker ? ? ? ? ? ? ? ? #重啟docker

4.2 docker鏡像的基本命令

A.查看docker本地有多少鏡像:docker images

B.拉取鏡像倉庫的某個鏡像:docker pull 鏡像名:tag,例如:docker pull hello-world:linux

C.只查看鏡像的ID: docker images -aq

D.刪除一個鏡像: docker rmi 鏡像名[:tag]? 或者? docker rmi 鏡像ID? ?

五. 容器的基本命令

A. 容器的啟動:docker run 鏡像名:tag?

B.查看正在運行的容器:docker container ls 或者 docker ps 或者 docker ps -n 2

注:docker ps -n 2表示查看最近運行或者運行過的兩個容器。

C.查看所有的容器,包括已經停止了的容器:docker container ls -a?或者?docker ps -a

D.以交互的方式啟動容器,例如我們啟動一個centos容器:docker run -i -t centos

? 注意:-t的是宿主機分配一個終端,并將該終端綁定到標準的輸入上;-i讓容器的標準輸入保持打開狀態。二者都是聯合在一起使用的。

如果以上述的方式啟動centos容器,那么我們如何回到我們的宿主機呢?有兩種方式:

  ? ? ? ? ? 1). 執行 exit 命令,該命令會關閉容器,然后退出。

? ? ? ? ? ? ? ? ? 2).按住ctrl + p + q, 容器不關閉,只是退出。

E.以后臺進程的方式啟動容器:docker run -d centos

細心的你一定會發現,我們以守護進程的方式啟動容器后,容器卻已經退出了(status為Exited)。原因是因為docker容器啟動后必須要有一個前臺進程,說白了就是一直要有事情干,那么怎么能讓他有事干了,我們可以開啟一個一直掛起的命令,例如:top tail,否則就會自動退出。那么有什么解決方法呢?其實這個問題解決的方法筆者搜集到三種(都是在網上查找的):

1).以交互的方式啟動容器,然后通過ctrl + p + q 不關閉容器退出容器,這種方式在上面已經給大家提到過:

docker run -it centos

  2).通過一個死循環間歇性的不停的輸出一個字符串 :

docker run -d centos /bin/bash -c "while true;do echo hello world;sleep 2;done"

? ? ? ? 3).通過我們上面提到過的top命令的方式開啟一個前臺進程,讓容器有事情干:

docker run -d centos /usr/bin/top -b

F.容器的停止,容器的停止有兩種方式:1.docker stop 容器ID;2.docker kill 容器ID。方式一是一種平滑、優雅的方式關閉容器;方式二是暴力的方式關閉容器。

G.刪除容器:docker rm [-f] 容器ID。-f表示強制刪除,正在運行的容器用該命令。

H.查看容器的日志:docker logs -t -f 容器ID。-t是顯示日志的時間,-f是監視日志的增長。

I.重新進入已經退出的容器:docker attach 容器ID

J.不進入到容器,直接通過命令操作容器:docker exec 容器ID ls -l /?

啟動mysql的命令:

docker run --name myMysql -e MYSQL_ROOT_PASSWORD=7890 -p 3307:3306 -d mysql:5.7.27

備注:啟動mysql容器,指定容器名為myMysql,指定root的密碼是7890,將宿主機的3307端口映射到mysql容器中的3306端口。

Docker進階

一. 數據卷(volume)

1.1 為什么需要數據卷

docker鏡像是由多個文件系統(只讀層)疊加而成,當我們啟動一個容器的時候,docker的服務端會加載鏡像的只讀層,并在最頂層創建一個可讀寫層。當運行的容器修改現有的文件,該文件會從只讀層拷貝到讀寫層,其實并沒有影響到鏡像本身,依然存在于鏡像中。當我們刪除掉容器,容器運行時的數據都會丟失,當我們通過鏡像重新run一個容器,該容器還是會回到最初的狀態。那么問題來了,我們該如何保存我們運行中的數據了?這個問題有兩種解決方法:a. 我們可以定期的將我們的容器通過commit的方式生成一個鏡像;b.通過數據卷來實現。很明顯我們不可能不停的commit來生成鏡像,有些朋友可能會說你這么說的意思是通過數據卷來實現唄,可我都不知道什么是數據卷,怎么知道它好用了?那么接下來我們就開始來介紹數據卷。

1.2 什么是數據卷

數據卷就是容器內部的數據目錄直接映射到宿主機上的目錄上,無論在宿主機還是容器內對數據的修改在另外一方都是可見的。

1.3 數據卷的使用

1.3.1 命令的使用

我們還是通過前面篇章中使用的centos鏡像來講解,其實也就一個命令,我們的工作也就是圍繞著該命令來講解:docker run -it -v /dataVolumn:/containerDataVolumn centos


?至于其他的命令在這里不作過多的解釋,只解釋一下 -v /dataVolumn:/containerDataVolumn 這個命令的意思,-v是綁定將容器中的目錄掛載到宿主機的目錄上,/dataVolumn:/containerDataVolumn中冒號前的路徑是指自動在宿主機上創建的目錄名(不用我們手動去創建),冒號后的路徑是指在容器中自動創建的目錄名。

1.3.2數據卷的創建與測試

我們前面提到過“論在宿主機還是容器內對數據的修改在另外一方都是可見的”,那么本小節我們回來測試這個問題。

A.我們在容器中 /containerDataVolumn 目錄下創建一個container.txt文件,并寫入內容,命令:echo "hello world" > container.txt

在宿主機的 /dataVolumn目錄下會查看到有container.txt文件,并查看內容,如下圖所示:

B.在宿主機的 /dataVolumn目錄下新建 host.txt文件,并寫入內容,命令為:echo "welcome" > host.txt

在容器的/containerDataVolumn目錄下會看到host.txt文件,并查看內容,如下圖所示:

C.刪除掉容器,查看宿主機 /dataVolumn目錄,文件并沒有丟失

D.我們可以通過 docker inspect 容器ID 命令查看容器的信息,其中hostConfig.binds可以查看到綁定信息,如下圖所示:

1.3.3 數據卷的其他創建方式

通過上面的方式創建數據卷的時候,我們每次在運行鏡像的時候都需要去指定宿主機目錄和容器目錄,不便于維護與遷移,給大家舉個例子:例如我們的日志文件是存放在容器中的 /cloud-project/logs目錄下,而且在項目的配置文件中也是指定到該目錄下,對應到我們的宿主機是/mycloud-project/logs目錄,如果說由于項目發布啟動的時候,運維人員寫錯了目錄名,那將是很大的問題。所以我們在生成鏡像文件的時候就指定數據卷的目錄豈不是更好。

  具體操作是,我們根據Dockerfile目錄中通過VOLUMN指定數據卷的位置,至于什么是Dockerfile,在后面的篇章中會講解。

A. 新建一個空的目錄:mkdir my-dockerfile

B. 新建Dockerfile文件

C.在Dockerfile中添加如下內容:

FROM centos

VOLUMN ["/containerDataVolumn"]

CMD /bin/bash

D.執行命令 docker build -t mycentos:me .? 生成名為mycentos,tag為me的新的鏡像文件。注意:最后的一個點不能省略,它不是結束的句號(我在這里栽了很大的跟頭)!!!

E. 根據mycentos:me這個鏡像啟動一個容器,觀察根目錄下會生成 containerDataVolumn文件夾,如下圖所示:

F. 那么如何查看,容器中的數據卷目錄對應的宿主機的目錄呢?上一小節我們講過,可以通過 docker inspect 容器ID 命令查看,結果如下圖所示:?

補充:mysql的數據卷的啟動方式,如下:

docker run --name myMysql -e MYSQL_ROOT_PASSWORD=7890 -v /mydatas/mysql/datas:/var/lib/mysql -p 3307:3306 -d mysql:5.7.27

二. 容器數據卷(了解)

我們在上一節講到使用數據卷實現容器數據的持久化,那么如何實現容器間數據的共享了?我們需要使用容器數據卷。其實就是利用數據卷的原理,將多個容器中的目錄映射到宿主機的同一個目錄,其實他們就是同一份文件。在一個容器中對數據的改變在其他容器中都是可以感知到的,原因說白了,每個容器中看到的其實就是同一份文件,我們可以通過:stat 文件名 查看文件的inode信息,發現inode的編號都一樣。

A. 通過? docker run -it -v /host-datas:/container-datas --name u1 ubuntu:18.04? 命令啟動一個容器。

B. 通過? docker run -it? --volumes-from u1 --name u2 ubuntu:18.04 命令啟動另外一個容器

C. 在u1容器中的 /container-datas 目錄下創建abc.txt文件,然后在u2容器中/container-datas目錄下可以看到該文件。同理在u2容器中創建一個文件,在u1容器中也能看到該文件。

三. Dockerfile

2.1 Dockerfile是什么

Dockerfile是docker中鏡像文件的的描述文件,說的直白點就是鏡像文件到底是由什么東西一步步構成的。例如我們在淘寶上買了一件商品,但是這個商品需要組裝才能使用,于是賣家就給了你一張圖紙,你就按照圖紙一步一步的組裝起來,然后就成了你所需要的樣子。那么Dockerfile就是這張圖紙,鏡像文件就是你需要的商品。Dockerfile名字可以隨便命名,但是不建議你這做,還是按照規范來使用,首字母要大寫。下面給出我們前幾個章節使用到的ubuntu為例,來看看它的Dockerfile是怎么樣的,如下圖所示:

2.2 Dockerfile、鏡像、容器

Dockerfile:是鏡像的構建文件,描述的鏡像是一步步怎么來的。

  鏡像:是通過Dockerfile做出來的,包含操作系統基礎文件和軟件運行環境,它使用分層的存儲方式。

  容器:是運行起來的鏡像,簡單理解,Docker鏡像相當于程序,容器相當于進程。

2.3 Dockerfile的基本語法及執行流程

2.3.1 Dockerfile的基本語法

a.每個保留字必須放在每一行的開頭,可以大寫也可以小寫,但是建議大寫;

  b.指令按照順序,從上往下依次執行;

  c.#表示注釋;

  d.每條執行指令都會創建一個新的鏡像,并且執行提交。

2.3.2 Dockerfile的執行流程

a.docker從基礎鏡像中執行一個容器;

   b.執行一條指令對容器進行修改;

   c.執行docker commit命令,提交新的鏡像;

   d.在基于剛剛提交的鏡像運行一個新的容器;

   e.執行Dockerfile中的下一條指令,按照b、c、d依次循環下去,直到所有的指令執行完畢。

2.3.3 演示講解

FROM centos ? ? ? ? ? ? ? ? ? ? ? ?? #指定要生成的鏡像的基礎鏡像,開頭第一句話必須也只能是FROM

MAINTAINER? qf@163.com ? ? ? ? ? ? ? #指定作者是誰

RUN apt-get install -y vim ? ? ? ? ? #執行 yum install -y vim 命令,安裝vim

RUN apt-get install -y net-tools ? ? #執行 yum install -y net-tools, 安裝net-tools工具

WORKDIR /dev/ ? ? ? ? ? ? ? ? ? ? ?? #啟動容器后,如果啟動交互模式,直接進入到哪個目錄

CMD ["/bin/bash"] ? ? ? ? ? ? ? ? ?? #啟動容器的時候,進入到/bin/bash這種命令行

如上代碼所示,FROM、MAINTAINER、RUN、WORKDIR、CMD均為關鍵字,按照標準的規范需要大寫;FROM centos表示基礎鏡像是centos,然后會啟動centos這個容器,執行第二行代碼又會生成新的鏡像文件,然后提交,周而復始。

2.4 Dockerfile關鍵字

關鍵字? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 作用

FROM????????????????????????????指定基礎鏡像

MAINTAINER????????????????????作者的信息

RUN????????????????????????????????執行什么命令

EXPOSE????????????????????容器對外暴露的端口

WORKDIR????????????進入到容器后進入到哪個目錄

ENV????????????????????????????????配置環境變量

ADD????????????????????????????將文件拷貝到鏡像中并解壓

COPY????????????????????????????將文件拷貝到鏡像中

VOLUME????????????????????????????????配置數據卷

CMD????????????????????????????????容器啟動時候執行的命令

ENTRYPOINT????????????????容器啟動時候執行的命令

A.ADD指令,現在定義這樣一個Dockerfile,代碼如下所示:

FROM ubuntu:18.04

MAINTAINER? qf@163.com

RUN mkdir /datas

ADD jdk-8u60-linux-x64.tar.gz /datas/

WORKDIR /datas/

CMD ["/bin/bash"]

首先必須將jdk-8u60-linux-x64.tar.gz文件拷貝到Dockerfile同級目錄下,如下圖所示:

執行命令:docker build -t myubuntu .? 構建myubuntu鏡像,如下圖所示:

然后啟動容器,進入到 /datas/目錄下,會發現 jdk1.8.0_60 目錄,表示add命令還執行了解壓命令,如下圖所示:

B.COPY命令,先定義一個Dockerfile, 代碼如下:

FROM centos

MAINTAINER? qf@163.com

RUN mkdir /datas

COPY jdk-8u60-linux-x64.tar.gz /datas/

WORKDIR /datas/

CMD ["/bin/bash"]

執行命令:docker build -t myubuntu .? 構建myubuntu鏡像。

然后啟動容器,進入到 /datas/目錄下,會看到jdk-8u60-linux-x64.tar.gz文件,并沒有解壓,如下圖所示:

C.ENV命令,配置環境變量,還是用上面提到的jdk為例,做過Java開發的朋友都知道,jdk需要配置環境變量,Dockerfile的內容如下所示:

FROM ubuntu ? ? ? ? ? ? ? ? ? ? ?

MAINTAINER qf@163.com ?

RUN mkdir -p /datas/

ADD jdk-8u60-linux-x64.tar.gz /datas/

ENV JAVA_HOME=/datas/jdk1.8.0_60 ? ? ? ? ? ? ? ? ?? #配置JAVA_HOME

ENV PATH=$JAVA_HOME/bin:$PATH ? ? ? ? ? ? ? ? ? ? ? #配置PATH

CMD ["/bin/bash"]

容器啟動后,輸入:java? -version命令,就能看到我們熟悉的內容了。

D.CMD關鍵字,在鏡像構建階段不執行,在容器啟動階段執行(而的RUN關鍵字定義的指令在容器構建階段就會執行,請記住它與CMD的區別)。如果一個Dockerfile中有多個CMD命令,后面的會覆蓋前面的,說白了只有最后一個生效,如下代碼和注釋:

............省略............

CMD echo "<<<<<<<<<<<nice to meet you>>>>>>>>>>"

CMD /bin/bash

CMD echo "==========How are you?=============" ?? #當容器啟動的時候只有該行代碼會執行,會將前兩行代碼覆蓋

CMD還有一個問題,就是當我們使用 docker run命令的時候,我們可以在整個docker命令的最后加上其他額外的命令,那么額外的命令會覆蓋Dockerfile中所有的CMD命令,例如我們執行如下命令:docker run -it centos ls / -l,最終的結果如下圖所示:?

E. ENTRYPOINT指令,和CMD命令差不多,如果一個Dockerfile中有多個ENTRYPOINT,只有最后一個生效。但是他們還是有區別的,如果ENTRYPOINT后面有CMD,當以exec的方式運行的時候,CMD的值會作為參數給ENTRYPOINT,可能很多人看到這句話不大理解,那么我們來兩個例子:

例一:

FROM centos ? ? ? ? ? ? ? ? ? ? ?

MAINTAINER? zhengjingmao@163.com ?

RUN mkdir -p /datas/

ENTRYPOINT ["echo", "hello"]

CMD ["world"] ? ? ? ? ? ?? #會將world作為echo hello的參數,最后的命令其實為echo hello world

例二:

FROM centos? ? ? ? ? ? ? ? ? ? ?

MAINTAINER? zhengjingmao@163.com?

RUN mkdir -p /datas/

ENTRYPOINT ["echo", "hello"]

總結:當我們理解了CMD和ENTRYPOINT兩個命令的區別后,以后在使用的過程中就不會出現各種問題了。

四. docker-compose

在開發一個應用的時候,我們需要其他的很多東西,例如數據庫,nginx,網站應用等很多的環境,而docker又推崇的是每一個容器只運行一個進程,那么我們勢必得很多的容器,那么我們得通過docker build命令一個個的構建鏡像,然后在通過docker run命令啟動一個個容器,那么當我們修改了應用后,我們又得去重復上面的操作。而且容器與容器之間存在著很多的依賴,我們在操作的時候還得去考慮先啟動哪個容器,在啟動另外一個容器,這些操作和步驟都得花上大量的精力。那么docker-compose的出現就是為了解決這個問題。

docker-compose是一種容器編排技術,我們可以編寫一個docker-compose.yml文件,在文件中編排好我們的服務,只用通過一個命令即可搞定所有的工作。

3.1 安裝docker-compose

A. 運行如下命令獲取最新版的docker-compose

curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

B. 給二進制文件加上執行權限

chmod +x /usr/local/bin/docker-compose

如果docker-compose命令無效,可以給這個文件創建一個在 /usr/bin 目錄下的一個軟連接,如下所示:

ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

C. 驗證docker-compose是否安裝成功

docker-compose --version

3.2 docker-compose.yml的編寫

version: "3.7"

services:

? mysql:

? ? image: mysql:5.7.26

? ? ports:

? ? ? - "3306:3306"

? ? environment:

? ? ? - MYSQL_ROOT_PASSWORD=miller

? ? network_mode: "host"

? ? volumes:

? ? ? - "/datas/db:/var/lib/mysql"

? ? ? - "/docker-compose/mysql/my.cnf:/etc/my.cnf"

? eureka-server:

? ? build:

? ? ? context: ./eureka-server

? ? ? dockerfile: Dockerfile

? ? ports:

? ? ? - "8761:8761"

? ? network_mode: "host"

? provider:

? ? build:

? ? ? context: ./provider

? ? ? dockerfile: Dockerfile

? ? ports:

? ? ? - "6666:6666"

? ? network_mode: "host"

? ? depends_on:

? ? ? - "mysql"

? ? command: ["./wait-for-it.sh", "mysql:3306", "--", "java", "-jar", "provider.jar"]

? consumer:

? ? container_name: consumer

? ? build:

? ? ? context: ./consumer

? ? network_mode: "host"

? ? ports:

? ? ? - "8080:8080"

version

指定docker-compose文件的版本,對應的版本信息如下:

services

定義服務。

image

指定基礎鏡像。

ports

指定對外開放的端口。

environment

配置環境變量。

network_mode

網絡模式,默認為bridge(橋接)模式。

volumes

指定數據卷。

context

要構建的鏡像的上下文,說白了就是相對于docker-compose.yml文件的位置。

dockerfile

指定Dockerfile文件的名字,如果名字為Dockerfile的話,不用指定。

depends_on

指定容器所依賴的另外一個容器的服務名,但是并不會等待所依賴的容器啟動才去啟動這個容器。

3.3 啟動

docker-compose up: 如果沒有構建過鏡像,首先會構建鏡像,然后啟動容器。

docker-compose up --build: 無論鏡像是否存在,首先會構建鏡像,然后啟動容器。

docker-compose start [service...]: 啟動已經存在的容器。

3.4 wait-for-it.sh使用

地址:https://github.com/vishnubob/wait-for-it

./wait-for-it.sh www.google.com:80 -- echo "google is up"

如果連接上谷歌的服務器,輸出“google is up”

五. Docker的工程化實踐

A. 創建spring-boot的工程。

在主類上加上@SpringBootApplication, 來標注該類為一個Spring-boot項目的啟動類。

B.? 編寫代碼。

C. 將spring-boot項目打包后的jar包上傳到ubuntu的/spring-boot/目錄下。

D. 執行:docker run -it -v /spring-boot:/jarDir -p 8088:8080 mcr.microsoft.com/java/jre:8u192-zulu-alpine? /bin/sh -c "java -jar /jarDir/spring-boot-1.0-SNAPSHOT.jar" 啟動我們的docker的jre容器,然后運行我們java程序。

E. docker run -it -e MYSQL_ROOT_PASSWORD=123456 -p 3305:3306 mysql:5.7.26,啟動mysql的容器。

F.? 將mysql容器的數據通過數據卷的方式映射到宿主的目錄下。

六. Idea與docker的整合

6.1 安裝docker插件

6.2 配置docker的端口

修改/lib/systemd/system/docker.service文件,將14行代碼改為:

ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock

6.3 插件設置

6.4 Dockerfile

將Dockerfile文件放在項目的根目錄下,文件內容如下:

FROM store/oracle/serverjre:8

MAINTAINER decent_cat@126.com

ADD /target/boot-1.0-SNAPSHOT.jar boot.jar

EXPOSE 8080

CMD ["java", "-jar", "boot.jar"]

6.5 運行配置

七. Docker私有倉庫的搭建

A. 拉取registry倉庫

docker pull registry:2

B. 啟動容器

docker run -d -p 5000:5000 --restart always --name registry registry:2

C. 在瀏覽器訪問:http://192.168.223.141:5000/v2/,會出現如下內容,表示registry啟動成功

D.更改 /etc/hosts 文件,在文件的末尾加入上下代碼,其中192.168.223.141 是本機IP

192.168.223.141? my-registry.com

E. 在 /etc/docker/daemon.json 文件中加入如下內容:

"insecure-registries": ["my-registry.com:5000"]

代碼的完整內容如下:

F. 重啟docker服務,命令如下:

systemctl daemon-reload

systemctl restart docker

G. 推送自己的鏡像到docker私有倉庫中:

# 將我們要推送到私有倉庫的centos鏡像打一個標簽,名字叫my-centos, 這是my-centos就與本地的centos關聯#? 上了

docker tag centos my-registry.com:5000/my-centos

# 將之前已經關聯的的鏡像推送到私有鏡像倉庫

docker push my-registry.com:5000/my-centos

H. 查看鏡像的命令

http://192.168.223.128:5000/v2/image_name/tags/list? ? #查看某個鏡像的所有的tag

附錄:


?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。