docker使用linux桥接,在宿主机虚拟一个docker容器网桥(docker0),docker启动一个容器时会根据docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能通过容器的Container-IP直接通信。
docker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法直接通过Container-IP访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主机(端口映射),即docker run 创建容器的时候,通过-p或者-P参数来启用。访问容器的时候,就通过【宿主机IP】:【容器端口】访问容器。
Host:容器不会虚拟出自己的网卡,配置主机的IP等,而是使用宿主机的IP和端口
Container:创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口的范围。
None:该模式关闭了容器的网络功能。
Bridge:默认为该模式,桥接,此模式会为每一个容器分配,设置IP等,并将容器连接到一个docker0的虚拟网桥,通过docker0 网桥以及iptables nat表配置与宿主机通信。
相当于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
指定新创建的容器和已经存在的一个容器共享一个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]
使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。
也就是说,这个Docker容器没有网卡、IP、路由等信息。这种网络模式下容器只有lo回环网络,没有其他网卡。
这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。none模式:使用 --net=none指定,使用none 模式,docker 容器有自己的network Namespace ,但是并不为Docker 容器进行任何网络配置。也就是说,这个Docker 容器没有网卡,ip, 路由等信息。这种网络模式下,容器只有lo 回环网络,没有其他网卡。
这种类型没有办法联网,但是封闭的网络能很好的保证容器的安全性该容器将完全独立于网络,用户可以根据需要为容器添加网卡。此模式拥有所有端口。(none网络模式配置网络)特殊情况下才会用到,一般不用。
bridge模式是docker的默认网络模式,不写 – net参数,就是bridge模式。
相当于Vmware中的 nat 模式,容器使用独立network Namespace,并连接到docker0虚拟网卡。通过docker0网桥以及iptables nat表配置与宿主机通信,此模式会为每一个容器分配Network Namespace、设置IP等,并将一个主机上的 Docker 容器连接到一个虚拟网桥上。
[root@localhost ~]#docker run -itd --name test3 centos:7 /bin/bash
8db340ca5fcf2927c818334e6ce9cd3b88f538a56bed2862a67f9458d4951a85
[root@localhost ~]#docker inspect test3 | grep -i 'networkmode'
"NetworkMode": "default",
[root@localhost ~]#docker network ls
配置 环境 网关 挂载 cmd信息
docker inspect 容器ID
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
可以先自定义网络,再使用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
随机映射端口(从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
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
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
-m(–memory=) 选项用于限制容器可以使用的最大内存
[root@localhost ~]#docker run -itd --name test3 -m 512m centos:7 /bin/bash
[root@localhost ~]#docker stats
创建容器,并限制写速度
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
[root@localhost ~]#docker system prune -a
创建的容器默认处于停止状态,不运行任何程序,需要再其中发起一个进程来启动容器
格式
docker create [选项] 镜像
常用选项:
-i:让容器开启标准输入
-t:让Docker分配一个伪终端tty
-it:合起来实现和容器交互的作用,运行一个交互式会话shell
[root@localhost ~]#docker create -it nginx:latest /bin/bash
格式
docker ps [选项] -a 显示所有的容器
##字段说明
CONTAINER ID:容器的ID号
IMAGE:加载的镜像
COMMAND :运行的程序
CREATED :创建时间
STATUS:当前的状态
PORTS:端口映射
NAMES:名称
格式
docker start 容器ID
[root@localhost ~]#docker start 993ddb2ddae1
993ddb2ddae1
[root@localhost ~]#docker ps -a
#加 -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"
格式
docker inspect 容器ID
[root@localhost ~]#docker ps -a #先查看运行时的ID
[root@localhost ~]#docker inspect 514d65555c3c # 查看容器IP地址
进入容器的容器状态必须是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
用户可以将任何一个 Docker 容器从一台机器迁移到另一台机器。在迁移过程中,可以使用docker export 命令将已经创建好的容器导出为文件,无论这个容器是处于运行状态还是停止状态均可导出。可将导出文件传输到其他机器,通过相应的导入命令实现容器的迁移
格式
docker export 容器ID/名称 > 文件名
[root@localhost ~]#docker export 179b109e1f9f > centos.bak
格式
docker import – 镜像名称:标签
docker import centos.bak centos:v1 #导入后会生成镜像,但不会创建容器
格式
docker rm [-f] 容器ID/名称
#不能删除正在运行状态的容器,只能-f强制删除,或者先停止容器 再删除
(1)运行状态的容器无法直接删除,加上 -f 强制删除
[root@localhost ~]#docker rm 92891a32c585
[root@localhost ~]#docker rm -f 92891a32c585
[root@localhost ~]#docker rm 179b109e1f9f
[root@localhost ~]#docker rm angry_lumiere
[root@localhost ~]#docker rm -f `docker ps -q`
[root@localhost ~]#docker ps -a | awk ' {print "docker rm "$1}' | bash
[root@localhost ~]#for i in `docker ps -a | grep -i exit | awk '{print $1}'`; do docker rm -f $i;done
[root@localhost ~]#docker stats
如何把脚本传入一个正在运行的容器,使用cp命令复制进去
#使用cp命令复制进去容器
docker cp start.sh cenos_v1:/opt
#使用cp命令从容器复制出来
docker cp cenos_v1:/opt/start.sh ./
docker中,假设运行一个业务容器,但是业务容器需要暴露三个端口,启动后发现自己少加了一个端口。如何动态添加端口(如何对已经运行的容器添加或者修改端口)?