1. 程式人生 > 其它 >Docker的資料管理、網路通訊和dockerfile-(2)

Docker的資料管理、網路通訊和dockerfile-(2)

Docker的資料管理、網路通訊和dockerfile

一、Docker的資料管理

管理Docker容器中資料主要有兩種方式:資料卷(Data Volumes)和資料卷容器(Data Volumes Containers)。

1. 資料卷

1.1 資料卷定義

資料卷是一個供容器使用的特殊目錄,位於容器中。可將宿主機的目錄掛載到資料捲上,對資料卷的修改操作立刻可見,並且更新資料不會影響映象,從而實現資料在宿主機與容器之間的遷移。資料卷的使用類似於Linux下對目錄進行的mount操作。

1.2 資料卷配置

宿主機目錄/var/www掛載到容器中的/data1。

注意:宿主機本地目錄的路徑必須是使用絕對路徑。如果路徑不存在,Docker會自動建立相應的路徑。

[root@docker ~]# cd /var/www

[root@docker www]# ls

cgi-bin html

[root@docker www]# docker run -it -v /var/www:/test --name test centos:7 bash

[root@704c227d8f3a /]# ls

anaconda-post.log bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys test tmp usr var

[root@704c227d8f3a /]# cd test

[root@704c227d8f3a test]# ls

cgi-bin html

[root@704c227d8f3a test]# echo 'test' > test.txt

[root@704c227d8f3a test]# exit

exit

[root@docker www]# ls

cgi-bin html test.txt

[root@docker www]# cat test.txt

test

2. 資料卷容器

如果需要在容器之間共享一些資料,最簡單的方法就是使用資料卷容器。資料卷容器是一個普通的容器,專門提供資料卷給其他容器掛載使用。

 

2.1 建立資料卷容器

[root@docker www]# docker run -it --name test1 -v /test1 -v /test2 centos:7 bash

[root@c2e17eaba020 /]# ls

anaconda-post.log bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys test1 test2 tmp usr var

[root@c2e17eaba020 /]# ls test1

[root@c2e17eaba020 /]# ls test2

[root@c2e17eaba020 /]# echo "this is test1" > test1/test1.txt

[root@c2e17eaba020 /]# echo "this is test2" > test2/test2.txt

2.2 使用--volume-from來掛載test1

[root@docker www]# docker run -it --name test1 -v /test1 -v test2 centos:7 bash

[root@c2e17eaba020 /]# ls

anaconda-post.log bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys test1 test2 tmp usr var

[root@c2e17eaba020 /]# ls test1

[root@c2e17eaba020 /]# ls test2

[root@c2e17eaba020 /]# echo "this is test1" > test1/test1.txt

[root@c2e17eaba020 /]# echo "this is test2" > test2/test2.txt

[root@c2e17eaba020 /]# exit

exit

[root@docker www]# docker run -it --volumes-from test1 --name test2 centos:7 bash

[root@ad08168f508d /]# ls

anaconda-post.log bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys test1 test2 tmp usr var

[root@ad08168f508d /]# ls test1

test1.txt

[root@ad08168f508d /]# cat test1/test1.txt

this is test1

[root@ad08168f508d /]# ls test2

test2.txt

[root@ad08168f508d /]# cat test2/test2.txt

this is test2

二、埠對映

在啟動容器的時候,如果不指定對應的埠,在容器外是無法通過網路來來訪問容器內的服務。埠對映機制將容器內的服務提供給外部網路訪問,實際上就是將宿主機的埠對映到容器中,使得外部網路訪問宿主機的埠便可訪問容器內的服務。

 

[root@docker www]# docker run -d --name test1 -P nginx

0a07519f54de9552a37d076613f9f5af4ff4b80d1d3c258762c45f876a29500b

[root@docker www]# docker run -d --name test2 -p 11111:80 nginx

9316ffd9e2aa98e8d1ea679128d308fc0f1842d854e8b772c7cd5c07647251a8

[root@docker www]# docker ps -a

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

9316ffd9e2aa nginx "/docker-entrypoint.…" 1 second ago Up 1 second 0.0.0.0:11111->80/tcp, :::11111->80/tcp test2

0a07519f54de nginx "/docker-entrypoint.…" 19 seconds ago Up 18 seconds 0.0.0.0:49154->80/tcp, :::49154->80/tcp test1

curl測試

 

[root@docker www]# curl http://192.168.122.10:11111

<!DOCTYPE html>

<html>

<head>

<title>Welcome to nginx!</title>

<style>

html { color-scheme: light dark; }

