Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python AWS ECS上的PostgreSQL:psycopg2.OperationalError端口号5432无效_Python_Django_Postgresql_Docker_Amazon Ecs - Fatal编程技术网

Python AWS ECS上的PostgreSQL:psycopg2.OperationalError端口号5432无效

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"

我在AWS ECS上通过psycopg2连接数据库时遇到问题。 我有一个应用程序容器和一个数据库容器。容器是链接的

应用程序有一个入口点脚本,用于在启动应用程序服务器之前检查数据库是否已启动

$ 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/alias
db
,我的名字是
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真的应该