Docker 核心技術與基本原理

1. Docker 簡介

1.1 背景

      首先,我們需要了解一下Docker產生的背景。在我們的服務器中,可能需要部署多個Web應用,這些Web應用採用不同的JDK版本、Tomcat版本等。這樣可能就會導致一個問題,當我們啓動項目時,並沒有按照我們的意願來選擇JDK的版本。因爲其他Web應用的依賴配置對該應用產生了影響,每個應用之間的環境沒有彼此隔離。

      當然,我們如果細心一點也可以做到每個應用只使用其所依賴的環境,可參考如何在一臺計算機上安裝多個 JDK ,看了之後你可能覺得好麻煩啊,爲什麼不一臺計算機部署一個項目,這樣就不會由於彼此依賴的環境沒有被隔離而產生影響。

      很多時候,如果一臺計算機上只部署一個項目,並不能夠充分的利用CPU和內存,極大的浪費了硬件資源。爲此,產生了虛擬機,虛擬機便是利用虛擬化技術以及宿主機的硬件資源,從而實現一臺虛擬化的計算機,其效果可以說是等同於一臺真實的計算機。

在這裏插入圖片描述

      從上圖中可以看到,我們可以在一臺計算機上開啓 3 臺虛擬機,這個時候便可以將項目部署到各自的虛擬機內。

      筆者在使用虛擬機的時候,由於原本是4GB的內存,開了三臺虛擬機後真實的物理機變得極爲卡頓,不得不加了內存條。同時,我們啓動虛擬機的過程也極爲緩慢,得好幾分鐘。隨着分佈式技術的發展,集羣環境極爲常見,我們對項目的一點改變,都需要使該項目所有的集羣進行改變,非常繁瑣,且效率低下。

      正是由於以上的種種不足,產生了Docker技術,總結爲以下幾點。

  • 開發和運維之間因爲環境不同而導致的矛盾
  • 集羣環境下每臺機器可輕鬆部署相同的應用
  • DevOps(流水線)

1.2 簡介

      Docker是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的容器中,然後發佈到任何流行的Linux機器上,也可以實現虛擬化,容器是完全使用沙箱機制,相互之間不會有任何接口。

      Docker是世界領先的軟件容器平臺。開發人員利用Docker可以消除協作編碼時"在我的機器上可正常工作"的問題。運維人員利用Docker可以在隔離容器中並行運行和管理應用,獲得更好的計算密度。企業利用Docker可以構建敏捷的軟件交付管道,以更快的速度、更高的安全性和可靠的信譽爲 LinuxWindows Server 應用發佈新功能。

在這裏插入圖片描述

1.3 Docker 優點

  • 簡化程序

      Docker讓開發者可以打包他們的應用以及依賴包到一個可移植的容器中,然後發佈到任何流行的Linux機器上,便可以實現虛擬化。

      Docker改變了虛擬化的方式,使開發者可以直接將自己的成果放入Docker中進行管理。方便快捷已經是Docker的最大優勢,過去需要用數天乃至數週的任務,在Docker容器的處理下,只需要數秒就能完成。

  • 避免選擇恐懼症

      如果你有選擇恐懼症,還是資深患者。Docker 幫你打包你的糾結!比如Docker鏡像;Docker 鏡像中包含了運行環境和配置,所以 Docker 可以簡化部署多種應用實例工作。比如Web應用、後臺應用、數據庫應用、大數據應用比如 Hadoop 集羣、消息隊列等等都可以打包成一個鏡像部署。

  • 節省開支

      一方面, 雲計算時代到來,使開發者不必爲了追求效果而配置高額的硬件,Docker 改變了高性能必然高價格的思維定勢。Docker 與雲的結合,讓雲空間得到更充分的利用。不僅解決了硬件管理的問題,也改變了虛擬化的方式。

1.4 Docker 和虛擬機

特性 Docker 虛擬機
啓動 秒級 分鐘級
硬盤使用 一般爲MB 一般爲GB
性能 接近原本 弱於原生
系統支持量 單機支持上千個 一般是幾十個

