使用 Boto3 S3 资源时 S3 Ninja 端点抛出无法连接错误

S3 Ninja endpoint throws could not connect error when using Boto3 S3 resource

我正在尝试将 S3 Ninja 与 Python 中的 boto3 一起使用,但是尽管有 docker 容器 运行,我还是无法配置 S3客户端使用 S3 Ninja。

尝试使用 boto3.session.Session().client().get_object() 获取对象时,我的尝试导致了以下错误。

s3 = S3()
content = s3.get('mybucket', 'myobject')

botocore.exceptions.EndpointConnectionError: Could not connect to the endpoint URL: "http://localhost:9444/mybucket/myobject.json"

按预期使用 curl http://localhost:9444/mybucket/myfile.json returns 文件,看起来 S3 Ninja 正在运行。但是S3客户端不知为何找不到。

我已经为端点尝试了以下两个值 URL。

class S3:

    client: boto3.client

    def __init__(self) -> None:
        local = os.environ.get('LOCAL')
        if local == 'true':
            self.client = boto3.session.Session().client(
                service_name='s3',
                aws_access_key_id='my_access_key',
                aws_secret_access_key='my_secret_key',
                endpoint_url='http://localhost:9444',
                config=botocore.client.Config(
                    s3={
                        'addressing_style': 'path'
                    }
                )
            )
        else:
            self.client = boto3.client('s3')

    def get(self, bucket_name: str, key: str) -> str:
        response = self.client.get_object(
            Bucket=bucket_name,
            Key=key)
        return response['Body'].read().decode('utf-8')

有什么问题?

这是一个令人沮丧的问题,一段时间后我发现这是由于我使用了 Lambda 函数引起的。

我问题中的代码是 Lambda 函数的一部分。函数和 API 是 运行 在本地使用 sam local start-api,任何调用实际上是 运行 在 docker 容器中。所以这个问题是 Lambda 容器无法与本地主机上的 S3 Ninja 通信,因为它不在本地主机上 运行ning。

此处的简单修复是针对默认 docker 网络(网桥)172.17.0.1 的 IP,而不是本地主机。

class S3:

    client: boto3.client

    def __init__(self) -> None:

        local = Environment.local == 'true'

        if local:
            logger.info('Using S3 Ninja to emulate the S3 API.')
            self.client = boto3.client(
                service_name='s3',
                aws_access_key_id='AKIAIOSFODNN7EXAMPLE',
                aws_secret_access_key='wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
                endpoint_url='http://172.17.0.1:9444/s3/'
            )
        else:
            self.client = boto3.client('s3')

也可以在单独的 docker 网络上 运行 S3 Ninja,然后在同一网络上启动本地 API。我不确定为什么需要这样做,但认为值得一提。

docker network create lambda-local
docker network inspect lambda-local # Record the gateway IP address.
docker run --name s3ninja --network lambda-local -d -p 9444:9000 scireum/s3-ninja:latest
sam local start-api --docker-network lambda-local
# Make sure to use the gateway IP address discovered using 'docker network inspect'.
endpoint_url='http://172.20.0.1:9444/s3/'