Docker容器基礎介紹和操作


1.容器簡介

1.什么是linux容器

Linux容器是與系統其他部分隔離開的一系列進程,從另一個鏡像運行,並由該鏡像提供支持進程所需的全部文件。容器提供的鏡像包含了應用的所有依賴項,因而在從開發到測試再到生產的整個過程中,它都具有可移植性和一致性。

更加詳細地來說,請您假定您在開發一個應用。您使用的是一台筆記本電腦,而且您的開發環境具有特定的配置。其他開發人員身處的環境配置可能稍有不同。
您正在開發的應用依賴於您當前的配置,還要依賴於某些特定文件。與此同時,您的企業還擁有標准化的測試和生產環境,且具有自身的配置和一系列支持文件。
您希望盡可能多在本地模擬這些環境,而不產生重新創建服務器環境的開銷。 因此,您要如何確保應用能夠在這些環境中運行和通過質量檢測,並且在部署過程中不出現令人頭疼的問題,也無需重新編寫代碼和進行故障修復?答案就是使用容器。
容器可以確保您的應用擁有必需的配置和文件,使得這些應用能夠在從開發到測試、再到生產的整個流程中順利運行,而不出現任何不良問題。這樣可以避免危機,做到皆大歡喜。

   雖然這只是簡化的示例,但在需要很高的可移植性、可配置性和隔離的情況下,我們可以利用 Linux 容器通過很多方式解決難題。無論基礎架構是在企業內部還是在雲端,或者混合使用兩者,容器都能滿足您的需求。

2.容器不就是虛擬化嗎

是,但也不竟然。我們用一種簡單的方式來思考一下:

虛擬化使得許多操作系統可同時在單個系統上運行。

容器則可共享同一個操作系統內核,將應用程序與系統其他部分隔離開。

 

 

                                                               圖 - 普通虛擬化技術和Docker的對比

這意味着什么?首先,讓多個操作系統在單個虛擬機監控程序上運行以實現虛擬化,並不能達成和使用容器同等的輕量級效果。事實上,在僅擁有容量有限的有限資源時,您需要能夠可以進行密集部署的輕量級應用。Linux 容器可從單個操作系統運行,在所有容器中共享該操作系統,因此應用和服務能夠保持輕量級,並行快速運行。

docker與Openstack的對比

 