2. Docker 架構

      Docker採用 C/S 架構,Client 通過接口與 Server 進程通信,從而實現容器的構建、運行和發佈。

在這裏插入圖片描述

2.1 Host(宿主機)

      安裝了Docker程序,並運行了Docker daemon的主機。

2.1.1 Docker Daemon(Docker 守護進程)

      運行在宿主機上,Docker守護進程,用戶通過Docker client(Docker命令)與Docker daemon交互。

2.1.2 Images(鏡像)

      將軟件環境打包好的模板,用來創建容器的,一個鏡像可以創建多個容器。

      鏡像分層結構

在這裏插入圖片描述
      位於下層的鏡像稱爲父鏡像(Parent Image),最底層的稱爲基礎鏡像(Base lmage)。

      最上層爲"可讀寫"層,其下的均爲“只讀”層。

2.1.3 Containers(容器)

      Docker的運行組件,啓動一個鏡像就是一個容器, 容器與容器之間相互隔離,並且互不影響。

2.2 Docker Client(Docker客戶端)

      Docker命令行工具,用戶是用Docker ClientDocker daemon進行通信並返回結果給用戶,也可以使用其他工具通過Docker ApiDecker doemon通信。

2.3 Registry(倉庫服務註冊)

      經常會和倉庫(Repository)混爲一談,實際上Registry上可以有多個倉庫每個倉庫可以看成是一個用戶, 一個用戶的倉庫放了多個鏡像。倉庫分爲公開倉庫和私有倉庫。

      最大的公開倉庫是官方的Docker Hub,國內也有如阿里雲、時速雲等,可以給國內用戶提供穩定快速的服務。用戶也可以在本地網絡內創建一個私有倉庫。 當用戶創建了自己的鏡像之後就可以使用 push 命令將它上傳到公有或者私有倉庫,這樣下次在另外一臺機器上使用這個鏡像時候,只需要從倉庫上pull下來就可以了。

3. Docker 安裝

      Docker提供了兩個版本:社區版(CE)和企業版(EE)。

      操作系統要求:

      以Centos7爲例,且Docker要求操作系統必須爲64位,且Centos內核版本爲3.1及以上。

      查看系統內核版本信息:uname -r

在這裏插入圖片描述

3.1 準備

      卸載舊版本:

yum list installed | grep docker
yum -y remove ......

      卸載後將保留/var/lib/docker的內容(鏡像、容器、存儲卷和網絡等)。

rm -rf /var/lib/docker

      1. 安裝依賴軟件包

yum insta11 -y yum-utils device-mapper-persistent-data lvm2
#安裝前可查看device-mapper-persi stent-data和1vm2是否已經安裝
rpm -qa | grep device-mapper-persistent-data
rpm -qa | grep lvm2

      2. 設置 yum

yum-config-manager --add-repo https://down1oad.docker.com/1inux/centos/docker-ce.repo

      3. 更新 yum 軟件包索引

yum makecache fast

3.2 安裝

      安裝最新版本 docker-ce

yum insta11 docker-ce -y

#安裝指定版本docker-ce可使用以下命令查看
yum list docker-ce.x86_64 --showduplicates | sort -r

#安裝完成之後可以使用命令查看
docker version

3.3 配置鏡像加速

  1. 找到/etc/docker目錄下的daemon.json文件,沒有則直接vi daemon.json
  2. 加入以下配置
#填寫自己的加速器地址
{
	"registry-mirrors": ["https://registry.docker-cn.com"]
}
  1. 通知 systemd 重載此配置文件
systemctl daemon-reload
  1. 重啓 docker 服務
systemctl restart docker

4. Docker 常用操作

4.1 鏡像常用操作

      查找鏡像

docker search 關鍵詞
# 搜索 docker hub 網站鏡像的詳細信息

      下載鏡像

docker pull 鏡像名:TAG
# TAG 表示版本,有些鏡像的版本顯式 latest,爲最新版本

      查看鏡像

docker images
# 查看本地所有鏡像

      刪除鏡像

