Docker-從安裝到卸載1.0

Docker

一、簡介

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

一個完整的Docker有以下幾個部分組成:

1. DockerClient客戶端

2. Docker Daemon守護進程

3. Docker Image鏡像

4. DockerContainer容器

Docker 架構

Docker 使用客戶端-服務器 (C/S) 架構模式,使用遠程API來管理和創建Docker容器。Docker 容器通過 Docker 鏡像來創建。容器與鏡像的關係類似於面向對象編程中的對象與類。

 

 

Docker採用 C/S架構 Docker daemon 作爲服務端接受來自客戶的請求,並處理這些請求(創建、運行、分發容器)。 客戶端和服務端既可以運行在一個機器上,也可通過 socket 或者RESTful API 來進行通信。

Docker daemon 一般在宿主主機後臺運行,等待接收來自客戶端的消息。 Docker 客戶端則爲用戶提供一系列可執行命令,用戶用這些命令實現跟 Docker daemon 交互。

核心概念

l 鏡像(image)

Docker 鏡像(Image)就是一個只讀的模板。例如:一個鏡像可以包含一個完整的操作系統環境,裏面僅安裝了 Apache 或用戶需要的其它應用程序。鏡像可以用來創建 Docker 容器,一個鏡像可以創建很多容器。Docker 提供了一個很簡單的機制來創建鏡像或者更新現有的鏡像,用戶甚至可以直接從其他人那裏下載一個已經做好的鏡像來直接使用。

鏡像(Image)就是一堆只讀層(read-only layer)的統一視角,也許這個定義有些難以理解,看看下面這張圖:

 

右邊我們看到了多個只讀層,它們重疊在一起。除了最下面一層,其它層都會有一個指針指向下一層。這些層是Docker內部的實現細節,並且能夠在docker宿主機的文件系統上訪問到。統一文件系統 (Union File System)技術能夠將不同的層整合成一個文件系統,爲這些層提供了一個統一的視角,這樣就隱藏了多層的存在,在用戶的角度看來,只存在一個文件系統。

 

l 倉庫(repository)

倉庫(Repository)是集中存放鏡像文件的場所。有時候會把倉庫和倉庫註冊服務器(Registry)混爲一談,並不嚴格區分。實際上,倉庫註冊服務器上往往存放着多個倉庫,每個倉庫中又包含了多個鏡像,每個鏡像有不同的標籤(tag)。

倉庫分爲公開倉庫(Public)和私有倉庫(Private)兩種形式。最大的公開倉庫是 Docker Hub,存放了數量龐大的鏡像供用戶下載。國內的公開倉庫包括 時速雲 、網易雲 等,可以提供大陸用戶更穩定快速的訪問。當然,用戶也可以在本地網絡內創建一個私有倉庫。

當用戶創建了自己的鏡像之後就可以使用 push 命令將它上傳到公有或者私有倉庫,這樣下次在另外一臺機器上使用這個鏡像時候,只需要從倉庫上 pull 下來就可以了。

Docker 倉庫的概念跟 Git 類似,註冊服務器可以理解爲 GitHub 這樣的託管服務。

 

l 容器(container)

Docker 利用容器(Container)來運行應用。容器是從鏡像創建的運行實例。它可以被啓動、開始、停止、刪除。每個容器都是相互隔離的、保證安全的平臺。可以把容器看做是一個簡易版的 Linux 環境(包括root用戶權限、進程空間、用戶空間和網絡空間等)和運行在其中的應用程序。

容器的定義和鏡像幾乎一模一樣,也是一堆層的統一視角,唯一區別在於容器的最上面那一層是可讀可寫的。

 

一個運行態容器被定義爲一個可讀寫的統一文件系統加上隔離的進程空間和包含其中的進程。下面這張圖片展示了一個運行中的容器。

 

正是文件系統隔離技術使得Docker成爲了一個非常有潛力的虛擬化技術。一個容器中的進程可能會對文件進行修改、刪除、創建,這些改變都將作用於可讀寫層。

 

優勢

