Python AWS ECS上的PostgreSQL:psycopg2.OperationalError端口号5432无效
我在AWS ECS上通过psycopg2连接数据库时遇到问题。 我有一个应用程序容器和一个数据库容器。容器是链接的 应用程序有一个入口点脚本,用于在启动应用程序服务器之前检查数据库是否已启动Python AWS ECS上的PostgreSQL:psycopg2.OperationalError端口号5432无效,python,django,postgresql,docker,amazon-ecs,Python,Django,Postgresql,Docker,Amazon Ecs,我在AWS ECS上通过psycopg2连接数据库时遇到问题。 我有一个应用程序容器和一个数据库容器。容器是链接的 应用程序有一个入口点脚本,用于在启动应用程序服务器之前检查数据库是否已启动 $ until psql -h "$DB_HOST" -U "$DB_USER" -c '' && >&2 echo "Postgres is up"; do >&2 echo "Postgres is unavailable - sleeping"
$ until psql -h "$DB_HOST" -U "$DB_USER" -c '' && >&2 echo "Postgres is up"; do
>&2 echo "Postgres is unavailable - sleeping"
sleep 1
done
> Is the server running on host "db" (172.17.0.3) and accepting
> TCP/IP connections on port 5432?
> Postgres is unavailable - sleeping
> Postgres is up
这部分工作正常,但一旦应用程序服务器启动并尝试连接到DB,我就会出现以下错误:
psycopg2.OperationalError: invalid port number: "tcp://172.17.0.3:5432"
我不知道会是什么情况。当使用Docker在本地运行时,这可以正常工作
如有任何提示,将不胜感激。谢谢 #/bin/bash
#!/bin/bash
set -e
cmd="$@"
if [ -z "$POSTGRES_USER" ]; then
export POSTGRES_USER=postgres
fi
export DATABASE_URL=postgres://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres:5432/$POSTGRES_USER
function postgres_ready(){
python << END
import sys
import psycopg2
try:
conn = psycopg2.connect(dbname="$POSTGRES_USER", user="$POSTGRES_USER", password="$POSTGRES_PASSWORD", host="postgres")
except psycopg2.OperationalError:
sys.exit(-1)
sys.exit(0)
END
}
until postgres_ready; do
>&2 echo "Postgres is unavailable - sleeping"
sleep 1
done
>&2 echo "Postgres is up - continuing..."
exec $cmd
set-e
cmd=“$@”
如果[-z“$POSTGRES_USER”];然后
导出POSTGRES\u USER=POSTGRES
fi
导出数据库\u URL=postgres://$postgres\u用户:$postgres_PASSWORD@postgres:5432/$POSTGRES\u用户
函数postgres_ready(){
python&2 echo“Postgres不可用-正在休眠”
睡眠1
完成
>&2 echo“Postgres正在启动-继续…”
exec$cmd
因此,让它有更多的背景。该应用程序是用Django编写的,下面是数据库配置部分:
DATABASES = {
'default': {
# Requests will be wrapped in a transaction automatically
# https://docs.djangoproject.com/en/1.10/topics/db/transactions/#tying-transactions-to-http-requests
'ATOMIC_REQUESTS': True,
'ENGINE': 'django.contrib.gis.db.backends.postgis',
'NAME': os.getenv('DB_NAME', 'postgres'),
'USER': os.getenv('DB_USER', 'postgres'),
'PASSWORD': os.getenv('DB_PASSWORD', 'secret'),
'HOST': os.getenv('DB_HOST', 'localhost'),
'PORT': os.getenv('DB_PORT', 5432),
'OPTIONS': {
'client_encoding': 'UTF8'
}
}
}
来自entry脚本的psql
命令使用默认的5432
端口连接正常
现在,当Django试图打开连接时,它使用了这个os.getenv('DB_PORT',5432)
调用中的默认值5432
,因为我没有显式地设置DB_PORT
ENV,也没有看到这样做的理由
出于想法,我已经在AWS ECS任务定义中明确设置了DB_PORT
ENV,令人惊讶的是,它成功了!无论出于何种原因(明确设置时,它可能被传递为str
,而不是int
)
我通过在任务配置中添加/删除ENV-var定义两次确认了这一点。我在Ruby on Rails中遇到了同样的问题。我有几乎相同的数据库配置,并且我也使用了两个链接容器用于app和database(不是直接的,而是通过Gitlab CI;它在引擎盖下创建容器并链接它们)我的环境变量有不同的名称:
POSTGRES\u主机
,POSTGRES\u端口
,等等。然而,您显式定义POSTGRES\u端口
的解决方案对我也很有效!但我不能就这样离开它,我想弄清楚为什么这样有帮助,以及是什么原因首先导致了问题。下面是我的发现。
错误显示:无效端口号:tcp://172.17.0.3:5432
。起初它看起来像是一个有效的端口5432,但实际上它是整个字符串tcp://172.17.0.3:5432"这不是一个有效的端口号。一些东西通过这个URI而不是端口号到PostgreSQL,这就是错误。通过PycPog连接,我使用PG GEM,但是它们都是C库的包装器,是PostgreSQL的一部分。让我们看看它是如何得到这个错误的。有一个文件:代码> FE-Connect。hich包含解析连接选项的函数。下面是(来自PostgreSQL 10,这是我使用的版本):
/*算出我们要使用的端口号*/
如果(通道->端口==NULL | |通道->端口[0]='\0')
thisport=DEF_PGPORT;
其他的
{
thisport=atoi(通道->端口);
如果(此端口<1 | |此端口>65535)
{
appendPQExpBuffer&conn->errorMessage,
libpq\u gettext(“无效端口号:\%s\”\n”),
通道->端口);
继续前进;
}
}
它说:如果ch->port
为NULL
或空字符串,则表示没有为任何端口提供连接选项,那么让我们使用DEF_PGPORT
,预编译的默认端口,通常为5432;如果存在ch->port
,则使用atoi
将其转换为int,并检查其是否在1和65535之间
如果ch->port
为“tcp://172.17.0.3:5432“
,atoi(ch->port)
返回0,小于1,因此我们得到这个错误
顺便说一句,在最近的PostgreSQL版本中,会出现一个信息更丰富的错误:无效整数值”tcp://172.17.0.3:5432对于关键字“port”
。这是因为用自定义错误检查字符串转换函数替换了上面的atoi
好的,这个URI出现在libpq连接选项中的端口号的位置。但是它是如何出现的呢?结果是,因为Docker
Docker容器可以有名称,可以是自动生成的,也可以是为运行
命令提供的--name
选项。当使用--link
选项链接两个容器时,可以指定另一个容器的名称和别名(可选)。默认情况下,别名与名称相同。您的数据库容器可能有name/aliasdb
,我的名字是postgres
(Gitlab默认用它的图像名命名一个容器,在我的例子中:)
链接容器时,Docker会根据容器名称/别名对这些变量进行命名。其中一个变量是\u PORT
,它包含容器公开端口的URI。不仅包含端口号,还包含完整的URI(就像从Docker PORT
命令中获得的URI)。这里是获取"tcp://172.17.0.3:5432“
from,Docker将其写入DB\u PORT
变量,因为您的数据库容器恰好命名为DB
毕竟,可能的解决办法是:
- Docker链接容器后重新定义
DB_PORT
变量(如您所做)
- 在配置中重命名
DB_PORT
变量
- 为db容器设置另一个别名
你深入到了这个兔子洞。令人印象深刻!非常感谢你的解释。不幸的是,我无法再在这个项目中检查它了。我刚刚遇到了完全相同的问题,GitLab CI服务和重叠的环境变量。这些都是一些意想不到的副作用。Docker真的应该