docker rmi -f 鏡像ID或者鏡像名:TAG
# 刪除指定本地鏡像
# -f 表示強制刪除

      獲取元信息

docker inspect 鏡像ID或者鏡像名:TAG
# 獲取鏡像的元信息,詳細信息

4.2 容器常用操作

      運行

docker run --name 容器名 -i -t -p 主機端口:容器端口 -d -v 主機目錄:容器目錄:ro 鏡像ID或鏡像名:TAG

# --name 指定容器名,可自定義,不指定自動命名
# -i 以交互模式運行容器
# -t 分配一個僞終端,即命令行,通常 -it 組合來使用
# -p 指定映射端口,將主機端口映射到容器內的端口
# -d 後臺運行容器
# -v 指定掛載主機目錄到容器陌路,默認爲 rw 讀寫模式,ro表示只讀 

      容器列表

docker ps -a -q
# docker ps 查看正在運行的容器
# -a 查看所有容器(運行中、未運行)
# -q 只查看容器的ID

      啓動容器

docker start 容器ID或容器名

      停止容器

docker stop 容器ID或容器名

      刪除容器

docker rm -f 容器ID或容器名
# -f 表示強制刪除

      進入正在運行容器

docker exec -it 容器ID或容器名 /bin/bash
# 進入正在運行的容器並且開啓交互模式終端
# /bin/bash 是固有寫法,作用是因爲 docker 後臺必須運行一個進程,否則容器就會退出,在這裏表示啓動容器後啓動bash
# 也可以用 docker exec 在運行中的容器執行命令

      查看日誌

docker logs 容器ID或容器名

      拷貝文件

docker cp 主機文件路徑 容器ID或容器名:容器路徑  # 主機中文件拷貝到容器中
docker cp 容器ID或容器名:容器路徑  主機文件路徑 # 容器中文件拷貝到主機中

      獲取容器元信息

docker inspect 容器ID或容器名

5. Docker 網絡

      Docker允許通過外部訪問容器或容器互聯的方式來提供網絡服務。

      安裝Docker時,會自動安裝一塊Docker網卡稱爲docker0, 用於Docker各容器及宿主機的網絡通信,網段爲172.0.0.1

      Docker網絡中有三個核心概念:沙盒(Sandbox) 、網絡(Network) 、端點(Endpoint) 。

  • 沙盒,提供了容器的虛擬網絡棧,也即端口套接字、IP路由表、防火牆等內容。隔離容器網絡與宿主機網絡,形成了完全獨立的容器網絡環境。
  • 網絡,可以理解爲Docker內部的虛擬子網,網絡內的參與者相互可見並能夠進行通訊。Docker的虛擬網絡和宿主機網絡是存在隔離關係的,其目的主要是形成容器間的安全通訊環境。
  • 端點,位於容器或網絡隔離牆之上的洞,主要目的是形成-一個可以控制的突破封閉的網絡環境的出入口。當容器的端點與網絡的端點形成配對後,就如同在這兩者之間搭建了橋樑,便能夠進行數據傳輸了。

5.1 Docker的四種網絡模式

      Docker服務在啓動的時候會創建三種網絡,bridgehostnone, 還有一種共享容器的模式container

在這裏插入圖片描述

5.1.1 Bridge

      橋接模式,主要用來對外通信的,docker 容器默認的網絡使用的就是 bridge

      使用 bridge 模式配置容器指定的網絡配置

# 配置容器的主機名
docker run --name t1 --network bridge -h [自定義主機名] -it --rm busybox

# 自定義 DNS
docker run --name t1 --network bridge --dns 114.114 -it --rm busy

# 給 host 文件添加一條
docker run --name t1 --network bridge --add--host [hostname]:[ip] -it --rm busy

5.1.2 Host

      host 類型的網絡就是主機網絡的意思,綁定到這種網絡上面的容器,內部使用的端口直接綁定在主機上對應的端口,而如果容器服務沒有使用端口,則無影響。(不需要進行端口映射了)

docker run --name tomcat -d --network host tomcat