作爲一種新興的虛擬化方式,Docker 跟傳統的虛擬化方式相比具有衆多的優勢。

Docker 在如下幾個方面具有較大的優勢:

l 更快速的交付和部署

Docker在整個開發週期都可以完美的輔助你實現快速交付。Docker允許開發者在裝有應用和服務本地容器做開發。可以直接集成到可持續開發流程中。

例如:開發者可以使用一個標準的鏡像來構建一套開發容器,開發完成之後,運維人員可以直接使用這個容器來部署代碼。 Docker 可以快速創建容器,快速迭代應用程序,並讓整個過程全程可見,使團隊中的其他成員更容易理解應用程序是如何創建和工作的。 Docker 容器很輕很快!容器的啓動時間是秒級的,大量地節約開發、測試、部署的時間。

l 高效的部署和擴容

Docker 容器幾乎可以在任意的平臺上運行,包括物理機、虛擬機、公有云、私有云、個人電腦、服務器等。 這種兼容性可以讓用戶把一個應用程序從一個平臺直接遷移到另外一個。

Docker的兼容性和輕量特性可以很輕鬆的實現負載的動態管理。你可以快速擴容或方便的下線的你的應用和服務,這種速度趨近實時。

l 更高的資源利用率

Docker 對系統資源的利用率很高,一臺主機上可以同時運行數千個 Docker 容器。容器除了運行其中應用外,基本不消耗額外的系統資源,使得應用的性能很高,同時系統的開銷儘量小。傳統虛擬機方式運行 10 個不同的應用就要起 10 個虛擬機,而Docker 只需要啓動 10 個隔離的應用即可。

l 更簡單的管理

使用 Docker,只需要小小的修改,就可以替代以往大量的更新工作。所有的修改都以增量的方式被分發和更新,從而實現自動化並且高效的管理。

 

侷限

Docker並不是全能的,設計之初也不是KVM之類虛擬化手段的替代品,簡單總結幾點:

l Docker是基於Linux 64bit的,無法在32bit的linux/Windows/unix環境下使用

l LXC是基於cgroup等linux kernel功能的,因此container的guest系統只能是linux base的

l 隔離性相比KVM之類的虛擬化方案還是有些欠缺,所有container公用一部分的運行庫

l 網絡管理相對簡單,主要是基於namespace隔離

l cgroup的cpu和cpuset提供的cpu功能相比KVM的等虛擬化方案相比難以度量(所以dotcloud主要是按內存收費)

l Docker對disk的管理比較有限

l container隨着用戶進程的停止而銷燬,container中的log等用戶數據不便收集

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

二、安裝部署(以centos7爲例)

u 在線安裝

1. Docker 要求 CentOS 系統的內核版本高於 3.10 ,查看本頁面的前提條件來驗證你的CentOS 版本是否支持 Docker 。

通過 uname -r 命令查看你當前的內核版本

2. 使用root權限登錄 Centos。確保 yum 包更新到最新。

sudo yum update

3. 卸載舊版本(如果安裝過舊版本的話)

sudo yum remove docker docker-common docker-selinux docker-engine

4. 安裝需要的軟件包, yum-util 提供yum-config-manager功能,另外兩個是devicemapper驅動依賴的

sudo yum install -y yum-utils device-mapper-persistent-data lvm2

更新國內源(需要的話)

一、備份
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup

二、下載新的CentOS-Base.repo 到/etc/yum.repos.d/
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo

或者

curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo

三、之後運行yum makecache生成緩存

5. 設置yum

 sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

6. 安裝docker

sudo yum install docker-ce  #由於repo中默認只開啓stable倉庫,故這裏安裝的是最新穩定版

sudo yum install <FQPN>   #例如:sudo yum install docker-ce-17.12.0.ce

7. 啓動並加入開機啓動

sudo systemctl start docker  #啓動docker

sudo systemctl enable docker  #加入開機啓動

8. 驗證安裝是否成功(clientservice兩部分表示docker安裝啓動都成功了)

docker version

 

