2023年10月

虚拟化和容器7——实验7 Docker网络管理应用

实验要求

了解Docker常用网络模式,掌握Docker常用网络模式的使用。本实验主要任务是利用busybox镜像建立容器,容器名称为test_busybox1和test_busybox2,将网络模式设置为none,并为容器配置IP地址,容器test_busybox1的IP设置为172.17.0.100,容器test_busybox2的IP设置为172.17.0.200,要求实现两容器互通。

前置准备

要求实验主机能够连接外网,已经正确安装Docker,并关闭防火墙和selinux。

实验过程

步骤1-3

# 步骤1.1: 创建容器test_busybox1,设置网络模式为none
docker run -dit --name=test_busybox1 --net=none busybox:latest

# 进入容器test_busybox1
docker exec -it test_busybox1 /bin/sh

# 步骤1.2: 查看IP地址(容器test_busybox1)
ip addr
# 从现象可以得知容器test_busybox1没有IP地址。

# 退出容器test_busybox1
exit

# 步骤2.1: 创建容器test_busybox2,设置网络模式为none
docker run -dit --name test_busybox2 --net=none busybox:latest
# 进入容器test_busybox2
docker exec -it test_busybox2 /bin/sh
# 步骤2.2: 查看IP地址(容器test_busybox2)
ip address
# 退出容器test_busybox2
exit

从现象可以得知容器test_busybox1,test_busybox2都没有IP地址。

步骤4

# 步骤3: 为容器test_busybox1设置IP地址为172.17.0.100
# 安装bridge-utils软件包
yum -y install bridge-utils

# 创建veth对,并将veth0加入docker0网桥
ip link add veth0 type veth peer name veth1
#           虚拟网桥           peer的name 
brctl addif docker0 veth0
# 桥接管理器 添加 管理桥接
brctl show


# 启动veth0,原神启动 (另外一个veth1也会自动启动)
ip link set veth0 up

# 获取容器test_busybox1的PID
pid1=$(docker inspect -f '{{.State.Pid}}' test_busybox1)
echo "容器test_busybox1的PID是:$pid1"


#有两种途径索引network namespace:名字(例如netns1)或者属于该namespace的进程PID。
#使用命名(Name):为网络命名空间分配可读的名称,然后使用该名称来引用和操作命名空间。这使得管理网络命名空间更加方便和直观。
#使用进程PID:每个网络命名空间都与一个进程相关联,通常是一个子进程。可以使用该进程的PID来访问和管理与之关联的网络命名空间。

# 创建network namespace软连接
mkdir -p /var/run/netns
ln -s /proc/$pid1/ns/net /var/run/netns/$pid1
ip netns ls

# 将veth1连接到容器test_busybox1的network namespace,并重命名为eth0
ip link set veth1 netns $pid1
ip netns exec $pid1 ip link set dev veth1 name eth0



# 启用eth0
ip netns exec $pid1 ip link set eth0 up

# 分配IP地址和设置网关
ip netns exec $pid1 ip addr add 172.17.0.100/24 dev eth0
ip netns exec $pid1 ip route add default via 172.17.0.1

安装包:

网桥:

veth0启动:

PID:


Docker State信息

  1. .Id: 容器的唯一标识符,通常是一个长字符串,也被称为容器ID。
  2. .Name: 容器的名称,通常是用户定义的名称,可以用来引用容器。
  3. .State.Status: 容器的状态,如运行中、停止等。
  4. .State.Running: 表示容器是否正在运行(布尔值)。
  5. .State.Pid: 容器内部主进程的PID。
  6. .Config.Image: 使用的容器镜像的名称。
  7. .Config.Cmd: 启动容器时使用的命令。
  8. .Config.Env: 容器的环境变量。
  9. .NetworkSettings.IPAddress: 容器的IP地址(如果有网络配置)。
  10. .HostConfig.Binds: 挂载到容器内部的卷或目录。
  11. .Mounts: 容器的挂载点信息。
  12. .Created: 容器创建的时间戳。
  13. .Ports: 容器的端口映射信息。
  14. .Labels: 用户定义的容器标签。
  15. .LogPath: 容器的日志文件路径。
  16. .HostConfig.NetworkMode: 容器的网络模式。