5.1.3 None

      從某種意義上來說,none 應該算不上網絡了,因爲它不使用任何網絡,會形成一個封閉的網絡容。

5.1.4 container

      共享一個容器的 network namespace,和 host 模式差不多,只是這裏不是使用宿主機網絡,而是使用的容器網絡。

5.2 開放端口

      Docker0NAT 橋,所以容器一般獲得的是私有網絡地址

      給 docker run 命令使用 -p 選項即可實現端口映射,無需手動添加規則

  • -p 選項的使用
    • -p <containerPort>
      • 將指定的容器端口映射到主機所有地址的一個動態端口。
    • -p <hostPort>:<containerPort>
      • 將容器端口<containerPort>映射到主機指定<ip>的動態端口
    • -p <ip>::<containerPort>
      • 將指定的容器端口<containerPort>映射到主機指定<ip>的動態端口
    • -p <ip>:<hostPort>:<containerPort>
      • 將指定的容器端口<containerPort>映射到主機指定<ip>的端口<hostPort>
  • 動態端口指隨機端口,可以用使用docker port命令查看具體映射結果
  • -P 暴露所有端口(所有端口指構建鏡像時EXPOSE的端口)

自定義docker0橋的網絡屬性信息:/etc/docker/daemon.json文件

{
    "bip":"192.168.1.5/24",
    "fixed-cidr":"10.20.0.0/16",
    "fixed-cidr-v6":"2001:db8::/64",
    "mtu":1500,
    "default-gateway":"10.20.1.1",
    "dns":["10.20.1.2","10.20.1.3"]
}

      核心選項爲bip,即bridge ip,用於指定docker0橋自身的IP地址;其他選項可通過此地址計算出

      創建自定義的橋

docker network create -d bridge --subnet "127.26.0.0/16" --gateway "127.26.0.1" mybr0

      注意,對網絡修改後,需要刪除之前的容器,否則 docker 啓動失敗,因爲之前容器的網絡配置被修改

6. 創建鏡像

      有時候從 Docker 鏡像倉庫中“下載的鏡像不能滿足要求,我們可以基於一個基礎鏡像構建一個自己的鏡像

      兩種方式:

●更新鏡像:使用docker commit命令

●構建鏡像:使用docker build命令,需要創建Dockerfile文件

6.1 更新鏡像

      先使用基礎鏡像創建一個容器, 然後對容器內容進行更改,然後使用docker commit命令提交爲一個新的鏡像(以tomcat爲例)。

  1. 根據基礎鏡像,創建容器
docker run --name mytomcat -p 80:8080 -d tomcat
  1. 修改容器內容
docker exec -it mytomcat /bin/bash
cd webapps/R0OT
rm -f index. jsp
echo he11o world > index. htm1
exit
  1. 提交爲新鏡像
docker commit -m="描述消息" -a="作者” 容器ID或容器名鏡像名:TAG
#例:
# docker commit -m="修改了首頁" -a="wangzhao" mytomcat wangzhao/tomcat:v1.0
  1. 使用新鏡像運行容器
docker run --name tom -p 8080:8080 -d wangzhao/tomcat:v1. 0

6.2 Dockerfile 構建鏡像

6.2.1 Dockerfile 是什麼

      Dockerfile是一個文本文檔,其中包含用戶可以在命令行上調用來構建鏡像的所有命令。使用docker build 用戶可以創建自動執行的構建,該構建可以連續執行多個命令行指令。

在這裏插入圖片描述

6.2.2 Dockerfile 格式

  • 格式
    • # 註釋
    • 指令
  • 指令不區分大小寫
    • 但是約定爲,指令是大寫,參數是小寫的形式
  • Dockerfile 中的指令按序執行
  • Dockerfile 第一個指令必須是FROM,用來指定構建鏡像的基礎鏡像

6.2.3 使用 Dockerfile 構建 SpringBoot 應用鏡像

一、準備

  1. 把你的 SpringBoot 項目打包成可執行 jar 包
  2. 把 jar 包上傳到 linux 服務器

二、構建

  1. jar 包路徑下創建 Dockerfile 文件vi Dockerfile
