grpc / grpc-swift

The Swift language implementation of gRPC.
Apache License 2.0
2.04k stars 420 forks source link

connection refused over docker network #2065

Closed Clement-Jean closed 1 month ago

Clement-Jean commented 1 month ago

What are you trying to achieve?

I'm trying use grpc-swift to communicate between two docker images (swift server and client) over a docker network. The communication works on localhost but not in docker.

NOTE: I'm using the V2 generated code.

What have you tried so far?

I built two images, one for the server and the other for the client. This looks like the following for the client:

FROM swift:6.0.0 AS builder
WORKDIR /root

COPY Package.swift .
ADD swift/app swift/app

RUN swift build -c release

FROM swift:6.0.0-slim
WORKDIR /root

COPY --from=builder /root .

ENTRYPOINT [".build/release/app_client"]

And I just replaces app_client by app_server in the server.

Then I ran the two images like so:

docker network create -d bridge grpc
docker run -it --rm --name server --network=grpc -p 50051 app/server
docker run -it --rm --name client --network=grpc app/client

and the client hangs up indefinitely. Note that I tried both http://server:50051 and the IP address since I noticed previously that hostnames (e.g. localhost) are not resolved.

I tried to override the entrypoint with /bin/bash and run iftop in the server to make sure the client was sending connection data and it looks like it receives that connection request but never accepts.

I then tried running this grpcurl command against the server:

grpcurl --plaintext --proto ./proto/app.proto -d '{"test": "test"}' server:50051 pkg.Service/MyRPC

and still iftop shows that it gets a connection request but doesn't accept it. grpcurl returns:

Failed to dial target host "server:50051": dial tcp 172.22.0.4:50051: connect: connection refused

I also tried not building with the -c release because I thought this was blocking my logs (swift-log) from being displayed.

Finally, I tried changing transport for both the client and server because I thought there might be some issue with NIO on Linux (I'm a swift beginner). So, before I had:

let server = GRPCServer(
    transport: .http2NIOPosix(
        address: .ipv4(host: "127.0.0.1", port: self.port),
        config: .defaults(transportSecurity: .plaintext)
    ),
    services: [AppService()]
)

and now I have:

let transport = HTTP2ServerTransport.Posix(
    address: .ipv4(host: "127.0.0.1", port: self.port),
    config: .defaults(transportSecurity: .plaintext)
)
let server = GRPCServer(
    transport: transport,
    services: [AppService()]
)

I'm not sure where to go from here...

glbrntt commented 1 month ago

Apologies @Clement-Jean -- I didn't get a chance to look into this properly today (I hope to next week). A couple of quick notes though:

I'm trying use grpc-swift to communicate between two docker images (swift server and client) over a docker network. The communication works on localhost but not in docker.

I'm not very familiar with docker networks (it's been a while...) but the fact it works over localhost makes me think this is a configuration / setup issue.

Note that I tried both http://server:50051 and the IP address since I noticed previously that hostnames (e.g. localhost) are not resolved.

This is expected behaviour right now, v2 is very much work-in-progress and we plan to add a DNS resolver very shortly.

I also tried not building with the -c release because I thought this was blocking my logs (swift-log) from being displayed.

That won't make a difference here.

Finally, I tried changing transport for both the client and server because I thought there might be some issue with NIO on Linux (I'm a swift beginner). So, before I had:

let server = GRPCServer(
    transport: .http2NIOPosix(
        address: .ipv4(host: "127.0.0.1", port: self.port),
        config: .defaults(transportSecurity: .plaintext)
    ),
    services: [AppService()]
)

and now I have:

let transport = HTTP2ServerTransport.Posix(
    address: .ipv4(host: "127.0.0.1", port: self.port),
    config: .defaults(transportSecurity: .plaintext)
)
let server = GRPCServer(
    transport: transport,
    services: [AppService()]
)

These are both the same, the first is just a convenience API.

Clement-Jean commented 1 month ago

Thank you for replying 🙏 I'm open to share the code with you if you need an example for reproduction. Let me know.

[it] makes me think this is a configuration / setup issue

I also believe this is the case. I just tried everything I could think of right now.

we plan to add a DNS resolver very shortly

for now, I played with swift-async-dns-resolver and it was easier than expected to get the host name resolved.

Apologies @Clement-Jean -- I didn't get a chance to look into this properly today

No worries!

PeterAdams-A commented 1 month ago

Try binding 0.0.0.0 rather than 127.0.0.1 on your sever and see if that makes a difference - should be quick to try. I've not used docker networking but I'd guess it has a separate interface.

Clement-Jean commented 1 month ago

@PeterAdams-A turns out it works now. Not sure if this is because I change to 0.0.0.0 or updated grpc-swift.

if it is the 0.0.0.0 ip address why would it be the case? all my other implementations are using 127.0.0.1...