3.容器發展簡史

 

      我們現在稱為容器技術的概念最初出現在 2000 年,當時稱為 FreeBSD jail,這種技術可將 FreeBSD 系統分區為多個子系統(也稱為 Jail)。Jail 是作為安全環境而開發的,系統管理員可與企業內部或外部的多個用戶共享這些 Jail

     Jail 的目的是讓進程在經過修改的 chroot (更改某個進程所能看到的根目錄,即將某進程限制在指定目錄中,保證該進程只能對該目錄及其子目錄的文件有所動作,從而保證整個服務器的安全。 環境中創建,而不會脫離和影響整個系統 在 chroot 環境中,對文件系統、網絡和用戶的訪問都實現了虛擬化。盡管 Jail 在實施方面存在局限性,但最終人們找到了脫離這種隔離環境的方法。

     但這個概念非常有吸引力。

     2001年,通過 Jacques Gélinas 的 VServer 項目,隔離環境的實施進入了 Linux 領域。正如 Gélinas 所說,這項工作的目的是“在高度獨立且安全的單一環境中運行多個通用Linux 服務器 [sic]。” 在完成了這項針對 Linux 中多個受控制用戶空間的基礎性工作后,Linux 容器開始逐漸成形並最終發展成了現在的模樣。

2.Docker簡介

 

1.什么是docker

Docker是PaaS 提供商 dotCloud 開源的一個基於 LXC (LXC是Linux原生支持的容器技術,可以提供輕量化的虛擬化,docker提供LXC的高級封裝,發展標准的配置方法)的高級容器引擎,源代碼托管在 Github 上, 基於go語言並遵從Apache2.0協議開源。Docker是通過內核虛擬化技術(namespace以及cgroups等)來提供容器的資源隔離與安全保障。由於Docker通過操作系統層的虛擬化實現隔離,所以Docker容器在運行時,不需要類似虛擬機( VM)額外的操作系統開銷,提高資源利用率。

Docker是使用Go語言編寫的一個程序運行、測試、交付的開放平台,Docker被設計為能夠使你快速地交付應用。在Docker中,你可以將你的程序分為不同的基礎部分,對於每一個基礎部分都可以當做一個應用程序來管理。Docker能夠幫助你快速地測試、快速地編碼、快速地交付,並且縮短你從編碼到運行應用的周期。Docker使用輕量級的容器虛擬化平台,並且結合工作流和工具,來幫助你管理、部署你的應用程序。Docker在其核心,Docker實現了讓幾乎任何程序都可以在一個安全、隔離的容器中運行。安全和隔離可以使你可以同時在機器上運行多個容器。Docker容器輕量級的特性,意味着可以得到更多的硬件性能。

2.Docker的組成和架構詳解

Docker 主機(Host):一個物理機或虛擬機,用於運行Docker服務進程和容器。

Docker服務端(Server):Docker守護進程,運行docker容器。

Docker客戶端(Client):客戶端使用docker命令或其他工具調用docker API。

Docker倉庫(Registry):保存鏡像的倉庫,類似於git或svn這樣的版本控制系統。

Docker鏡像(Images):鏡像可以理解為創建實例使用的模板。

Docker容器(Container):容器是從鏡像生成對外提供服務的一個或一組服務。

統一的官方倉庫:https://hub.docker.com/

 

 

 

 Docker原理建立-->傳送-->運行

 通過Docker Hub或者自己的Docker倉庫分享Docker鏡像, 從Docker鏡像創建Docker容器, 在容器里運行應用程序。

Docker組件:鏡像(Image)、容器(Container)、倉庫(Repository)

Docker架構:C/S架構

-> Docker使用客戶端-服務器(client-server)架構模式。
-> Docker 客戶端會與Docker守護進程進行通信。Docker 守護進程會處理復雜繁重的任務,例如建立、運行、發布你的 Docker 容器。
-> Docker 客戶端和守護進程可以運行在同一個系統上,當然也可以使用Docker客戶端去連接一個遠程的 Docker 守護進程。
-> Docker 客戶端和守護進程之間通過socket或者RESTful API進行通信。

 

 Docker守護進程

如上圖所示,Docker守護進程運行在一台主機上。用戶並不直接和守護進程進行交互,而是通過 Docker 客戶端間接和其通信。

Docker客戶端

Docker 客戶端,實際上是 docker 的二進制程序,是主要的用戶與 Docker 交互方式。它接收用戶指令並且與背后的 Docker 守護進程通信,如此來回往復。

Docker內部

要理解Docker內部構建,需要理解以下三種部件:
Docker 鏡像 - Docker Images
Docker 倉庫 - Docker Registry
Docker 容器 - Docker Containers

Docker鏡像是Docker容器運行時的只讀模板,每一個鏡像由一系列的層 (layers) 組成。Docker 使用 UnionFS 來將這些層聯合到單獨的鏡像中。UnionFS 允許獨立文件系統中的文件和文件夾(稱之為分支)被透明覆蓋,形成一個單獨連貫的文件系統。正因為有了這些層的存在,Docker 是如此的輕量。當你改變了一個 Docker 鏡像,比如升級到某個程序到新的版本,一個新的層會被創建。因此,不用替換整個原先的鏡像或者重新建立(在使用虛擬機的時候你可能會這么做),只是一個新 的層被添加或升級了。現在你不用重新發布整個鏡像,只需要升級,層使得分發 Docker 鏡像變得簡單和快速。

 

Docker倉庫用來保存鏡像,可以理解為代碼控制中的代碼倉庫。同樣的,Docker 倉庫也有公有和私有的概念。公有的 Docker 倉庫名字是 Docker Hub。Docker Hub 提供了龐大的鏡像集合供使用。這些鏡像可以是自己創建,或者在別人的鏡像基礎上創建。Docker 倉庫是 Docker 的分發部分。

 

Docker容器和文件夾很類似,一個Docker容器包含了所有的某個應用運行所需要的環境。每一個 Docker 容器都是從 Docker 鏡像創建的。Docker 容器可以運行、開始、停止、移動和刪除。每一個 Docker 容器都是獨立和安全的應用平台,Docker 容器是 Docker 的運行部分。

 

libcontainer
Docker 從 0.9 版本開始使用 libcontainer 替代 lxc,libcontainer 和 Linux 系統的交互圖如下:

3.Docker鏡像是如何工作的

Docker鏡像是Docker容器運行時的只讀模板,每一個鏡像由一系列的層(layers)組成;Docker使用UnionFS(聯合文件系統)來將這些層聯合到單獨鏡像中,UnionFS文件系統允許獨立文件系統中的文件和文件夾(稱之為分支)被透明覆蓋,形成一個單獨連貫的文件系統。

正因為有了這些層(layers)的存在,Docker才會如此的輕量。當你改變了一個Docker鏡像,比如升級到某個程序到新的版本,一個新的層會被創建。因此,不用替換整個原先的鏡像或者重新建立(在使用虛擬機的時候你可能會這么做),只是一個新的層被添加或升級了。所以你不用重新發布整個鏡像,只需要升級。層使得分發Docker鏡像變得簡單和快速。

每個鏡像都是從一個基礎的鏡像開始的,比如ubuntu,一個基礎的Ubuntu鏡像,或者是Centos,一個基礎的Centos鏡像。你可以使用你自己的鏡像作為新鏡像的基礎,例如你有一個基礎的安裝了Nginx的鏡像,你可以使用該鏡像來建立你的Web應用程序鏡像。(Docker通常從Docker Hub獲取基礎鏡像)

Docker鏡像從這些基礎的鏡像創建,通過一種簡單、具有描述性的步驟,我們稱之為 指令(instructions)。每一個指令會在鏡像中創建一個新的層,指令可以包含這些動作:

->  運行一個命令。
->  增加文件或者文件夾。
->  創建一個環境變量。
->  當運行容器的時候哪些程序會運行。
這些指令存儲在Dockerfile文件中。當你需要建立鏡像的時候,Docker可以從Dockerfile中讀取這些指令並且運行,然后返回一個最終的鏡像。

4.Docker倉庫的用處

Docker倉庫是Docker鏡像的存儲倉庫。可以推送鏡像到Docker倉庫中,然后在Docker客戶端,可以從Docker倉庫中搜索和拉取鏡像。

5.Docker容器是如何工作的

一個Docker容器包含了一個操作系統、用戶添加的文件和元數據(meta-data)。每個容器都是從鏡像建立的,鏡像告訴Docker容器內包含了什么,當容器啟動時運行什么程序,還有許多配置數據。Docker鏡像是只讀的,當Docker運行一個從鏡像建立的容器,它會在鏡像頂部添加一個可讀寫的層,應用程序可以在這里運行。

6.Docker 技術是否與傳統的 Linux 容器相同?

  不相同。Docker 技術最初是基於 LXC 技術構建(大多數人都會將這一技術與“傳統的” Linux 容器聯系在一起),但后來它逐漸擺脫了對這種技術的依賴。

 就輕量級虛擬化 這一功能來看,LXC 非常有用,但它無法提供出色的開發人員或用戶體驗。除了運行容器之外,Docker 技術還具備其他多項功能,包括簡化用於構建容器、傳輸鏡像以及控制鏡像版本的流程。

 

 

   傳統的Linux 容器使用 init 系統來管理多種進程。這意味着,所有應用程序都作為一個整體運行。與此相反,Docker 技術鼓勵應用程序各自獨立運行其進程,並提供相應工具以實現這一功能。這種精細化運作模式自有其優勢。

 

7.Docker容器運行時會做哪些事情?

使用docker命令時,Docker客戶端都告訴Docker守護進程運行一個容器。

# docker run -i -t ubuntu /bin/bash

可以來分析這個命令,Docker客戶端使用docker命令來運行,run參數表明客戶端要運行一個新的容器。

Docker客戶端要運行一個容器需要告訴Docker守護進程的最小參數信息是:
->  這個容器從哪個鏡像創建,這里是ubuntu,基礎的Ubuntu鏡像。
->  在容器中要運行的命令,這里是/bin/bash,在容器中運行Bash shell。

那么運行這個命令之后在底層發生了什么呢?按照順序,Docker做了這些事情:
->  拉取ubuntu鏡像:Docker檢查ubuntu鏡像是否存在,如果在本地沒有該鏡像,Docker會從Docker Hub下載。如果鏡像已經存在,Docker會使用它來創建新的容器。
->  創建新的容器:當Docker有了這個鏡像之后,Docker會用它來創建一個新的容器。
->  分配文件系統並且掛載一個可讀寫的層:容器會在這個文件系統中創建,並且一個可讀寫的層被添加到鏡像中。
->  分配網絡/橋接接口:創建一個允許容器與本地主機通信的網絡接口。
->  設置一個IP地址:從池中尋找一個可用的IP地址並且服加到容器上。
->  運行你指定的程序:運行指定的程序。
-> 捕獲並且提供應用輸出:連接並且記錄標准輸出、輸入和錯誤讓你可以看到你的程序是如何運行的。
由此就可以擁有一個運行着的Docker容器了!從這里開始你可以管理你的容器,與應用交互,應用完成之后,可以停止或者刪除你的容器。

8.docker的目標和用途

Docker用途:簡單配置、代碼流水線管理、開發效率、應用隔離、服務器整合、調試能力、多租戶、快速部署

 

Docker可以快速交付應用程序 

Docker可以為你的開發過程提供完美的幫助。Docker允許開發者在本地包含了應用程序和服務的容器進行開發,之后可以集成到連續的一體化和部署工作流中。

舉個例子,開發者們在本地編寫代碼並且使用Docker和同事分享其開發棧。當開發者們准備好了之后,他們可以將代碼和開發棧推送到測試環境中,在該環境進行一切所需要的測試。從測試環境中,你可以將Docker鏡像推送到服務器上進行部署。

Docker可以讓開發和拓展更加簡單

Docker的以容器為基礎的平台允許高度可移植的工作。Docker容器可以在開發者機器上運行,也可以在實體或者虛擬機上運行,也可以在雲平台上運行。Docker的可移植、輕量特性同樣讓動態地管理負載更加簡單。你可以用Docker快速地增加應用規模或者關閉應用程序和服務。Docker的快速意味着變動幾乎是實時的

Docker可以達到高密度和更多負載

Docker輕巧快速,它提供了一個可行的、符合成本效益的替代基於虛擬機管理程序的虛擬機。這在高密度的環境下尤其有用。例如,構建你自己的雲平台或者PaaS,在中小的部署環境下同樣可以獲取到更多的資源性能。

Docker改變了什么?

-> 面向產品:產品交付
-> 面向開發:簡化環境配置
-> 面向測試:多版本測試
-> 面向運維:環境一致性
-> 面向架構:自動化擴容

9.docker底層技術介紹

命名空間   [Namespaces]

什么是namespaces?

namespace 是 linux 內核提供的特性,為虛擬化而生,是 Linux 內核用來隔離內核資源的方式。通過 namespace 可以讓一些進程只能看到與自己相關的一部分資源,而另外一些進程也只能看到與它們自己相關的資源,這兩撥進程根本就感覺不到對方的存在。具體的實現方式是把一個或多個進程的相關資源指定在同一個 namespace 中。那么內核資源有哪些呢,或者說docker容器化技術用了哪些namespaces技術呢,下面我來一 一介紹下。

=>   pid namespace:使用在進程隔離(Process ID)
不同用戶的進程就是通過pid namespace隔離開的,且不同 namespace 中可以有相同 PID。
具有以下特征:
-> 每個namespace中的pid是有自己的pid=1的進程(類似 /sbin/init 進程,一般是內核完成初始化之后的第一個進程init。)
-> 每個 namespace 中的進程只能影響自己的同一個 namespace 或子 namespace 中的進程
-> 因為 /proc 包含正在運行的進程,因此在 container 中的 pseudo-filesystem (偽文件系統)的 /proc 目錄只能看到自己namespace 中的進程
-> 因為 namespace 允許嵌套,父 namespace 可以影響子 namespace 的進程,所以子 namespace 的進程可以在父namespace中看到,但是具有不同的 pid

=>   mnt namespace:使用在管理掛載點(Mount)
類似 chroot(更改root目錄,就是更改根目錄),將一個進程放到一個特定的目錄執行。mnt namespace 允許不同namespace的進程看到的文件結構不同,這樣每個namespace 中的進程所看到的文件目錄就被隔離開了。同 chroot 不同,每個 namespace 中的 container 在 /proc/mounts 的信息只包含所在namespace的mount point。

=>   net namespace:使用在進程網絡接口(Networking)
網絡隔離是通過 net namespace 實現的, 每個 net namespace 有獨立的 network devices, IP addresses, IP routing tables, /proc/net 目錄。這樣每個 container 的網絡就能隔離開來。 docker 默認采用 veth 的方式將 container 中的虛擬網卡同 host 上的一個 docker bridge 連接在一起。

=>   uts namespace:使用在隔離內核和版本標識 (Unix Timesharing System)
UTS ("UNIX Time-sharing System") namespace 允許每個 container 擁有獨立的 hostname 和 domain name, 使其在網絡上可以被視作一個獨立的節點而非 Host 上的一個進程。

=>   ipc namespace:使用在管理進程間通信資源 (InterProcess Communication)
container 中進程交互還是采用 Linux 常見的進程間交互方法 (interprocess communication - IPC), 包括常見的信號量、消息隊列和共享內存。然而同 VM 不同,container 的進程間交互實際上還是 host 上具有相同 pid namespace 中的進程間交互,因此需要在IPC資源申請時加入 namespace 信息 - 每個 IPC 資源有一個唯一的 32bit ID。

=>  user namespace:使用在管理空戶空間
每個 container 可以有不同的 user 和 group id, 也就是說可以以 container 內部的用戶在 container 內部執行程序而非 Host 上的用戶。

有了以上6種namespace從進程、網絡、IPC、文件系統、UTS 和用戶角度的隔離,一個 container 就可以對外展現出一個獨立計算機的能力,並且不同container從OS層面實現了隔離。然而不同 namespace 之間資源還是相互競爭的,仍然需要類似ulimit 來管理每個container所能使用的資源。

資源配額 [cgroups]

Docker還使用到了cgroups技術來管理群組。使應用隔離運行的關鍵是讓它們只使用你想要的資源。這樣可以確保在機器上運行的容器都是良民(good multi-tenant citizens)。群組控制允許Docker分享或者限制容器使用硬件資源。例如,限制指定的容器的內容使用。

cgroups實現了對資源的配額和度量。 cgroups 的使用非常簡單,提供類似文件的接口,在 /cgroup 目錄下新建一個文件夾即可新建一個 group,在此文件夾中新建 task 文件,並將 pid 寫入該文件,即可實現對該進程的資源控制。具體的資源配置選項可以在該文件夾中新建子 subsystem ,{子系統前綴}.{資源項} 是典型的配置方法, 如 memory.usageinbytes 就定義了該 group 在 subsystem memory 中的一個內存限制選項。另外,cgroups 中的 subsystem 可以隨意組合,一個 subsystem 可以在不同的 group 中,也可以一個 group 包含多個 subsystem - 也就是說一個 subsystem。

=>  memory
內存相關的限制

=>  cpu
在 cgroup 中,並不能像硬件虛擬化方案一樣能夠定義 CPU 能力,但是能夠定義 CPU 輪轉的優先級,因此具有較高 CPU 優先級的進程會更可能得到 CPU 運算。 通過將參數寫入 cpu.shares ,即可定義改 cgroup 的 CPU 優先級 - 這里是一個相對權重,而非絕對值

=>  blkio
block IO 相關的統計和限制,byte/operation 統計和限制 (IOPS 等),讀寫速度限制等,但是這里主要統計的都是同步 IO

=>  devices
設備權限限制

Docker 聯合文件系統

聯合文件系統(UnionFS)是用來操作創建層的,使它們輕巧快速。Docker使用UnionFS提供容器的構造塊。Docker可以使用很多種類的UnionFS包括AUFS, btrfs, vfs, and DeviceMapper。

Docker 容器格式

Docker連接這些組建到一個包裝中,稱為一個 container format(容器格式)。默認的容器格式是libcontainer。Docker同樣支持傳統的Linux容器使用LXC。在未來,Docker也許會支持其它的容器格式,例如與BSD Jails 或 Solaris Zone集成。

3.安裝Docker

環境說明

#我們這里准備兩台節點進行測試
[root@linux-test-no ~]# cat /etc/redhat-release 
CentOS Linux release 7.4.1708 (Core)
[root@linux-test-no ~]# uname -r
3.10.0-693.el7.x86_64
[root@linux-test-no ~]# hostname -I
172.31.46.38
[root@centos2-no ~]# hostname -I
172.31.46.78

兩個節點上都進行操作

[root@centos2-no ~]# wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo
[root@centos2-no ~]# sed -i 's#download.docker.com#mirrors.ustc.edu.cn/docker-ce#g' /etc/yum.repos.d/docker-ce.repo
[root@centos2-no ~]# yum install docker-ce -y

修改在docker01配置:

#修改啟動文件,監聽遠程端口
[root@linux-test-no ~]# vim /usr/lib/systemd/system/docker.service
[root@linux-test-no ~]# systemctl daemon-reload
[root@linux-test-no ~]# systemctl enable docker.service
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.
[root@linux-test-no ~]# systemctl restart docker.service
#檢查是否啟動
[root@linux-test-no ~]# ps -ef

在docker2進行測試

[root@centos2-no ~]# docker -H 172.31.46.38 info
Client:
 Debug Mode: false

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 19.03.12
 Storage Driver: overlay2

1.Docker基礎命令操作

查看docker相關信息

[root@linux-test-no ~]# docker version
Client: Docker Engine - Community
 Version:           19.03.12
 API version:       1.40
 Go version:        go1.13.10
 Git commit:        48a66213fe
 Built:             Mon Jun 22 15:46:54 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.12
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.10
  Git commit:       48a66213fe
  Built:            Mon Jun 22 15:45:28 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

配置docker鏡像加速

 

vi /etc/docker/daemon.json
{
  "registry-mirrors": ["https://registry.docker-cn.com"]
}    

 

2.啟動第一個容器

[root@linux-test-no ~]# docker run -d -p 80:80 nginx

參數說明

參數

說明

run

創建並運行一個容器

-d

放入后台

-p

端口映射

nginx

鏡像名稱

3.Docker鏡像生命周期

 

 

4.docker鏡像相關操作

1.搜索官方倉庫鏡像

[root@linux-test-no ~]# docker search centos
NAME                               DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
centos                             The official build of CentOS.                   6104                [OK]                
ansible/centos7-ansible            Ansible on Centos7                              132                                     [OK]
consol/centos-xfce-vnc             Centos container with "headless" VNC session…   117                                     [OK]
jdeathe/centos-ssh                 OpenSSH / Supervisor / EPEL/IUS/SCL Repos - …   115                                     [OK]
centos/systemd                     systemd enabled base container.                 86                                      [OK]

列表說明

參數

說明

NAME

鏡像名稱

DESCRIPTION

鏡像說明

STARS

點贊數量

OFFICIAL

是否是官方的

AUTOMATED

是否是自動構建的

 

2.獲取鏡像

根據鏡像名稱拉取鏡像

[root@linux-test-no ~]# docker pull centos
Using default tag: latest
latest: Pulling from library/centos
6910e5a164f7: Pull complete 
Digest: sha256:4062bbdd1bb0801b0aa38e0f83dece70fb7a5e9bce223423a68de2d8b784b43b
Status: Downloaded newer image for centos:latest
docker.io/library/centos:latest

查看當前主機鏡像列表

[root@linux-test-no ~]# docker image list
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              8cf1bfb43ff5        5 days ago          132MB
centos              latest              831691599b88        5 weeks ago         215MB

列表參數說明
REPOSITORY 鏡像倉庫
TAG 標簽
IMAGE ID 鏡像ID
CREATED 創建時間
VIRTUAL SIZE 鏡像大小

拉第三方鏡像方法

docker pull index.tenxcloud.com/tenxcloud/httpd
docker pull 倉庫服務器:端口/項目名稱/鏡像名稱:tag(版本)號

3.導出鏡像

[root@linux-test-no ~]# docker image list
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              8cf1bfb43ff5        5 days ago          132MB
centos              latest              831691599b88        5 weeks ago         215MB
#導出鏡像
[root@linux-test-no ~]# docker image save centos > docker-centos.tar.gz
[root@linux-test-no ~]# ll
total 443940
-rw-r--r--  1 root root       478 Jul 13 18:00 add-memberof.ldif
-rw-------. 1 root root      1367 Mar 18  2019 anaconda-ks.cfg
-rw-r--r--  1 root root       342 Jul 13 18:08 base.ldif
-rw-r--r--  1 root root       868 Jul 13 17:29 changedomain.ldif
-rw-r--r--  1 root root       120 Jul 13 16:23 changepwd.ldif
-rw-r--r--  1 root root       686 Jul 15 15:32 derby.log
-rw-r--r--  1 root root 222584320 Jul 27 11:31 docker-centos.tar.gz

4.刪除鏡像

[root@linux-test-no ~]# docker image rm centos:latest #紅色字體為我們要刪除的鏡像,centos為鏡像名稱,latest為鏡像標簽。
Untagged: centos:latest
Untagged: centos@sha256:4062bbdd1bb0801b0aa38e0f83dece70fb7a5e9bce223423a68de2d8b784b43b
Deleted: sha256:831691599b88ad6cc2a4abbd0e89661a121aff14cfa289ad840fd3946f274f1f
Deleted: sha256:eb29745b8228e1e97c01b1d5c2554a319c00a94d8dd5746a3904222ad65a13f8
[root@linux-test-no ~]# docker image list
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              8cf1bfb43ff5        5 days ago          132MB

5.導入鏡像

[root@linux-test-no ~]# docker image load -i docker-centos.tar.gz #紅色字體為你要導入的鏡像
eb29745b8228: Loading layer [==================================================>]  222.6MB/222.6MB
Loaded image: centos:latest
[root@linux-test-no ~]# docker image list
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              8cf1bfb43ff5        5 days ago          132MB
centos              latest              831691599b88        5 weeks ago         215MB

6.查看鏡像的詳細信息

[root@linux-test-no ~]# docker image inspect centos #紅色字體為要查看的鏡像名稱

7.手動將容器保存為鏡像

#我們這里基於docker官方centos 6.8鏡像進行測試,默認我們從官方的下載的os鏡像沒有安裝任何服務,就連最基礎的sshd服務都不會有。所以我們無法從外部通過ssh直接連接容器。
[root@linux-test-no ~]# docker pull centos:6.8
[root@linux-test-no ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
#啟動一個centos6.8的鏡像,在容器中安裝sshd服務,並修改系統密碼
[root@linux-test-no ~]# docker run -it -p 1022:22 centos:6.8 /bin/bash
[root@f94fe91f659e /]# yum install openssh-server -y
#chpasswd是批量修改用戶密碼的命令,使用格式如下,我們這里把root密碼修改為123456
[root@f94fe91f659e /]# echo "root:123456" |chpasswd
#啟動ssd服務
[root@f94fe91f659e /]# /etc/init.d/sshd start
#查看容器的ip地址,我們看到地址為172.17.0.2
[root@f94fe91f659e /]# ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:16583 errors:0 dropped:0 overruns:0 frame:0
          TX packets:14133 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:40026232 (38.1 MiB)  TX bytes:970789 (948.0 KiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1 
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)
#我們這個時候新開一個終端,在宿主機本地測試通過ssh連接容器,輸入密碼,發現測試成功
[root@linux-test-no ~]# ssh 172.17.0.2
The authenticity of host '172.17.0.2 (172.17.0.2)' can't be established.
RSA key fingerprint is SHA256:bsUbjHkMxqvOdix+HKXAcemrm3ImCvxYs8Ozwq5bXI4.
RSA key fingerprint is MD5:6e:f5:d2:b2:27:81:7d:7f:1d:73:1a:2f:e4:68:14:df.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '172.17.0.2' (RSA) to the list of known hosts.
root@172.17.0.2's password: 
[root@f94fe91f659e ~]#
#這里面如果希望不從宿主機上連接此容器,從別的機器連接此容器,只需連接的時候指定宿主機的地址和容器上的22端口映射到宿主機的端口就行了。

將容器提交為鏡像

[root@linux-test-no ~]# docker commit -p -a "qingbai" -m "centos6.8-sshd" f94fe91f659e  centos6-ssh #容器提交的基本語法為docker commit [選項] 容器名或容器ID [鏡像名[:標簽]] 上面-p的作用是在提交的時候,將容器暫停。 -a的作用是指明提交鏡像的作者 -m的作用是提交時的說明文字 所以上面的命令的作用就是以容器ID為f94fe91f659e的容器為基礎,提交為鏡像centos6-ssh,我這里在設鏡像名的時候沒有指定標簽,默認就會幫我們設為latest,如果要設標簽的話, 只需要在容器名后面加上冒號加標簽,如(centos6-ssh:v1)並在提交過程中暫停容器,指明提交作者為qingbai,並附上鏡像說明centos6.8-sshd #我們查看本地鏡像倉庫,發現鏡像已經生成
[root@linux-test-no ~]# docker image list
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos6-ssh         latest              58486de03672        20 seconds ago      342MB
nginx               latest              8cf1bfb43ff5        10 days ago         132MB
centos              latest              831691599b88        6 weeks ago         215MB
centos              6.8                 82f3b5f3c58f        16 months ago       195MB

使用新的鏡像啟動容器

#sshd -D 表示已后台后台守護進程方式運行sshd服務
[root@linux-test-no ~]# docker run -d -p 1122:22 centos6-ssh:latest /usr/sbin/sshd -D
bbb78fad8aba3a62447e834020e42d6d524e14d1ce05180548b2c8f01d184841

對新鏡像啟動的容器進行測試,看是否生效

[root@linux-test-no ~]# docker ps
CONTAINER ID        IMAGE                COMMAND               CREATED             STATUS              PORTS                  NAMES
bbb78fad8aba        centos6-ssh:latest   "/usr/sbin/sshd -D"   22 seconds ago      Up 22 seconds       0.0.0.0:1122->22/tcp   strange_franklin
[root@linux-test-no ~]# docker exec -it bbb78fad8aba /bin/bash
[root@bbb78fad8aba /]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
86: eth0@if87: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
[root@bbb78fad8aba /]# exit
#測試發現,新鏡像生成的容器中默認加了sshd服務。
[root@linux-test-no ~]# ssh 172.17.0.2
root@172.17.0.2's password:
[root@bbb78fad8aba ~]#

5.容器的日常管理

1.容器的起/停和查看

最簡單的運行一個容器

[root@linux-test-no ~]# docker run nginx

創建容器,兩步走(不常用)

[root@linux-test-no ~]# docker create centos:latest  /bin/bash     #這條語句的意思就是通過centos:latest鏡像創建容器,並不運行
8d9578c38a6f2b8c4bebc4f81c56d3670067a5824b26db1da9444b78237d913d
[root@linux-test-no ~]# docker ps -a     #這條語句的意思是查看顯示所有的容器,包括未運行的
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
8d9578c38a6f        centos:latest       "/bin/bash"         3 seconds ago       Created                                 wonderful_saha
[root@linux-test-no ~]# docker start 8d9578c38a6f       #啟動一個容器,后面跟的是上面容器的CONTAINER ID
8d9578c38a6f
[root@linux-test-no ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
8d9578c38a6f        centos:latest       "/bin/bash"         51 seconds ago      Exited (0) 7 seconds ago

快速啟動容器的方法

[root@linux-test-no ~]# docker run  centos:latest  /usr/bin/sleep 20  #這條語句的意思是直接通過centos:latest鏡像創建容器並運行,
並執行/usr/bin/sleep 20這個命令
現在基本上通過docker run來創建運行容器,它背后其實包含獨立的兩步,一步是docker create 創建容器,另一步是docker start啟動容器。
通過上面的步驟,我們發現docker start啟動容器后,docker ps去看,容器顯示幾秒前退出,並不在運行,這是因為,容器內的第一個進程必須
一直處於運行的狀態,否則這個容器,就會處於退出狀態!

查看正在運行的容器(下面兩條命令都行)

 

[root@linux-test-no ~]# docker container ls
CONTAINER ID        IMAGE               COMMAND               CREATED             STATUS              PORTS               NAMES
abc685cb2007        centos:latest       "/usr/bin/sleep 50"   4 seconds ago       Up 3 seconds                            sleepy_jones
[root@linux-test-no ~]# docker ps
CONTAINER ID        IMAGE               COMMAND               CREATED             STATUS              PORTS               NAMES
abc685cb2007        centos:latest       "/usr/bin/sleep 50"   7 seconds ago       Up 7 seconds                            sleepy_jones

 

查看你容器詳細信息/ip

[root@linux-test-no ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
988a3716e9bb        centos:latest       "/usr/bin/sleep 200"   4 seconds ago       Up 3 seconds                            keen_mcnulty
[root@linux-test-no ~]# docker container  inspect  988a3716e9bb #通過這條命令就可以看到容器的詳細信息
[
    {
        "Id": "988a3716e9bbeaa0f23d4fbe43d17c3189641026be5a13a98989a14f0cb457b1",
        "Created": "2020-07-27T07:51:22.925441099Z",
        "Path": "/usr/bin/sleep",
        "Args": [
            "200"
.....

查看你所有的容器(包括未運行的)

 

[root@linux-test-no ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                         PORTS               NAMES
988a3716e9bb        centos:latest       "/usr/bin/sleep 200"   26 minutes ago      Exited (0) 22 minutes ago                          keen_mcnulty
abc685cb2007        centos:latest       "/usr/bin/sleep 50"    28 minutes ago      Exited (0) 27 minutes ago                          sleepy_jones
35bdf2a164b0        centos:latest       "/usr/bin/sleep 40"    29 minutes ago      Exited (0) 28 minutes ago                          recursing_burnell
2eb97fa49c18        centos:latest       "/usr/bin/sleep 20"    About an hour ago   Exited (0) About an hour ago                       awesome_rhodes
71fdafc25dc6        centos:latest       "/bin/bash"            About an hour ago   Exited (0) About an hour ago

 

停止容器(下面兩個命令都行)

 

[root@linux-test-no ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
0caba1282af5        centos:latest       "/usr/bin/sleep 200"   10 seconds ago      Up 9 seconds                            romantic_mestorf
[root@linux-test-no ~]# docker stop 0caba1282af5
0caba1282af5
或
[root@linux-test-no ~]# docker container kill 0caba1282af5

2.進入容器的方法

啟動時進去方法

[root@linux-test-no ~]# docker run -it nginx:latest /bin/bash    #參數:-it 可交互終端
root@7b960ee8d35b:/# 
退出/離開容器
同時按住ctrl,p,q三個按鍵可以做到退出容器但不關閉,docker ps查看有
同時按住ctrl+d退出容器且關閉容器,docker ps查看無

 

啟動后進入容器的方法

啟動一個docker

[root@linux-test-no ~]# docker run -it centos:latest
[root@1961edb8d554 /]# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 09:21 pts/0    00:00:00 /bin/bash
root        14     1  0 09:21 pts/0    00:00:00 ps -ef

1.使用attach命令可以進入正在運行的容器,使用此方法類似於vnc,操作會在各個容器界面顯示。如下

2.exec進入容器方法(推薦使用

[root@linux-test-no ~]# docker exec -it 7b960ee8d35b /bin/bash    #-it參數是創建一個新的終端,此方法表述在已運行的容器id為7b960ee8d35b的容器中開啟一個交互式的終端
root@7b960ee8d35b:/#
exec方法進入已運行的容器和attach方法不一樣,會單獨建立一個終端,就是不會像attach一樣,所有操作會在所有使用attach進入的界面同步顯示。
此方法進入按ctrl+d鍵退出,只會退出終端,並不會同步關閉容器,而attach通過ctrl+d鍵退出終端,會同步關閉容器。

3.刪除容器

刪除單個容器:

[root@linux-node2 ~]# docker rm ID/名稱
加-f 強制刪除,包括正在運行中的容器

刪除所有容器:

[root@linux-test-no ~]# docker rm -f  `docker ps -a -q`   #-f表示強制刪除容器,包括正在運行的容器,要刪除單獨的容器,把后面的紅體字部分改成容器id.

4.啟動時進行端口映射

-p參數端口映射

[root@linux-test-no ~]# docker run -d -p 88:80 nginx:latest    #-d參數表示后台運行容器,並返回容器ID;這條命令的意思表示本地的88端口映射到容器的80端口

不同指定映射方法

參數

說明

-p hostPort:containerPort    

端口映射  -p 8080:80

-p ip:hostPort:containerPort 

配置監聽地址 -p 10.0.0.100:8080:80        (本地指定ip和指定端口映射到容器指定端口)

-p ip::containerPort         

隨機分配端口 -p 10.0.0.100::80       (本地指定IP和本地隨機端口映射到容器指定端口)

-p hostPort:containerPort:udp

指定協議 -p 8080:80:tcp    (本地指定端口和容器指定端口和指定協議,默認為tcp)

-p 81:80 –p 443:443          

一次性映射多個端口

 

隨機映射

 

docker run -P (大P)# 需要鏡像支持

 

查看指定容器已映射的端口

[root@linux-test-no ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
16d0a0cfe9b9        nginx:latest        "/docker-entrypoint.…"   15 minutes ago      Up 15 minutes       0.0.0.0:88->80/tcp   charming_joliot
[root@linux-test-no ~]# docker port 16d0a0cfe9b9
80/tcp -> 0.0.0.0:88

5.自定義容器名稱

[root@linux-test-no ~]# docker run -it --name nginx-test nginx:latest      #--name參數為通過鏡像啟動容器時指定容器名稱,nginx-test就是指定的容器名,指定
容器名稱的時候要唯一,不能起兩個同樣名稱的容器

6.容器日志的查看

命令格式:

docker logs [選項] 容器ID
選項:

     --details顯示提供給日志的其他詳細信息

-f,--follow跟隨日志輸出

     --since string顯示自時間戳記以來的日志(例如2013-01-02T13:23:37Z)或相對時間(例如42m持續42分鍾)

-n,--tail string從日志末尾開始顯示的行數(默認為“ all”)

-t,--timestamps顯示時間戳

     --until string在時間戳(例如2013-01-02T13:23:37Z)或相對(例如42m持續42分鍾)之前顯示日志

用法如下:

查看指定時間后的日志,只顯示最后100行
docker logs -f -t --since="2020-12-17" --tail=100 CONTAINER_ID
查看某時間段日志:(下面的表示顯示2020年2月16號之后到2020年2月17號之前之間的日志,並加上時間戳顯示)
docker logs -t --since="2020-02-16T13:23:37" --until "2020-02-17T12:23:37" CONTAINER_ID

 

6.Docker數據卷的管理

Docker數據持久化:

容器在運行期間產生的數據是不會寫在鏡像里面的,重新用此鏡像啟動新的容器就會初始化鏡像,會加一個全新的讀寫入層來保存數據。如果想做到數據持久化,Docker提供數據卷(Data volume)或者數據容器卷來解決問題,另外還可以通過commit提交一個新的鏡像來保存產生的數據。

Docker Volume數據卷可以實現:
-> 繞過“拷貝寫”系統,以達到本地磁盤IO的性能,(比如運行一個容器,在容器中對數據卷修改內容,會直接改變宿主機上的數據卷中的內容,所以是本地磁盤IO的性能,而不是先在容器中寫一份,最后還要將容器中的修改的內容拷貝出來進行同步。)
-> 繞過“拷貝寫”系統,有些文件不需要在docker commit打包進鏡像文件。
-> 數據卷可以在容器間共享和重用數據
-> 數據卷可以在宿主和容器間共享數據
-> 數據卷數據改變是直接修改的
-> 數據卷是持續性的,直到沒有容器使用它們。即便是初始的數據卷容器或中間層的數據卷容器刪除了,只要還有其他的容器使用數據卷,那么里面的數據都不會丟失。

docker 數據卷的使用場景

從上面的介紹我們看出,docker內部數據持久化,做的不太好,一般容器內產生的數據會隨着容器的的消失而消失。所以一般我們為了保存一些重要數據,會使用docker數據卷。docker數據卷一般會在以下場景使用。

1.日志輸出

2.靜態web頁面

3.應用配置文件

4.多容器間目錄或文件共享

1.掛載本地指定目錄

#下面命令的意思,通過nginx:latest鏡像創建容器,並在容器內部創建數據卷/usr/share/nginx/html,此目錄可存在,可不存在,如不存在則會自動創建,然后指定此數據卷掛載宿主
機目錄/iflytek/data1下面。此目錄也可不存在,屆時會自動創建。如果不指定宿主機目錄,則數據卷會默認掛載宿主機的一個目錄。默認在/var/lib/docker/volumes目錄下數據卷后
面跟的ro表示,創建的數據卷設為容器內只讀,如果不指定,默認是讀寫。

[root@linux-test-no ~]# docker run -d -p 80:80 -v /iflytek/data1:/usr/share/nginx/html:ro nginx:latest

 容器內站點目錄: /usr/share/nginx/html

在宿主機寫入數據,查看

[root@linux-test-no ~]#  echo "test1" > /iflytek/data1/index.html
[root@linux-test-no ~]# curl 172.31.46.38:80
test1

進入容器,嘗試往數據卷內寫入數據

[root@linux-test-no ~]# docker exec -it 2984edf77b32 /bin/bash
root@2984edf77b32:/# cd /usr/share/nginx/html/
root@2984edf77b32:/usr/share/nginx/html# ls
index.html
root@2984edf77b32:/usr/share/nginx/html# cat index.html        #這里我們看到數據卷和宿主機的文件已完成同步。
test1
root@2984edf77b32:/usr/share/nginx/html# echo "test1.1" > index.html #我們嘗試往數據卷內寫入數據,發現寫不進去,這是因為我們開通創建數據卷的時候設為只讀了。
bash: index.html: Read-only file system
一個宿主機目錄可以同時掛載多個容器內的數據卷,這就啟到了共享卷的作用。

2.創建數據卷容器,並掛載它

#這里我沒指定宿主機的目錄,所以這里只會在容器內創建一個數據卷,如果你想創建多個數據卷,你只需在命令里,再加一個-v后面跟你要創建的數據卷名稱就可以了,這個時候此容器就可以
被理解為數據卷容器,數據卷會默認在宿主機生成一個目錄。一般即便是刪除了初始的數據卷容器,或是刪除掛載了初始化數據卷容器的容器,但只要是有容器在使用該數據卷,那么它里面的數
據就不會丟失!(除非是沒有容器在使用它們)

[root@linux-test-no ~]# docker run -d -p 8081:80 -v /usr/share/nginx/html nginx:latest 360a4cbff9e19ca681372d403ab930a2b6a66a8e6b499ed0176f0b076e3216d5 [root@linux-test-no ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 360a4cbff9e1 nginx:latest "/docker-entrypoint.…" 22 seconds ago Up 22 seconds 0.0.0.0:8081->80/tcp zealous_archimedes 2984edf77b32 nginx:latest "/docker-entrypoint.…" 36 minutes ago Up 36 minutes 0.0.0.0:80->80/tcp suspicious_rubin
#這里inspect表示顯示容器的詳細信息,我們會在詳細信息里看到如下一段,其中source后面為我們創建數據卷的掛載的宿主機目錄,Destination后面就是數據卷的地址
[root@linux
-test-no ~]# docker inspect 360a4cbff9e1 。。。。。。 "Mounts": [ { "Type": "volume", "Name": "ba4c873f3990856dfa9d64bea2669ca16f9e20879d9214da5a96021b05b2f435", "Source": "/var/lib/docker/volumes/ba4c873f3990856dfa9d64bea2669ca16f9e20879d9214da5a96021b05b2f435/_data", "Destination": "/usr/share/nginx/html", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], 。。。。。。
#一般如果沒有改數據卷的默認目錄的話,也可以通過下面命令直接查到,這后面的360a4cbff9e1是你的容器ID
[root@linux-test-no ~]# docker inspect 360a4cbff9e1 |grep /var/lib/docker/volumes
                "Source": "/var/lib/docker/volumes/ba4c873f3990856dfa9d64bea2669ca16f9e20879d9214da5a96021b05b2f435/_data",
[root@linux-test-no ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
360a4cbff9e1        nginx:latest        "/docker-entrypoint.…"   35 minutes ago      Up 35 minutes       0.0.0.0:8081->80/tcp   zealous_archimedes
2984edf77b32        nginx:latest        "/docker-entrypoint.…"   About an hour ago   Up About an hour    0.0.0.0:80->80/tcp     suspicious_rubin
#往數據卷內寫入測試數據,測試其他容器掛載數據卷容器中的數據卷會不會生效。
[root@linux-test-no ~]# echo "test1.1" > /var/lib/docker/volumes/ba4c873f3990856dfa9d64bea2669ca16f9e20879d9214da5a96021b05b2f435/_data/index.html
#下面的命令意思是創建容器nginx-test1.1,掛載360a4cbff9e1容器中的數據卷,--volumes-from后面填的是你要掛載的數據卷容器的ID或者容器名,--rm參數的作用是退出容器后,刪除
容器。
[root@linux-test-no ~]# docker run -it -p 8082:80 --rm --volumes-from 360a4cbff9e1 --name nginx-test1.1 nginx:latest /bin/bash
#現在我們進到容器里來,我們看到360a4cbff9e1容器中的數據卷已被掛載,數據已同步過來了。
root@013f376bef15:/# cat /usr/share/nginx/html/index.html
test1.1

3.創建卷后掛載

 Docker 新版本中引入了 docker volume 命令來管理 Docker volume。

使用默認的 'local' driver 創建一個volume數據卷
#下面的命令就是查看容器上已有的數據卷
[root@linux-test-no ~]# docker volume ls DRIVER VOLUME NAME #創建數據卷的命令如下,--name后面跟你要創建的數據卷名,他會默認在數據卷目錄下創建一個你指定的數據卷名稱,就是他會在/var/lib/docker/volumes下生成一個數據卷test1。
[root@linux
-test-no ~]# docker volume create --name test1 test1 [root@linux-test-no ~]# docker volume ls DRIVER VOLUME NAME local test1 [root@linux-test-no ~]# ls /var/lib/docker/volumes/ metadata.db test1 #下面的命令里中用戶掛載了我們剛剛創建的數據卷test1,掛載已有數據卷的操作就是-v跟的是你要掛載的數據卷名稱和你容器中的目錄,這樣就掛載成功了。其實如果你-v后面的宿主機目錄
填寫的是一個不存在的相對路徑,而不是絕對路徑的話,他也會默認的數據卷目錄下幫你自動創建一個數據卷並命名為你填寫的相對路徑,就算此數據卷默認不存在。例如如果-v后面跟的是
test3:/volune 這里test3數據卷不存在,系統會默認幫你在默認的數據卷目錄下創建一個test3數據卷。就是相當於省去了docker volume create步驟。
[root@linux
-test-no ~]# docker run -d -p 8081:80 --name test1 -v test1:/volume nginx:latest 3de69cb9aa75a06d4cca8bb0dc78e435514381b0049a8f16301e027c173fe62c [root@linux-test-no ~]# docker inspect test1 |grep /var/lib/docker/volumes "Source": "/var/lib/docker/volumes/test1/_data",
#上面的命令結果就是test1數據卷對應在本機上的目錄/var/lib/docker/volumes/test1/_data掛載給容器內的/volume目錄

4.備份數據卷和恢復

#我們先創建一個容器test1,包含一個數據卷/test1
[root@linux-test-no iflytek]# docker run -it -p 8081:80 --name test1 -v /test1 nginx:latest /bin/bash root@d0d32aa5ab4b:/# cd /test1 #測試往數據卷里寫入數據
root@d0d32aa5ab4b:
/test1# mkdir test1.1 root@d0d32aa5ab4b:/test1# ls test1.1 #開始進行數據卷的備份操作,啟動一個新的容器並且從你要備份的數據卷容器中掛載卷,然后掛載當前目錄到容器中為backup,並備份test1卷中所有的數據為test.tar,執行完成之后刪除
容器--
rm,此時備份就在當前的目錄下,名為test.tar。

[root@linux
-test-no iflytek]# docker run --rm --volumes-from test1 -v $(pwd):/backup nginx:latest tar cvf /backup/test.tar /test1 tar: Removing leading `/' from member names /test1/ /test1/test1.1/ [root@linux-test-no iflytek]# ls data1 data2 data3 data4 lost+found test.tar
#總結就是備份數據卷就是
先創建一個容器,並掛載要備份的容器數據卷,再掛載數據卷(pwd):/backup目錄到容器/bakcup,在容器中執行要備份的數據目錄(我這里是test1)/backup
也就是備份到宿主機$(
pwd):/backup目錄。

#下面我們來演示怎么恢復數據卷,恢復給另外的容器
[root@linux-test-no iflytek]# docker ps -a

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                   PORTS               NAMES
d0d32aa5ab4b        nginx:latest        "/docker-entrypoint.…"   2 hours ago         Exited (0) 2 hours ago                       test1
#我們這里把之前的test1容器刪除掉
[root@linux-test-no iflytek]# docker rm -f d0d32aa5ab4b

d0d32aa5ab4b
[root@linux-test-no iflytek]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAM
#我們這里啟動一個test2容器,並創建test1數據卷。新容器創建時掛載的數據卷路徑最好是和之前備份的數據卷路徑一致,要不然只能恢復一部分數據。列如老的數據卷容器里有
test1和test2數據卷,然后我們啟動新容器創建數據卷的時候,只創建了test1數據卷,那么恢復的時候也只會恢復test1,不會恢復test2。不過這也不是絕對的,這個看你備份
的時候備份哪些卷,比如我們在老數據卷容器中只備份了test1卷沒有備份test2卷,那新容器就算掛載了test2卷,恢復也沒數據。

[root@linux-test-no iflytek]# docker run -p 8081:80 -it -v /test1 --name test2 nginx:latest /bin/bash

#這里我們發現現在新創建的test1數據卷里沒有任何東西
root@f5164f9124b2:/# ls /test1

root@f5164f9124b2:/#
#這個時候我們可以在開一個終端來做恢復數據卷的操作,我們需要先cd到存放我們備份文件所在的目錄,然后執行恢復操作,如下,下面的命令的意思是創建一個新的臨時容器並掛載我們要恢復數據卷
的數據卷容器test2,這個時候新建的容器中就會有掛載test2中的數據卷test1,然后在把宿主機本地的目錄掛載臨時容器中的backup數據卷,然后在本地目錄下的備份文件也就是backup下面的
備份文件進行解壓縮到根下面,因為一開始我們備份的時候是直接備份/test1的,數據解壓縮的話,就會把數據恢復到test1下面,正好之前我們掛載了test2中的數據卷test1。所以數據就恢復到test
2數據卷容器中的test1下面去了,這就達到了恢復數據卷的效果

[root@linux-test-no ~]# cd /iflytek
[root@linux-test-no iflytek]# docker run --rm --volumes-from test2 -v $(pwd):/backup nginx:latest tar xvf /backup/test.tar -C /
test1/
test1/test1.1/
#這個時候我們再新創建的數據卷容器test2里,查看數據卷有沒有恢復,我們發現數據卷已恢復
root@f5164f9124b2:/# ls /test1
test1.1
root@f5164f9124b2:/#
#上面我們演示的是恢復到其他容器,恢復到同一個容器其實意思一樣,我們只需要改--volumes-from后面跟的值就可以了。

5.容器數據卷的管理

數據卷是被設計用來持久化數據的,它的生命周期獨立於容器,Docker不會在容器被刪除后自動刪除數據卷,並且也不存在垃圾回收這樣的機制來處理沒有任何容器引用的數據卷。如果需要在刪除容器的同時移除數據卷。可以在刪除容器的時候使用 docker rm -v 這個命令。無主的數據卷可能會占據很多空間,要清理會很麻煩

---------------------
本文著作權歸作者所有。
商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
來源地址:https://www.php.cn/docker/456656.html
來源:php中文網(www.php.cn)
© 版權聲明:轉載請附上原文鏈接!
數據卷是被設計用來持久化數據的,它的生命周期獨立於容器,Docker不會在容器被刪除后自動刪除數據卷,並且也不存在垃圾回收這樣的機制來處理沒有任何容器引用的數據卷。如果需要在刪除容器的同時移除數據卷。可以在刪除容器的時候使用 docker rm -v 這個命令。無主的數據卷可能會占據很多空間,要清理會很麻煩。

---------------------
本文著作權歸作者所有。
商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
來源地址:https://www.php.cn/docker/456656.html
來源:php中文網(www.php.cn)
© 版權聲明:轉載請附上原文鏈接!
數據卷是被設計用來持久化數據的,它的生命周期獨立於容器,Docker不會在容器被刪除后自動刪除數據卷,並且也不存在垃圾回收這樣的機制來處理沒有任何容器引用的數據卷。如果需要在刪除容器的同時移除數據卷。可以在刪除容器的時候使用 docker rm -v 這個命令。無主的數據卷可能會占據很多空間,要清理會很麻煩。

---------------------
本文著作權歸作者所有。
商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
來源地址:https://www.php.cn/docker/456656.html
來源:php中文網(www.php.cn)
© 版權聲明:轉載請附上原文鏈接!
數據卷是被設計用來持久化數據的,它的生命周期獨立於容器,Docker不會在容器被刪除后自動刪除數據卷,並且也不存在垃圾回收這樣的機制來處理沒有任何容器引用的數據卷。如果需要在刪除容器的同時移除數據卷。可以在刪除容器的時候使用 docker rm -v 這個命令。無主的數據卷可能會占據很多空間,要清理會很麻煩。

---------------------
本文著作權歸作者所有。
商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
來源地址:https://www.php.cn/docker/456656.html
來源:php中文網(www.php.cn)
© 版權聲明:轉載請附上原文鏈接!

 數據卷是被設計用來持久化數據的,它的生命周期獨立於容器,Docker不會在容器被刪除后自動刪除數據卷,並且也不存在垃圾回收這樣的機制來處理沒有任何容器引用的數據卷。如果需要在刪除容器的同時移除數據卷。可以在刪除容器的時候使用 docker rm -v 這個命令。無主的數據卷可能會占據很多空間,要清理會很麻煩
1.列出所有數據卷

 

[root@linux-test-no iflytek]# docker volume ls
DRIVER              VOLUME NAME
local               5fe072dd48041e24d2424e75f6281a4ccd9ca925d62ec74be83326eb6a1918f7
local               6c1bc17941dfa0f924f64ec67eac02dd4208625ebfebadf46304403f641d5620
local               58b1e859ee8bb76f92de82b9a2f8b72cbbf018777291e741fb47bc66882a5d19

 

使用--filter dangling=true 過濾 不在使用的數據卷

 

[root@linux-test-no iflytek]# docker volume ls --filter dangling=true
DRIVER              VOLUME NAME
local               6c1bc17941dfa0f924f64ec67eac02dd4208625ebfebadf46304403f641d5620
local               58b1e859ee8bb76f92de82b9a2f8b72cbbf018777291e741fb47bc66882a5d19

 

2.創建一個數據卷,可以設置,--name,--path,--mode。 也可以不用

擁有一切自動生成的參數

[root@linux-test-no iflytek]# docker volume create

3.刪除一個數據卷

[root@linux-test-no iflytek]# docker volume rm 后面跟VOLUME NAME(卷名)

4.嚴禁把容器正在使用的數據卷和綁定掛載的數據卷刪除(刪除數據卷的時候可以通過下面命令進行刪除)

docker volume ls --filter dangling=true #這個是過濾掉不在使用的數據卷,然后你可以選擇性刪除

docker volume ls --filter dangling=true | grep local |awk '{print $2}'|xargs docker volume rm   #這個是刪除所有不在使用的數據卷

6.容器數據卷的總結

通過上面的介紹我們知道什么是數據卷,什么是數據卷容器,但有的同學可能會問,這上面的掛載本地指定目錄,創建數據卷容器並掛載它,還有創建卷后掛載都有什么區別呢。下面我來介紹一下

1.掛載本地指定目錄,顧名思義,就是我們可以指定數據卷的的宿主機掛載目錄,這一般在下面場景中會用到,就是現在生成一個大文件,我發現默認的數據卷目錄空間不太夠了,所以這個時候我們就需要指定數據卷的宿主機掛載目錄,這個有一個小缺點就是宿主機掛載目錄不唯一,以后管理起來可能不太方便

2.創建數據卷容器並掛載它,主要起的是保證這個數據卷可以一直提供服務,不會造成數據丟失。但是如果一個數據卷被創建出來后,如果沒有任何容器去使用他,那么此數據卷就會丟失,我所說的丟失不是講數據真的沒了。只是當我們再次創建同名數據卷的時候,並不會找回以前的數據卷里的數據,但這個也不是絕對的。其實造成這個現狀的原因是當我們通過-v參數創建數據卷的時候,默認會在默認的數據卷目錄/var/lib/docker/volumes/創建一個目錄,不過這個目錄名是不規則的(為了好解釋,我們之間取這個目錄名為123),在容器內部如果我們創建數據卷的時候沒有指定宿主機目錄,那么容器的內部邏輯就會把你創建的數據卷默認掛這個123。所以只要有容器用這個數據卷,數據卷就會一直掛着這個123。但是如果沒有容器在使用這個數據卷了,那掛載就會自動斷開。因為這個目錄名是不規則的,所以我們在數據卷層面就會認為此數據卷丟失了,當我們在創建一個同名的數據名時候,內部不會在掛載123,可能去掛載另一個456了。但是123目錄會還在,只要你不刪除它。所以我上面講的找不會數據不是絕對的,就是因為你記性好,真的記住了這個不規則的目錄名,所以當我們要找回數據的時候,只需指定數據卷掛載宿主機上這個不規則的目錄名就行了。

3.因為有上面2的情況,所以我們可以先創建數據卷,然后在進行掛載。通俗易懂就是我把上面的不規則目錄名規范化了,就算后面數據卷沒容器使用,數據也能再輕易找回來。

其實上面使用數據卷的三種方法,總結起來就是掛載本地指定目錄可以防止空間不足,缺點是掛載不在一個目錄下,管理起來不太方便。然后創建卷后掛載創建數據卷容器並掛載它升級版更推薦使用,優點是掛載都在一個目錄下,管理起來更方便點。缺點是可能造成空間壓力。

 4.容器數據卷如果我們掛載的時候,宿主機目錄是空的,然后關聯到一個容器的目錄,如果容器內的目錄下默認是有文件的,那么啟動的容器,會默認已宿主機目錄為准,就是會清空

容器內被關聯的目錄下的文件或目錄。

7.Dockerfile自動構建docker鏡像

DockerFile 可以說是一種可以被 Docker 程序解釋的腳本DockerFile 是由一條
條的命令組成的,每條命令對應 linux 下面的一條命令, Docker 程序將這些
DockerFile 指令再翻譯成真正的 linux 命令,其有自己的書寫方式和支持的命
令, Docker 程序讀取 DockerFile 並根據指令生成 Docker 鏡像,相比手動制作鏡
像的方式, DockerFile 更能直觀的展示鏡像是怎么產生的,有了 DockerFile,當
后期有額外的需求時,只要在之前的 DockerFile 添加或者修改響應的命令即可
重新生成新的 Docke 鏡像,避免了重復手動制作鏡像的麻煩

1.Dockerfile指令集

 

dockerfile主要組成部分:

 

基礎鏡像信息 FROM centos:6.8

制作鏡像操作指令RUN yum insatll openssh-server -y

容器啟動時執行指令 CMD ["/bin/bash"]

dockerfile常用指令:

 

         FROM 這個鏡像的媽媽是誰?(指定基礎鏡像)

         MAINTAINER 告訴別人,誰負責養它?(指定維護者信息,可以沒有)

         RUN 你想讓它干啥(在命令前面加上RUN即可)

         ADD 給它點創業資金(COPY文件,會自動解壓)

         WORKDIR 我是cd,今天剛化了妝(設置當前工作目錄)

         VOLUME 給它一個存放行李的地方(設置卷,掛載主機目錄)

         EXPOSE 它要打開的門是啥(指定對外的端口)

         CMD 奔跑吧,兄弟!(指定容器啟動后的要干的事情)

 

 

 

 

2.創建一個Dockerfile

[root@linux-test-no ~]# cd /opt/ #這里建議目錄結構按照業務類型或系統類型等方式划分,方便后期鏡像比較多的時候 進行分類。不過只是建議,具體你想把dockerfile文件放到哪里看你自己
[root@linux-test-no opt]# mkdir dockerfile/{web/{nginx,tomcat,jdk,apache},system/{centos,ubuntu,redhat}} -pv
[root@linux-test-no opt]# cd dockerfile/system/centos/
[root@linux-test-no centos]# pwd
/opt/dockerfile/system/centos
#編寫dockerfile,生成的鏡像的時候會在執行命令的當前目錄查找 Dockerfile 文件, 所以名稱不可寫錯, 而且 D 必須大寫 Dockerfile文件中第一行,必須是 From xxx (xxx 是基礎鏡像) ,下面每一行指定有什么用,上面已經講過了,不用再解釋了。
[root@linux
-test-no centos]# vim Dockerfile FROM centos:6.8 RUN yum install openssh-server -y RUN echo "root:123456" |chpasswd RUN /etc/init.d/sshd start CMD ["/usr/sbin/sshd","-D"]

3.通過dockerfile文件構建docker鏡像

[root@linux-test-no centos]# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos6-ssh         latest              58486de03672        18 hours ago        342MB
nginx               latest              8cf1bfb43ff5        10 days ago         132MB
centos              latest              831691599b88        6 weeks ago         215MB
centos              6.8                 82f3b5f3c58f        16 months ago       195MB
#下面命令中,-t 為鏡像標簽打標簽並指定鏡像名, . 表示當前路徑。因為我們要構建鏡像的Dockerfile在本地目錄下,所以我們用了. 如果需要的dockerfile文件不在本地目錄下,而是
在其他目錄下,我們則需要把.換成指定的其他目錄。
[root@linux
-test-no centos]# docker image build -t centos6.8-ssh:test1 .
#測試發現我們通過Dockerfile文件構建的docker鏡像成功。
[root@linux-test-no ~]# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos6.8-ssh       test1               922e349f2760        About an hour ago   342MB
centos6-ssh         latest              58486de03672        19 hours ago        342MB
nginx               latest              8cf1bfb43ff5        11 days ago         132MB
centos              latest              831691599b88        6 weeks ago         215MB
centos              6.8                 82f3b5f3c58f        16 months ago       195MB
#測試使用自構建的鏡像啟動成功
[root@linux-test-no ~]# docker run -d -p 2022:22 centos6.8-ssh:test1
2e2a32d93d8bd82e88eb83fa93ae1fc2841d46885b25c6027bf5d58b4604dd44

 8.Docker中的鏡像分層

 Docker 支持通過擴展現有鏡像,創建新的鏡像。實際上,Docker Hub 中 99% 的鏡像都是通過在 base 鏡像中安裝和配置需要的軟件構建出來的。

 

 

 

   從上圖可以看到,新鏡像是從 base 鏡像一層一層疊加生成的。每安裝一個軟件,就在現有鏡像的基礎上增加一層。

1.Docker鏡像為什么分層

鏡像分層最大的一個好處就是共享資源。

比如說有多個鏡像都從相同的 base 鏡像構建而來,那么 Docker Host 只需在磁盤上保存一份 base 鏡像;同時內存中也只需加載一份 base 鏡像,就可以為所有容器服務了。而且鏡像的每一層都可以被共享。

如果多個容器共享一份基礎鏡像,當某個容器修改了基礎鏡像的內容,比如/etc 下的文件,這時其他容器的 /etc 是不會被修改的,修改只會被限制在單個容器內。這就是容器 Copy-on-Write 特性。

 

2 .可寫的容器層

當容器啟動時,一個新的可寫層被加載到鏡像的頂部。這一層通常被稱作“容器層”,“容器層”之下的都叫“鏡像層”。

 

 

 所有對容器的改動 - 無論添加、刪除、還是修改文件都只會發生在容器層中。只有容器層是可寫的,容器層下面的所有鏡像層都是只讀的

3.容器層的細節說明

鏡像層數量可能會很多,所有鏡像層會聯合在一起組成一個統一的文件系統。如果不同層中有一個相同路徑的文件,比如 /a,上層的 /a 會覆蓋下層的 /a,也就是說用戶只能訪問到上層中的文件 /a。在容器層中,用戶看到的是一個疊加之后的文件系統。

文件操作的

 

文件操作

說明

添加文件

在容器中創建文件時,新文件被添加到容器層中。

讀取文件

在容器中讀取某個文件時,Docker 從上往下依次在各鏡像層中查找此文件。一旦找到,立即將其復制到容器層,然后打開並讀入內存。

修改文件

在容器中修改已存在的文件時,Docker 會從上往下依次在各鏡像層中查找此文件。一旦找到,立即將其復制到容器層,然后修改之。

刪除文件

在容器中刪除文件時,Docker 也是從上往下依次在鏡像層中查找此文件。找到后,會在容器層中記錄下此刪除操作。(只是記錄刪除操作)

 

 

只有當需要修改時才復制一份數據,這種特性被稱作 Copy-on-Write。可見,容器層保存的是鏡像變化的部分,不會對鏡像本身進行任何修改。

這樣就解釋了我們前面提出的問題:容器層記錄對鏡像的修改,所有鏡像層都是只讀的,不會被容器修改,所以鏡像可以被多個容器共享。

 

9.docker私有倉庫(registry)

Docker Registry 作為 Docker 的核心組件之一負責鏡像內容的存儲與分發,客戶
端的 docker pull 以及 push 命令都將直接與 registry 進行交互,最初版本的 registry
Python 實現,由於設計初期在安全性,性能以及 API 的設計上有着諸多的缺陷,

該版本在 0.9 之后停止了開發,由新的項目 distribution(新的 docker register 被稱為

Distribution)來重新設計並開發下一代 registry,新的項目由 go 語言開發,所有的

API,底層存儲方式,系統架構都進行了全面的重新設計已解決上一代 registry 中存在

的問題, 2016 4 月份 rgistry 2.0 正式發布, docker1.6 版本開始支持 registry 2.0

而八月份隨着 docker 1.8 發布, docker hub 正式啟用 2.1 版本 registry 全面替代之

前版本 registry,新版 registry 對鏡像存儲格式進行了重新設計並和舊版不兼容,

docker 1.5 和之前的版本無法讀取 2.0 的鏡像,另外, Registry 2.4 版本之后支持了

回收站機制,也就是可以刪除鏡像了,在 2.4 版本之前是無法支持刪除鏡像的,所以

如果你要使用最好是大於 Registry2.4 版本的。
本部分將介紹通過官方提供的 docker registry 鏡像來簡單搭建一套本地私有倉庫環境。

這種容器私服有點像nexus,就是maven私服,你理解了maven私服就理解了容器私服。

1.創建一個普通的倉庫

#查看本地鏡像中是否有registry鏡像,這里我們看沒有
[root@linux-test-no ~]# docker image list REPOSITORY TAG IMAGE ID CREATED SIZE centos6.8-ssh test1 922e349f2760 22 hours ago 342MB centos6-ssh latest 58486de03672 40 hours ago 342MB nginx latest 8cf1bfb43ff5 11 days ago 132MB centos latest 831691599b88 6 weeks ago 215MB centos 6.8 82f3b5f3c58f 16 months ago 195MB #下載registry鏡像。
[root@linux
-test-no ~]# docker pull registry
#基於registry鏡像創建容器私有倉庫,--restart=always的作用是讓此容器隨着docker服務的重啟而重啟,這樣的啟動方式適合與一些監控程序,跟着機器一起啟動,出問題也會自動重啟。
在上面我們介紹數據卷的時候我們講過,容器內的數據一般會隨着容器的消失而消失,所以我們為了讓私庫內的鏡像不消失,所以一般我們會通過-v參數掛載一個宿主機目錄,/var/lib/registry
目錄是registry容器內存放鏡像的默認目錄。
[root@linux-test-no ~]# docker run -d -p 5000:5000 --restart=always --name qingbai_registry -v /iflytek/my_registry:/var/lib/registry  registry:latest
7d1aba329d0cdc6a084efd646c8e3e59930e50ba93dca3ec40ed43f31554db24
[root@linux-test-no ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
7d1aba329d0c        registry:latest     "/entrypoint.sh /etc…"   45 seconds ago      Up 45 seconds       0.0.0.0:5000->5000/tcp   qingbai_registry
4a7a77ebc5e7        centos:6.8          "/bin/bash"              13 hours ago        Up 12 hours                                  test2
655769f1e67f        centos:6.8          "/bin/bash"              13 hours ago        Up 13 hours   
#Docker從1.3.X之后,與docker registry交互默認使用的是https,然而此處搭建的私有倉庫只提供http服務,所以我們需要在docker的客戶機(即上傳鏡像到私有倉庫里或從私有倉庫下載鏡像的客戶機
上修改以下配置文件。使其支持http服務,不然我們后續使用的時候會報錯。
[root@linux-test-no ~]# vim /etc/docker/daemon.json
{
  "registry-mirrors": ["https://registry.docker-cn.com"],
  "insecure-registries": ["172.31.46.38:5000"] 這里是我們要加的行,里面地址填的是私有倉庫所在服務器的地址。
}
[root@linux-test-no ~]# systemctl restart docker.service
#修改完配置后,重啟docker服務,讓修改生效,我們發現我們上面--restart=always參數起了作用,registry隨着docker服務的重啟而重啟了。
不過這里用--restart=always參數的時候我們需要注意一點,如果我們不想要這個容器了,我們不能通過平常的docker rm 和docker stop命令,因為通過這些命令刪除
不掉容器,還可能出現其他問題,而是需要更新 restart 的狀態。例如:docker update --restart=no nginx:latest 這樣之后, 這個容器就不會在自動啟動了。
后我們就可以通過傳統方式刪除容器
[root@linux-test-no ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
7d1aba329d0c        registry:latest     "/entrypoint.sh /etc…"   9 minutes ago       Up 3 minutes        0.0.0.0:5000->5000/tcp   qingbai_registry

 測試上傳鏡像到私庫和從私庫上拉鏡像

#查看本地現有鏡像
[root@linux-test-no ~]# docker image list REPOSITORY TAG IMAGE ID CREATED SIZE centos6.8-ssh test1 922e349f2760 25 hours ago 342MB centos6-ssh latest 58486de03672 43 hours ago 342MB nginx latest 8cf1bfb43ff5 12 days ago 132MB registry latest 2d4f4b5309b1 6 weeks ago 26.2MB centos latest 831691599b88 6 weeks ago 215MB centos 6.8 82f3b5f3c58f 16 months ago 195MB #開始上傳鏡像到私有倉庫,我們這里需要先給要上傳的鏡像打個tag,格式如下,centos6.8-ssh:test1為我們要上傳的鏡像名和tag號172.31.46.38:5000為我們要傳的私庫地址
/后面是你要在私庫里把這個鏡像重新取的名字和tag號
[root@linux
-test-no ~]# docker tag centos6.8-ssh:test1 172.31.46.38:5000/centos6.8-ssh:test1 #我們看到本地多了一個鏡像172.31.46.38:5000/centos6.8-ssh這個就是我們打的tag
[root@linux
-test-no ~]# docker image list REPOSITORY TAG IMAGE ID CREATED SIZE 172.31.46.38:5000/centos6.8-ssh test1 922e349f2760 25 hours ago 342MB centos6.8-ssh test1 922e349f2760 25 hours ago 342MB centos6-ssh latest 58486de03672 43 hours ago 342MB nginx latest 8cf1bfb43ff5 12 days ago 132MB registry latest 2d4f4b5309b1 6 weeks ago 26.2MB centos latest 831691599b88 6 weeks ago 215MB centos 6.8 82f3b5f3c58f 16 months ago 195MB #開始上傳鏡像,push后面跟的就是我們的上面打的tag
[root@linux
-test-no ~]# docker push 172.31.46.38:5000/centos6.8-ssh
#我們通過下面的命令查看私庫里現在有哪些鏡像
[root@linux-test-no ~]# curl -XGET http://172.31.46.38:5000/v2/_catalog
{"repositories":["centos6.8-ssh"]}
#我們這里測試把本地剛剛上傳的鏡像刪除,然后再從私庫里下載回來
[root@linux-test-no ~]# docker image rm centos6.8-ssh:test1

Untagged: centos6.8-ssh:test1
[root@linux-test-no ~]# docker image rm 172.31.46.38:5000/centos6.8-ssh:test1
#我們這里看到剛剛打的tag鏡像和源鏡像已刪除。
[root@linux-test-no ~]# docker image list

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos6-ssh         latest              58486de03672        43 hours ago        342MB
nginx               latest              8cf1bfb43ff5        12 days ago         132MB
registry            latest              2d4f4b5309b1        6 weeks ago         26.2MB
centos              latest              831691599b88        6 weeks ago         215MB
centos              6.8                 82f3b5f3c58f        16 months ago       195MB
#我們現在測試從私庫里拉我們剛剛上傳的鏡像,
[root@linux-test-no ~]# docker pull 172.31.46.38:5000/centos6.8-ssh:test1

#測試成功,我們在本地看到了此鏡像。這樣,我們就完成了私庫的搭建,也就可以在同一局域網內的其他機器上,從該私有倉庫中pull下來該鏡像
[root@linux-test-no ~]# docker image list

REPOSITORY                        TAG                 IMAGE ID            CREATED             SIZE
172.31.46.38:5000/centos6.8-ssh   test1               922e349f2760        26 hours ago        342MB
centos6-ssh                       latest              58486de03672        44 hours ago        342MB
nginx                             latest              8cf1bfb43ff5        12 days ago         132MB
registry                          latest              2d4f4b5309b1        6 weeks ago         26.2MB
centos                            latest              831691599b88        6 weeks ago         215MB
centos                            6.8                 82f3b5f3c58f        16 months ago       195MB



 

2.帶basic(用戶名和密碼)認證的倉庫

上面我們創建的倉庫,有一個安全風險,就是任何人都可以上傳鏡像和拉取鏡像。所以為了安全,容器倉庫會設為basic認證的倉庫。那么帶basic認證的倉庫

怎么配置呢,如下。

1.安裝加密工具

[root@linux-test-no ~]# yum install httpd-tools -y

2.設置認證密碼

[root@linux-test-no ~]# mkdir /opt/registry-var/auth/ -p
[root@linux-test-no ~]# htpasswd  -Bbn clsn 123456  > /opt/registry-var/auth/htpasswd

3.啟動容器,在啟動時傳入認證參數

#這里我們基於上面的普通倉庫進行操作
[root@linux-test-no ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
7d1aba329d0c        registry:latest     "/entrypoint.sh /etc…"   7 hours ago         Up 7 hours          0.0.0.0:5000->5000/tcp   qingbai_registry
#這里我們需要先把容器的restart狀態改變,讓其不隨docker服務的重啟而重啟
[root@linux-test-no ~]# docker update --restart=no qingbai_registry
qingbai_registry
#然后我們重啟docker進行驗證,關閉上面已在運行的倉庫。
[root@linux-test-no ~]# systemctl restart docker
[root@linux-test-no ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
#開始啟動帶basic認證的倉庫,下面前一面一個-v是把我們在宿主機上創建的認證目錄和容器內的認證目錄關聯,讓倉庫運行的時候可以讀取我們在宿主機上創建的用戶名和密碼並進行驗證。
下一個-v是把倉庫容器中的鏡像存放目錄映射到宿主機上,-e REGISTRY_AUTH_HTPASSWD_PATH后面填認證文件所在的目錄。因為我上面用戶名和密碼放在htpasswd文件下,所以我這里填寫
/auth/htpasswd
[root@linux-test-no ~]# docker run -d -p 5000:5000 -v /opt/registry-var/auth/:/auth/ -v /iflytek/my_registry:/var/lib/registry -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd registry 996e778baea4c6b913397c4a902f520355c4ad6bc62beb1cead22bfb201032cd

4.使用驗證用戶測試

#登陸用戶
[root@linux-test-no ~]# docker login 172.31.46.38:5000 Username: clsn Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded #推送鏡像到倉庫
[root@linux
-test-no ~]# docker push 172.31.46.38:5000/centos:6.8 The push refers to repository [172.31.46.38:5000/centos] ad337ac82f03: Layer already exists 6.8: digest: sha256:3e472cabf40e9beee56affc1fdce0e897dadc4e6063c00cd16bcbdbd3ba96864 size: 529
#認證文件保存位置
[root@linux-test-no ~]# cat .docker/config.json
{
    "auths": {
        "172.31.46.38:5000": {
            "auth": "Y2xzbjoxMjM0NTY="
        }
    },
    "HttpHeaders": {
        "User-Agent": "Docker-Client/19.03.12 (linux)"
    }
}

 

10.docker-compose容器編排工具

當在宿主機啟動較多的容器時候, 如果都是手動操作會覺得比較麻煩而且容器出錯,這個時候推薦使用 docker 單機編排工具 docker composeDocker Compose
docker 容器的一種編排服務, docker compose 是一個管理多個容器的工具,比如可以解決容器之間的依賴關系, 就像啟動一個 web 就必須得先把數據庫服務
先啟動一樣, docker compose 完全可以替代 docker run 啟動容器。

1.安裝docker-compose

 

#下載pip軟件
[root@linux-test-no ~]# yum install -y python2-pip
#下載docker-compose
[root@linux-test-no ~]# pip install --upgrade pip
[root@linux-test-no ~]# pip install docker-compose
#下載docker-compose之前建議開啟國內pip下載,另下載過程中可能會報錯,報錯解決方法參考下面博客
https://www.cnblogs.com/felixqiang/p/11946644.html
#查看docker-compose版本
[root@linux-test-no ~]# docker-compose version
/usr/lib64/python2.7/site-packages/cryptography/__init__.py:39: CryptographyDeprecationWarning: Python 2 is no longer supported by the Python core team. Support for it is now deprecated in cryptography, and will be removed in a future release.
  CryptographyDeprecationWarning,
docker-compose version 1.26.2, build unknown
docker-py version: 4.2.2
CPython version: 2.7.5
OpenSSL version: OpenSSL 1.0.1e-fips 11 Feb 2013

 

國內開啟pip下載加速:https://developer.aliyun.com/mirror/pypi?spm=a2c6h.13651102.0.0.3e221b11i6opDK

[root@linux-test-no ~]# mkdir ~/.pip/
[root@linux-test-no ~]# cat > ~/.pip/pip.conf << 'EOF'
> [global]
> index-url = https://mirrors.aliyun.com/pypi/simple/
> [install]
> trusted-host=mirrors.aliyun.com
> EOF

 2.編排啟動容器

1.創建文件目錄

#目錄可以在任意目錄, 推薦放在有意義的位置。
[root@linux-test-no ~]# mkdir /opt/my_wordpress/
[root@linux-test-no ~]# cd /opt/my_wordpress/
[root@linux-test-no my_wordpress]# 

2.編寫編排文件啟動單個容器

#編排文件是一個 yml 格式的配置文件,因此要嚴格注意前后的縮進和格式,不然通過編排文件啟動容器的時候會有各種問題。 
[root@linux-test-no my_wordpress]# vim docker-compose.yml web1: #這里是填容器的id,每一個容器都可以設自己的id image: nginx:latest #這里寫鏡像名,表示從哪個鏡像啟動,如果鏡像本地不存在,會自動去倉庫拉 expose: #這里表示開放什么端口,這里可寫可不寫,對應下面的prots。 - 80 - 443 volumes: #這里表示掛載數據卷 - /iflytek/data1:/usr/share/nginx/html restart: always
container_name: nginx-web1 #這里指定啟動后的容器名 ports: #這里表示映射的端口號
- "80:80" - "443:443" [root@linux-test-no my_wordpress]# cat /iflytek/data1/index.html #這里准備測試web界面 test1
[root@linux-test-no my_wordpress]# docker-compose up #通過docker-compose文件前台啟動容器,如果想后台的話,只需執行docker-compose up -d,還有啟動命令一定要在
docker-compose文件所在目錄執行

#剛剛因為我們是前台啟動的,所以我們這里重新開一個端口看容器是否啟動和測試web能否訪問,結果如下,我們發現docker-compose啟動成功
[root@linux-test-no ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                      NAMES
1f2919530ece        nginx:latest        "/docker-entrypoint.…"   14 minutes ago      Up 14 minutes       0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   nginx-web1
996e778baea4        registry            "/entrypoint.sh /etc…"   28 hours ago        Up 28 hours         0.0.0.0:5000->5000/tcp                     musing_yalow
[root@linux-test-no ~]# curl 172.31.46.38:80
test1

3.編寫編排文件啟動多個容器

#編排文件如下,通過下面我們看出,啟動幾個容器,就寫幾個容器ID名就行了,然后在容器ID下面寫上你自己啟動時要配置的參數
[root@linux-test-no my_wordpress]# vim docker-compose.yml web1: image: nginx:latest expose: - 80 - 443 volumes: - /iflytek/data1:/usr/share/nginx/html restart: always container_name: nginx-web1 ports: - "80:80" - "443:443" web2: image: nginx:latest expose: - 80 - 443 volumes: - /iflytek/data2:/usr/share/nginx/html restart: always container_name: nginx-web2 ports: - "81:80" - "4443:443" [root@linux-test-no my_wordpress]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 996e778baea4 registry "/entrypoint.sh /etc…" 28 hours ago Up 28 hours [root@linux-test-no my_wordpress]# cat /iflytek/data2/index.html test2.web2
#通過docker-compose編排文件后台啟動容器
[root@linux-test-no my_wordpress]# docker-compose up -d
#測試發現docker-compose編排文件啟動多容器成功。
[root@linux-test-no my_wordpress]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                       NAMES
0b55534de6da        nginx:latest        "/docker-entrypoint.…"   44 seconds ago      Up 42 seconds       0.0.0.0:81->80/tcp, 0.0.0.0:4443->443/tcp   nginx-web2
187305da8f7a        nginx:latest        "/docker-entrypoint.…"   44 seconds ago      Up 42 seconds       0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp    nginx-web1
996e778baea4        registry            "/entrypoint.sh /etc…"   29 hours ago        Up 29 hours         0.0.0.0:5000->5000/tcp                      musing_yalow
[root@linux-test-no my_wordpress]# curl 172.31.46.38:80
test1
[root@linux-test-no my_wordpress]# curl 172.31.46.38:81
test2.web2

11.Docker鏡像加速配置

國內下載國外的鏡像有時候會很慢,因此可以更改 docker 配置文件添加一個加
速器, 可以通過加速器達到加速下載鏡像的目的。

1.獲取加速地址

瀏覽器打開 http://cr.console.aliyun.com, 注冊或登錄阿里雲賬號,點擊左側的
鏡像加速器, 將會得到一個專屬的加速地址, 而且下面有使用配置說明:

2.生成配置文件

 

按阿里官方的操作手冊,我們在本地生成配置文件

[root@gitlab ~]# mkdir -p /etc/docker
[root@gitlab ~]# sudo tee /etc/docker/daemon.json <<-'EOF'
> {
>   "registry-mirrors": ["https://9l7fbd59.mirror.aliyuncs.com"]
> }
> EOF
{
  "registry-mirrors": ["https://9l7fbd59.mirror.aliyuncs.com"]
}
[root@gitlab ~]# cat /etc/docker/daemon.json 
{
  "registry-mirrors": ["https://9l7fbd59.mirror.aliyuncs.com"]
}

3.重啟docker服務

[root@gitlab ~]# systemctl daemon-reload
[root@gitlab ~]# systemctl restart docker

12.Docker網絡類型

docker的默認邏輯網絡圖如下

 

 

 

Docker 服務安裝完成之后,默認在每個宿主機會生成一個名稱為 docker0 的網卡
IP 地址都是 172.17.0.1/16,並且會生成三種不能類型的網絡,如下

[root@gitlab ~]# ifconfig docker0
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:4b:88:44:4e  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0 #這個命令是看容器的網絡列表的
[root@gitlab
~]# docker network ls NETWORK ID NAME DRIVER SCOPE 17d7ac9c1b55 bridge bridge local 8391899dee5d host host local 3aa485e206ff none null local

1.docker的網絡類型

 

Bridge默認docker網絡隔離基於網絡命名空間,在物理機上創建docker容器時會為每一個docker容器分配網絡命名空間,並且把容器IP橋接到物理機的虛擬網橋上。

 

Network

其實在docker 1.9版本之后,新增了一個網絡類型network(用戶自定義網絡),可以使用docker network create創建

允許容器使用第三方的網絡實現或者創建單獨的bridge網絡,提供網絡隔離能力。這個我們有需要的時候講解。

這些網絡模式在相互網絡通信方面的對比如下所示:

 

 

南北向通信指容器與宿主機外界的訪問機制,東西向流量指同一宿主機上,與其他容器相互訪問的機制。

2.為容器配置none類型網絡(就是不為容器配置網絡功能)

此模式下創建容器是不會為容器配置任何網絡參數的,如:容器網卡、IP、通信路由等,全部需要自己去配置,所以極少使用。

#指定容器啟動時用的網絡類型是需在啟動參數里加上--net=后面跟你要指定的類型網絡
[root@linux-test-no ~]# docker run -it --name net_none --net=none centos:latest /bin/bash #驗證,我們剛剛指定了none類型網絡,我們現在進容器發現容器中並沒有配置任何網絡功能。
[root@b61605f1ceb5
/]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever

3.為容器配置Container類型網絡(就是與其他容器共享網絡配置)

邏輯圖如下:

 

 

 此模式和host模式很類似,只是此模式創建容器共享的是其他容器的IP和端口而不是物理機,此模式容器自身是不會配置網絡和端口,創建此模式容器進去后,你會發現里邊的IP是你所指定的那個容器IP並且端口也是共享的,因此這個容器的端口不能和被指定容器的端口沖突, 但是新容器其它還是互相隔離的,如進程等。

 

#起一個測試的被共享網絡的測試容器。
[root@linux-test-no ~]# docker run -it -d --name test1 centos:latest /bin/bash 556135e167bd6849ff98ee23e2eab079245a1f0baeb16d76a67cf98970461a38 [root@linux-test-no ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 556135e167bd centos:latest "/bin/bash" 8 seconds ago Up 7 seconds test1 [root@linux-test-no ~]# docker exec -it test1 /bin/bash #查看網絡配置
[root@556135e167bd
/]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 122: eth0@if123: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever #起一個Container類型網絡的容器,格式為--net=container:后面跟你要指定的容器名或容器ID
[root@linux-test-no ~]# docker run -it -d --name net_container --net=container:test1 centos:latest /bin/bash 3868b33234b30acdde241abe2fe48990d187813e4239f38cc58e9c79c292b5ff [root@linux-test-no ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3868b33234b3 centos:latest "/bin/bash" 3 seconds ago Up 3 seconds net_container 556135e167bd centos:latest "/bin/bash" 9 minutes ago Up 9 minutes test1 [root@linux-test-no ~]# docker exec -it net_container /bin/bash #查看網絡配置是否和測試容器一樣
[root@556135e167bd
/]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 122: eth0@if123: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever

 

4.Host類型網絡(使用宿主機網絡)

網絡邏輯圖如下:

 

 

啟動的容器如果指定了使用 host 模式,那么新創建的容器不會創建自己的虛擬
網卡,而是直接使用宿主機的網卡和
IP 地址, 因此在容器里面查看到的 IP 信息
就是宿主機的信息,訪問容器的時候直接使用宿主機
IP+容器端口即可,不過容
器的其他資源們必須文件系統、 系統進程等還是和宿主機保持隔離。
此模式的網絡性能最高,但是各容器之間端口不能相同, 適用於運行容器端口比
較固定的業務。

這個模式認為是不安全的

#我們先看一下宿主機的網絡配置
[root@linux-test-no ~]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether fa:16:3e:75:0f:be brd ff:ff:ff:ff:ff:ff inet 172.31.46.38/24 brd 172.31.46.255 scope global dynamic eth0 valid_lft 39286sec preferred_lft 39286sec inet6 fe80::f816:3eff:fe75:fbe/64 scope link valid_lft forever preferred_lft forever 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP link/ether 02:42:62:93:42:75 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:62ff:fe93:4275/64 scope link valid_lft forever preferred_lft forever 123: veth38cafa1@if122: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP link/ether 86:33:44:5f:8f:bb brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet6 fe80::8433:44ff:fe5f:8fbb/64 scope link valid_lft forever preferred_lft forever #看下宿主機的系統,等下有用
[root@linux
-test-no ~]# cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) #啟動一個host類型網絡的容器,啟動格式為加一個啟動參數--net=host
[root@linux
-test-no ~]# docker run -it --name net_host --net=host centos:latest /bin/bash #我們現在已經進容器了,看網絡配置,和宿主機一樣。這里可能會有人問,你這明明在宿主機上,怎么講進容器了,我們看下面
[root@linux
-test-no /]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether fa:16:3e:75:0f:be brd ff:ff:ff:ff:ff:ff inet 172.31.46.38/24 brd 172.31.46.255 scope global dynamic eth0 valid_lft 39175sec preferred_lft 39175sec inet6 fe80::f816:3eff:fe75:fbe/64 scope link valid_lft forever preferred_lft forever 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:62:93:42:75 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:62ff:fe93:4275/64 scope link valid_lft forever preferred_lft forever 123: veth38cafa1@if122: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether 86:33:44:5f:8f:bb brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet6 fe80::8433:44ff:fe5f:8fbb/64 scope link valid_lft forever preferred_lft forever #看到這里我們發現,我們是進到容器里了,因為宿主機系統和容器系統不一樣。出現這樣的原因是我們啟動的時候指定的是host類型網絡,這是host類型網絡的特性
[root@linux
-test-no /]# cat /etc/redhat-release CentOS Linux release 8.2.2004 (Core)

13.容器間的互聯

容器的連接(linking)系統是除了端口映射外,另一種跟容器中應用交互的方式。

該系統會在源和接收容器之間創建一個隧道,接收容器可以看到源容器指定的信息。

容器間的互聯分為單主機容器上的相互通信,和跨主機的容器相互通信

1.同宿主機下不同容器間的容器名互聯

同宿主機下不同容器間的互聯,很多博客采用docker run --link的方式進行,下面我來進行演示。

docker run --link可以用來鏈接2個容器,使得源容器(被鏈接的容器)和接收容器(主動去鏈接的容器)之間可以通過容器名或者別名通信,並且接收容器可以獲取源容器的一些數據,如源容器的環境變量。

--link的格式:

--link <name or id>:alias

其中,name和id是源容器的name和id,alias是源容器在link下的別名。

別名的作用就是自定義的容器名稱可能后期會發生變化,那么一旦名稱發生變化,程序之間也要隨之發生變化,比如程序通過容器名稱進行服務調用,但是容器名稱發生變化之后再使用之前的名稱肯定是無法成功調用,每次都進行更改的話又比較麻煩, 因此可以使用自定義別名的方式解決,即容器名稱可以隨意更改,只要不更改別名即可

[root@linux-test-no ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
#創建並啟動測試源容器test1
[root@linux-test-no ~]# docker run -d -it --name test1 centos:6.8
655769f1e67fb292111837508f798beec2d07926e5cb65d0048420a3566e028c
[root@linux-test-no ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
655769f1e67f        centos:6.8          "/bin/bash"         6 minutes ago       Up 6 minutes                            test1
#創建並啟動名為test2的接收容器,並把該容器和名為test1,別名設為test1.1的容器鏈接起來。其中test1是源容器名,test1.1是我們為源容器設的別名。 接收容器可以通過源容器名或者源容器的別名進行鏈接
[root@linux-test-no ~]# docker run -t -i --name test2 --link test1:test1.1 centos:6.8 /bin/bash
#測試發現接收容器可以通過源容器名進行鏈接。
[root@4a7a77ebc5e7 /]# ping test1
PING test1.1 (172.17.0.2) 56(84) bytes of data.
64 bytes from test1.1 (172.17.0.2): icmp_seq=1 ttl=64 time=0.484 ms
64 bytes from test1.1 (172.17.0.2): icmp_seq=2 ttl=64 time=0.060 ms
64 bytes from test1.1 (172.17.0.2): icmp_seq=3 ttl=64 time=0.078 ms
64 bytes from test1.1 (172.17.0.2): icmp_seq=4 ttl=64 time=0.070 ms
^C
--- test1.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3167ms
rtt min/avg/max/mdev = 0.060/0.173/0.484/0.179 ms
#測試發現接收容器可以通過別名進行鏈接。
[root@4a7a77ebc5e7 /]# ping test1.1
PING test1.1 (172.17.0.2) 56(84) bytes of data.
64 bytes from test1.1 (172.17.0.2): icmp_seq=1 ttl=64 time=0.087 ms
64 bytes from test1.1 (172.17.0.2): icmp_seq=2 ttl=64 time=0.085 ms
#查看接收容器的地址為172.17.0.3
[root@4a7a77ebc5e7 /]# ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:03  
          inet addr:172.17.0.3  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:648 (648.0 b)  TX bytes:0 (0.0 b)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1 
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)


[root@linux-test-no ~]# docker exec -it test1 /bin/bash
#查看源容器的為172.17.0.2,由此確認,通過link鏈接后,接收容器可以通過容器名和別名鏈接源容器
[root@655769f1e67f /]# ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:17 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:1362 (1.3 KiB)  TX bytes:672 (672.0 b)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1 
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)
#從下面的結果我們看出,源容器無法通過容器名去連接接收容器。
[root@655769f1e67f
/]# ping test2 ping: unknown host test2 #源容器可以通過地址和接收容器鏈接 [root@655769f1e67f /]# ping 172.17.0.3 PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data. 64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.476 ms 64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.054 ms 64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.061 ms
從上面我們的測試,我們看出在--link標簽下,接收容器就是通過設置環境變量和更新接收容器的/etc/hosts文件來獲取源容器的信息,並與之建立通信和傳遞數據的。
也就是--link其實就是替我們做了一個host映射。
但是這個有一個弊端,就是通過--link,實現的容器名連接,只是單向的,而不是雙向的(但是如果你兩邊都執行一下--link也能實現雙向容器名連接),但是這個比較
繁瑣,與其說這是--link的弊端,不如講是默認網絡類型bridge(docker0)的一個弊端。如果我們想實現容器名雙向連接,可以參考下面的自定義網絡(同宿主機下不同
容器間的互聯)

2.自定義bridge類型網絡(同宿主機下不同容器之間容器名互聯)

操作如下。

[root@linux-test-no ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
76f868577929        bridge              bridge              local
79232f7835db        host                host                local
58d353d474cd        none                null                local
#使用下面的命令在宿主機上創建名為mynet的bridge網絡。 --drivwe指定創建的網絡類型為什么,也可以直接寫成-d,類似於加了一個什么網絡驅動。
--subnet 指定mynet網絡所在的網絡,一般填寫宿主機所在的網絡,不強制,--gateway指定網關,一般為宿主機網關,不強制。
[root@linux-test-no ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet 
f63927707f46915214e4eec31b728703fa20fcacc4fbf3c485e9b0a2a58b87d9
#驗證一下網絡是不是創建成功。
[root@linux
-test-no ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
76f868577929 bridge bridge local
79232f7835db host host local
f63927707f46 mynet bridge local
58d353d474cd none
null local

以上我們就解決了,我們上面講的弊端(默認bridge網絡,無法實現同宿主機下容器間通過容器名的互聯的問題)。下面我們來驗證一下

#通過--net選項可以指定我們創建的容器使用什么網絡,默認我們不指定的話,這里是指定bridge。
[root@linux-test-no ~]# docker run -d -it --name test1 --net mynet centos 221e5c7e687cf9e44d8ed48048616bdbb4bc10476195e8c648dce00512fb7b61 [root@linux-test-no ~]# docker run -d -it --name test2 --net mynet centos 9c7fbe8951240df4a7f0975c5a19961ed001aea347e417c727078c31e08c1c22 [root@linux-test-no ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9c7fbe895124 centos "/bin/bash" 10 seconds ago Up 10 seconds test2 221e5c7e687c centos "/bin/bash" 17 seconds ago Up 16 seconds test1 [root@linux-test-no ~]# docker exec -it test1 /bin/bash [root@221e5c7e687c /]# ping test2 PING test2 (192.168.0.3) 56(84) bytes of data. 64 bytes from test2.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.101 ms 64 bytes from test2.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.079 ms ^C --- test2 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1ms rtt min/avg/max/mdev = 0.079/0.090/0.101/0.011 ms [root@221e5c7e687c /]# exit exit [root@linux-test-no ~]# docker exec -it test2 /bin/bash [root@9c7fbe895124 /]# ping test1 PING test1 (192.168.0.2) 56(84) bytes of data. 64 bytes from test1.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.048 ms 64 bytes from test1.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.085 ms ^C --- test1 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1000ms rtt min/avg/max/mdev = 0.048/0.066/0.085/0.020 ms

 

3.Docker跨主機通信之macvlan(一般用的比較少)

macvlan的邏輯圖如下

 我們這里測試在兩台宿主機上進行容器通過macvlan的鏈接的測試

#以下操作是在宿主機1上做的
#使用下面的命令在宿主機上創建名為mcv1的macvlan網絡。 -d指定創建的網絡類型為什么,類似於加了一個什么網絡驅動。
--subnet 指定macvlan網絡所在的網絡,一般填寫宿主機所在的網絡,--gateway指定網關,一般為宿主機網關。-o parent指定用來分配macvlan網絡的物理網卡,因為macvlan創建的時候,

需要關聯一個物理網卡才行。
[root@linux-test-no ~]# docker network create -d macvlan --subnet 172.31.46.0/24 --gateway 172.31.46.1 -o parent=eth0 mcv1 ceede34b513e7e1e5376e7f0b4ac90ef591467558a188d1035d8dd1060bc777f #查看我們的docker網絡類型,發現生成了一個macvlan類型網絡的macv1。
[root@linux
-test-no ~]# docker network ls NETWORK ID NAME DRIVER SCOPE e6d919586ae3 bridge bridge local 79232f7835db host host local ceede34b513e mcv1 macvlan local 58d353d474cd none null local #這里我們還需要把我們macvlan關聯的物理網卡開啟混雜模式,不然可能出現ping不通的情況。
混雜模式(Promiscuous Mode)是指一台機器能夠接收所有經過它的數據流,而不論其目的地址是否是他
[root@linux
-test-no ~]# ip link set eth0 promisc on #啟動一個容器c1,通過--network指定使用什么類型網絡,我們這里是名為mcv1的macvlan類型網絡。--ip指定容器內的地址,防止容器地址自動分配,導致沖突
[root@linux
-test-no ~]# docker run -itd --name c1 --ip=172.31.46.101 --network mcv1 centos:latest 489ad6f309b9772d7327ccf732f3c3575a43390ac02a0a18ac1be12c76faae77 [root@linux-test-no ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 489ad6f309b9 centos:latest "/bin/bash" 43 seconds ago Up 42 seconds c1 3868b33234b3 centos:latest "/bin/bash" 39 hours ago Up 39 hours net_container 556135e167bd centos:latest "/bin/bash" 39 hours ago Up 39 hours test1 #我們進到我們剛剛創建的容器中,查看地址是否是我們指定的
[root@linux
-test-no ~]# docker exec -it c1 /bin/bash [root@489ad6f309b9 /]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 124: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default link/ether 02:42:ac:1f:2e:65 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.31.46.101/24 brd 172.31.46.255 scope global eth0 valid_lft forever preferred_lft forever #以下操作是在宿主機2上進行的操作
#這里執行的步驟和宿主機1上一樣,也是類似起一個macvlan的驅動。驅動名要和宿主機1一樣都指定成mcv1

[root@gitlab
~]# docker network create -d macvlan --subnet 172.31.46.0/24 --gateway 172.31.46.1 -o parent=eth0 mcv1 f0e34200bed181a1a626bc3a214f86111ab87fbb8d5ed37f6948a1685d4190f8 [root@gitlab ~]# docker network ls NETWORK ID NAME DRIVER SCOPE b25338243647 bridge bridge local 8391899dee5d host host local f0e34200bed1 mcv1 macvlan local 3aa485e206ff none null local #然后我們這里把我們在宿主機2上配置了macvlan驅動的物理網卡設為混雜模式,從上面我們看出,我們起macvlan驅動的時候,指定的是eth0網卡
[root@gitlab
~]# ip link set eth0 promisc on #啟動一個容器C2,指定我們要使用的名為mcv1的macvlan類型網絡,這里因為我們是要和宿主機1下的c1容器通信,所以我們要在一個macvlan通道macv1下。
[root@gitlab
~]# docker run -itd --name c2 --ip=172.31.46.102 --network mcv1 centos:latest 5659b8fd85155a1d35f423597eb90658c5fe6e6ebab737980894babca336219a [root@gitlab ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5659b8fd8515 centos:latest "/bin/bash" 2 seconds ago Up 1 second c2 [root@gitlab ~]# docker exec -it c2 /bin/bash [root@5659b8fd8515 /]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 5: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default link/ether 02:42:ac:1f:2e:66 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.31.46.102/24 brd 172.31.46.255 scope global eth0 valid_lft forever preferred_lft forever

 

 

 

 

 

 

使用--filter dangling=true 過濾 不在使用的數據卷

---------------------
本文著作權歸作者所有。
商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
來源地址:https://www.php.cn/docker/456656.html
來源:php中文網(www.php.cn)
© 版權聲明:轉載請附上原文鏈接!

 


免責聲明!

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



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