netns:

执行完之后,可以看到已经分配到网卡:

目前这个namespace叫2133

然后再命名空间里执行了一些命令。

步骤5

配置容器test_busybox2的网络

# 创建一对虚拟以太网设备veth2和veth3,这两个设备是成对出现的,数据可以在两个设备之间传送
ip link add veth2 type veth peer name veth3

# 将veth2这端加入到docker0桥接器中,这样veth2就能和docker0桥接器上的其他网络设备进行通信了
brctl addif docker0 veth2

# 显示当前桥接器的信息,可以看到docker0桥接器及其所连接的网络接口
brctl show

# 启用veth2网络接口,使其能够进行数据传输
ip link set veth2 up

# 使用docker命令检查名为test_busybox2的容器,提取容器的进程ID
docker inspect test_busybox2 | grep Pid

# 用docker inspect命令获取名为test_busybox2的容器的PID,并将其存储在变量pid2中
pid2=$(docker inspect -f '{{.State.Pid}}' test_busybox2)

# 输出容器test_busybox2的PID
echo "容器test_busybox2的PID是:$pid2"

# 为容器的网络命名空间创建一个软链接,方便后续的操作。/var/run/netns/目录通常用于存放网络命名空间
ln -s /proc/$pid2/ns/net /var/run/netns/$pid2

# 将veth3这端的网络接口移到容器test_busybox1的网络命名空间中
ip link set veth3 netns $pid2

# 在test_busybox1容器的网络命名空间内,将网络接口veth3重命名为eth0
ip netns exec $pid2 ip link set dev veth3 name eth0

# 启用容器内的eth0网络接口
ip netns exec $pid2 ip link set eth0 up

# 为容器内的eth0接口分配IP地址172.17.0.200,并设置子网掩码为24位
ip netns exec $pid2 ip addr add 172.17.0.200/24 dev eth0

# 设置容器内的网络路由,使其默认网关为172.17.0.1,即docker0桥的IP地址
ip netns exec $pid2 ip route add default via 172.17.0.1

[root@node-a docker]# ip link add veth2 type veth peer name veth3
[root@node-a docker]# brctl addif docker0 veth2
[root@node-a docker]# brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.0242398240fb       no              veth0
                                                        veth2
                                                        veth271d838
                                                        veth588fc94
[root@node-a docker]# ip link set veth2 up
[root@node-a docker]# docker inspect test_busybox2 | grep Pid
            "Pid": 2212,
            "PidMode": "",
            "PidsLimit": null,
[root@node-a docker]# pid2=$(docker inspect -f '{{.State.Pid}}' test_busybox2)
[root@node-a docker]# echo "容器test_busybox2的PID是:$pid2"
容器test_busybox2的PID是:2212
[root@node-a docker]# ln -s /proc/$pid2/ns/net /var/run/netns/$pid2
[root@node-a docker]# ip link set veth3 netns $pid2
[root@node-a docker]# ip netns exec $pid2 ip link set dev veth3 name eth0
[root@node-a docker]# ip netns exec $pid2 ip link set eth0 up
[root@node-a docker]# ip netns exec $pid2 ip addr add 172.17.0.200/24 dev eth0
[root@node-a docker]# ip netns exec $pid2 ip route add default via 172.17.0.1
[root@node-a docker]# docker exec -it test_busybox2 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
12: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue qlen 1000
    link/ether 92:7f:5d:85:1e:69 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.200/24 scope global eth0
       valid_lft forever preferred_lft forever
[root@node-a docker]#

步骤6:测试

docker exec -it test_busybox2 ip addr
docker exec -it test_busybox2 ping -c 4 172.17.0.100
docker exec -it test_busybox1 ip addr
docker exec -it test_busybox1 ping -c 4 172.17.0.200

虚拟化和容器——6 Docker资源控制

基于cgroups

https://tech.meituan.com/2015/03/31/cgroups.html

1. 对CPU的控制

步骤1:限制CPU命令速率。

(1)利用centos:7镜像分别生成容器名为centos1和centos2的容器,其中centos1容器不限制cpu的使用率,centos2容器将cpu的使用率限制为20%。

