您现在的位置是:首页 >技术交流 >Docker容器---网络、容器操作网站首页技术交流

Docker容器---网络、容器操作

指尖_流逝的年华 2023-05-27 16:00:02
简介Docker容器---网络、容器操作

一、docker实现原理

docker使用linux桥接,在宿主机虚拟一个docker容器网桥(docker0),docker启动一个容器时会根据docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能通过容器的Container-IP直接通信。

docker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法直接通过Container-IP访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主机(端口映射),即docker run 创建容器的时候,通过-p或者-P参数来启用。访问容器的时候,就通过【宿主机IP】:【容器端口】访问容器。

二、docker网路模式

Host:容器不会虚拟出自己的网卡,配置主机的IP等,而是使用宿主机的IP和端口

Container:创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口的范围。

None:该模式关闭了容器的网络功能。

Bridge:默认为该模式,桥接,此模式会为每一个容器分配,设置IP等,并将容器连接到一个docker0的虚拟网桥,通过docker0 网桥以及iptables nat表配置与宿主机通信。

1、Host模式

相当于Vmware中的桥接模式,与宿主机在同一个网络中,但没有独立IP地址。

Docker使用了Linux的Namespaces技术来进行资源隔离,如PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等。

一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、iptable规则等都与其他的Network Namespace隔离。

一个Docker容器一般会分配一个独立的Network Namespace。 但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡、配置自己的IP等,而是使用宿主机的IP和端口。

#创建容器web 1,指定网络模式为 host
#因为是host模式,所有宿主机和容器共享ip和端口
[root@localhost ~]#docker run -d --name web1 --net=host nginx

#访问宿主机的ip和80端口,则可以访问到web3的nginx服务
 firefox  http://192.168.10.137:80

在这里插入图片描述
在这里插入图片描述

2、container模式

指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。
在这里插入图片描述

#基于镜像centos:7 创建一个名为test1的容器
[root@localhost ~]#docker run  -itd --name test1 centos:7 /bin/bash
[root@localhost ~]#docker inspect -f '{{.State.Pid}}' c9da0f0f01a6
#查看容器的pid号
root@localhost ~]#docker inspect -f '{{.State.Pid}}' c9da0f0f01a6
69330
#查看该容器的命名空间编号
[root@localhost ~]#ls -l /proc/69330/ns
总用量 0
lrwxrwxrwx. 1 root root 0 4月  19 14:57 ipc -> ipc:[4026532582]
lrwxrwxrwx. 1 root root 0 4月  19 14:57 mnt -> mnt:[4026532580]
lrwxrwxrwx. 1 root root 0 4月  19 14:04 net -> net:[4026532585]
lrwxrwxrwx. 1 root root 0 4月  19 14:57 pid -> pid:[4026532583]
lrwxrwxrwx. 1 root root 0 4月  19 14:57 user -> user:[4026531837]
lrwxrwxrwx. 1 root root 0 4月  19 14:57 uts -> uts:[4026532581]

#创建test2容器,使用container网络模式,和test1共享network Namespace
[root@localhost ~]#docker run -itd --name test2 --net=container:test1 centos:7 /bin/bash
#查看test2容器的pid
[root@localhost ~]#docker inspect -f '{{.State.Pid}}' 6a2639e850d2
70732
#查看该容器的命名空间编号
[root@localhost ~]#ls -l /proc/70732/ns
总用量 0
lrwxrwxrwx. 1 root root 0 4月  19 15:04 ipc -> ipc:[4026532661]
lrwxrwxrwx. 1 root root 0 4月  19 15:04 mnt -> mnt:[4026532659]
lrwxrwxrwx. 1 root root 0 4月  19 15:04 net -> net:[4026532585]
lrwxrwxrwx. 1 root root 0 4月  19 15:04 pid -> pid:[4026532662]
lrwxrwxrwx. 1 root root 0 4月  19 15:04 user -> user:[4026531837]
lrwxrwxrwx. 1 root root 0 4月  19 15:04 uts -> uts:[4026532660]

在这里插入图片描述

3、none模式

使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。
也就是说,这个Docker容器没有网卡、IP、路由等信息。这种网络模式下容器只有lo回环网络,没有其他网卡。
这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。none模式:使用 --net=none指定,使用none 模式,docker 容器有自己的network Namespace ,但是并不为Docker 容器进行任何网络配置。也就是说,这个Docker 容器没有网卡,ip, 路由等信息。这种网络模式下,容器只有lo 回环网络,没有其他网卡。
这种类型没有办法联网,但是封闭的网络能很好的保证容器的安全性该容器将完全独立于网络,用户可以根据需要为容器添加网卡。此模式拥有所有端口。(none网络模式配置网络)特殊情况下才会用到,一般不用。

4、bridge模式

