背景

开发反馈组件化环境, 多个人通过 DBeavr无法正常连接到组件化PG环境, 只有一个同事PC电脑可以连接.

分析

检查 pg_hba.conf

[root@localhost ~]# cat /data/pgdata/pg_hba.conf
# "local" is for Unix domain socket connections only
local   all             all                                     md5
# IPv4 local connections:
host    all             all             127.0.0.1/32            md5
# IPv6 local connections:
host    all             all             ::1/128                 md5
# replication privilege.
local   replication     all                                     md5
host    replication     all             127.0.0.1/32            md5
host    replication     all             ::1/128                 md5
host    all             all             0.0.0.0/0               md5

初步判断通过 外部 IP 是允许访问数据库的

检查 postgresql.conf

[root@localhost ~]# cat /data/pgdata/postgresql.conf  | grep listen_add
listen_addresses = '*'		# what IP address(es) to listen on;
[root@localhost ~]# cat /data/pgdata/postgresql.conf  | grep port
port = 5432				# (change requires restart)
#ssl_passphrase_command_supports_reload = off
					# supported by the operating system:
					# supported by the operating system:
					#   %r = remote host and port

进一步确认, PG 是在监听来自所有IP的, 并且是在监听 5432 端口的

从数据库配置层面判断是正常的.

检查监听

[root@localhost ~]# ss -tunlp | grep postgres
tcp   LISTEN 0      2460         0.0.0.0:5432       0.0.0.0:*    users:(("postgres",pid=3073754,fd=10))
tcp   LISTEN 0      2460            [::]:5432          [::]:*    users:(("postgres",pid=3073754,fd=11))

可以看到 PG服务是正在监听 来自所有IP的 5432端口访问的. 包括 IPV4 与 IPV6 形式的 IP.

从本机访问

[root@localhost ~]# telnet 192.112.3.65 5432
Trying 192.112.3.65...
Connected to 192.112.3.65.
Escape character is '^]'.

可以正常访问

从其他服务器访问

[root@ums53 ~]# telnet 192.112.3.65 5432
Trying 192.112.3.65...
telnet: connect to address 192.112.3.65: Connection refused
[root@ums53 ~]#

无法正常访问

基于此, 判断是防火墙导致的.

检查防火墙

# 如果使用 firewalld
sudo firewall-cmd --permanent --add-port=5432/tcp
sudo firewall-cmd --reload

# 或者添加服务
sudo firewall-cmd --permanent --add-service=postgresql
sudo firewall-cmd --reload

# 如果使用 iptables
sudo iptables -A INPUT -p tcp --dport 5432 -j ACCEPT
sudo service iptables save

实际操作结果


[root@localhost ~]# sudo iptables -L -n | grep 5432
ACCEPT     6    --  192.112.3.65         0.0.0.0/0            tcp dpt:5432
ACCEPT     6    --  127.0.0.1            0.0.0.0/0            tcp dpt:5432
ACCEPT     6    --  192.112.1.22         0.0.0.0/0            tcp dpt:5432
REJECT     6    --  0.0.0.0/0            0.0.0.0/0            tcp dpt:5432 reject-with icmp-port-unreachable


[root@localhost ~]# sudo iptables -L INPUT -n | grep 5432
ACCEPT     6    --  192.112.3.65         0.0.0.0/0            tcp dpt:5432
ACCEPT     6    --  127.0.0.1            0.0.0.0/0            tcp dpt:5432
ACCEPT     6    --  192.112.1.22         0.0.0.0/0            tcp dpt:5432
REJECT     6    --  0.0.0.0/0            0.0.0.0/0            tcp dpt:5432 reject-with icmp-port-unreachable

sudo systemctl status firewalld
sudo firewall-cmd --list-all
sudo firewall-cmd --list-ports
firewalld.service - firewalld - dynamic firewall daemon
     Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; preset: enabled)
     Active: inactive (dead)
       Docs: man:firewalld(1)

FirewallD is not running
FirewallD is not running

现在问题清楚了。您当前的防火墙规则只允许特定的 IP 地址访问 PostgreSQL 端口 5432,而拒绝了所有其他连接:

ACCEPT     6    --  192.112.3.65         0.0.0.0/0            tcp dpt:5432  # 仅允许本机
ACCEPT     6    --  127.0.0.1            0.0.0.0/0            tcp dpt:5432  # 仅允许本地回环
ACCEPT     6    --  192.112.1.22         0.0.0.0/0            tcp dpt:5432  # 仅允许特定IP
REJECT     6    --  0.0.0.0/0            0.0.0.0/0            tcp dpt:5432  # 拒绝所有其他IP

解决方案

方案 1: 允许特定网段访问(推荐)

# 允许 192.112.0.0/16 网段访问 PostgreSQL
sudo iptables -I INPUT -p tcp -s 192.112.0.0/16 --dport 5432 -j ACCEPT

# 或者允许更具体的网段,如 192.112.3.0/24
sudo iptables -I INPUT -p tcp -s 192.112.3.0/24 --dport 5432 -j ACCEPT

方案 2: 允许特定 IP 访问

# 允许特定 IP 访问,例如从 192.112.1.100 访问
sudo iptables -I INPUT -p tcp -s 192.112.1.100 --dport 5432 -j ACCEPT

方案 3: 允许所有 IP 访问(谨慎使用)

# 允许所有 IP 访问 PostgreSQL(安全风险较高)
sudo iptables -I INPUT -p tcp --dport 5432 -j ACCEPT

方案 4: 删除当前的拒绝规则并添加允许规则

# 1. 先添加允许规则
sudo iptables -I INPUT -p tcp --dport 5432 -j ACCEPT

# 2. 删除最后的拒绝规则(REJECT 规则)
sudo iptables -D INPUT -p tcp --dport 5432 -j REJECT --reject-with icmp-port-unreachable

验证规则

# 查看更新后的规则
sudo iptables -L -n | grep 5432

# 从其他机器测试连接
telnet 192.112.3.65 5432

保存规则(重要)

# 保存 iptables 规则,使重启后仍然有效
sudo service iptables save

# 或者在某些系统上
sudo iptables-save > /etc/sysconfig/iptables

同时检查 PostgreSQL 配置

确保 PostgreSQL 配置允许远程连接:

# 检查 PostgreSQL 配置
sudo cat /var/lib/pgsql/data/postgresql.conf | grep -E "listen_addresses|port"

# 检查访问控制配置
sudo cat /var/lib/pgsql/data/pg_hba.conf

根据您的防火墙规则,问题确实是防火墙配置导致的。您只允许了特定 IP 访问,而其他机器被拒绝了连接。按上述方案更新防火墙规则即可解决问题。

为啥我通过 执行iptables -L | grep 5432 无法查询到结果

这个问题的原因是 iptables -Liptables -L -n 的输出格式不同:

-n 参数的作用

-n 参数表示 “numeric”,它会以数字形式显示 IP 地址和端口号,而不是尝试解析为主机名和服务名。

详细解释

不使用 -n 参数时:

  • 端口号 5432 会被解析为服务名(如果在 /etc/services 中有定义)
  • 可能显示为 “postgresql” 而不是 “5432”
  • IP 地址可能会被反向解析为主机名

使用 -n 参数时:

  • 端口号显示为原始数字 “5432”
  • IP 地址显示为原始数字格式
  • 这样你才能用 grep 5432 找到结果

验证方法

# 不使用 -n 时的输出(可能显示服务名)
sudo iptables -L

# 使用 -n 时的输出(显示数字端口)
sudo iptables -L -n

# 检查 /etc/services 文件中是否定义了 postgresql
grep 5432 /etc/services

在您的 /etc/services 文件中,5432 端口很可能被定义为 “postgresql” 服务,所以不使用 -n 参数时显示的是 “postgres” 而不是 “5432”,这就是为什么 grep 5432 没有结果的原因。

如果您想在不使用 -n 的情况下搜索 PostgreSQL 规则,可以使用:

sudo iptables -L | grep -i postgres

[root@localhost ~]# iptables -L | grep -iE "(postgres|5432)"
ACCEPT     tcp  --  localhost.localdomain  anywhere           tcp dpt:postgres
ACCEPT     tcp  --  localhost            anywhere             tcp dpt:postgres
ACCEPT     tcp  --  192.112.1.22         anywhere             tcp dpt:postgres
REJECT     tcp  --  anywhere             anywhere             tcp dpt:postgres reject-with icmp-port-unreachable
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