一、數據卷管理
用戶在使用 Docker 的過程中,勢必需要查看容器內應用產生的數據,或者 需要將容器內數據進行備份,甚至多個容器之間進行數據共享,這必然會涉及 到容器的數據管理
(1)Data Volume (數據卷)
(2)Data Volume Dontainers --- 數據卷容器
Data Volume ---數據卷
Data Volume 本質上是 Docker Host 文件系統中的目錄或文件,使用類似 與 Linux 下對目錄或者文件進行 mount 操作。數據卷可以在容器之間共享 和重用,對數據卷的更改會立馬生效,對數據卷的更新不會影響鏡像,卷會一 直存在,直到沒有容器使用
Data Volume 有以下特點:
a)Data Volume 是目錄或文件,而非沒有格式化的磁盤(塊設備)。
b)容器可以讀寫 volume 中的數據。
c)volume 數據可以被永久的保存,即使使用它的容器已經銷毀。
Data Volume的使用:
通過-v 參數格式為 <host path>:<container path>
a)利用 nginx的鏡像運行一個容器,並在容器內創建一個數據卷掛載到容器 的 /web 目錄上
[root@localhost ~]# docker run -dti -v /web nginx:latest /bin/bash
d4e002045c2bd022a826dbd2805b121dd43c41443d86eeb6515f616bf52c8549
b)運行一個容器,本地創建/date目錄掛載到容器的/var/log/目錄上
docker run -dti -v /data:/var/log nginx /bin/bash
docker run -dti -v /data:/var/log centos:latest /bin/bash
25773c239584614e301644db01b7275377887c9bbefe8c54cf5cd6be2917ab54
DataVolumeDontainers --- 數據卷容器
如果用戶需要在容器之間共享一些持續更新的數據,最簡單的方法就是使用數據 卷容器,其實數據卷容器就是一個普通的容器,只不過是專門用它提供數據卷供 其他容器掛載使用
Data Volume Dontainers使用:
a)創建一個名為 dbdata 的數據卷,並在其中創建一個數據卷掛載到 /dbdata
docker run -dti -v /dbdata --name dbser centos:7.0
--name 參數為給容器指定名字為dbser方便記憶
[root@localhost ~]# docker run -dti -v /dbdata --name dbser centos:latest
82b264b29e56700afebaa7acec8c69309964f27dafd271454048b8b7a113720e
b)其他容器使用--volume-from 去掛載dbdata容器中的/dbdata數據卷 eg :創建 db1&db2 兩個容器, 並掛載 /dbdata 數據卷到本地
docker run -dti --volumes-from dbserver --name db1 centos:7.0
docker run -dti --volumes-from dbserver --name db2 centos:7.0
此時,容器 db1 和 db2 同時掛載了同一個數據卷到本地相同 /dbdata 目錄。三個容器任何一個目錄下的寫入,都可以時時同步到另外兩個
[root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES aff1e64343bf centos:latest "/bin/bash" 4 minutes ago Up 4 minutes db2 893450737ade centos:latest "/bin/bash" 4 minutes ago Up 4 minutes db1 82b264b29e56 centos:latest "/bin/bash" 6 minutes ago Up 6 minutes dbser 在db2中創建jam文件,寫入0330 [root@localhost ~]# docker exec -it aff1e64343bf /bin/bash [root@aff1e64343bf dbdata]# echo "0330" >jam [root@aff1e64343bf dbdata]# cat jam 0330 在db1中查看是否存在jam文件 [root@localhost ~]# docker exec -it 893450737ade /bin/bash [root@893450737ade /]# cd dbdata/ [root@893450737ade dbdata]# ls jam [root@893450737ade dbdata]# cat jam 0330 在dbser中查看jam文件是否存在 [root@localhost ~]# docker exec -it 82b264b29e56 /bin/bash [root@82b264b29e56 /]# ls dbdata [root@82b264b29e56 /]# cd dbdata/ [root@82b264b29e56 dbdata]# ls jam [root@82b264b29e56 dbdata]# cat jam 0330
二、docker網絡介紹
大量的互聯網應用服務需要多個服務組件,這往往需要多個容器之間通過網絡 通信進行相互配合
docker 網絡從覆蓋范圍可分為單個 host 上的容器網絡和跨多個 host 的網絡 docker 目前提供了映射容器端口到宿主主機和容器互聯機制來為容器提供網絡服務,在啟動容器的時候,如果不指定參數,在容器外部是沒有辦法通過網絡來訪問容器內部的網絡應用和服務的
docker 安裝時會自動在host上創建三個網絡,我們查看一下docker網絡:
docker network ls
[root@localhost ~]# docker network list NETWORK ID NAME DRIVER SCOPE 460b8a01b798 bridge bridge local d4ae07a1372e host host local 63bead0d7ffc none null local
二、docker--none網絡
none 網絡就是什么都沒有的網絡。掛在這個網絡下的容器除了lo,沒有其他任何網卡。容器創建時,可以通過 --network=none 指定使用 none 網絡。
none 網絡的應用
封閉的網絡意味着隔離,一些對安全性要求高並且不需要聯網的應用可以使用 none 網絡。
比如某個容器的唯一用途是生成隨機密碼,就可以放到 none 網絡中避免密 碼被竊取。
三、docker--host網絡
連接到 host 網絡的容器,共享 docker host 的網絡棧,容器的網絡配置與 host 完全一樣。可以通過 --network=host 指定使用 host 網絡
在容器中可以看到 host 的所有網卡,並且連 hostname 也是 host 的。host 網絡的使用場景又是什么呢?
直接使用 Docker host 的網絡最大的好處就是性能,如果容器對網絡傳輸效率 有較高要求,就可以選擇 host 網絡。
當然不便之處就是犧牲一些靈活性,比如要考慮端口沖突問題,Docker host 上已經使用的端口就不能再用了。
Docker host 的另一個用途是讓容器可以直接配置 host 網路。比如某些跨 host 的網絡解決方案,其本身也是以容器方式運行的,這些方案需要對網絡進 行配置,比如管理 iptables
四、docker--bridge網絡
docker 安裝時會創建一個 命名為 docker0 的 linux bridge。如果不指定 --network,創建的容器默認都會掛到 docker0 上
當前 docker0 上沒有任何其他網絡設備,我們創建一個容器看看有什么變化
[root@localhost docker]# brctl show bridge name bridge id STP enabled interfaces docker0 8000.0242ec43479a no vethb2a3b02 #以密鑰對的形式掛到docker0
一個新的網絡接口 vethb2a3b02 被掛到了 docker0 上,vethb2a3b02 就是 新創建容器的虛擬網卡。
進入剛才運行的容器查看網絡,容器有一個網卡 eth0@if9
[root@localhost docker]# docker exec -it 5449774b40e5 /bin/sh / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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 8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever
實際上 eth0@if9 和 vethb2a3b02是一對 veth pair
veth pair 是一種成對出現的特殊網絡設備,可以把它們想象成由一根虛擬網線 連接起來的一對網卡,網卡的一頭(eth0@if9)在容器中,另一頭 (vethb2a3b02)掛在網橋 docker0 上,其效果就是將 eth0@if9 也掛在了 docker0 上
可以看到,eth0@if9 已經配置了 IP 172.17.0.3,為什么是這個網段呢?
看一下 bridge 網絡的配置信息:
docker network inspect bridge
Config": [ { "Subnet": "172.17.0.0/16"
可以看到bridge 網絡配置的 subnet 就是 172.17.0.0/16,並且網關是 172.17.0.1, 在docker0上
容器創建時,docker 會自動從 172.17.0.0/16 中分配一個 IP,這里 16 位的 掩碼保證有足夠多的 IP 可以供容器使用,(主機位是16位)
五、創建 user--defined網絡
我們可通過 bridge 驅動創建類似前面默認的 bridge 網絡
1)利用bridge驅動創建名為my-net2網橋(docker會自動分配網段):
docker network create --driver bridge my-net2
可以看到新創建的網絡也自動被分配了子網ip。
[root@localhost ~]# docker network create --driver bridge net2 2edd5371dd2fbcb32c9c2b2a9420cb806e406edc011379c7c7c70f53d6c74585 [root@localhost ~]# docker network list NETWORK ID NAME DRIVER SCOPE 460b8a01b798 bridge bridge local d4ae07a1372e host host local 2edd5371dd2f net2 bridge local 63bead0d7ffc none null local [root@localhost ~]# docker network inspect net2
。。。
Config": [ { "Subnet": "172.18.0.0/16", "Gateway": "172.18.0.1"
刪除網橋:brctl delbr 網橋名
(4)利用bridge驅動創建名為net3網橋(user-defined網段及網關)
[root@localhost ~]# docker network create --driver bridge --subnet 172.18.2.0/24 --gateway 172.18.2.1 net3
報錯:Error response from daemon: Pool overlaps with other one on this address space
這是因為新創建的網絡自定義的子網ip與已有的網絡子網ip沖突。
只需要重新定義子網ip段就行
[root@localhost ~]# docker network create --driver bridge --subnet 192.18.2.0/24 --gateway 192.18.2.1 net3 3f028deb3aa0b37ee69e3a04a0edb14c00b1933a415c2d0961a9eec7b4b2ecb1
重新查看網絡配置信息:
[root@localhost ~]# docker network inspect net3 "Config": [ { "Subnet": "192.18.2.0/24", "Gateway": "192.18.2.1"
可以看到自定義的網絡配置成功。
(5)啟動容器使用新建的net3網絡
docker run -itd --network=net3(網絡名) 鏡像名 /bin/sh(環境名)
[root@localhost ~]# docker run -itd --network=net3 busybox:latest /bin/sh 632e2d8245ade9e0a8ee9cf13d7105f19a2d28728e3d38b65423eb34ef38ac4c [root@localhost ~]# docker exec -it 632e2d8245ad /bin/sh / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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 18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:c0:12:02:03 brd ff:ff:ff:ff:ff:ff inet 192.18.2.3/24 brd 192.18.2.255 scope global eth0 valid_lft forever preferred_lft forever
可以看到使用新建網絡net3啟動的容器會自動分配一個net3子網段內的ip。
(6)啟動容器使用net3網絡並指定ip(只有使用 --subnet 創建的網絡才 能指定靜態 IP,如果是docker自動分配的網段不可以指定ip)
[root@localhost ~]# docker run -itd --network=net3 --ip 192.18.2.4 busybox:latest /bin/sh
當然,這個指定的ip也要在net3的子網范圍內。
[root@localhost dbdate]# docker run -itd --network=bridge --ip 172.17.0.3 busybox:latest /bin/sh
docker: Error response from daemon: user specified IP address is supported on user defined networks only.
如上的報錯就是因為運行容器時選中的網絡不是使用--subnet定義的網絡,所以不能指定ip。
(7)讓已啟動不同vlan的ningx容器,可以連接到net2(其實在nigx中新建了my-net2的網卡)
docker run -itd --network=net3 busybox:latest /bin/sh
docker network connect net2 容器名(id)
[root@localhost ~]# docker run -itd --network=net3 busybox:latest /bin/bash e42da501655faa6e2067a6d9ee6c49016ec49bb0dc750b78a82f2540751840c5
[root@localhost docker]# docker network connect net2 0d3e78d4298c [root@localhost docker]# docker exec -it 0d3e78d4298c /bin/sh / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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 20: eth0@if21: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:c0:12:02:04 brd ff:ff:ff:ff:ff:ff inet 192.18.2.4/24 brd 192.18.2.255 scope global eth0 valid_lft forever preferred_lft forever 24: eth1@if25: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff inet 172.18.0.2/16 brd 172.18.255.255 scope global eth1 valid_lft forever preferred_lft forever
可以看到此容器同時擁有了net2和net3的子網ip。
(8)使用--name指定啟動容器名字,可以使用docker自帶DNS通信,但只能 工作在user-defined 網絡,默認的 bridge 網絡是無法使用 DNS 的。
root@localhost docker]# docker run -itd --network=net3 --name=b1 busybox 203fc1c4fb19dc1212da8f97dc8654b5b928f9ab1406bed4c39a31f76b686d4c [root@localhost docker]# docker run -itd --network=net3 --name=b2 busybox 5dfabb01d5d718429e382acb4115a1d8c4c7e2e89c302b899bcf5923be1df527 [root@localhost docker]# docker exec -it b1 /bin/sh / # ping b2 PING b2 (192.18.2.7): 56 data bytes 64 bytes from 192.18.2.7: seq=0 ttl=64 time=0.417 ms 64 bytes from 192.18.2.7: seq=1 ttl=64 time=0.110 ms 64 bytes from 192.18.2.7: seq=2 ttl=64 time=0.099 ms
在創建容器時使用相同網絡,並且給容器命名的話
意思是給兩個容器之間做了域名解析和配置相同網段,所以能ping通
(9)容器之間的網絡互聯
a). 首先創建一個 db 容器
[root@localhost ~]# docker run -itd --name db busybox
b). 創一個 web 容器,並使其連接到 db
[root@localhost ~]# docker run -itd --name web --link db:dblink busybox /bin/sh
-link db:dblink 實際是連接對端的名字和這個鏈接的名字,也就是和 db 容器 建立一個叫做 dblink 的鏈接
c).查看鏈接的情況
docker ps -a
[root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 141e370eea76 busybox "/bin/sh" 8 seconds ago Up 7 seconds web 9f89a1945f6b busybox "sh" 54 seconds ago Up 53 seconds db
d)進入web容器,使用 ping 命令來測試網絡鏈接的情況
[root@localhost ~]# docker exec -it 141e370eea76 /bin/sh/ # ping db PING db (172.17.0.4): 56 data bytes 64 bytes from 172.17.0.4: seq=0 ttl=64 time=0.445 ms
發現可以ping通,連接有效
e)嘗試進入db容易,使用ping命令測試
[root@localhost docker]# docker exec -it 9f89a1945f6b /bin/sh / # ping web ping: bad address 'web'
發現無法ping通,因此可以推斷出容器之間的網絡連通是單向的,即哪個容器建立了連接,哪個容易才能連接到另一個容器,反之不行。
(10)容器端口映射 在啟動容器的時候,如果不指定參數,在容器外部是沒有辦法通過網絡來訪問容 器內部的網絡應用和服務的
當容器需要通信時,我們可以使用 -P (大) &&-p (小)來指定端口映射
-P : Docker 會隨機映射一個 49000 ~ 49900 的端口到容器內部開放的網絡端口
p :則可以指定要映射的端口,並且在一個指定的端口上只可以綁定一個容器。
支持的格式有
iP : HostPort : ContainerPort
IP : : ContainerPort
IP : HostPort :
如果不指定就隨機
查看映射
docker port 容器名
拓展:用腳本刪除所有容器
[root@localhost docker]# for id in `docker ps -a | grep a | awk -F " +" '{print $1}'` ;do docker rm -f $id ;done
a)映射所有接口地址,此時綁定本地所有接口上的 5000 到容器的 5000 接口, 訪問任何一個本地接口的 5000 ,都會直接訪問到容器內部
docker run -dti -p 5000:5000 nginx /bin/bash
b)多次使用可以實現多個接口的映射
[root@localhost docker]# docker run -itd -p 5000:22 -p 5001:23 nginx /bin/bash
查看容器信息,發現新容器的的22,23端口都映射到了宿主機的5000和5001端口。
[root@localhost docker]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ea3b9412d96d nginx "/bin/bash" 5 seconds ago Up 5 seconds 80/tcp, 0.0.0.0:5000->22/tcp, 0.0.0.0:5001->23/tcp hardcore_darwin
c)映射到指定地址的指定接口 此時會綁定本地 192.168.4.169 接口上的 5000 到容器的80 接口
docker run -dti -p 192.168.253.9:5000:80 nginx /bin/bash
[root@localhost docker]# docker run -dti -p 192.168.253.9:5000:80 nginx /bin/bash
[root@localhost docker]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 132746ef0996 nginx "/bin/bash" About a minute ago Up About a minute 192.168.253.9:5000->80/tcp practical_lichterman
d) 映射到指定地址的任意接口 此時會綁定本地 192.168.4.169 接口上的任意一個接口到容器的 5000 接口
docker run -dti -p 192.168.4.169::5000 nginx /bin/bash
e) 使用接口標記來指定接口的類型
docker run -dti -p 192.168.4.169::5000/UDP nginx /bin/bash
指定接口位udp類型
(11)實驗:通過端口映射實現訪問本地的 IP:PORT 可以訪問到容器內的 web
a)將容器80端口映射到主機8080端口,注意末尾不要加環境變量
docker run -itd -p 80:80 --name nginx nginx:latest
b) 查看剛運行docker
docker ps -a
[root@localhost docker]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0382dfbbd606 nginx:latest "nginx -g 'daemon of…" 5 seconds ago Up 4 seconds 0.0.0.0:80->80/tcp nginx
c) 進入容器
docker exec -it nginx /bin/sh,並在 容器內部編輯網頁文件 index.html
# cd /usr/share/nginx/ # ls html # cd html # ls 50x.html index.html # echo '123' > index.html
e)到宿主機上打開瀏覽器輸入 IP:PORT 訪問驗證
一些報錯:
1)[root@localhost /]# docker run -itd --name busy busybox:latest /bin/bash
e105747eb16e52da2637379d75e221f46812955c929696234abbf1321fd56da3
docker: Error stat /bin/bash: no such file or directory": unknown
這是因為環境變量不可用,換成/bin/sh或者不加環境變量
2)[root@localhost /]# docker run -itd --name busy busybox:latest /bin/sh
docker: Error response from daemon: Conflict. The container name "/busy" is already in use by container "e105747eb16e52da2637379d75e221f46812955c929696234abbf1321fd56da3". You have to remove (or rename) that container to be able to reuse that name.
這是因為容器名已經存在,需要刪除已經存在的容器名
3)[root@localhost /]# docker network create --driver bridge my-net2
Error networks have overlapping IPv4
這是因為網橋沖突,刪除沖突的網橋。
brctl delbr 網橋
systemctl restart docker
4)error:executable file not found in $PATH": unknown
這是因為命令的順序錯誤
5)root@localhost /]# docker run -it --network=my-net3 --ip 192.168.253.13 busybox:latest /bin/sh
docker: Error response from daemon: Invalid address 192.168.253.13: It does not belong to any of this network's subnets.
這是因為自定義的ip不在可使用ip的范圍內。
6)Error No chain/target/match by that name.
這是因為沒有重啟docker,或者關閉firewalld和iptables(不建議)
7)docker: Error response from daemon: driver failed programming external connectivity on endpoint vibrant_kepler (0838e9c00e2ffcec24bbd333000cc4de9bd0fa2420c1c330ddb77dfd9d1d534f): Bind for 192.168.253.9:5000 failed: port is already allocated.
這是因為宿主機的端口已經被別的服務占用。
8)宿主機映射到容器之后,使用宿主機ip:port來訪問容器的httpd或者nginx服務
報錯連接被拒絕
這是因為端口映射的時候加入了環境變量,去掉環境變量即可。
網絡排查命令:
iptables -t nat -L
ip r
tcpdump -i docker0 -n icmp
tcpdump -i eth0 -n icmp