#やりたかったこと
①AWS S3内に保存されているxmlファイルを読み込み、必要なデータ取得
②pythonプログラムからdockerコンテナ内のPostgresに接続 ←躓いたパート1
③psycopg2を用いて、クエリ実行してデータ取得 ←躓いたパート2
④データ加工後、クエリ実行してPostgresに保存
#躓いたパート1の問題点
最初Pythonのファイルには下記のように記述していた
。
# DB接続情報
postgre_user_name = "admin"
postgre_user_password = "password"
postgre_server_port = 5432
postgre_database_name = "hugahoge"
connection = psycopg2.connect(f"host=localhost port={postgre_server_port} dbname={postgre_database_name} user={postgre_user_name} password={postgre_user_password}")
実行時は、sam local invokeの後にオプションでPostgresが立ち上がっているコンテナのIDを指定していた。
結果、そんなネットワークは見つからないよ、とエラー。
% sam local invoke --docker-network 8f1abbbc8138
.
.
.
docker.errors.NotFound: 404 Client Error: Not Found ("network 8f1abbbc8138 not found")
それもそのはず、オプションコマンド名にもあるように、指定するのはコンテナIDではなく、コンテナが接続されているネットワークIDもしくは名前を指定する必要がある。凡ミス。
#躓いたパート2の解決方法
Dockerネットワークを生成し、確認。
% docker network create sam-calc-price-network
c87bcb8cee0e92f57a10de53b2a4930e8e3cf890b5f7448299e45bad3ffed3c4
% docker network inspect sam-calc-price-network
[
{
"Name": "sam-calc-price-network",
"Id": "c87bcb8cee0e92f57a10de53b2a4930e8e3cf890b5f7448299e45bad3ffed3c4",
"Created": "2020-12-23T05:06:07.9437227Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
Postgresのコンテナをネットワークに接続し、確認。
% docker network connect sam-calc-price-network dev-postgres
% docker network inspect sam-calc-price-network
[
{
"Name": "sam-calc-price-network",
"Id": "c87bcb8cee0e92f57a10de53b2a4930e8e3cf890b5f7448299e45bad3ffed3c4",
"Created": "2020-12-23T05:06:07.9437227Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"8f1abbbc813844cb52395b65c711d56cc4701058f2d436bf25ffd553280aa133": {
"Name": "dev-postgres",
"EndpointID": "dd5ab005654b3a58b1604014ba1284e1690e5cd009b8d7bf62db655caf3e0657",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
気を取り直して、DockerネットワークIDを指定して実行!
% sam local invoke --docker-network c87bcb8cee0e92f57a10de53b2a4930e8e3cf890b5f7448299e45bad3ffed3c4
[ERROR] OperationalError: could not connect to server: Connection refused
Is the server running on host "localhost" (127.0.0.1) and accepting
TCP/IP connections on port 5432?
could not connect to server: Cannot assign requested address
Is the server running on host "localhost" (::1) and accepting
TCP/IP connections on port 5432?
…えええ。
色々調べた結果、ユーザー側からみるローカルホストとコンテナからコンテナを見たときのローカルホストは違うらしい。コンテナから見たローカルホストはコンテナ名らしいので、下記のようにPythonファイルを書き換えた。
# DB接続情報
postgre_user_name = "admin"
postgre_user_password = "password"
postgre_server_port = 5432
postgre_database_name = "fugahoge"
connection = psycopg2.connect(dbname=f"{postgre_database_name}",
user=f"{postgre_user_name}",
password=f"{postgre_user_password}",
host="dev-postgres")
#躓いたパート2の問題点
再度、実行!
{"errorMessage": "relation \"place\" does not exist\nLINE 1: SELECT contract_id FROM place WHERE num...\n ^\n", "errorType": "UndefinedTable", "stackTrace": [" File \"/var/task/app.py\", line 145, in lambda_handler\n num = get_contract_id(df['num'][i])\n", " File \"/var/task/app.py\", line 139, in get_contract_id\n cur.execute(sql_sentence)\n"]}%
…えええ。違うエラー。
とりあえずDBには接続できた。けど存在しているはずのテーブルが無いと言われる。
SAMから実行ではなく、スクリプトとして実行する分には問題なくデータが取得できる。
ということは、コンテナからクエリを実行するとき特有の問題なのかな。
#躓いたパート2の解決方法
色々調べたが、解決方法がわからなかった…。
とりあえず、クエリ実行時にテーブルのschemaを指定してあげたらいけた。
######before
def get_contract_id(num):
cur = connection.cursor()
sql_sentence = "SELECT id FROM place WHERE number = %s;"
cur.execute(sql_sentence, (num,))
return cur.fetchall()
######after
def get_contract_id(num):
cur = connection.cursor()
sql_sentence = "SELECT id FROM public.place WHERE number = %s;"
cur.execute(sql_sentence, (num,))
return cur.fetchall()