bridge模式是docker的默认网络模式,不写 – net参数,就是bridge模式。

相当于Vmware中的 nat 模式,容器使用独立network Namespace,并连接到docker0虚拟网卡。通过docker0网桥以及iptables nat表配置与宿主机通信,此模式会为每一个容器分配Network Namespace、设置IP等,并将一个主机上的 Docker 容器连接到一个虚拟网桥上。

  • 当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
  • 从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备。veth设备总是成对出现的,它们组成了一个数据的通道,数据从一个设备进入,就会从另一个设备出来。因此,veth设备常用来连接两个网络设备。
  • Docker将veth pair 设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以veth*这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过 brctl show 命令查看。
    容器之间通过veth pair进行访问
  • 使用 docker run -p 时,docker实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables
    -t nat -vnL 查看。
[root@localhost ~]#docker run -itd --name test3 centos:7 /bin/bash
8db340ca5fcf2927c818334e6ce9cd3b88f538a56bed2862a67f9458d4951a85
[root@localhost ~]#docker inspect  test3 | grep -i 'networkmode'
            "NetworkMode": "default",

在这里插入图片描述

三、自定义网络

1、查看网络模式列表

[root@localhost ~]#docker network ls

在这里插入图片描述

2、查看容器信息

配置 环境 网关 挂载 cmd信息

docker inspect  容器ID

在这里插入图片描述

3、指定分配IP地址

docker run -itd --name test1 --network bridge --ip 172.17.0.10 centos:7 /bin/bash
#以上会报错,因为用户使用的ip地址不被规则所允许,docker0定义的就是按照顺序来,所有需要创建一个

docker network create --subnet=172.18.0.0/16 zz

在这里插入图片描述
进入容器

[root@localhost ~]#docker exec -it test2 bash
[root@c9da0f0f01a6 /]# yum install -y net-tools

在这里插入图片描述
在这里插入图片描述

4、自定义网络固定IP

可以先自定义网络,再使用IP运行docker

[root@localhost ~]#docker run -itd --name test02 --net zz --ip 172.18.0.8 centos:7 /bin/bash
[root@localhost ~]#docker inspect test02 |grep IPAddress

在这里插入图片描述

四、暴露端口

两个端口一样的情况下,暴露出去会导致地址冲突,所有需要docker0上需要做一个端口映射,通过ens33暴露出去端口不同就可以

[root@localhost ~]#docker run -itd -p 8082:80 nginx:latest /bin/bash
[root@localhost ~]#docker ps -a
[root@localhost ~]#docker exec -it 21441c32b54a /bin/bash

在这里插入图片描述
网页测试
在这里插入图片描述
在这里插入图片描述

五、容器端口映射

1、创建端口映射

随机映射端口(从32768开始)docker run -d --name  为容器指定名称 -P   镜像

指定映射端口docker   run -d --name 为容器指定名称  -p  宿主机端口:容器内端口   镜像

#使用nginx镜像创建容器,名称为web1 ,随机映射端口
[root@localhost ~]#docker run -d --name web1 -P nginx:latest
[root@localhost ~]#docker ps -a
CONTAINER ID   IMAGE          COMMAND                   CREATED         STATUS         PORTS                                     NAMES
44e97729e4c8   nginx:latest   "/docker-entrypoint.…"   5 seconds ago   Up 5 seconds   0.0.0.0:32770->80/tcp, :::32770->80/tcp   web1
#使用nginx镜像创建容器,名称为web2,将容器内的80端口映射到宿主机的39901端口
[root@localhost ~]#docker run -d --name web2 -p 39901:80 nginx:latest
[root@localhost ~]#docker ps -a
CONTAINER ID   IMAGE          COMMAND                   CREATED              STATUS              PORTS                                     NAMES
993ddb2ddae1   nginx:latest   "/docker-entrypoint.…"   3 seconds ago        Up 2 seconds        0.0.0.0:39901->80/tcp, :::39901->80/tcp   web2
44e97729e4c8   nginx:latest   "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:32770->80/tcp, :::32770->80/tcp   web1
#主机查看端口号
[root@localhost ~]#ss -natp | grep docker
LISTEN     0      128          *:39901                    *:*                   users:(("docker-proxy",pid=78182,fd=4))
LISTEN     0      128          *:32770                    *:*                   users:(("docker-proxy",pid=77893,fd=4))
LISTEN     0      128         :::39901                   :::*                   users:(("docker-proxy",pid=78188,fd=4))
LISTEN     0      128         :::32770                   :::*                   users:(("docker-proxy",pid=77900,fd=4))
#实际上是通多nat表进行转发
[root@localhost ~]#iptables -nL -t nat

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

六、资源控制

1、CPU资源控制