#指定基礎鏡像,本地沒有會從dockerHub pu11下來
FROM java:8

#從宿主機的當前目錄下拷貝可執行jar包複製到基礎鏡像的根目錄下
ADD xxxxx.jar /xxxxx.jar

#鏡像要暴露的端口,如要使用端口,在執行docker run命令時使用-p生效
EXPOSE 80

#在鏡像運行爲容器後執行的命令
ENTRYPOINT ["java","-jar","/xxxxx.jar"]
  1. 使用docker build命令構建鏡像,基本語法
docker build -t wangzhao/lemoncinema:v1 .
# -f 指定dockerfile 文件的路徑
# -t 指定鏡像名字和TAG
# . 指當前目錄,這裏實際需要一個上下文路徑

在這裏插入圖片描述

三、運行

docker run --name lemoncinema -p 80:8080 664118cc3020

在這裏插入圖片描述

6.2.4 Dockerfile 常用指令

FROM

      FROM 指令是最重要的一個並且必須爲Dockerfile文件的第一個非註釋行,用於爲鏡像文件構建過程指定基礎鏡像,後續的指令運行於此鏡像提供的運行環境。

      這個基礎鏡像可以是任何可用鏡像,默認情況下docker build會從本地倉庫找指定的鏡像文件,如果不存在就會從Docker Hub上拉取。

      語法:

FROM <image>
FROM <image>:<tag>

MAINTAINER(將被廢棄)

      Dockerfile 的製作者提供的本人詳細信息

      Dockerfile 不限制 MAINTAINER 出現的位置,但是推薦放到FROM指令之後

      語法:

MAINTAINER <name>

      name可以是任何文本信息,一般用作者名稱或者郵箱

LABEL(作用同MAINTAINER)

      給鏡像指定各種元數據

      語法:

LABEL <key>=<value> <key>=<value> <key>=<value>...

      一個Dockerfile可以寫多個LABEL,但是不推薦這麼做,Dockerfile每一條指令都會生成一層鏡像,如果LABEL太長可以使用\符號換行。

      構建的鏡像會繼承繼承鏡像的LABEL,並且會去掉重複的,但如果值不同,則後面的值會覆蓋前面的值。

COPY

      用於從宿主機複製文件到創建的新鏡像文件

      語法:

COPY <src>...<dest>
COPY ["<src>",..."<dest>""]
# <src>:要複製的源文件或者目錄,可以使用通配符
# <dest>: 目標路徑,即正在創建的 image 的文件系統路徑:建議<dest>使用絕對路徑,否則 COPY 指令則以WORKDIR爲其起始路徑

      注意:如果你的路徑中有空白符,通常會使用第二種格式

      規則:

  • <src>必須是build上下文中的路徑,不能是其父目錄中的文件
  • 如果<src>是目錄,則其內部我呢見或子目錄會被遞歸複製,但<src>目錄自身不會被複制
  • 如果指定了多個<src>,或在<src>中使用了通配符,則<dest>必須是一個目錄,則必須以/符號結尾
  • 如果<dest>不存在,將會被自動創建,包括其父目錄路徑

ADD

      基本用法和COPY指令一樣,ADD 支持使用TAR文件和URL路徑

      語法:

ADD <src>...<dest>
ADD ["<src>",..."<dest>"]

      規則:

  • COPY 規則相同
  • 如果<src>爲URL並且<dest>沒有以/結尾,則<src>指定文件將被下載到<dest>
  • 如果<src>爲本地系統上的壓縮格式的tar文件,它會展開成一個目錄;但是通過URL獲取的tar文件不會自動解壓
  • 如果<src>有多個,直接或間接使用了通配符指定多個資源,則<dest>必須是目錄並且以\結尾

WORKDIR

      用於爲 Dockerfile 中所有的RUNCMDENTRYPOINTCOPYADD指定工作目錄,只會影響當前WORKDIR之後的指令。

      語法:

WORKDIR <dirpath>

      在Dockerfile文件中,WORKDIR可以出現多次,路徑可以是相對路徑,但是它是相對於前一個WORKDIR指令指定的路徑。

      另外,WORKDIR可以是ENV指定的變量。

VOLUME

      用來創建掛載點,可以掛載宿主機上的卷或者其他容器上的卷。

      語法:

VOLUME <mountpoint>
VOLUME ["<mountpoint>"]

      不能指定宿主機中的目錄,宿主機掛載的目錄是自動生成的。

ENV

      用來給鏡像定義所需要的環境變量,並且可以被Dockerfile文件中位於其後的其他指令(如ENV、ADD、COPY等)所調用,調用格式:$varivale_name或者${variable_name}

      語法:

ENV <KEY> <VALUE>
ENV <KEY>=<VALUE>...

第一種格式中,<key>之後的所有內容都會被視爲value的組成部分,所以一次只能設置一個變量。

第一種格式可以一個設置多個變量,如果<value>當中有空格可以使用\進行轉義或者對value加引號進行標識,另外\也可以用來續行

ARG

      用法同ENV

      語法:

ARG <name>[=<default value>]

      指定一個變量,可以在docker build 創建鏡像的使用,使用--build-arg <varname>=<value>來指定參數

RUN

      用來指定docker build過程中運行指定的命令

      語法:

RUN <command>
RUN ["<executable>", "<paraml>", "<param2>"]

      第一種格式裏面的參數一般是一個shell命令,以/bin/sh -c來運行它。

      第二種格式中的參數是一個JSON格式的數組,其中<executable>是要運行的命令,後面是傳遞給命令的選項或者參數;但是這種格式不用用/bin/sh -c發起,所以常見的shell操作像變量替換和通配符替換不會進行;如果你運行的命令依賴shell特性,可以替換成類型一下的格式

RUN ["/bin/bash", "-c", "<executable>", "<paraml>"]

CMD

      容器啓動時運行的命令

      語法:

CMD <command>
CMD ["executable", "param1", "param2"]
CMD ["<param1>","<param2>"]

      前兩種語法和RUN相同

      第三種語法用於爲ENTRYPOINT指令提供默認參數

      RUN和CMD區別

  • RUN 指令運行於鏡像文件構建過程中,CMD 則運行於基於Dockerfile構建的鏡像文件啓動爲一個容器的時候
  • CMD指令的主要目的在於給啓動的容器指定默認要運行的程序,且在運行結束後,容器也將終止;不過,CMD命令可以被docker run 的命令行選項給覆蓋
  • Dockerfile中可以存在多個CMD指令,但是隻有最後一個會生效

ENTRYPOINT

      類似於CMD指令功能,用於給容器指定默認運行程序

      語法:

ENTRYPOINT <command>
ENTRYPOINT ["<executable>","<paraml>","<param2>"]

      和CMD不同的是ENTRYPOINT啓動的程序不會被docker run命令指定的參數所覆蓋,而且,這些命令行參數會被當做參數傳遞給ENTRYPOINT指定的程序(但是,docker run命令的--entrypoint參數可以覆蓋ENTRYPOINT

      docker run命令傳入的參數會覆蓋CMD指令的內容並且附加到ENTRYPONT命令作爲其參數使用。

      同樣,Dockerfile中可以存在多個ENTRYPOINT指令,但是隻有最後一個會生效。

      Dockerfile中如果既有CMD又有ENTRYPOINT,並且CMD是一個完整的可執行命令,那麼誰在最後誰生效。

ONBUILD

      用來在 Dockerfile 中定義一個觸發器

      語法:

ONBUILD <instruction>

      Dockerfile 用來構建鏡像文件,鏡像文件也可以當成是基礎鏡像被另外一個Dockerfile用作FROM指令參數。

      在後面這個Dockerfile中的FROM指令在構建過程中執行的時候,會觸發基礎鏡像裏面的ONBUILD指令。

      ONBUILD不能自我嵌套,ONBUILD不會觸發FROMMAINTAINER指令。

      在ONBUILD指令中使用ADDCOPY要小心,因爲新構建過程中的上下文在缺少指定的源文件的時候會失效。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章