body { width: 35em; margin: 0 auto;

font-family: Tahoma, Verdana, Arial, sans-serif; }

</style>

</head>

<body>

<h1>Welcome to nginx!</h1>

<p>If you see this page, the nginx web server is successfully installed and

working. Further configuration is required.</p>

 

<p>For online documentation and support please refer to

<a href="http://nginx.org/">nginx.org</a>.<br/>

Commercial support is available at

<a href="http://nginx.com/">nginx.com</a>.</p>

 

<p><em>Thank you for using nginx.</em></p>

</body>

</html>

[root@docker www]# curl http://192.168.122.10:49154

<!DOCTYPE html>

<html>

<head>

<title>Welcome to nginx!</title>

<style>

html { color-scheme: light dark; }

body { width: 35em; margin: 0 auto;

font-family: Tahoma, Verdana, Arial, sans-serif; }

</style>

</head>

<body>

<h1>Welcome to nginx!</h1>

<p>If you see this page, the nginx web server is successfully installed and

working. Further configuration is required.</p>

 

<p>For online documentation and support please refer to

<a href="http://nginx.org/">nginx.org</a>.<br/>

Commercial support is available at

<a href="http://nginx.com/">nginx.com</a>.</p>

 

<p><em>Thank you for using nginx.</em></p>

</body>

</html>

三、容器互聯

容器互聯是通過容器的名稱在容器間建立一條專門的網路通訊隧道。簡單點說,就是會在源容器和接收容器之間建立一條隧道,接收容器可以看到源容器指定的資訊。

 

1. 建立容器互聯

[root@docker www]# docker run -itd -P --name test1 centos:7 bash

d83da111bcb2307629c6a5f0614dd1697b1be8c26725ce50377627814f13d00b

[root@docker www]# docker run -itd -P --name test2 --link test1:TEST centos:7 bash

##--link test1:TEST指定互聯容器名為test1,別名為TEST

2adcd159aba40a293f2a8385b2c3dbaceaaa99c6fa289bf556a6f03bb1e1d170

2. 進入test2測試(ping 容器名/別名)

[root@docker www]# docker exec -it test2 bash

[root@2adcd159aba4 /]# ping test1

PING TEST (172.17.0.2) 56(84) bytes of data.

64 bytes from TEST (172.17.0.2): icmp_seq=1 ttl=64 time=0.061 ms

64 bytes from TEST (172.17.0.2): icmp_seq=2 ttl=64 time=0.050 ms

^C

--- TEST ping statistics ---

2 packets transmitted, 2 received, 0% packet loss, time 1002ms

rtt min/avg/max/mdev = 0.050/0.055/0.061/0.009 ms

[root@2adcd159aba4 /]# ping TEST

PING TEST (172.17.0.2) 56(84) bytes of data.

64 bytes from TEST (172.17.0.2): icmp_seq=1 ttl=64 time=0.075 ms

64 bytes from TEST (172.17.0.2): icmp_seq=2 ttl=64 time=0.048 ms

^C

--- TEST ping statistics ---

2 packets transmitted, 2 received, 0% packet loss, time 1000ms

rtt min/avg/max/mdev = 0.048/0.061/0.075/0.015 ms

四、Docker映象的建立

建立映象有三種方法,分別為基於已有映象建立、基於本地模板建立以及基於Dockerfile建立。

 

1. 基於現有映象建立

1.1 首先啟動一個映象,在容器裡做修改

[root@docker ~]# docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

nginx latest 87a94228f133 28 hours ago 133MB

centos 7 eeb6ee3f44bd 3 weeks ago 204MB

[root@docker ~]# docker create -it --name test1 centos:7 bash

ae03a782eb8fed80190bfee1c5e459c1e82e1406a55627553e93edc943645217

[root@docker ~]# docker ps -a

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

ae03a782eb8f centos:7 "bash" 2 seconds ago Created test1

1.2 然後將修改後的容器提交為新的映象,需要使用該容器的ID號建立新映象

[root@docker ~]# docker commit -m "new" -a "centos" test1 centos:test1

sha256:3e6e91b628effd49a7fa8fea422057cb392c76e852b2d60f9d7287bfa172ff88

[root@docker ~]# docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

centos test1 3e6e91b628ef 10 seconds ago 204MB

nginx latest 87a94228f133 28 hours ago 133MB

centos 7 eeb6ee3f44bd 3 weeks ago 204MB

commit常用選項:

-m:說明資訊

-a:作者資訊

-p:生成過程中停止容器的執行

 