u 離線安裝

1. 下載docker安裝包和相關依賴

地址:https://download.docker.com/linux/centos/7/x86_64/stable/Packages/

docker-ce-18.09.2-3.el7.x86_64.rpm

docker-ce-cli-18.09.2-3.el7.x86_64.rpm

audit-libs-python-2.8.4-4.el7.x86_64.rpm

checkpolicy-2.5-8.el7.x86_64.rpm

containerd.io-1.2.2-3.el7.x86_64.rpm

container-selinux-2.9-4.el7.noarch.rpm

libcgroup-0.41-20.el7.x86_64.rpm

libsemanage-python-2.5-14.el7.x86_64.rpm

libtool-ltdl-2.4.2-22.el7_3.x86_64.rpm

policycoreutils-python-2.5-29.el7.x86_64.rpm

python-IPy-0.75-6.el7.noarch.rpm

setools-libs-3.3.8-4.el7.x86_64.rpm

2. docker安裝包和相關依賴上傳到服務器上(Centos7)

3. 安裝所有包rpm -ivh * --nodeps --force

4. 啓動並加入開機啓動

systemctl enable docker

systemctl start docker

5. 驗證安裝是否成功docker version

 

三、操作

u 命令

容器操作:

docker create  #創建一個容器但是不啓動它
docker run  #創建並啓動一個容器
docker stop  #停止容器運行,發送信號SIGTERM
docker start  #啓動一個停止狀態的容器
docker restart  #重啓一個容器
docker rm  #刪除一個容器
docker kill  #發送信號給容器,默認SIGKILL
docker attach  #連接(進入)到一個正在運行的容器
docker wait  #阻塞一個容器,直到容器停止運行

獲取容器信息:

docker ps  #顯示狀態爲運行(Up)的容器
docker ps -a  #顯示所有容器,包括運行中(Up)的和退出的(Exited)
docker inspect  #深入容器內部獲取容器所有信息
docker logs  #查看容器的日誌(stdout/stderr)
docker events  #得到docker服務器的實時的事件
docker port  #顯示容器的端口映射
docker top  #顯示容器的進程信息
docker diff  #顯示容器文件系統的前後變化

導出容器:

docker cp  #從容器裏向外拷貝文件或目錄
docker export  #將容器整個文件系統導出爲一個tar包,不帶layerstag等信息

執行:

docker exec  #在容器裏執行一個命令,可以執行bash進入交互式

鏡像操作:

docker images  #顯示本地所有的鏡像列表
docker import  #從一個tar包創建一個鏡像,往往和export結合使用
docker build  #使用Dockerfile創建鏡像(推薦)
docker commit  #從容器創建鏡像
docker rmi  #刪除一個鏡像
docker load  #從一個tar包創建一個鏡像,和save配合使用
docker save  #將一個鏡像保存爲一個tar包,帶layerstag信息
docker history  #顯示生成一個鏡像的歷史命令
docker tag  #爲鏡像起一個別名 

鏡像倉庫(registry)操作:

docker login  #登錄到一個registry
docker search  #registry倉庫搜索鏡像
docker pull  #從倉庫下載鏡像到本地
docker push  #將一個鏡像pushregistry倉庫中 

 

Docker的常用命令

 

u 鏡像(image)

1)Dockerfile詳解

 

Dockerfile的指令是忽略大小寫的,建議使用大寫,使用 # 作爲註釋,每一行只支持一條指令,每條指令可以攜帶多個參數。

Dockerfile的指令根據作用可以分爲兩種,構建指令和設置指令。

構建指令:用於構建image,其指定的操作不會在運行image的容器上執行;

設置指令:用於設置image的屬性,其指定的操作將在運行image的容器中執行。

 

l FROM(指定基礎image)

 

構建指令,必須指定且需要在Dockerfile其他指令的前面。後續的指令都依賴於該指令指定的image。FROM指令指定的基礎image可以是官方遠程倉庫中的,也可以位於本地倉庫。

該指令有兩種格式:

FROM <image>                  #指定基礎image爲該image的最後修改的版本

FROM <image>:<tag>              #指定基礎image爲該image的一個tag版本。

 

 

l MAINTAINER(用來指定鏡像創建者信息)

 

構建指令,用於將image的製作者相關的信息寫入到image中。當我們對該image執行docker inspect命令時,輸出中有相應的字段記錄該信息。

MAINTAINER <name> 

 

l RUN(安裝軟件用)

 

構建指令,RUN可以運行任何被基礎image支持的命令。如基礎image選擇了Ubuntu,那麼軟件管理部分只能使用ubuntu的命令。

RUN <command> (the command is run in a shell - `/bin/sh -c`) 
RUN ["executable", "param1", "param2" ... ]  (exec form) 

 

l CMD(設置container啓動時執行的操作)

 

設置指令,用於container啓動時指定的操作。該操作可以是執行自定義腳本,也可以是執行系統命令。該指令只能在文件中存在一次,如果有多個,則只執行最後一條。

CMD ["executable","param1","param2"] (like an exec, this is the preferred form) 
CMD command param1 param2 (as a shell)

ENTRYPOINT指定的是一個可執行的腳本或者程序的路徑,該指定的腳本或者程序將會以param1和param2作爲參數執行。所以如果CMD指令使用上面的形式,那麼Dockerfile中必須要有配套的ENTRYPOINT。當Dockerfile指定了ENTRYPOINT,那麼使用下面的格式:

CMD ["param1","param2"] (as default parameters to ENTRYPOINT) 

 

l ENTRYPOINT(設置container啓動時執行的操作)

 

設置指令,指定容器啓動時執行的命令,可以多次設置,但是隻有最後一個有效。

ENTRYPOINT ["executable", "param1", "param2"] (like an exec, the preferred form) 
ENTRYPOINT command param1 param2 (as a shell) 

該指令的使用分爲兩種情況,一種是獨自使用,另一種和CMD指令配合使用。
當獨自使用時,如果你還使用了CMD命令且CMD是一個完整的可執行的命令,那麼CMD指令和ENTRYPOINT會互相覆蓋只有最後一個CMD或者ENTRYPOINT有效。

# CMD指令將不會被執行,只有ENTRYPOINT指令被執行 
CMD echo “Hello, World!” 
ENTRYPOINT ls -l 

另一種用法和CMD指令配合使用來指定ENTRYPOINT的默認參數,這時CMD指令不是一個完整的可執行命令,僅僅是參數部分;ENTRYPOINT指令只能使用JSON方式指定執行命令,而不能指定參數。

FROM ubuntu 
CMD ["-l"] 
ENTRYPOINT ["/usr/bin/ls"] 

 

l USER(設置container容器的用戶)

 

設置指令,設置啓動容器的用戶,默認是root用戶

# 指定memcached的運行用戶 
ENTRYPOINT ["memcached"] 
USER daemon 
 
ENTRYPOINT ["memcached", "-u", "daemon"] 

 

l EXPOSE(指定容器需要映射到宿主機器的端口)

 

設置指令,該指令會將容器中的端口映射成宿主機器中的某個端口。當你需要訪問容器的時候,可以不是用容器的IP地址而是使用宿主機器的IP地址和映射後的端口。要完成整個操作需要兩個步驟,首先在Dockerfile使用EXPOSE設置需要映射的容器端口,然後在運行容器的時候指定-p選項加上EXPOSE設置的端口,這樣EXPOSE設置的端口號會被隨機映射成宿主機器中的一個端口號。也可以指定需要映射到宿主機器的那個端口,這時要確保宿主機器上的端口號沒有被使用。EXPOSE指令可以一次設置多個端口號,相應的運行容器的時候,可以配套的多次使用-p選項。

# 映射一個端口 
EXPOSE port1 
# 相應的運行容器使用的命令 
docker run -p port1 image 
 
# 映射多個端口 
EXPOSE port1 port2 port3 
# 相應的運行容器使用的命令 
docker run -p port1 -p port2 -p port3 image 
# 還可以指定需要映射到宿主機器上的某個端口號 
docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 image 

