03 . Docker数据资源管理与网络

时间:2022-07-25
本文章向大家介绍03 . Docker数据资源管理与网络,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Docker数据卷

在容器中管理数据主要有两种方式

# 数据卷(Data volumes)
# 数据卷容器(Data volume containers)

# 数据卷是一个可供一个或多个容器使用的特殊目录,它绕过	UFS,可以提供很多有用的特性:

# 1. 数据卷可以在容器之间共享和重用
# 2. 对数据卷的修改会立即生效
# 3. 对数据卷的更新,不会影响镜像
# 4. 卷会一直存在,知道没有容器使用

# 数据卷的使用类似于Linux下对目录或文件进行mount.
创建一个数据卷

在用 docker run 命令的时候,使用 -v 标记来创建一个数据卷并挂载到容器里。在一次 run 中多次使用 可以挂载多个数据卷。Dockerfile中使用VOLUME也能实现一样效果. 下面创建一个 web 容器,并加载一个数据卷到容器的 /webapp 目录。

docker run -itd --name nginx_web -v /nginx_web:/usr/share/nginx/html nginx:latest
docker exec -it d4d bash
echo 1 > /usr/share/nginx/html/index.html
cat /nginx_web/index.html 
1
echo 4 > /nginx_web/index.html
docker inspect --format='{{.NetworkSettings.IPAddress}}' d4d
172.17.0.2
curl 172.17.0.2
4

# Docker挂载数据卷默认权限是读写,用户可以通过:ro指定为只读.
docker run -d --name web -v /nginx_web:/usr/share/nginx/html:ro nginx:latest
docker exec -it web /bin/bash
echo 5 > /usr/share/nginx/html/index.html
bash: /usr/share/nginx/html/index.html: Read-only file system

echo 5 > /nginx_web/index.html 
curl 172.17.0.2
5
数据卷容器
  • 如果你有一些持续更新的数据需要在容器之间共享,最好创建数据卷容器。
  • 数据卷容器,其实就是一个正常的容器,专门用来提供数据卷供其它容器挂载的。
  • 首先,创建一个命名的数据卷容器: dbdata
docker run -d -v /dbdata --name dbdata training/postgres echo Data-only container for postgres
# 发现创建好的数据卷容器是出于停止运行的状态,因为使用 --volumes-from 参数
# 所挂载数据卷的容器自己并不需要保持在运行状态。

# 然后我们再创建容器挂载这个数据卷。
docker run -d --volumes-from dbdata --name db1 training/postgres
docker run -d --volumes-from dbdata --name db2 training/postgres
# 还可以使用多个 --volumes-from 参数来从多个容器挂载多个数据卷。 
# 也可以从其他已经挂载了数据卷的容器来挂载数据卷。

# 如果删除了挂载的容器(包括 dbdata、db1 和 db2),数据卷并不会被自动删除。
# 如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时,
# 要使用 docker rm -v 命令来指定同时删除关联的容器。 
# 这可以让用户在容器之间升级和移动数据卷。
利用数据卷容器来备份、恢复、迁移数据卷
# 首先使用 --volumes-from 标记来创建一个加载 dbdata 容器卷的容器,
# 并从本地主机挂载当前到容器的 /backup 目录。命令如下:
docker run -itd  --volumes-from dbdata -v /dbdata:/backup centos:7.7.1908 /bin/bash
docker exec -it 7456 /bin/bash
# 将此处的etc数据假设是重要的应用程序数据,防止容器宕机丢失,我们先备份.
tar -zcf /dbdata/etc.tar.gz /etc/
[root@745690bc3a7c ~]# ll -h /dbdata/
total 660K
-rw-r--r-- 1 root root 660K Dec 13 08:04 etc.tar.gz

# 突然有一天容器坏了进不去了,我们可以去查看一些容器数据卷.看到里面有我们之前挂载的数据.
docker exec -it db1 /bin/bash
root@45f97c29e5b3:/# ls -lh /dbdata/etc.tar.gz 
-rw-r--r-- 1 root root 660K Dec 13 08:04 /dbdata/etc.tar.gz
# 接下来我们只需要再创建一个跟以前一样的容器,挂载此数据卷容器,就可以数据恢复了.