2. 基於本地模板建立

通過匯入作業系統模板檔案可以生成映象,模板可以從OPENVZ開源專案下載,下載地址為http://openvz.org/Download/template/precreated

 

[root@docker ~]# wget http://download.openvz.org/template/precreated/debian-7.0-x86-minimal.tar.gz

[root@docker ~]# cat debian-7.0-x86-minimal.tar.gz | docker import - debian:test

sha256:f7fd702b88cc14fbcc011dc0883edbf45dca3de99b0aef3fc8d184544c07fb5b

[root@docker ~]# docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

debian test f7fd702b88cc 36 seconds ago 215MB

centos test1 3e6e91b628ef About an hour ago 204MB

nginx latest 87a94228f133 29 hours ago 133MB

centos 7 eeb6ee3f44bd 3 weeks ago 204MB

2.1 補充:URL下載方式

方法一:

wget 下載路徑 -O 儲存路徑

方法二:

curl -L 下載路徑 -o 儲存路徑

 

2.2 補充:載入選項

通過docker save儲存的映象,使用docker load載入入docker

通過docker export儲存的映象,使用docker export載入入docker

 

3. 基於dockerfile建立

3.1 聯合檔案系統(UnionFS)

UnionFS(聯合檔案系統):Union檔案系統(UnionFS)是一種分層、輕量級並且高效能的檔案系統,它支援對檔案系統的修改作為一次提交來一層層的疊加,同時可以將不同目錄掛載到同一個虛擬檔案系統下。AUFS、OverlayFS及Devicemapper都是一種UnionFS。

Union檔案系統是Docker映象的基礎。映象可以通過分層來進行整合,基於基礎映象(沒有父映象),可以製作各種具體的應用映象。

 

特性:一次同時載入多個檔案系統,但從外面看起來,只能看到一個檔案系統,聯合載入會把各層檔案系統疊加起來,這樣最終的檔案系統還會包含所有底層的檔案和目錄。

 

我們下載的時候看到的一層層的就是聯合檔案系統。

 

3.2 映象載入原理

3.2.1 bootfs

Docker的映象實際上由一層一層的檔案系統組成,這種層級的檔案系統就是UnionFS。

bootfs主要包含bootloader和kernel,bootloader主要是引導載入kernel,Linux剛啟動時會載入bootfs檔案系統。

在Docker映象的最底層是bootfs,這一層與我們典型的Linux/Unix系統是一樣的,包含boot載入完成之後整個核心就都在記憶體中了,此時記憶體的使用權已由bootfs轉交給核心,此時系統也會解除安裝bootfs。

 

3.2.2 rootfs

rootfs,在bootfs之上。包含的就是典型Linux系統中的/dev,/proc,/etc等標準目錄和檔案。rootfs就是各種不同的作業系統的發行版,比如Ubuntu,Centos等等。

我們可以理解成一開始核心裡什麼都沒有,操作一個命令下載debian,這是就會在核心上面加了一層基礎映象;再安裝一個emacs,會在基礎映象上疊加一層image;接著再安裝一個apache,又會在images上面再疊加一層image。最後他們看起來就像一個檔案系統即容器的rootfs。在Docker的體系裡把這些rootfs叫做Docker的映象。但是,此時的每一層rootfs都是read-only的,我們此時還不能對其進行操作。當我們建立一個容器,也就是將Docker映象進行例項化,系統會在一層或是多層read-only的rootfs之上分配一層空的read-write的rootfs。




3.2.3 Docker的輕量化原因

因為對於精簡的OS,rootfs可以很小,只需要包含最基本的命令、工具和程式庫就可以了,因為底層直接用宿主機的kernel,自己只需要提供rootfs就可以了,由此可見對於不同的linux發行版,bootfs基本是一致的,rootfs會有差別,因此不同的發行版可以公用bootfs。

 

3.3 Dockerfile

3.3.1 Dockerfile定義

Docker映象是一個特殊的檔案系統,除了提供容器執行時所需的程式、庫、資源、配置等檔案外,還包含了一些為執行準備的一些配置引數(如匿名卷、環境變數、使用者等)。映象不包含任何動態資料,其內容在構建之後也不會被改變。

映象的定期實際上就是定期每一層所新增的配置、檔案。如果我們可以把每一層修改、安裝、構建、操作的命令都寫入一個指令碼,用這個指令碼來構建、定製映象,那麼映象構建透明性的問題、體積的問題就都會解決。這個指令碼就是Dockerfile。