端口映射是docker比較重要的一個功能,原因在於我們每次運行容器的時候容器的IP地址不能指定而是在橋接網卡的地址範圍內隨機生成的。宿主機器的IP地址是固定的,我們可以將容器的端口的映射到宿主機器上的一個端口,免去每次訪問容器中的某個服務時都要查看容器的IP的地址。對於一個運行的容器,可以使用docker port加上容器中需要映射的端口和容器的ID來查看該端口號在宿主機器上的映射端口。

 

l ENV(用於設置環境變量)

 

構建指令,在image中設置一個環境變量。

ENV <key> <value> 

設置了後,後續的RUN命令都可以使用,container啓動後,可以通過docker inspect查看這個環境變量,也可以通過在docker run --env key=value時設置或修改環境變量。
假如你安裝了JAVA程序,需要設置JAVA_HOME,那麼可以在Dockerfile中這樣寫:

ENV JAVA_HOME /path/to/java/dirent

 

l ADD(從src複製文件到container的dest路徑)

 

構建指令,所有拷貝到container中的文件和文件夾權限爲0755,uid和gid爲0;如果是一個目錄,那麼會將該目錄下的所有文件添加到container中,不包括目錄;如果文件是可識別的壓縮格式,則docker會幫忙解壓縮(注意壓縮格式);如果<src>是文件且<dest>中不使用斜槓結束,則會將<dest>視爲文件,<src>的內容會寫入<dest>;如果<src>是文件且<dest>中使用斜槓結束,則會<src>文件拷貝到<dest>目錄下。

ADD <src> <dest>

<src> 是相對被構建的源目錄的相對路徑,可以是文件或目錄的路徑,也可以是一個遠程的文件url;
<dest> 是container中的絕對路徑

 

l VOLUME(指定掛載點)

 

設置指令,使容器中的一個目錄具有持久化存儲數據的功能,該目錄可以被容器本身使用,也可以共享給其他容器使用。我們知道容器使用的是AUFS,這種文件系統不能持久化數據,當容器關閉後,所有的更改都會丟失。當容器中的應用有持久化數據的需求時可以在Dockerfile中使用該指令。

FROM base 
VOLUME ["/tmp/data"] 

 

l WORKDIR(切換目錄)

 

設置指令,可以多次切換(相當於cd命令),對RUN,CMD,ENTRYPOINT生效。

 

u 容器(container)

1)網絡

同一網絡中的容器、網關之間都是可以通信的

docker提供幾種網絡,它決定容器之間和外界和容器之間如何去相互通信。

docker network ls   #查看網絡 

 

Docker進程啓動時,會在主機上創建一個名爲docker0的虛擬網橋,此主機上啓動的Docker容器會連接到這個虛擬網橋上。虛擬網橋的工作方式和物理交換機類似,這樣主機上的所有容器就通過交換機連在了一個二層網絡中。從docker0子網中分配一個IP給容器使用,並設置docker0的IP地址爲容器的默認網關。在主機上創建一對虛擬網卡veth pair設備,Docker將veth pair設備的一端放在新創建的容器中,並命名爲eth0(容器的網卡),另一端放在主機中,以vethxxx這樣類似的名字命名,並將這個網絡設備加入到docker0網橋中。

 

 

1. bridge橋接網絡

除非創建容器的時候指定網絡,不然容器就會默認的使用橋接網絡。屬於這個網絡的容器之間可以相互通信,不過外界想要訪問到這個網絡的容器呢,需使用橋接網絡,有點像主機和容器之間的一座橋,對容器有一點隔離作用。實際是在iptables做了DNAT規則,實現端口轉發功能。可以使用iptables -t nat -vnL查看。默認docker0 IP爲172.17.0.1。

 

2. host主機網絡