资源配置

内存资源
# 设置内存我们可以有四种方式:
# 默认的方式设置最低值,容器可以使用大于此最低值的内存数
# 设置memory不能使用超过L的值
# memory不能超过L,swap+memory总使用量不能超过S

第一种情况(默认不做任何限制)

docker run -ti -m 300M --memory-swap -1 centos:7.7.1908  /bin/bash

第二种情况(memory最多使用300M,swap没有限制)

docker run -itd -m 500m centos:7.7.1908 /bin/bash

第三种情况 (我们只设置了memory限制时300M,swap没有指定,默认被设置为与memory一样的值。memory+swap一共是600M)

docker run -ti -m 300M --memory-swap 1G centos:7.7.1908  /bin/bash

第四种情况

如果发生内存溢出错误,内核讲kill掉容器中的进程。如果你想控制,可以配合使用- -oom-kill-disable参数。如果没有制定-m参数,可能导致当内存溢出时内核会杀死主机进程。 例子: 设置容器内存限制100M,并且阻止 OOM killer

docker run -ti -m 100M --oom-kill-disable centos:7.7.1908 /bin/bash
CPU资源限制

默认情况下,所有容器获得CPU周期的比例相同。可以通过改变容器的CPU加权占有率相对于其他正在运行容器的加权占有率的比例来调整。 修改1024的比例,使用-c或--cpu-sharesflag的权重设置为2或更高。 该比例只适用在CPU密集型进程运行时。当在一个容器中的任务处于空闲状态,其他容器可以使用剩余空闲CPU时间。实际CPU时间将根据在系统上运行的容器的数目而变化。 例如,考虑三个容器的情况,一个拥有cpu的1024和另外两个有512 CPU共享时间,三个容器进程都尝试使用100%的CPU,第一个容器将获得的50%总的CPU时间。如果您添加CPU值为1024的第四个容器中,第一个容器只得到了CPU的33%。剩余的容器将分别占用CPU的16.5%,16.5%和33%。 在多核心系统中,CPU时间的份额分布在所有CPU核心。即使容器被限制为CPU时间小于100%时,它可以使用每个单独的CPU核心的100%。例如,在一个拥有超过三个核心的系统中, 如果启动一个容器设置-c=512跑一个进程,另外一个设置-c=1024,跑2个进程,内存分配将会如下配置:

PID    container    CPU CPU share
100    {C0}     0   100% of CPU0
101    {C1}     1   100% of CPU1
102    {C1}     2   100% of CPU2

--cpu-period参数

# 默认设置为100ms,当然我们也可以自己设置cpu周期,限制容器CPU用量。通常该参数伴随--cpu-quota参数使用。
--cpu-quota参数
# 限制CPU用量。默认值0,意味着允许容器获得1个CPU的100%的资源量。设置50000限制CPU资源的50%。
docker run -ti --cpu-period=50000 --cpu-quota=25000 centos /bin/bash
# 如果是单核心系统,将意味着容器将每50ms获得50%运行周期。

--cpuset参数

# 设置容器允许运行的cpu号(在多核心系统中):
# 设置容器在CPU1和CPU3上运行
$ sudo docker run -ti --cpuset-cpus="1,3" centos /bin/bash
# 设置容器在CPU0、CPU1、CPU2上运行
docker run -ti --cpuset-cpus="0-2" centos /bin/bash
# 设置容器在指定mems上执行(只在NUMA系统中有效):
# 容器只能在memory nodes 1和2上运行
docker run -ti --cpuset-mems="1,3" centos /bin/bash
网络限制

--bkio-weight参数

默认情况下,所有容器获得相同比例的blokIO带宽,这个比例值是500。要修改此比例,使用--blkio-weight设置容器的blkio相对于其他运行容器权重。它的取值范围是10~1000。 下面的例子中,设置了两个不同blkio:

docker run -ti --name c1 --blkio-weight 300 centos /bin/bash
docker run -ti --name c2 --blkio-weight 600 centos /bin/bash
如果同时设置两个容器blockIO,利用如下指令:
time dd if=/mnt/zerofile of=test.out bs=1M count=1024 oflag=direct

