Docker组件分析一:docker-proxy

2020-11-13

查看/usr/bin下与docker有关的二进制执行文件:

-rwxr-xr-x.   1 1000   1000  34519704 7月  18 2019 containerd
-rwxr-xr-x.   1 1000   1000   6038112 7月  18 2019 containerd-shim
-rwxr-xr-x.   1 1000   1000  65632394 7月  18 2019 docker
-rwxr-xr-x.   1 1000   1000  71650528 7月  18 2019 dockerd
-rwxr-xr-x.   1 1000   1000    764144 7月  18 2019 docker-init
-rwxr-xr-x.   1 1000   1000   2851084 7月  18 2019 docker-proxy
-rwxr-xr-x.   1 1000   1000  19491032 7月  18 2019 ctr
-rwxr-xr-x.   1 1000   1000   8514432 7月  18 2019 runc

这些组件根据工作职责可以分为以下三大类。

  • Docker 相关的组件:docker、dockerd、docker-init 和 docker-proxy
  • containerd 相关的组件:containerd、containerd-shim 和 ctr
  • 容器运行时相关的组件:runc

先看docker-proxy。docker-proxy 主要是用来做端口映射的。当我们使用docker run命令启动容器时,如果使用了 -p 参数,docker-proxy 组件就会把容器内相应的端口映射到主机上来,底层是依赖于iptables实现的。

使用以下命令启动一个 nginx 容器并把容器的 80 端口映射到主机的 8080 端口

[root@k8s-master bin]# docker run --name=nginx -d -p 8080:80 nginx

查看一下启动的容器 IP:

[root@k8s-master bin]# docker inspect --format '{{ .NetworkSettings.IPAddress }}' nginx
172.17.0.2

ps 命令查看一下主机上是否有 docker-proxy 进程

[root@k8s-master bin]# ps aux |grep docker-proxy
root      48045  0.0  0.1 103292  4144 ?        Sl   15:19   0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 8080 -container-ip 172.17.0.2 -container-port 80
root      82391  0.0  0.0 112824   980 pts/0    S+   15:45   0:00 grep --color=auto docker-proxy

查看一下主机上 iptables nat 表的规则

[root@k8s-master bin]# iptables -L -nv -t nat
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
   16  1557 cali-PREROUTING  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* cali:6gwbT8clXdHdC1b1 */
   24  2087 KUBE-SERVICES  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
    2   113 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)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 3 packets, 180 bytes)
 pkts bytes target     prot opt in     out     source               destination         
16367  986K cali-OUTPUT  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* cali:tVnHkvAo15HuiPy0 */
16409  989K KUBE-SERVICES  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
 1890  113K DOCKER     all  --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT 3 packets, 180 bytes)
 pkts bytes target     prot opt in     out     source               destination         
16371  986K cali-POSTROUTING  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* cali:O3lYWMrLQYEMJtB5 */
16769 1010K KUBE-POSTROUTING  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */
    0     0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0           
    0     0 MASQUERADE  tcp  --  *      *       172.17.0.2           172.17.0.2           tcp dpt:80

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

通过最后一行规则我们可以得知,通过DNAT服务(目标地址转换)当我们访问主机的 8080 端口时,iptables 会把流量转发到 172.17.0.2 的 80 端口