如果啓動容器的時候使用host模式,那麼這個容器將不會獲得一個獨立的Network Namespace,而是和宿主機共用一個Network Namespace。容器將不會虛擬出自己的網卡,配置自己的IP等,而是使用宿主機的IP和端口。但是,容器的其他方面,如文件系統、進程列表等還是和宿主機隔離的。只用這種網絡的容器會使用主機的網絡,這種網絡對外界是完全開放的,能夠訪問到主機,就能訪問到容器。

 

3. 使用none模式

Docker容器擁有自己的Network Namespace,但是,並不爲Docker容器進行任何網絡配置。也就是說,這個Docker容器沒有網卡、IP、路由等信息。需要我們自己爲Docker容器添加網卡、配置IP等。使用此種網絡的容器會完全隔離。

 

4. 使用user-defined 網絡

Docker 提供三種 user-defined 網絡驅動:bridge, overlay macvlanoverlay 和 macvlan 用於創建跨主機的網絡

 

我們可通過 bridge 驅動創建類似前面默認的 bridge 網絡(自動分配172.18.0.0/16 網段)

 

 

創建時也可以用 --subnet 和 --gateway 參數來指定網段和網關

 

 

 

刪除命令:docker network rm 網絡ID/名稱

 

 

容器要使用新的網絡,需要在啓動時通過 --network

 

 

2)Docker存儲

容器存放數據的兩種方式 storage driver  data volume

 

n storage driver方式

storage driver管理的鏡像層和容器層,即鏡像內文件系統。

對於某些容器,直接將數據放在由storage driver維護的層中是很好的選擇,比如那些無狀態的應用。無狀態意味着容器沒有需要持久化的數據,隨時可以從鏡像直接創建。比如busybox,它是一個工具箱,我們啓動busybox是爲了執行諸如wget,ping之類的命令,不需要保存數據供以後使用,使用完直接退出,容器刪除時存放在容器層中的工作數據也一起被刪除,下次再啓動新容器時又是一個乾淨如初的內部文件系統。

 

docker info | grep "Storage Driver"  #查看系統底成文件系統

Ubuntu 用的 AUFS,底層文件系統是 extfs,各層數據存放在 /var/lib/docker/aufs。

Redhat/CentOS 的默認 driver 是 Device Mapper,SUSE 則是 Btrfs。

 

這種方式存儲方式在構建鏡像過程中把數據copy在鏡像中

 

n data volume方式

² data volume 介紹

Data Volume 本質上是 Docker Host 文件系統中的目錄或文件,能夠直接被 mount 到容器的文件系統中。Data Volume 有以下特點:

    1. Data Volume 是目錄或文件,而非沒有格式化的磁盤(塊設備)。

    2. 容器可以讀寫 volume 中的數據。

    3. volume 數據可以被永久的保存,即使使用它的容器已經銷燬。

好,現在我們有數據層(鏡像層和容器層)和 volume 都可以用來存放數據,具體使用的時候要怎樣選擇呢?考慮下面幾個場景:

    1. Database 軟件 vs Database 數據

    2. Web 應用 vs 應用產生的日誌

    3. 數據分析軟件 vs input/output 數據

    4. Apache Server vs 靜態 HTML 文件

相信大家會做出這樣的選擇:

    1. 前者放在數據層中。因爲這部分內容是無狀態的,應該作爲鏡像的一部分。

    2. 後者放在 Data Volume 中。這是需要持久化的數據,並且應該與鏡像分開存放。

還有個大家可能會關心的問題:如何設置 voluem 的容量?

因爲 volume 實際上是 docker host 文件系統的一部分,所以 volume 的容量取決於文件系統當前未使用的空間,目前還沒有方法設置 volume 的容量。

 

在具體的使用上,docker 提供了兩種類型的 volume:bind mount 和 docker managed volume。

 

Ø data volume-bind mount

例如 docker host 上有目錄 $HOME/htdocs:

