Docker存储

docker提供数据卷来实现数据共享与持久化,而数据卷的挂载有两种方式:
•挂载主机目录(Bind mounts)
•数据卷容器(Data Volumes)

数据卷是一个可供容器使用的特殊目录,它绕过文件系统,可以提供很多有用的特性:
•数据卷可以在容器之间共享和重用
•对数据卷的修改会立马生效
•对数据卷的更新不会影响镜像
•卷会一直存在,只到没有容器使用

挂载主机目录

  1. 以读写方式挂载主机目录

[root@c7docker1 ~]# docker run -d -P —name webserver01 -v /www:/usr/local/apache2/htdocs httpd
176b71ed27b1cd2d4a13fc50b333d064a9812b848024110a957038503657316e
[root@c7docker1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
176b71ed27b1 httpd “httpd-foreground” About a minute ago Up About a minute 0.0.0.0:32769->80/tcp webserver01
[root@c7docker1 ~]# cat /www/index.html
hello world!
[root@c7docker1 ~]# curl http://192.168.163.130:32769
hello world!
[root@c7docker1 ~]# docker exec -it 176 /bin/bash
root@176b71ed27b1:/usr/local/apache2# cd htdocs/
root@176b71ed27b1:/usr/local/apache2/htdocs# pwd
/usr/local/apache2/htdocs
root@176b71ed27b1:/usr/local/apache2/htdocs# touch test
root@176b71ed27b1:/usr/local/apache2/htdocs# ls
index.html test

  1. 以只读方式挂载主机目录

[root@c7docker1 ~]# docker run -d -P —name webserver02 -v /www:/usr/local/apache2/htdocs:ro -v /etc/localtime:/etc/localtime:ro httpd
628298acc11f9703cccce5e6c9518659895de52af6a69542083156f90ae084c5
[root@c7docker1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
628298acc11f httpd “httpd-foreground” 8 seconds ago Up 5 seconds 0.0.0.0:32770->80/tcp webserver02
176b71ed27b1 httpd “httpd-foreground” 30 minutes ago Up 30 minutes 0.0.0.0:32769->80/tcp webserver01
[root@c7docker1 ~]# docker exec -it 628 /bin/bash
root@628298acc11f:/usr/local/apache2# date
Tue Dec 4 15:56:48 CST 2018
root@628298acc11f:/usr/local/apache2# cd htdocs/
root@628298acc11f:/usr/local/apache2/htdocs# touch test123
touch: cannot touch ‘test123’: Read-only file system
root@628298acc11f:/usr/local/apache2/htdocs# echo “hello test” >index.html
bash: index.html: Read-only file system

数据卷容器

  1. 创建一个数据卷容器

docker run -d -v /dbdata —name dbdata centos:7 sleep 3600
db4011f9028011e33042f14aba95d948a750970b76472305222b0b1d86c9488c
[root@c7docker1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
db4011f90280 centos:7 “sleep 3600” 4 seconds ago Up 2 seconds dbdata
628298acc11f httpd “httpd-foreground” 11 minutes ago Up 11 minutes 0.0.0.0:32770->80/tcp webserver02
176b71ed27b1 httpd “httpd-foreground” 42 minutes ago Up 42 minutes 0.0.0.0:32769->80/tcp webserver01
[root@c7docker1 ~]# docker volume ls
DRIVER VOLUME NAME
local 1397ca274779c785cd1fba174a5ca52e31692948d8b587092804d90dad9141cf
local a07a7421c066ad29de2dd6fa691e46bf38ad80bb6c9250e7d12fedda08bc2956
[root@c7docker1 ~]# docker exec -it db /bin/bash
[root@db4011f90280 /]# ls
anaconda-post.log bin dbdata dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
[root@db4011f90280 /]# cd dbdata/
[root@db4011f90280 dbdata]# ll
total 0
[root@db4011f90280 dbdata]# touch db.data
[root@db4011f90280 dbdata]# ls
db.data
[root@db4011f90280 dbdata]# exit
[root@c7docker1 ~]# docker run -d —volumes-from dbdata —name nginx01 nginx
Unable to find image ‘nginx:latest’ locally
latest: Pulling from library/nginx
a5a6f2f73cd8: Already exists
1ba02017c4b2: Pull complete
33b176c904de: Pull complete
Digest: sha256:20732552e9cc42509f3a50f930ef0be5c668d787d7680f46535a7908e0763c5b
Status: Downloaded newer image for nginx:latest
9922bd7d7e50f48890b902c99a20fbe2b08bba171573327ccdbb41659a480708
[root@c7docker1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9922bd7d7e50 nginx “nginx -g ‘daemon of…” 6 seconds ago Up 4 seconds 80/tcp nginx01
db4011f90280 centos:7 “sleep 3600” 5 minutes ago Up 4 minutes dbdata
628298acc11f httpd “httpd-foreground” 16 minutes ago Up 16 minutes 0.0.0.0:32770->80/tcp webserver02
176b71ed27b1 httpd “httpd-foreground” About an hour ago Up About an hour 0.0.0.0:32769->80/tcp webserver01
[root@c7docker1 ~]# docker exec -it 992 /bin/bash
root@9922bd7d7e50:/# ls
bin boot dbdata dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@9922bd7d7e50:/# ls dbdata/
db.data
root@9922bd7d7e50:/# exit
exit
[root@c7docker1 ~]# docker run -d —volumes-from dbdata —name nginx02 nginx
73f3115533c140cab38b3a953346edbc2b301b143c79af58385213f40ae02abf
[root@c7docker1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
73f3115533c1 nginx “nginx -g ‘daemon of…” 5 seconds ago Up 3 seconds 80/tcp nginx02
9922bd7d7e50 nginx “nginx -g ‘daemon of…” 56 seconds ago Up 54 seconds 80/tcp nginx01
db4011f90280 centos:7 “sleep 3600” 5 minutes ago Up 5 minutes dbdata
628298acc11f httpd “httpd-foreground” 17 minutes ago Up 17 minutes 0.0.0.0:32770->80/tcp webserver02
176b71ed27b1 httpd “httpd-foreground” About an hour ago Up About an hour 0.0.0.0:32769->80/tcp webserver01
[root@c7docker1 ~]# docker exec -it 73 /bin/bash
root@73f3115533c1:/# ls
bin boot dbdata dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@73f3115533c1:/# ls dbdata/
db.data
root@73f3115533c1:/#

  1. 利用数据卷容器迁移数据

备份数据:
#先创建一个容器worker,并使用—volumes-from将dbdata挂载到worker容器,然后使用-v参数将容器的/backup目录映射到宿主机的backup目录。然后在容器中执行备份操作,这样就把数据备份到宿主机的/backup目录中了

docker run -it —volumes-from dbdata -v /backup:/backup —name worker centos:6
tar zcf /backup/backup.tar.gz /dbdata

还原数据:
#创建一个新容器,并用-v参数挂载本地的备份目录,然后执行解压操作,将备份文件解压至/dbdata目录
docker run -it -v /dbdata —name dbdata2 centos:6 /bin/bash #创建一个容器dbdata2
docker run -it —volumes-from dbdata2 -v /backup:/backup centos:6 tar xf /backup/backup.tar.gz

删除数据盘

  1. 查看主机上现有的数据盘

[root@c7docker1 ~]# docker volume ls
DRIVER VOLUME NAME
local 4dcde604b6a54e653aa4be2a89b8755b9c3b99d29a6b3c6f8c7ecd39f15518e3
local 1397ca274779c785cd1fba174a5ca52e31692948d8b587092804d90dad9141cf
local a07a7421c066ad29de2dd6fa691e46bf38ad80bb6c9250e7d12fedda08bc2956

  1. 默认情况下,在删除容器时,docker并不会删除其数据盘,查看没有容器在使用的数据盘方法如下:

[root@c7docker1 ~]# docker volume ls -f dangling=true
DRIVER VOLUME NAME
local 4dcde604b6a54e653aa4be2a89b8755b9c3b99d29a6b3c6f8c7ecd39f15518e3
local 1397ca274779c785cd1fba174a5ca52e31692948d8b587092804d90dad9141cf
local a07a7421c066ad29de2dd6fa691e46bf38ad80bb6c9250e7d12fedda08bc2956

  1. 如果想要删除没有使用的数据盘,使用如下指令:

[root@c7docker1 ~]# \
docker volume rm 4dcde604b6a54e653aa4be2a89b8755b9c3b99d29a6b3c6f8c7ecd39f15518e3
4dcde604b6a54e653aa4be2a89b8755b9c3b99d29a6b3c6f8c7ecd39f15518e3

  1. 删除掉容器时,同时删掉数据盘,则使用:

docker rm -v container_name

Docker网络

简介

当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连接在了一个二层网络中。从docker0子网中分配一个ip给容器使用,并设置docker0的ip地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看。而这种网络模式即称之为bridge网络模式。

除了bridge模式以外,docker原生网络,还支持另外两种模式: none和host

可以通过如下方法查看docker的网络:
[root@c7docker1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
4ab1f9040991 bridge bridge local
1b372a769452 host host local
5759bed2180e none null local

bridge网络

bridge网络基本用法

结构示意图
Docker基础四(存储与网络) - 图1
查看bridge网络信息:
# 通过如下命令会列出bridge网络的相关信息,其中”Containers”字段的表示是信息是指当前节点上有哪些容器使用了该网络
[root@c7docker1 ~]# docker network inspect bridge
[
{
“Name”: “bridge”,
“Id”: “4ab1f90409910285176cc6e98a1f8be8b13c55d8bbddaae5e2ad2ed2620c48bd”,
“Created”: “2018-12-04T15:00:42.622485337+08:00”,
“Scope”: “local”,
“Driver”: “bridge”,
“EnableIPv6”: false,
“IPAM”: {
“Driver”: “default”,
“Options”: null,
“Config”: [
{
“Subnet”: “172.16.10.1/24”,
“Gateway”: “172.16.10.1”
}
]
},
“Internal”: false,
“Attachable”: false,
“Ingress”: false,
“ConfigFrom”: {
“Network”: “”
},
“ConfigOnly”: false,
“Containers”: {
“176b71ed27b1cd2d4a13fc50b333d064a9812b848024110a957038503657316e”: {
“Name”: “webserver01”,
“EndpointID”: “92fb7624f1804d86428e2b52a82508582b7d5b5e986e9caa2a3b7251ec09e72d”,
“MacAddress”: “02:42:ac:10:0a:02”,
“IPv4Address”: “172.16.10.2/24”,
“IPv6Address”: “”
},
“628298acc11f9703cccce5e6c9518659895de52af6a69542083156f90ae084c5”: {
“Name”: “webserver02”,
“EndpointID”: “34b409591927f0473a64e80c132da3c60013acb34d7124161a17aa1098ad9be7”,
“MacAddress”: “02:42:ac:10:0a:03”,
“IPv4Address”: “172.16.10.3/24”,
“IPv6Address”: “”
}
},
“Options”: {
“com.docker.network.bridge.default_bridge”: “true”,
“com.docker.network.bridge.enable_icc”: “true”,
“com.docker.network.bridge.enable_ip_masquerade”: “true”,
“com.docker.network.bridge.host_binding_ipv4”: “0.0.0.0”,
“com.docker.network.bridge.name”: “docker0”,
“com.docker.network.driver.mtu”: “1500”
},
“Labels”: {}
}
]

基于bridge网络的容器访问外部网络

默认情况下,基于bridge网络容器即可访问外部网络,这是因为默认情况下,docker使用了iptables的snat转发来实现容器对外部的访问(需要内核开启net.ipv4.ip_forward=1)

外部网络访问基于bridge网络的容器

如果想让外界可以访问到基于bridge网络创建的容器提供的服务,则必须要告诉docker要使用的端口。
可以通过如下方法查看镜像会使用哪些端口:
root@c7docker1 ~]# docker inspect nginx:latest |grep -2 “ExposedPorts”
“AttachStdout”: false,
“AttachStderr”: false,
“ExposedPorts”: {
“80/tcp”: {}
},

“AttachStdout”: false,
“AttachStderr”: false,
“ExposedPorts”: {
“80/tcp”: {}
},

在创建容器的时候可以指定这个容器的端口与主机端口的映射关系:
[root@c7docker1 ~]# docker run -d —name webserver03 -p 8888:80 nginx
a67e63fb37ab4ec3a64cb1ab0c7d7ada1389204c3d0ba7454502f21a15676c6e
-p: 可以指定主机与容器的端口关系,冒号左边是主机的端口,右边是映射到容器中的端口
-P:该参数会分配镜像中所有的会使用的端口,并映射到主机上的随机端口

查看容器的端口情况
[root@c7docker1 ~]# docker port a67
80/tcp -> 0.0.0.0:8888

none网络

故名思议,none网络就是什么都没有的网络。使用none网络的容器除了lo,没有其他任何网卡,完全隔离。用于既不需要访问外部服务,也不允许外部服务访问自己的应用场景。

查看none网络信息:
[root@c7docker1 ~]# docker network inspect none
[
{
“Name”: “none”,
“Id”: “5759bed2180e59df1c39e9d0ffc611049628b46c1bcdf6195ad4d0d26fb8ebec”,
“Created”: “2018-11-29T16:15:11.148324726+08:00”,
“Scope”: “local”,
“Driver”: “null”,
“EnableIPv6”: false,
“IPAM”: {
“Driver”: “default”,
“Options”: null,
“Config”: []
},
“Internal”: false,
“Attachable”: false,
“Ingress”: false,
“ConfigFrom”: {
“Network”: “”
},
“ConfigOnly”: false,
“Containers”: {},
“Options”: {},
“Labels”: {}
}
]

创建使用none网络容器

[root@c7docker1 ~]# docker run -d —name web_network-none —net none nginx
bcba83658cc0db8f8ffc2544d7cc507217c45aa8a34bcc3c60a2cdf614bbdcd1
[root@c7docker1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bcba83658cc0 nginx “nginx -g ‘daemon of…” 5 seconds ago Up 3 seconds web_network-none

host网络

使用host网络的主机,与宿主机共享网络地址,可以获得最好的数据转发性能。缺点是,同一个宿主机上的多个容器共享同一个ip地址,如果多容器使用相同的端口,需要自行解决端口冲突问题。

同样的,可以通过如下方式查看host网络信息:
[root@c7docker1 ~]# docker network inspect host
[
{
“Name”: “host”,
“Id”: “1b372a769452d13c4733d96220e5160c577c0e26dc0e5b501a778bdbc0703c90”,
“Created”: “2018-11-29T16:15:11.278910033+08:00”,
“Scope”: “local”,
“Driver”: “host”,
“EnableIPv6”: false,
“IPAM”: {
“Driver”: “default”,
“Options”: null,
“Config”: []
},
“Internal”: false,
“Attachable”: false,
“Ingress”: false,
“ConfigFrom”: {
“Network”: “”
},
“ConfigOnly”: false,
“Containers”: {},
“Options”: {},
“Labels”: {}
}
]
创建一个使用host网络容器
[root@c7docker1 ~]# docker run -d —name web_network-host —net host nginx
db3ced23161740cc8a1ec399b772a9601e6714daa245b24929f454060aca86a5
[root@c7docker1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
db3ced231617 nginx “nginx -g ‘daemon of…” 9 seconds ago Up 7 seconds web_network-host

自定义网络

Docker除了提供三种的默认网络模式之外,也允许用户针对一些特定的应用场景去创建一些自定义的网络。这样属于这个网络的容器就可以单独隔离出来,它们之间可以相互通信,而不在这个网络的容器就不能直接访问到它们。一个容器可以属于多个网络,同一个自定义网络下的容器可以通过各自的容器名访问到对方,因为会使用到docker内嵌的一个dns功能。

Docker提供三种自定义网络驱动:
•bridge
•overlay
•macvlan

自定义bridge网络

创建一个自定义网络

1、创建一个叫作my_net的自定义网络:
docker network create —driver bridge my_net #—driver用于指定网络类型

可以通过docker network ls 查看到新创建的my_net网络相关信息,Subnet表示这个网络下的子网IP段,那么基于my_net自定义网络创建的容器IP都会以该IP段开头。

2、基于my_net网络创建容器:
docker run -d —name web2 —net my_net nginx

通过指定子网和网关的方式创建自定义网络

1、通过指定子网和网关的方式创建my_net2网络:
docker network create —driver bridge —subnet 172.22.16.0/24 —gateway 172.22.16.1 my_net2

2、创建一个容器使用my_net2网络:
docker run —it —network=my_net2 busybox

3、创建一个容器的使用my_net2网络的同时指定其ip地址:
docker run —it —network=my_net2 —ip=172.22.16.8 busybox

使用自定义网络与默认网络互通

假设我们在默认的bridge网络中,还有一个httpd的容器:
docker run -d —name webserver httpd:2.4

此时默认网络中的容器与my_net2网络中的容器是无法互相通信的。宿主机上网络结构如下:

Docker基础四(存储与网络) - 图2

如果想让默认bridge网络的httpd与my_net2中的容器通信,可以给httpd容器添加一块自定义网络的网卡,使用如下指令:
docker network connect my_net2 webserver

如果要将webserver新添加的这块网卡移除,可以使用如下命令:
docker network disconnect bridge webserver

同一台宿主机容器互联

同一台宿主机上的容器互联有两种方式,第一种是基于ip,默认情况下,同一个宿主机上的容器ip是互通的。另一种方式是使用—link实现:
docker run -d —name db1 -e “MYSQL_ROOT_PASSWORD=123456” -P mysql:5.6

docker run -d —link db1:db1 —name webserver1 httpd:2.4