cgroups,是一个非常强大的linux内核工具,他不仅可以限制被 namespace 隔离起来的资源, 还可以为资源设置权重、计算使用量、操控进程启停等等。 所以 cgroups(Control groups)实现了对资源的配额和度量。

cgroups有四大功能

●资源限制:可以对任务使用的资源总额进行限制
●优先级分配:通过分配的cpu时间片数量以及磁盘IO带宽大小,实际上相当于控制了任务运行优先级
●资源统计:可以统计系统的资源使用量,如cpu时长,内存用量等
●任务控制:cgroup可以对任务执行挂起、恢复等操作

(1)设置CPU使用率上限

Linux通过CFS(Completely Fair Scheduler,完全公平调度器)来调度各个进程对CPU的使用。CFS默认的调度周期是100ms。我们可以设置每个容器进程的调度周期,以及在这个周期内各个容器最多能使用多少 CPU 时间。

使用 --cpu-period 即可设置调度周期,使用 --cpu-quota 即可设置在每个周期内容器能使用的CPU时间。两者可以配合使用。

CFS 周期的有效范围是 1ms~1s,对应的 --cpu-period 的数值范围是 1000~1000000。 周期100毫秒 而容器的 CPU 配额必须不小于 1ms,即 --cpu-quota 的值必须 >= 1000。
在这里插入图片描述
压力测试

[root@localhost ~]#docker exec -it 95f0d90ff3aa /bin/bash
[root@95f0d90ff3aa /]# vim /cpu.sh
#!/bin/bash
i=0
while true
do
let i++
done

[root@95f0d90ff3aa /]# vim /cpu.sh
[root@95f0d90ff3aa /]# chmod +x /cpu.sh 
[root@95f0d90ff3aa /]# ./cpu.sh 
#在另开一个窗口
[root@localhost /]#top

在这里插入图片描述

设置50%的比例分配CPU使用时间上限

[root@localhost ~]#docker run -itd --name test2 --cpu-quota 50000 centos:7 /bin/bash
[root@localhost ~]#cd /sys/fs/cgroup/cpu/docker/f9221c47b85d75f204d82ab1c9a30e3043ac6e872a8e518d52ca567e27f0091a/
[root@localhost f9221c47b85d75f204d82ab1c9a30e3043ac6e872a8e518d52ca567e27f0091a]#echo 50000 > cpu.cfs_quota_us

[root@localhost f9221c47b85d75f204d82ab1c9a30e3043ac6e872a8e518d52ca567e27f0091a]#docker exec -it f9221c47b85d /bin/bash
[root@localhost ~]#docker exec -it f9221c47b85d /bin/bash
[root@f9221c47b85d /]# vim /cpu.sh

#!/bin/bash
i=0
while true
do
let i++
done

[root@f9221c47b85d /]# chmod  +x /cpu.sh 
[root@f9221c47b85d /]# ./cpu.sh 
[root@localhost ~]#top

在这里插入图片描述
(2)设置CPU资源占用比(设置多个容器时才有效)

Docker 通过 --cpu-shares 指定 CPU 份额,默认值为1024,值为1024的倍数。

[root@localhost ~]#docker run -itd --name c1 --cpu-shares 512 centos:7
[root@localhost ~]#docker run -itd --name c2 --cpu-shares 1024 centos:7

[root@localhost ~]#docker exec -it f0f4b57bb776 /bin/bash
[root@f0f4b57bb776 /]# yum install -y epel-release
[root@f0f4b57bb776 /]# yum install -y stress

在这里插入图片描述

2.内存使用的限制

-m(–memory=) 选项用于限制容器可以使用的最大内存

[root@localhost ~]#docker run -itd --name test3 -m 512m  centos:7 /bin/bash
[root@localhost ~]#docker stats

在这里插入图片描述

3、磁盘IO配额控制(blkio)的限制

创建容器,并限制写速度

root@localhost ~]#docker run  -it --name test4 --device-write-bps /dev/sda:1MB centos:7 /bin/bash
[root@71bc94927214 /]# dd if=/dev/zero of=test4.out bs=1M count=10 oflag=direct

在这里插入图片描述
清理docker占用的磁盘空间

[root@localhost ~]#docker system prune -a

在这里插入图片描述

七、docker容器操作

1、创建容器

创建的容器默认处于停止状态,不运行任何程序,需要再其中发起一个进程来启动容器

格式
  docker create [选项] 镜像

常用选项:
-i:让容器开启标准输入
-t:让Docker分配一个伪终端tty
-it:合起来实现和容器交互的作用,运行一个交互式会话shell

[root@localhost ~]#docker create -it nginx:latest /bin/bash

在这里插入图片描述

2、查看所有容器以及状态

格式
docker ps [选项]   -a 显示所有的容器