通過 -v 將其 mount 到 httpd 容器:

  docker run -tid -v $HOME/htdocs:/usr/local/nginx/html httpd

  [-v 的格式爲 <host path>:<container path>。

  /usr/local/apache2/htdocs 就是 apache server 存放靜態文件的地方。

  由於 /usr/local/apache2/htdocs 已經存在,原有數據會被隱藏起來,取而代之的是 host $HOME/htdocs/ 中的數據,

  這與 linux mount 命令的行爲是一致的。

  bind mount 可以讓 host 與容器共享數據。這在管理上是非常方便的.即使容器沒有了,bind mount 也還在。

  這也合理,bind mount 是 host 文件系統中的數據,只是借給容器用用,哪能隨便就刪了啊]

另外,bind mount 時還可以指定數據的讀寫權限,默認是可讀可寫,可指定爲只讀:

  docker run -tid -v $HOME/htdocs:/usr/local/nginx/html:ro httpd ro

  設置了只讀權限,在容器中是無法對 bind mount 數據進行修改的。

  只有 host 有權修改數據,提高了安全性.

 另外,bind mount 可以掛載當個文件

  [docker run -tid -v /etc/passwd:/etc/passwd httpd.

  注意:使用單一文件有一點要注意:host 中的源文件必須要存在,不然會當作一個新目錄 bind mount 給容器]

 

缺點:bind mount 的使用直觀高效,易於理解,但它也有不足的地方:

  bind mount 需要指定 host 文件系統的特定路徑,這就限制了容器的可移植性,

  當需要將容器遷移到其他 host,而該 host 沒有要 mount 的數據或者數據不在相同的路徑時,操作會失敗。

 

Ø data volume-docker managed volume

docker managed volume 與 bind mount 在使用上的最大區別是不需要指定 mount 源,指明 mount point 就行了。還是以 httpd 容器爲例:

docker run -tid -v /usr/local/nginx/html httpd

我們通 -v 告訴 docker 需要一個 data volume,並將其 mount 到 /usr/local/apache2/htdocs。那麼這個 data volume 具體在哪兒呢?

這個答案可以在容器的配置信息中找到,執行 docker inspect 容器ID命令:

"Mounts": [

    {

        "Name": "f4a0a1018968f47960efe760829e3c5738c702533d29911b01df9f18babf3340",

        "Source": "/var/lib/docker/volumes/f4a0a1018968f47960efe760829e3c5738c702533d29911b01df9f18babf3340/_data",

        "Destination": "/usr/local/apache2/htdocs",

        "Driver": "local",

        "Mode": "",

        "RW": true,

        "Propagation": ""

    }

],

docker inspect 的輸出很多,我們感興趣的是 Mounts 這部分,這裏會顯示容器當前使用的所有 data volume,包括 bind mount 和 docker managed volume。

Source 就是該 volume 在 host 上的目錄

