0.1 启动容器

docker run -itd --name nginx -p 80:80 nginx

0.2 打开iptables调试功能

通过调试可以看 iptables 几个表 (raw mangle nat filter ) 的顺序,谁先谁后, 可以自己测试一下.

modprobe ipt_LOG #centos6
modprobe nf_log_ipv4 #centos7
# 查看
sysctl net.netfilter.nf_log.2
   #centos 7
     net.netfilter.nf_log.2 = nf_log_ipv4
# raw 表 添加规则, 打开调试. 
iptables -t raw -A PREROUTING -p tcp --dport 80 -j TRACE 
iptables -t raw -A OUTPUT -p tcp --dport 80 -j TRACE
iptables -t raw -nL

0.3 查看 NAT 表

iptables -t nat -nvL --line-numbers
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 12 packets, 883 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 DOCKER     all  --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT 12 packets, 883 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0
2        0     0 MASQUERADE  tcp  --  *      *       172.17.0.2           172.17.0.2           tcp dpt:80

Chain DOCKER (2 references)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0
2        0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.2:80

0.4 查看 filter 表

iptables -t filter -nvL --line-numbers
Chain INPUT (policy ACCEPT 523 packets, 31567 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1       40  7071 DOCKER-USER  all  --  *      *       0.0.0.0/0            0.0.0.0/0
2       40  7071 DOCKER-ISOLATION-STAGE-1  all  --  *      *       0.0.0.0/0            0.0.0.0/0
3       15   833 ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
4        3   156 DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0
5       22  6082 ACCEPT     all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0
6        0     0 ACCEPT     all  --  docker0 docker0  0.0.0.0/0            0.0.0.0/0

Chain OUTPUT (policy ACCEPT 274 packets, 92208 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain DOCKER (1 references)
num   pkts bytes target     prot opt in     out     source               destination
1        3   156 ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.2           tcp dpt:80

Chain DOCKER-ISOLATION-STAGE-1 (1 references)
num   pkts bytes target     prot opt in     out     source               destination
1       22  6082 DOCKER-ISOLATION-STAGE-2  all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0
2       40  7071 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain DOCKER-ISOLATION-STAGE-2 (1 references)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 DROP       all  --  *      docker0  0.0.0.0/0            0.0.0.0/0
2       22  6082 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain DOCKER-USER (1 references)
num   pkts bytes target     prot opt in     out     source               destination
1       40  7071 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/

0.5 watch 日志


tail -f /var/log/kern.log
# 或 ?
tail -f /var/log/messages
#或 ?
dmesg --follow

0.6 外部浏览器访问 nginx

上面我的操作我是在虚拟机里的.

0.7 观察日志

流量进来先走 nat:PREROUTING -> 如果有转发就走filter:FORWARD->nat:POSTROUTING

TRACE: raw:PREROUTING:policy:2 IN=eth0 OUT=
# nat:PREROUTING:rule:1 找 nat:PREROUTING 第一条规则, target 是 DOCKER
TRACE: nat:PREROUTING:rule:1 IN=eth0 OUT=
#  nat:DOCKER: 的第一条规则 in 不匹配, 所以 继续下一条规则. 第2条匹配了.
TRACE: nat:DOCKER:rule:2 IN=eth0 OUT=
# 走filter 的 forward(因为前面的规则里nat:DOCKER:rule:2  再根据路由)
# 跳转到 DOCKER-USER
TRACE: filter:FORWARD:rule:1 IN=eth0 OUT=docker0 
# 跳这DOCKER-USER 第一条. 是个return (return的意思是,结束子chains,返回到原来的chains 继续它的下一条)
# 可以理解为 main函数里 调用了 A 函数, A函数里面return了. 你到了main ,执行 A函数后面的语句.
TRACE: filter:DOCKER-USER:return:1 IN=eth0 OUT=docker0
# 回到forward的第二条 发现是跳 DOCKER-ISOLATION-STAGE-1
TRACE: filter:FORWARD:rule:2 IN=eth0 OUT=docker0
# DOCKER-ISOLATION-STAGE-1的第一条 没有符合规则, 继续第二条看是否匹配, 匹配了.
# 第二条是个return 
TRACE: filter:DOCKER-ISOLATION-STAGE-1:return:2 IN=eth0 OUT=docker0
# 继续回到forward.  (看第3条规则没匹配,因为是还没有建立连接)
TRACE: filter:FORWARD:rule:4 IN=eth0 OUT=docker0
# accept 了..
TRACE: filter:DOCKER:rule:1 IN=eth0 OUT=docker0
TRACE: nat:POSTROUTING:policy:3 IN= OUT=docker0
# 后续
TRACE: filter:FORWARD:rule:1 IN=eth0 OUT=docker0
TRACE: filter:DOCKER-USER:return:1 IN=eth0 OUT=docker0
TRACE: filter:FORWARD:rule:2 IN=eth0 OUT=docker0
TRACE: filter:DOCKER-ISOLATION-STAGE-1:return:2 IN=eth0 OUT=docker0
# 看 这个时候匹配上了. 因为已经建立连接了.
TRACE: filter:FORWARD:rule:3 IN=eth0 OUT=docker0
Back to top