docker publish 端口和iptables 问题

docker publish port 可以发布端口。

docker run -p 8080:80 xxxxxxx

这样 其他机器可以,可以通过宿主机器的ip:8080 访问docker 容器的80端口。 也就是说 docker 通过-p 实现了端口转发的功能。
这个时候查看iptables情况

iptables -L -n
   
Chain DOCKER (1 references)
target     prot opt source               destination         
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.2           tcp dpt:15672
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.2           tcp dpt:5672
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.4           tcp dpt:3306
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.5           tcp dpt:6000
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.3           tcp dpt:8848
    
    ##开放的白名单端口
Chain IN_public_allow (1 references)
target     prot opt source               destination         
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:22 ctstate NEW
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:9966 ctstate NEW
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:12306 ctstate NEW
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:443 ctstate NEW
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 ctstate NEW
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:9977 ctstate NEW
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:5100 ctstate NEW
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8089 ctstate NEW
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8000 ctstate NEW
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8010 ctstate NEW
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8090 ctstate NEW
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:53306 ctstate NEW

Chain IN_public_deny (1 references)
target     prot opt source               destination         

Chain IN_public_log (1 references)
target     prot opt source               destination         

Chain OUTPUT_direct (1 references)
target     prot opt source               destination      

查看iptables docker 转发情况

iptables -t nat  -nvL DOCKER
Chain DOCKER (2 references)
pkts bytes target     prot opt in     out     source               destination         
  20  1200 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:15672 to:172.17.0.2:15672
   0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:5672 to:172.17.0.2:5672
   0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:53306 to:172.17.0.4:3306
   0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:6000 to:172.17.0.5:6000
  10   520 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8848 to:172.17.0.3:8848

可以发现 只要是in 符合!docker0网络环境,就可以进行nat转发

而在默认情况下, docker 的容器都是通过docker0 网桥相互访问如下图。

docker publish 端口和iptables 问题_第1张图片

但是在docker 容器里面通过宿主机ip:发布端口访问却是不行的

举个场景:

目前有一个nacos 服务, 和mysql 服务。

mysql docker run 预计

docker run  -d \
        --privileged=true \
        --restart=always  \
        -e MYSQL_ROOT_PASSWORD=root \
        -p ${port}:3306 \
        -v /home/mysql/data:/var/lib/mysql \
        -v ${PWD}/conf:/etc/mysql/conf.d \
        -v ${PWD}/log:/var/log/mysql \
        -v /etc/localtime:/etc/localtime \
        --name ${name}  smc-mysql:5.7

根据端口查询mysql的ip, 172.17.0.5 就是mysql的IP , nacos ip是172.17.0.2

Chain DOCKER (1 references)
target     prot opt source               destination         
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.2           tcp dpt:8848
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.3           tcp dpt:6000
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.4           tcp dpt:15672
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.4           tcp dpt:5672
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.5           tcp dpt:3306

本机的ip 10.172.15.195

           ip a
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    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
2: enp61s0f0:  mtu 1500 qdisc mq portid 00bed50537e0 state UP qlen 1000
    link/ether 00:be:d5:05:37:e0 brd ff:ff:ff:ff:ff:ff
    inet 10.172.15.195/24 brd 10.172.15.255 scope global enp61s0f0
       valid_lft forever preferred_lft forever
3: enp61s0f1:  mtu 1500 qdisc mq portid 00bed50537e1 state DOWN qlen 1000
    link/ether 00:be:d5:05:37:e1 brd ff:ff:ff:ff:ff:ff
4: enp61s0f2:  mtu 1500 qdisc mq portid 00bed50537e2 state DOWN qlen 1000
    link/ether 00:be:d5:05:37:e2 brd ff:ff:ff:ff:ff:ff
5: enp61s0f3:  mtu 1500 qdisc mq portid 00bed50537e3 state DOWN qlen 1000
    link/ether 00:be:d5:05:37:e3 brd ff:ff:ff:ff:ff:ff
6: docker0:  mtu 1500 qdisc noqueue state UP
    link/ether 02:42:57:c3:24:2a brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
234: vethc14661e@if233:  mtu 1500 qdisc noqueue master docker0 state UP
    link/ether 1a:d1:b0:cd:f8:07 brd ff:ff:ff:ff:ff:ff link-netnsid 0
236: veth01be069@if235:  mtu 1500 qdisc noqueue master docker0 state UP
    link/ether b2:25:cb:98:56:bc brd ff:ff:ff:ff:ff:ff link-netnsid 1
238: veth5326f54@if237:  mtu 1500 qdisc noqueue master docker0 state UP
    link/ether 0e:db:a9:97:94:7c brd ff:ff:ff:ff:ff:ff link-netnsid 2
240: veth2fd6c88@if239:  mtu 1500 qdisc noqueue master docker0 state UP
    link/ether 66:11:0a:f9:34:09 brd ff:ff:ff:ff:ff:ff link-netnsid 3

这个时候本地ping nacos ip 和mysql Ip , 发现是通的。

[root@localhost mysql]# ping 172.17.0.5
PING 172.17.0.5 (172.17.0.5) 56(84) bytes of data.
64 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.144 ms
64 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.050 ms
^C
--- 172.17.0.5 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.050/0.097/0.144/0.047 ms
[root@localhost mysql]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.091 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.047 ms
^C
--- 172.17.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.047/0.069/0.091/0.022 ms