Dockerfile是一個文字檔案,其內包含了一條條的指令(Instruction),每一條指令構建一層,因此每一條執行的內容,就是描述該層應當如何構建。有了Dockerfile,當我們需要定製自己額外的需求時,只需在Dockerfile上新增或者修改指令,重新生成image即可,省去了敲命令的麻煩。

除了手動生成Docker映象之外,可以使用Dockerfile自動生成映象。Dockerfile是由多條的指令組成的檔案,其中每條指定對應Linux中的一條命令,Docker程式將讀取Dockerfile中的指令生成指定映象。

 

3.3.2 Docker映象結構的分層

映象不是一個單一的檔案,而是有多層構成。容器其實是在映象的最上面加了一層讀寫層,在執行容器裡做的任何檔案改動,都會寫到這個讀寫層。如果刪除了容器,也就刪除了其最上面的讀寫層,檔案改動也就丟失了。Docker使用儲存驅動管理映象每層內容及可讀寫層的容器層。

(1)Dockerfile中的每個指令都會建立一個新的映象層;

(2)映象層江北快取和複用;

(3)當Dockerfile的指令修改了,複製的檔案變化了,或者構建映象時指定的變數不同了,對應的映象層快取就會失效;

(4)某一層的映象快取失效,它之後的映象層快取都會失效;

(5)映象層是不可變的,如果在某一層中新增一個檔案,然後在下一層中刪除它,則映象中依然會包含該檔案,只是這個檔案在Docker容器中不可見了。

 

3.4 Docker映象結構的分層

3.4.1 FROM 映象

指定新映象所基於的基礎映象,第一條指令必須為FROM指令,每建立一個映象就需要一條FROM指令。

 

3.4.2 MAINTAINER 名字

說明新映象的維護人資訊

 

3.4.3 RUN 命令

在所基於的映象上執行命令,並提交到新的映象中

 

3.4.4 ENTRYPOINT ["要執行的程式","引數1","引數2"]

設定容器啟動時第一個執行的命令機器引數。

可以通過使用命令docker run --entrypoint來覆蓋映象中的ENTRYPOINT指令的內容。

 

3.4.5 CMD ["要執行的程式","引數1","引數2"]

上面的是exec形式,shell形式:CMD 命令 引數1 引數2

啟動容器時預設執行的命令或者指令碼,Dockerfile只能有一條CMD命令。如果指定多條命令,只執行最後一條命令,可使用;或&&。

如果在docker run 時制定了命令或者映象中有ENTRYPOINT,那麼CMD就會被覆蓋。

CMD可以為ENTRYPOINT指令提供預設引數。

 

3.4.6 EXPOSE 埠號

指定新映象載入到Docker時要開啟的埠

 

3.4.7 ENV 環境變數 變數值

設定一個環境變數的值,會被後面的RUN使用

 

3.4.8 ADD 原始檔/目錄 目標檔案/目錄

將原始檔複製到映象中,原始檔要與Dockerfile位於相同目錄中,或者是一個URL

有如下注意事項:

 

如果原路徑是個檔案,且目標路徑是以/結尾,則docker會把目標路徑當做一個目錄,會把原始檔拷貝到該目錄下。

如果目標路徑不存在,則會自動建立目標路徑。

如果源路徑是個檔案,且目標路徑不是以/結尾,則docker會把目標路徑當作一個檔案。

如果目標路徑不存在,會以目標路徑為名建立一個檔案,內容同源檔案;

如果目標檔案是個存在的檔案,會用原始檔覆蓋它,當然只是內容覆蓋,檔名還是目標檔名。

如果目標檔案實際是個存在的目錄,則會原始檔拷貝到該目錄下。注意,這種情況下,最好顯示的以/結尾,以避免混淆。

如果源路徑是個目錄,且目標路徑不存在,則docker會自動以目標路徑建立一個目錄,把源路徑目錄下的檔案拷貝進來。

如果目標路徑是個已經存在的目錄,則docker會把源路徑目錄下的檔案拷貝到該目錄下。

如果原始檔是個歸檔檔案(壓縮檔案),則docker會自動幫解壓。

URL下載和解壓特性不能一起使用。任何壓縮檔案通過URL拷貝,都不會自動解壓。

3.4.9 COPY 原始檔/目錄 目標檔案/目錄

只複製本地主機上的檔案/目錄複製到目標地點,原始檔/目錄要與Dockerfile在相同的目錄中。

 

3.4.10 VOLUME ["目錄"]

在容器中建立一個掛載點

 

3.4.11 USER 使用者名稱/UID

指定執行容器時的使用者

 