##字段说明
CONTAINER ID:容器的ID号
IMAGE:加载的镜像
COMMAND :运行的程序
CREATED :创建时间
STATUS:当前的状态
PORTS:端口映射
NAMES:名称

在这里插入图片描述

3、启动容器

格式
docker start 容器ID 

[root@localhost ~]#docker start 993ddb2ddae1
993ddb2ddae1
[root@localhost ~]#docker ps -a

在这里插入图片描述

4、启动容器(一次性执行)—— docker run

#加 -d 选项让 Docker 容器以守护形式在后台运行。并且容器所运行的程序不能结束。

#例1:
docker run -itd nginx:latest /bin/bash

在这里插入图片描述

#例2:执行后不退出,以守护进程方式执行持续性任务
docker run -d centos:7 /usr/local/bash -c "while true;do echo zz;done" 

在这里插入图片描述

5、查看容器ip地址

格式
docker inspect 容器ID 

[root@localhost ~]#docker ps -a    #先查看运行时的ID
[root@localhost ~]#docker inspect 514d65555c3c  # 查看容器IP地址

在这里插入图片描述
在这里插入图片描述

6、进入容器

进入容器的容器状态必须是up状态、和shell 是两种运行模式

docker run -it会创建前台进程,但是会在输入exit后终止进程。
docker attach会通过连接stdin,连接到容器内输入输出流,会在输入exit后终止容器进程。
docker exec -it 会连接到容器,可以像SSH一样进入容器内部,进行操作,可以通过exit退出容器,不影响容器运行。

格式
docker exec -it 容器ID/名称 /bin/bash
-i 选项表示让容器的输入保持打开;
-t 选项表示让 Docker 分配一个伪终端。
#例:进入(三种方式)
[root@localhost ~]#docker run -it centos:7 /bin/bash   #先运行容器
[root@localhost ~]#docker ps -a  
①使用run进入,可以使用ctrl+d退出,直接退出终端
③docker attach,会通过连接stdin,连接到容器内输入输出流,公在输入exit后终止容器进程(临时性的,不推荐)

(1)使用run进入,一次性进入
在这里插入图片描述
(2)永久性进入,用docker exec
在这里插入图片描述
在这里插入图片描述

7、容器导出/导入

用户可以将任何一个 Docker 容器从一台机器迁移到另一台机器。在迁移过程中,可以使用docker export 命令将已经创建好的容器导出为文件,无论这个容器是处于运行状态还是停止状态均可导出。可将导出文件传输到其他机器,通过相应的导入命令实现容器的迁移

格式
docker export 容器ID/名称 > 文件名
[root@localhost ~]#docker export 179b109e1f9f > centos.bak

导出
在这里插入图片描述

格式
docker import – 镜像名称:标签
docker import centos.bak  centos:v1	#导入后会生成镜像,但不会创建容器

导入
在这里插入图片描述

8、删除容器

格式
docker rm [-f] 容器ID/名称
#不能删除正在运行状态的容器,只能-f强制删除,或者先停止容器 再删除

(1)运行状态的容器无法直接删除,加上 -f 强制删除

[root@localhost ~]#docker rm 92891a32c585
[root@localhost ~]#docker rm -f 92891a32c585

在这里插入图片描述
(2)已退出的容器,可以直接删除

[root@localhost ~]#docker rm 179b109e1f9f

在这里插入图片描述
(3)基于名称匹配的方式删除

[root@localhost ~]#docker rm  angry_lumiere

在这里插入图片描述
(4)删除所有运行状态的容器

[root@localhost ~]#docker rm -f `docker ps -q`

在这里插入图片描述
(5)有选择性的批量删除<正则匹配>

[root@localhost ~]#docker ps -a | awk ' {print "docker rm  "$1}' | bash

在这里插入图片描述
(6)删除退出状态的容器

[root@localhost ~]#for i in `docker ps -a | grep -i exit | awk '{print $1}'`; do docker rm -f $i;done

在这里插入图片描述
(7)查看docker消耗资源状态

[root@localhost ~]#docker stats

在这里插入图片描述
总结

如何把脚本传入一个正在运行的容器,使用cp命令复制进去

#使用cp命令复制进去容器
docker cp start.sh cenos_v1:/opt
#使用cp命令从容器复制出来
docker cp cenos_v1:/opt/start.sh ./

docker中,假设运行一个业务容器,但是业务容器需要暴露三个端口,启动后发现自己少加了一个端口。如何动态添加端口(如何对已经运行的容器添加或者修改端口)?

  • 首先,我们可以修改/var/lib/docker/containers/containers_id中两个文件
  • hostconfig.json 中的 portbinding:{}修改端口或添加端口
  • 修改config.v2.json文件,修改对应的Ports{}来添加/修改端口
  • 最后,重启守护进程。
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。