但是实际上 nacos 的docker 容器访问mysql 却是失败的,出现类似下面错误

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'configOpsController' defined in URL [jar:file:/home/nacos/target/nacos-server.jar!/BOOT-INF/lib/nacos-config-1.3.0.jar!/com/alibaba/nacos/config/server/controller/ConfigOpsController.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'externalDumpService': Invocation of init method failed; nested exception is ErrCode:500, ErrMsg:Nacos Server did not start because dumpservice bean construction failure :
No DataSource set
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769)
    at  
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
 org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:136)
    ... 40 common frames omitted
Caused by: java.lang.IllegalStateException: No DataSource set
    at org.springframework.util.Assert.state(Assert.java:73)
    at org.springframework.jdbc.support.JdbcAccessor.obtainDataSource(JdbcAccessor.java:77)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:371)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:452)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:462)
    at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:473)
    at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:480)
    at com.alibaba.nacos.config.server.service.repository.ExternalStoragePersistServiceImpl.findConfigMaxId(ExternalStoragePersistServiceImpl.java:702)
    at com.alibaba.nacos.config.server.service.dump.DumpAllProcessor.process(DumpTask.java:198)
    at com.alibaba.nacos.config.server.service.dump.DumpService.dumpConfigInfo(DumpService.java:249)
    at com.alibaba.nacos.config.server.service.dump.DumpService.dumpOperate(DumpService.java:155)
    ... 48 common frames omitted

接下来 打开mysql的防火墙端口

firewall-cmd --permanent --zone=public --add-port=53306/tcp
success
[root@localhost logs]# firewall-cmd --reload
success
[root@localhost logs]#

然后重新nacos docker run ,发现这个时候mysql 访问通了

2020-10-13 12:49:57,919 INFO Initializing Spring embedded WebApplicationContext

2020-10-13 12:49:57,919 INFO Root WebApplicationContext: initialization completed in 5704 ms

2020-10-13 12:49:58,507 INFO Use Mysql as the driver

2020-10-13 12:49:58,632 INFO HikariPool-1 - Starting...

2020-10-13 12:49:58,968 INFO HikariPool-1 - Start completed.

2020-10-13 12:49:59,689 INFO Nacos-related cluster resource initialization

2020-10-13 12:49:59,701 INFO The cluster resource is initialized

2020-10-13 12:50:00,332 INFO Reflections took 124 ms to scan 1 urls, producing 6 keys and 24 values

2020-10-13 12:50:00,394 INFO Reflections took 3 ms to scan 1 urls, producing 2 keys and 12 values

2020-10-13 12:50:00,408 INFO Reflections took 5 ms to scan 1 urls, producing 3 keys and 15 values

2020-10-13 12:50:01,704 INFO Initializing ExecutorService 'applicationTaskExecutor'

2020-10-13 12:50:01,970 INFO Adding welcome page: class path resource [static/index.html]

2020-10-13 12:50:02,767 INFO Creating filter chain: Ant [pattern='/**'], []

2020-10-13 12:50:02,870 INFO Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@362a019c, org.springframework.security.web.context.SecurityContextPersistenceFilter@3af17be2, org.springframework.security.web.header.HeaderWriterFilter@65e61854, org.springframework.security.web.csrf.CsrfFilter@27a5328c, org.springframework.security.web.authentication.logout.LogoutFilter@303e3593, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@37f21974, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@224b4d61, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1d9bec4d, org.springframework.security.web.session.SessionManagementFilter@4fcee388, org.springframework.security.web.access.ExceptionTranslationFilter@6c345c5f]

2020-10-13 12:50:03,153 INFO Exposing 2 endpoint(s) beneath base path '/actuator'

2020-10-13 12:50:03,192 INFO Initializing ExecutorService 'taskScheduler'

2020-10-13 12:50:03,650 INFO Tomcat started on port(s): 8848 (http) with context path '/nacos'

2020-10-13 12:50:03,657 INFO Started Nacos in 13.31 seconds (JVM running for 14.129)

2020-10-13 12:50:03,657 INFO Nacos Log files: /home/nacos/logs

2020-10-13 12:50:03,660 INFO Nacos Log files: /home/nacos/conf

2020-10-13 12:50:03,660 INFO Nacos Log files: /home/nacos/data

2020-10-13 12:50:03,660 INFO Nacos started successfully in stand alone mode. use external storage

2020-10-13 12:50:04,567 INFO Initializing Spring DispatcherServlet 'dispatcherServlet'

2020-10-13 12:50:04,567 INFO Initializing Servlet 'dispatcherServlet'

2020-10-13 12:50:04,593 INFO Completed initialization in 26 ms

这个原因就是 docker 防火墙 nat 来源是非docker网络允许转发, docker 网络不允许转发,需要添加防火墙白名单。
个人认为, 这个应该属于docker iptables 网络这块设计不合理导致的。
不过docker 提供了关闭iptables的功能。

解决措施,关闭docker iptables 功能

在/etc/docker/daemon.json 添加,“iptables”:false 关闭防火墙即可。

"iptables":false

关闭防火墙之后,docker publish的端口,必须要要在iptables 白名单中管理,才能被外部访问, 这样符合常规的认知

你可能感兴趣的:(docker)