docker pull centos:7
docker run -dit --name centos1 centos:7 /bin/bash
# 限制CPU百分之20000
docker run -dit --name centos2 --cpu-quota 20000 centos:7 /bin/bash

100000微秒
020000只能使用百分之20

--cpu-quota 20000: --cpu-quota定义了容器每--cpu-period(默认为100000微秒,即100ms)可以获得的最大CPU时间,单位为微秒。--cpu-quota 20000意味着在默认的100ms周期中,容器最多只能使用20ms的CPU时间。

(2)通过查看对应的cgroup配置文件 /sys/fs/cgroup/cpu/docker/容器编号/cpu.cfs_quota_us来查看各容器cpu的使用率。

#这里是你的容器名
cat /sys/fs/cgroup/cpu/docker/86ff33795a71f86236011598c9cbaea55c4a319bd142e6ffb845e055d4db4fd9/cpu.cfs_quota_us

没限制的(-1

(3)如需修改对应容器的cpu使用率,可以直接修改cgroup配置文件 /sys/fs/cgroup/cpu/docker/容器编号/cpu.cfs_quota_us的值来实现。

修改占用为百分之40

echo 40000 >> /sys/fs/cgroup/cpu/docker/9b19d5677dd03ad0f0f4bd3eee7659b7845fb34e78e42e819f21b6338fdc6342/cpu.cfs_quota_us

cat /sys/fs/cgroup/cpu/docker/9b19d5677dd03ad0f0f4bd3eee7659b7845fb34e78e42e819f21b6338fdc6342/cpu.cfs_quota_us

这里虽然是追加写,但是并不会追加,linux都是文件,估计是直接内核交互了。?

删掉这俩实验容器

docker rm -f centos1 centos2

步骤2:多任务按比例分享CPU

(1)利用centos:7镜像创建centos3和centos4容器。设置容器权重,使用centos3和centos4的cpu占比为33.3%和66.7% 。

docker run -dit --name=centos3 --cpu-shares 512 centos:7 /bin/bash
docker run -dit --name=centos4 --cpu-shares 1024 centos:7 /bin/bash

docker ps -a

(2)打开另一个终端,使用docker stats命令查看状态。

docker stats

(3)分别打开两个终端,利用两个终端分别进行centos1和centos2容器,安装压力测试包stress。(4)分别在两个容器内启用4个线程。

容器3

#进入容器
docker exec -it centos3 /bin/bash
yum -y install epel-release
yum -y install stress
stress -c 4

容器4

docker exec -it centos4 /bin/bash
yum -y install epel-release
yum -y install stress
stress -c 4

(5)再次利用docker stats命令查看。

还是挺准的
132/(66+132)=0.666666666667

步骤3: 查看cpu内核使用

通过查看Cgroup配置文件为/sys/fs/cgroup/cpuset/docker/容器编号/cpuset.cpus。

1.CPU限制

这个没有文件诶。

应该是默认没有启用

docker run -dit --cpuset-cpus="0,1" --name my_container nginx

这样就有啦

[root@node-a cpuset]# cd docker/8aae2d1e6621d076570cb4e9fc10d099a46475f25add3440848ec1bd243a1f16/
[root@node-a 8aae2d1e6621d076570cb4e9fc10d099a46475f25add3440848ec1bd243a1f16]# cat cpuset.cpus
0-1

删除容器

docker rm -f my_container

2. 对内存使用的限制

docker run -dit --name=centos5 -m 512m centos:7 /bin/bash
docker run -dit --name=centos6 centos:7 /bin/bash

步骤2:打开一个终端,使用docker stats命令查看状态

docker stats

CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT   MEM %     NET I/O     BLOCK I/O     PIDS
8df1885fca97   centos6   0.00%     400KiB / 1.777GiB   0.02%     656B / 0B   0B / 0B       1
501410e22049   centos5   0.00%     1.965MiB / 512MiB   0.38%     656B / 0B   9.61MB / 0B   1

步骤3:查看容器对应的Cgroup配置文件可查看容器内存限制。

cat /sys/fs/cgroup/memory/docker/501410e22049929b244235423c19239b50cc61a082834dba85cb18c59e2f7470/memory.limit_in_bytes

536870912 // 536870912=512×1024×1024

计算机组成原理4

实验过程:

RAM ROM引脚

RAM

随机存储器针脚:
sel(片选)

load data

clr

A

D

ROM

Sel引脚:

D 引脚:

A 引脚:

任务1:存储器位扩展

在这个任务中,我们将使用Logisim来创建一个存储器位扩展电路。位扩展是通过多个存储器器件来扩展字长的一种方式。我们将使用4个322位芯片来组成一个328位的存储器,并改变地址、设置片选sel和加载ld信号来模拟位扩展。
  1. 打开Logisim并创建一个新的电路。
  2. 在电路中添加4个322位的存储器芯片,并将它们连接在一起,以创建一个328位的存储器。设置每个存储器的地址范围,确保它们不重叠。
  3. 添加一个地址输入端口(Address BUS),一个片选sel输入端口,一个加载ld输入端口,以及一个输出端口。
  4. 连接地址输入端口到存储器的地址输入,并将片选sel和加载ld连接到相应的存储器控制端口。
  5. 使用Logisim的时钟源来改变地址、设置sel和ld信号,观察输出结果。

322 位芯片组成 328 位的存储器

32*2 地址是32个(有5个地址位,32个单元),数据位宽是2位(每个单元两个bit,也就是输出两个bit)

存储器选择5地址位宽 + 2数据位宽

任务2:存储器字扩展

利用logisim组件做如下电路
字扩展指的是增加存储器中字的数量。如下图⽤4个328位芯⽚组成1288位存储器。了解数据总线(Address BUS)和地址总线(Data BUS)概念和简单应用
  1. 打开Logisim并创建一个新的电路。
  2. 在电路中添加4个328位的存储器芯片,并将它们连接在一起,以创建一个1288位的存储器。设置每个存储器的地址范围,确保它们不重叠。
  3. 添加一个地址输入端口(Address BUS)和一个片选sel输入端口。
  4. 连接地址输入端口到存储器的地址输入,并将片选sel连接到相应的存储器控制端口。
  5. 使用Logisim来改变地址和片选信号,观察输出结果。
总地址位
7 6    5 4 3 2 1
<片选><-----地址------>

解码器

右边的针脚

加上load data 、 clear 线路

任务3:存储器字位扩展

存储器字位扩展(4片324位存储器位组成2片328位存储器字扩展为64*8位存储器)
  1. 打开Logisim并创建一个新的电路。
  2. 在电路中添加4个324位的存储器芯片,并将它们连接在一起,以创建2片328位的存储器。设置每个存储器的地址范围,确保它们不重叠。
  3. 添加一个地址输入端口(Address BUS)和一个片选sel输入端口。
  4. 连接地址输入端口到存储器的地址输入,并将片选sel连接到相应的存储器控制端口。
  5. 使用Logisim来改变地址和片选信号,观察输出结果。

两片合起来

6     5 4 3 2 1
<片选><-----地址------>

片选1

片选2

任务4:学号和成绩显示电路

完成如下学号、成绩显示电路(注:为降低难度,存储显示系统为十六进制,使用时不要输入十进制以外数据,直观上做十进制数据操作)
  1. 打开Logisim并创建一个新的电路。
  2. 添加一个只读存储器(Read-Only Memory,ROM)组件,并设置其大小和地址范围,以适应学号和成绩数据的存储。
  3. 添加一个地址输入端口和一个片选sel输入端口,并将它们连接到ROM。
  4. 添加一个显示组件,用于显示学号和成绩数据。

  1. 设置ROM加载镜像,读入相应的学号成绩文本文件。

先保存镜像,然后加载镜像

填入数据就行

v2.0 raw
0 1 2 3 4 5 6 7 
8 9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
v2.0 raw
90 91 92 93 94 95 96 97
98 99 a0 80 81 82 83 84
85 86 87 88 89 70 71 72
73 74 75 76 77 78 79 99

  1. 模拟电路运行,并通过更改地址来查看不同的学号和成绩数据。

CLK模拟:

这里100存了a0当做100分

任务5:RAM写入实验

RAM写入实验 在logisim的管理窗口创建如下子电路,完成下图的绘制,利用启用时钟模拟在RAM中的所有单元写入数据。
  1. 打开Logisim并创建一个新的电路。
  2. 添加一个RAM组件,并设置其大小和地址范围。
  3. 添加一个地址输入端口和一个数据输入端口,以便将数据写入RAM。
  4. 添加一个时钟源(Clock)以便模拟时钟信号。
  5. 使用时钟模拟将数据写入RAM中的各个单元。
  6. 添加一个数据输出端口,以显示RAM中的存储数据,并可以更改测试数据。

数据随便弄点

v2.0 raw
0 1 2 3 4 5 6 7 
8 9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28

这样就可以啦

记得时钟线一定要连好。

任务6:8*16K 32位存储器电路

做如下8*16K 32位存储器电路(更改存储数据)
  1. 打开Logisim并创建一个新的电路。
  2. 添加8个32位存储器芯片,并设置其大小和地址范围,以创建8*16K 32位存储器。
  3. 添加一个地址输入端口和一个数据输出端口。
  4. 连接地址输入端口到存储器的地址输入,并将数据输出端口连接到存储器的数据输出。
  5. 使用Logisim来更改地址总线地址数据,观察输出数据的变化。

16*32的

画完了

计算机组成原理3

https://type.dayiyi.top/index.php/archives/222/

实验过程

1. RS触发器

1.1 介绍

RS触发器是数字电路中的核心元件,经常被用作更复杂触发器的基础。例如,它可以进一步改进为D触发器,以完成更多的任务。RS触发器在数字电路中负责同步和管理电路的工作。

1.2 电路结构与绘制

RS触发器由两个与非门或或非门(如G1和G2)构成,通过交叉连接输入输出端得到。这种交叉连接创建了正反馈,这是所有触发器电路的关键特性。

  • 输入:R、S
  • 输出:Q、~Q

状态定义如下:

  • 0态:Q=0,~Q=1
  • 1态:Q=1,~Q=0

1.3 模拟分析

  1. 当使用或非门作RS触发器时,如果R、S同时为1,那么Q和~Q输出都会为0。这破坏了互补逻辑关系。若同时撤销(变为0),RS触发器将处于不稳定状态。
  2. 对于与非门组成的RS触发器,当R、S都为0时,Q和~Q都为1,这也破坏了互补逻辑关系。同样,如果它们同时变为1,触发器将不稳定。

1.4 真值表

RSQ~Q描述
00不变不变保持状态
0110置1
1001置0
11不确定不确定不稳定状态
  • 当R=0,S=0时,输出Q和~Q不会发生改变,保持当前状态。
  • 当R=0,S=1时,Q输出为1,而~Q输出为0。这称为"Set"或置1操作。
  • 当R=1,S=0时,Q输出为0,而~Q输出为1。这称为"Reset"或置0操作。
  • 当R=1,S=1时,这是一个禁止的输入组合,因为它导致输出进入一个不确定或不稳定的状态。在实际电路中,这种组合通常避免使用。

1.5 触发器


2. D触发器

2.1 介绍

D触发器是一个记忆元件,有两个稳定状态,常用作时序电路的基础。它在数字逻辑电路中是非常重要的。它可以根据电平触发或边沿触发来工作。电平触发时,当CP(时钟脉冲)为1时触发。而边沿触发则在CP的前沿(从0变为1)进行。D触发器可以置0或置1,当CP=0时,输入信号不会有任何效果,它的状态保持不变,因此也被称为D锁存器。

2.2 真值表

CPDQ_next描述
0x不变保持状态
100传输0到Q
111传输1到Q
  • 当CP(时钟脉冲)为0时,无论D(数据输入)是什么值,Q的输出都不会改变,因此它被称为"保持"或"锁存"状态。
  • 当CP为1时,D的值被传输或复制到Q输出。因此,如果D=0,Q将输出0,如果D=1,Q将输出1。

2.3 触发器

自带的触发器

3. 制作4位寄存器

3.1 电路设计:

  1. 准备4个D触发器。
  2. 为每个D触发器设置一个并行输入(D0,D1,D2,D3)和一个并行输出(Q0,Q1,Q2,Q3)。
  3. 所有的D触发器应共用同一个时钟信号CP。
  4. 当CP有一个上升沿时,每个D触发器的输入值都会被“锁存”或传输到其对应的Q输出。

3.2 画图

3.3 模拟运行:

  • 设置输入D0-D3。
  • 触发时钟信号。

正常啦

4. 在Logisim中完成8位寄存器

4.1电路设计:

  1. 在Logisim中打开一个新的工作区。
  2. 添加8个D触发器。
  3. 为每个D触发器设置一个并行输入(D0-D7)和一个并行输出(Q0-Q7)。
  4. 所有的D触发器都应该连接到同一个时钟信号。

4.2 画图

4.3模拟运行:

  1. 使用Logisim的工具更改D输入的值。
  2. 激活时钟信号。
  3. 测试

RST:

5.利用组件构建 MIPS 8位寄存器设计如下(简化只设计0-1号寄存器)

隧道标记:R1# 为RD1输出选择端 RD1数据输出端1
R2# 为RD2输出选择端 RD2数据输出端2
WE为写使能
CLK为时钟输入 Din为数据输入端

MIPS(Microprocessor without Interlocked Pipeline Stages)是一个RISC(Reduced Instruction Set Computer)架构的微处理器系列。RISC是一种设计思路,它通过减少每条指令所做的工作和简化指令集来提高性能。MIPS架构在过去的几十年中已被广泛应用于许多应用程序,从桌面计算机到嵌入式系统。

MIPS寄存器是存储数据的基本单位,对数据的读写操作都会经过寄存器。在MIPS架构中,寄存器的读写都是同步的,需要时钟信号。

任务:

1. 当WE=1时,通过多路解复用器选择相应寄存器(相应寄存器使能)

选择0 寄存器:

选择1 寄存器:

选择2 寄存器:

选择3 寄存器:

2. 设置DIN数据,R1、R2选择输入端口

设置寄存器选择4寄存器,数据位00011111

3. 给定CLK时钟(电平0-1) RD1、RD2端输出数据

点击时钟:

写到寄存器4

R2读取寄存器4:

R1 读取寄存器4:

4. 测试寄存器电路以上,并扩展完成8位0-3位寄存器电路,分析并模拟运行电路并测试(结果写入实验报告)

感谢老师的文件,已经扩展完了。

主要的内容就是,解码器多点,然后加上两个

DMX MUX上面的线路上多点点就可以啦。

5.根据以上例程利用组件构建 MIPS 32位寄存器设计如下(简化只设计0-3号寄存器)

这里扩展

6.当WE=1时,通过多路解复用器选择相应寄存器(相应寄存器使能)

选择就行了。

这里
0 0 0 寄存器(恒为0的寄存器)

0 1 1 寄存器

1 0 2 寄存器

1 1 3 寄存器

7.设置DIN数据,R1、R2选择输入端口

可以玩玩啦

  • 选择输入寄存器(WR)
  • WE 启动选择
  • Din写入数据
  • R1 选择要读的寄存器
  • R2 选择要读的寄存器
  • 跳时钟
  • 就可以显示数据啦。

8. 给定CLK时钟(电平0-1) RD1、RD2端输出数据

done
但那个附录小故事还是挺好看的。

虚拟化和容器——实验5 常用命令的使用

创建一个容器 ,名字为CentosTest

docker pull centos:7
docker create -it --name CentosTest centos:7

启动容器:

docker start CentosTest

在容器里执行命令(bin/bash):

docker exec -it CentosTest /bin/bash
ls
exit

退出后查看容器状态:

docker ps -a

仍然在运行

创建一个nginx容器NginxTest,nginx:latest,并且映射到80端口

docker run -dit -p 80:80 --name NginxTest nginx:latest

替换容器内的index.html

#在容器外:
echo "欢迎使用Docker容器" >> index.html
docker cp index.html NginxTest:/usr/share/nginx/html

尝试看看

curl 127.0.0.1

导出容器

docker export -o nginxtest.tar NginxTest
ls

导入容器

docker import nginxtest.tar nginx:v1.0
docker images

输出容器和宿主机的端口映射关系:

docker inspect -f {{.NetworkSettings.Ports}} NginxTest
docker port NginxTest

删除容器NginxTest CentosTest

docker rm -f NginxTest CentosTest