• 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加端口访问了  
    

    docker3

    当使用-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 就创建了在主机和所有容器之间一个虚拟共享网络。

    docker5

    快速配置指南

    # 下面是一个跟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服务即可生效.

  • 相关阅读:
    mysql 数据库信息常用命令
    Linux 目录详细介绍
    RPC调用和HTTP调用的区别
    maven 常见命令
    SpringCloud微服务常见组件理解
    Java实现CORS跨域请求
    Java 静态代理和动态代理例子
    Mabatis中#{}和${}的区别
    针对海量数据和高并发的主要解决方案
    SOAP webserivce 和 RESTful webservice 对比及区别
  • 原文地址:https://www.cnblogs.com/you-men/p/13124941.html
Copyright © 2020-2023  润新知