Docker网络

外部访问容器

Docker允许通过外部访问容器或容器互联的方式来提供网络服务. 容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过-P或-p参数来指定端口映射. 当使用-P标记时,Docker会随机映射一个49000-49900的端口到内部容器开放的网络端口.

docker run -d -P nginx:latest  
  
docker ps   
CONTAINER ID  IMAGE         CREATED  STATUS         PORTS          NAMES  
853b948aa479 nginx:latest 4 seconds ago  Up 3 seconds 0.0.0.0:1025->80 /tczealous_booth  
# 此时1025就可以通过公网IP加端口访问了  

当使用-p(小写的)则可以指定要映射的端口,并且在一个指定端口上只可以绑定一个容器,支持可是有ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort.

docker run -d -p 5000:80 nginx:latest  

映射到指定地址的指定端口

docker run -d -p 127.0.0.1:5000:80 nginx:latest  
  
# 还可以使用udp标记来指定udp端口  
docker run -d -p 5000:80/udp nginx:latest  
  
# -p标记可以多次使用来绑定多个端口  
docker run -d -p 5000:80 -p 1314:3306 nginx:latest  

查看映射端口配置

docker port 10b0bc0  
80/tcp -> 0.0.0.0:5000  

容器的互联

容器的连接(linking)系统是除了端口映射外,另一种跟容器中应用交互的方式 该系统会在源和接受容器之间创建一个隧道,接受容器可以看到源容器指定的信息.

自定义容器命名

连接系统依据容器的名称来执行。因此,首先需要自定义一个好记的容器命名。 虽然当创建容器的时候,系统默认会分配一个名字。自定义命名容器有2个好处:

# 1 . 自定义的命名,比较好记,比如一个web应用容器我们可以给它起名叫web

# 1 . 当要连接其他容器时候,可以作为一个有用的参考点,比如连接web容器到db容器

使用 --name标记可以为容器自定义命名

docker run -d -P --name web nginx:latest
5597113c7667403419cdf395747c526463e0feeb62af27d8214f66fb782905da
docker port 5597
80/tcp -> 0.0.0.0:1026
docker inspect -f "{{ .Name}}" 5597
/web
# 注意:
# --rm和 -d参数不能同时使用
# 容器的名称是唯一的。如果已经命名了一个叫`web`的容器,当你要再次使用web	这个名称的时候,
# 需要先用docker rm来删除之前创建的同名容器。
# 在执行docker run的时候如果添加 --rm标记,则容器在终止后会立刻删除。
容器互联

使用--link参数可以让容器之间安全的进行交互

下面创建一个新的数据库容器
docker run -d --name mysql -e MYSQL_ROOT_PASSWORD=youmen mariadb

# 接下来我们创建一个新的web容器,并将它连接到db容器.
docker run -d -P --name nginx --link mysql1:mysql1 nginx:latest

# 我们从下面的hosts文件看到,web容器链接到db容器,web容器将允许访问db容器的信息.
docker exec -it web bash
cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.2	mysql1 fa014ed6cd71
172.17.0.3	e43d7916f5b1

# Docker在两个互联的容器创建了一个安全隧道,而且不用映射他们的端口到宿主主机上,
# 在启动mariadb的时候并没有使用-p和-P标记,从而避免了暴露数据库端口到外部网络上.

# Docker使用2中方式为容器公开链接信息
1. 环境变量
2. 更新/etc/hosts文件

# 用户可链接多个父容器到子容器,比如连接多个web到db容器上,
# 可以用Busybox镜像关联然后ping一下,说明是能互通的。

高级网络配置

当Docker启动时,会自动在主机上创建一个docker0虚拟网桥,实际上是Linux 的一个bridge,可以理解为一个软件交换机。它会在挂载到它的网口之间进行转发。 同时,Docker随机分配一个本地未占用的私有网段(在 RFC1918 中定义)中的一个地址给 docker0接口。比如典型的 172.17.42.1,掩码为 255.255.0.0。此后启动的容器内的网口也会自动分配一个同一网段(172.17.0.0/16 )的地址。 当创建一个Docker容器的时候,同时会创建了一对 veth pair接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即 eth0 ;另一端在本地并被挂载到docker0网桥,名称以 veth开头(例如 vethAQI2QT)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker 就创建了在主机和所有容器之间一个虚拟共享网络。