原來,每當容器申請 mount docker manged volume 時,docker 都會在/var/lib/docker/volumes 下生成一個目錄(例子中是 "/var/lib/docker/volumes/f4a0a1018968f47960efe760829e3c5738c702533d29911b01df9f18babf3340/_data ),這個目錄就是 mount 源。

volume 的內容跟容器原有 /usr/local/apache2/htdocs 完全一樣,這是怎麼回事呢?

這是因爲:如果 mount point 指向的是已有目錄,原有數據會被複制到 volume 中。

但要明確一點:此時的 /usr/local/apache2/htdocs 已經不再是由 storage driver 管理的層數據了,它已經是一個 data volume。

我們可以像 bind mount 一樣對數據進行操作,例如更新數據 :

 

簡單回顧一下 docker managed volume 的創建過程:

1.容器啓動時,簡單的告訴 docker "我需要一個 volume 存放數據,幫我 mount 到目錄 /abc"。

2. docker 在 /var/lib/docker/volumes 中生成一個隨機目錄作爲 mount 源。

3. 如果 /abc 已經存在,則將數據複製到 mount 源,

4. 將 volume mount 到 /abc

 

對比

l 相同點:兩者都是 host 文件系統中的某個路徑。        

l 不同點

 

 

n 容器之間共享數據

² 共享host目錄

只需要將同一個host目錄掛載到不同的容器即可。

 

² volume container共享數據

volume container是專門爲其他容器提供volume的容器。它提供的卷的類型可以是bind mount,也可以是docker managed volume。通過下面的命令創建一個volume container:

 

此處只需要create即可,不需要run,因爲其他容器只需獲取到他的這個掛載點,並不需要他的數據。

其他容器啓動的時候可以通過--volumes-from參數使用vc_data這個volume container容器的掛載點,命令如下:

 

這樣web1、web2就有了相同的掛載點。

 

volume container 的特點:

Ø  bind mount 相比,不必爲每一個容器指定host path,所有path都在 volume container中定義好了,容器只需與volume container關聯。實現了容器與host的解耦。

Ø 使用volume container的容器其mount point是一致的,有利於配置的規範和標準化,但也帶來一定的侷限,使用時需要綜合考慮。

 

² data-packed volume container

這種場景是將數據先放到鏡像中,build此鏡像,然後create此鏡像,其他容器的--volumes-from設置爲此容器。這樣run出來的容器都會共享同一份數據。

我們用下面的 Dockfile 構建鏡像:

 

ADD命令將靜態文件添加到容器目錄/usr/local/apache2/htdocs。

VOLUME 的作用與-v等效,用來創建docker managed volume,mount point 爲usr/local/apache2/htdocs,因爲這個目錄就是ADD添加的目錄,所以會將已有數據拷貝到volume中。用下面的命令build詞鏡像:

 

創建此鏡像的容器:

 

此處不再需要-v,因爲datapacked的鏡像VLOUME已經實現了。

啓動其他容器:

 

這樣也可實現容器之間共享數據,而且此數據保存在datapacked中。這種方式適合只使用靜態文件共享場景。並且datapacked中包含了共享數據,可移植性非常強。

 

² Volume管理

docker volume ls  #查看宿主機上所有vloume

docker inspect <container>  #查看某一容器具體的信息

dcoker vloume rm <iamgeid>  #刪除某一個volume

 

如果想批量刪除孤兒volume,可以執行:

docker volume rm $(docker volume ls -q)docker volume rm $(docker volume ls -q)

 

 

3)進入容器的4種方式

l 使用docker attach

l 使用SSH

l 使用nsenter

l 使用exec

1. 使用docker attach

docker attach 容器ID

缺點:當多個窗口同時使用該命令進入該容器時,所有的窗口都會同步顯示。如果有一個窗口阻塞了,那麼其他窗口也無法再進行操作。因爲這個原因,所以docker attach命令不太適合於生產環境,平時自己開發應用時可以使用該命令。

 

2. 使用SSH

在鏡像(或容器)中安裝SSH Server,這樣就能保證多人進入容器且相互之間不受干擾了

但是卻不建議使用ssh進入到Docker容器內
關於爲什麼
不建議使用,請參考如下文章:

爲什麼不需要在 Docker 容器中運行 sshd

3. 使用nsenter

關於什麼是nsenter請參考如下文章:

https://github.com/jpetazzo/nsenter

系統默認將我們需要的nsenter安裝到主機中

如果沒有安裝的話,按下面步驟安裝即可(注意是主機而非容器或鏡像)

² wget https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz

² tar -xzvf util-linux-2.24.tar.gz  

² cd util-linux-2.24/  

² ./configure --without-ncurses

² make nsenter

² sudo cp nsenter /usr/local/bin

nsenter可以訪問另一個進程的名稱空間。所以爲了連接到某個容器我們還需要獲取該容器的第一個 進程的PID。可以使用docker inspect命令來拿到該PID。

docker ps  #獲取容器ID
docker inspect -f {{.State.Pid}} 容器ID   #獲取進程PID

在拿到該進程PID之後我們就可以使用nsenter命令訪問該容器了。

nsenter --target 容器PID --mount --uts --ipc --net --pid

4. 使用exec

docker在1.3.X版本之後還提供了一個新的命令exec用於進入容器

使用該命令進入一個已經在運行的容器

docker ps  #獲取容器ID

docker exec -it 容器ID /bin/bash

 

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