3.4.12 WORKDIR 路徑

為後續的RUN、CMD、ENTRYPOINT指定工作目錄

 

3.4.13 ONBUILD 命令

指定所生成的映象作為一個基礎映象時所要執行的命令。

當在一個Dockerfile檔案中加上ONBUILD指令,該指令對利用該Dockerfile構建映象(比如為A映象)不會產生實質性影響。

但是當編寫一個新的Dockerfile檔案來基於A映象構建一個映象(比如為B映象)時,這時構建A映象的Dockerfile檔案中的ONBUILD指令就生效了,在構建B映象的過程中,首先會執行ONBUILD指令指定的指令,然後才會執行其他指令。

 

3.4.14 HEALTHCHECK

健康檢查

 

3.5 編寫Dockerfile格式

在編寫Dockerfile時,有嚴格的格式需要遵循:

● 第一行必須使用FROM指令知名所基於的映象名稱;

● 之後使用MAINTAINER指令說明維護該映象的使用者資訊;

● 然後是映象操作相關指令,如RUN指令。沒執行一條指令,都會給基礎映象新增新的一層;

● 最後使用CMD指令指定啟動容器時要執行的命令操作。

 

3.6 Dockerfile案例-httpd

3.6.1 建立工作目錄

[root@docker ~]# mkdir /opt/apache

[root@docker ~]# cd /opt/apache/

[root@docker apache]# vim Dockerfile

 

FROM centos:7

#基於centos:7的基礎映象

MAINTAINER this is apache image <test>

#定義映象的使用者資訊

RUN yum -y update;yum install -y httpd

#映象操作指令安裝apche軟體

EXPOSE 80

#開啟80埠

ADD index.html /var/www/index.html

#複製網站首頁檔案

 

##前臺啟動方法一(需準備執行指令碼)

ADD run.sh /run.sh

#將執行指令碼複製到映象中

RUN chmod 755 /run.sh

CMD ["/run.sh"]

#啟動容器時執行指令碼

 

##前臺啟動方法二(無需其他指令碼)

ENTRYPOINT ["/usr/sbin/apachectl"]

CMD ["-D","FOREGROUND"]

#前臺啟動apache,CMD為ENTRYPOINT傳遞引數

3.6.2 準備執行指令碼(前臺啟動方法一)

[root@docker apache]# vim run.sh

 

#!/bin/bash

rm -rf /run/httpd/*

#清理httpd的快取

/usr/sbin/apachectl -D FOREGROUND

#指定為前臺執行

因為Docker容器僅在它的1號程序(PID為1)執行時,會保持執行。如果1號程序退出了,Docker容器也就退出了。

 

3.6.3 準備網頁頁面

[root@docker apache]# echo "this is test web" > index.html

[root@docker apache]# ls

Dockerfile index.html run.sh

3.6.4 生成映象

方法一:

 

[root@docker apache]# docker build -t http:test1 .

方法二:

 

[root@docker apache]# docker build -t http:test2 .

[root@docker apache]# docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

httpd test2 6440a6fa57e0 56 seconds ago 623MB

httpd test1 5ebb94751288 3 minutes ago 623MB

debian test f7fd702b88cc 4 hours ago 215MB

centos test1 3e6e91b628ef 5 hours ago 204MB

nginx latest 87a94228f133 33 hours ago 133MB

centos 7 eeb6ee3f44bd 3 weeks ago 204MB

3.6.5 新映象執行容器

[root@docker apache]# docker run -itd --name test1 -p 11111:80 httpd:test1

[root@docker apache]# docker run -itd --name test2 -p 22222:80 httpd:test2

[root@docker apache]# docker ps -a

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

4ff1f0b80978 httpd:test2 "/usr/sbin/apachectl…" 3 seconds ago Up 2 seconds 0.0.0.0:22222->80/tcp, :::22222->80/tcp test2

2609fc4c8c14 httpd:test1 "/run.sh" 2 minutes ago Up 2 minutes 0.0.0.0:11111->80/tcp, :::11111->80/tcp test1

3.6.6 測試

[root@docker apache]# curl http://192.168.122.10:11111

this is test web

[root@docker apache]# curl http://192.168.122.10:22222

this is test web

3.6.7 如果有網路報錯提示

WARNING: IPv4 forwarding is disabled. Networking will not work.

解決方法:

 

copy

[root@docker ~]# echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf

[root@docker ~]# sysctl -p

net.ipv4.ip_forward = 1

[root@docker ~]# systemctl restart network

[root@docker ~]# systemctl restart docker