快速配置指南

# 下面是一个跟Docker网络相关的命令列表.
# 其中有些命令选项只有在Docker服务启动的时候才能配置,而且不能马上生效.
-b  BRIDGE or  --bridge=bridge		# 指定容器挂载的网桥
--bip=CIDR				# 定制docker0的掩码
-H SOCKET...or --host=SOCKET...  	# docker服务接受命令的通道
--icc=true | false			# 是否支持容器之间进行通信.
--ip-forward=true|false			# 请看下文容器之间的通信
--iptables=true|false			# 禁止Docker添加iptables规则
--mtu=BYTES				# 容器网络中的MTU

# 下面2个命令选项既可以在启动服务时指定,也可以在Docker服务启动(docker run)时候指定,
# 在Docker服务启动时候会成为默认值,后面执行docker run时可以覆盖设置的默认值。
--dns=IP_ADDRESS ...			# 使用指定的DNS服务器
--dns=search=DOMAIN...			# 指定DNS搜索域

# 最后这些选项只有在docker run执行时使用,因为他是针对docker容器的特性内容
-h HOSTNAME or --hostname=HOSTNAME	# 配置容器主机名
--link=CONTAINER_NAME:ALIAS		# 添加到另一个容器的连接
--net=bridge |none|container:NAME_or_ID |host	# 配置容器的桥接模式
-P SPEC or --publish=SPEC		# 映射容器端口到宿主主机
-P or --publish-all=true |false		# 映射容器所有端口到宿主主机.

容器访问控制

容器访问外部网络

容器的访问控制,主要通过Linux上的iptables防火墙来进行管理和实现,iptables是linux上默认的防火墙,且大多数发行版都自带.

# 容器要想访问外部网络,则需要本地系统的转发支持,在linux系统中,检查转发是否打开:
sysctl -p|grep ipv4.ip_forward
net.ipv4.ip_forward = 0
# 如果为0说明没有开启转发,需要手动打开,到这个/etc/sysctl.conf配置文件加上并sysctl -p刷新生效即可.

容器之间访问

容器之间相互访问,需要两方面的支持 容器的网络拓扑是否已经失联,默认情况下,所有容器都会被连接到docker0网桥上. 本地系统的防火墙软件iptables是否允许通过.

访问所有端口

当启动docker服务的时候,默认会添加一条转发策略到iptables的FORWARD链上,策略为通过(ACCEPT)还是禁止(DROP)取决于配置--icc=true(缺省值)还是--icc=false,当然,如果手动指定--iptables=false则不会添加iptables规则. 可见,默认情况下,不同容器之间是允许网络互通的,为了安全考虑,可以在/etc/default/docker文件配置DOCKER_OPTS=--icc=false来禁止它。

访问指定端口

在通过-icc=false关闭网络访问后,还可以通过--link=CONTAINER_NAME:ALIAS选项来访问容器的开放端口. 例如,在启动Docker服务时,可以同时使用icc=false --iptables=true参数关闭允许相互的网络访问,并让Docker可以修改系统中的iptables规则.之后,启动容器(docker run)时使用--link=CONTAINER_NAME:ALIAS选项,docker会在iptable中为两个容器分别添加一条ACCEPT规则,允许相互访问开放的端口(取决于Dockerfile中的EXPOSE行),当添加了--link=CONTAINER_NAME:ALIAS选项后,添加了iptables规则. 注意: --link=CONTAINER_NAME:ALIAS中的CONTAINER_NAME目前必须是Docker分配的名字,或使用--name参数指定的名字,否则主机名不会被识别.

映射容器端口到宿主机的实现

默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。 外部访问容器实现 容器允许外部访问可以通过-P或者-p来启用,但不管哪种办法,其实是在本地的iptable的nat表添加相应的规则。 如果希望永久绑定到某个固定的IP地址,可以在Docker配置文件/etc/default/docker中指定 DOCKER_OPTS="--ip=IP_ADDRESS",之后重启Docker服务即可生效.