2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Dockerで立ち上げたPostgresにSAMでbuildしたpsycopg2からクエリを実行する方法

Last updated at Posted at 2020-12-24

#やりたかったこと
①AWS S3内に保存されているxmlファイルを読み込み、必要なデータ取得
②pythonプログラムからdockerコンテナ内のPostgresに接続 ←躓いたパート1
③psycopg2を用いて、クエリ実行してデータ取得 ←躓いたパート2
④データ加工後、クエリ実行してPostgresに保存

#躓いたパート1の問題点
最初Pythonのファイルには下記のように記述していた

app.py
# 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()
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?