Docker Engine API - Connection reset by peer - docker

I'm trying to make requests to the Docker API remotely.
I have the docker engine running on virtual machine, and I'm making the requests from docker containers.
Firstly, I've done this to make the Docker daemon listen on a specific IP and port:
edit /lib/systemd/system/docker.service
ExecStart=/usr/bin/docker -H fd:// -H=tcp://0.0.0.0:5555
systemctl daemon-reload
sudo service docker restart
I configured to listen on 0.0.0.0, so it will be reachable at any IPv4 address.
When I test this via curl on host, it works fine. e.g: curl localhost:5555/services
However, my goal is to make requests from containers. Here is how I construct the docker client inside my go program:
cli, err := client.NewClientWithOpts(
client.WithHost("tcp://192.168.56.1:5555"),
)
if err != nil {
panic(err)
}
networkFilters := filters.NewArgs()
networkFilters.Add("driver", "overlay")
networks, err := cli.NetworkList(context.Background(), types.NetworkListOptions{Filters: networkFilters})
if err != nil {
panic(err)
}
The error I'm having:
http: panic serving 10.255.0.2:39632: error during connect: Get http://192.168.56.1:5555/v1.40/networks?filters=%7B%22driver%22%3A%7B%22overlay%22%3Atrue%7D%7D: read tcp 172.18.0.3:36126->192.168.56.1:5555: read: connection reset by peer
Any ideas? Thanks

Related

Accessing webserver inside WSL from Windows(chrome)

I'm using WSL(v2) and have a web server running inside it.
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
kind-control-plane Ready control-plane 3d21h v1.25.0
And I can ping my "website" from within WSL [ping mysite.com] just fine
On my Windows side, I have Docker Desktop running.
Under Containers:
NAME IMAGE STATUS PORTS
kind-control-plane kindest/node:<none> Running 443,42725,80
I have also enabled all [WSL] related options under Docker Desktop -> Settings
I want to access this website in Chrome and tried:
localhost:443 = err 400
localhost:42725 = Client sent an HTTP request to an HTTPS server. With https, err 403
localhost:80 = err 404
I also tried adding the port 42725 to my firewall allowed list but nothing seems to change.
I searched and found multiple Q&As pointing me here:
https://learn.microsoft.com/en-us/windows/wsl/networking
I tried these:
netsh interface portproxy add v4tov4 listenport=80listenaddress=0.0.0.0 connectport=80connectaddress={hostname -I}
netsh interface portproxy add v4tov4 listenport=443listenaddress=0.0.0.0 connectport=443connectaddress={hostname -I}
but nothing changes.
However, when I do this
netsh interface portproxy add v4tov4 listenport=42725listenaddress=0.0.0.0 connectport=42725connectaddress={hostname -I}
And then try to restart:
$ docker start kind-control-plane
Error response from daemon: Ports are not available: exposing port TCP 127.0.0.1:42725 -> 0.0.0.0:0: listen tcp 127.0.0.1:42725: bind: An attempt was made to access a socket in a way forbidden by its access permissions.
Error: failed to start containers: kind-control-plane
I also tried a completely different [listenport] but it didn't work either.
I'm actually not sure what ports to put inside the listenport/connectport options. Also, should I change listenaddress=0.0.0.0 to something else?
Any suggestions? Thanks!

Connection refused: when uwsgi and nginx in different containers

I am trying to setup two docker containers(yes separate without docker-compose): one with nginx and one with uwsgi with basic flask app.
I run containers in same network within docker
My nginx config for site added/linked to sites-enabled(everything else is default):
server {
listen 80;
server_name 127.0.0.1;
location / {
include uwsgi_params;
uwsgi_pass 0.0.0.0:8080;
}
}
My uwsgi.ini
[uwsgi]
module = app:app
master = true
processes = 2
socket = 0.0.0.0:8080
uwsgi entry point in docker looks like
.local/bin/uwsgi --ini uwsgi.ini
Containers run fine on their own - uwsgi receives request on 8080 and nginx receives expected requests. How ever when I try to access 127.0.0.1 i get 502 status code and nginx logs error:
1 connect() failed (111: Connection refused) while connecting to
upstream, client: 192.168.4.1, server: 127.0.0.1, request: "GET /
HTTP/1.1", upstream: "uwsgi://0.0.0.0:8080", host: "127.0.0.1"
By googling i find solution that rather use one container and some_socket.sock as file or use docker compose. Apparently problem with permissions, but I do not know how to solve them or diagnose.
I launch containers with these commands:
docker run --network app_network --name nginx --rm -p 80:80 my_nginx
docker run --network app_network --name flaskapp --rm -p 8080:8080 my_uwsgi
EDIT
You can simply use the hostname of the docker container in the uwsgi_pass directive as both docker containers are on the same subnet.
location / {
include uwsgi_params;
uwsgi_pass flaskapp:8080;
}
0.0.0.0 isn't the IP address of the server, it essentially tells the server to be hosted on every IP that the device has allocated.
To connect to it from nginx, you will need to use the IP address of the container instead.
You can find the IP address of the container running uWsgi with the following command:
docker inspect CONTAINER_ID
Where CONTAINER_ID is the ID of the container you started uwsgi in.
From here you can update the nginx config as follows:
uwsgi_pass IP_ADDRESS:8080;
Where IP_ADDRESS is the one you found from the command above
You can also set the ip address of the container when you start it with the following option
--ip <ip>
Be careful, however, to ensure that the IP address you set is in the same subnet as the standard IP's assigned.

Docker :: assign different IP address to each container on Synology NAS

I'm getting familiar with Docker thanks to my NAS Syonlogy 1515+.
I have created a SQL Server 2019 container called sqlserver4 that listen on port 1433:
sudo docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=My_Password" -p 1433:1433 --name sqlserver4 -d mcr.microsoft.com/mssql/server:2019-latest
And I have then created a second one called sqlserver5 that listen on port 1533:
sudo docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=My_Password" -p 1533:1533 --name sqlserver5 -d mcr.microsoft.com/mssql/server:2019-latest
All good, my two servers are there at the IP Address 192.168.1.44
I can connect through SSMS to the first one, the sqlserver4:
But when I try to connect to the second one, the sqlserver5 I receive the error:
A connection was successfully established with the server, but then an
error occurred during the pre-login handshake. (provider: TCP
Provider, error: 0 - The specified network name is no longer
available.) (Microsoft SQL Server, Error: 64)
It's easy to see where the problem is: even if they are on different port, 1433 and 1533 the IP Address is always the same 192.168.1.44
How can I setup a different IP Address for each container?
EDIT:
#David Maze suggested me to stop sqlserver4 and try to connect to sqlserver5. My assumption was wrong, I cannot connect to sqlserver5 neither. But fun fact, the error changes:
A connection was successfully established with the server, but then an
error occurred during the pre-login handshake. (provider: TCP
Provider, error: 0 - An existing connection was forcibly closed by the
remote host.) (Microsoft SQL Server, Error: 10054)

How do you dockerize a WebSocket Server?

I'm having trouble with putting my WebSocket server in a Docker container.
This is the server code, which writes to a new connection with "connected".
// server.go
func RootHandler(w http.ResponseWriter, r *http.Request) {
upgrader := websocket.Upgrader{ // (Uses gorilla/websocket)
ReadBufferSize: 4096,
WriteBufferSize: 4096,
}
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
panic(err)
}
if err = conn.WriteMessage(websocket.TextMessage, []byte("connected")); err != nil {
panic(err)
}
}
func main() {
fmt.Println("server is running")
// For graceful shutdown
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
server := http.Server{Addr: "localhost:8000"}
defer server.Close()
http.HandleFunc("/", RootHandler)
go func() {
err := server.ListenAndServe()
if err != nil && err != http.ErrServerClosed {
panic(err)
}
}()
<-stop
}
Here is the client:
// client.go
func main() {
connection, _, err := websocket.DefaultDialer.Dial("ws://localhost:8000", nil)
if err != nil {
panic(err)
}
_, b, err := connection.ReadMessage()
if err != nil {
panic(err)
}
fmt.Println(string(b)) // "connected"
}
Running server.go then client.go prints "connected", showing that the code is working. Now I want to put the server in a Docker container. This is dockerfile:
FROM golang:1.11.4-alpine3.8
COPY . $GOPATH/src/websocket-test
WORKDIR $GOPATH/src/websocket-test
RUN ["go", "build", "server.go"]
EXPOSE 8000
CMD ["./server"]
I use these commands to build and start the container, exposing 8000/tcp.
docker build -t websocket-test .
docker run -p 8000:8000 websocket-test
I can confirm that the server is running because it prints "server is running". If I start client.go outside the container, it panics:
panic: read tcp [::1]:60328->[::1]:8000: read: connection reset by peer
What I expect is the same outcome as before—printing "connected" on the client side. The error message means that the server dropped the connection before the handshake. I don't understand the "60328" number. As far as I know, WebSocket doesn't change ports on upgrade, so I should be okay with exposing just 8000.
I do not know what I must change to be able to connect via WebSocket to my server.
When you specify a hostname or IP address​ to listen on (in this case localhost which resolves to 127.0.0.1), then your server will only listen on that IP address.
Listening on localhost isn't a problem when you are outside of a Docker container. If your server only listens on 127.0.0.1:8000, then your client can easily connect to it since the connection is also made from 127.0.0.1.
When you run your server inside a Docker container, it'll only listen on 127.0.0.1:8000 as before. The 127.0.0.1 is a local loopback address and it not accessible outside the container.
When you fire up the docker container with -p 8000:8000, it'll forward traffic heading to 127.0.0.1:8000 to the container's IP address, which in my case is 172.17.0.2.
The container gets an IP addresses within the docker0 network interface (which you can see with the ip addr ls command)
So, when your traffic gets forwarded to the container on 172.17.0.2:8000, there's nothing listening there and the connection attempt fails.
The fix:
The problem is with the listen address:
server := http.Server{Addr: "localhost:8000"}
To fix your problem, change it to
server := http.Server{Addr: ":8000"}
That'll make your server listen on all it container's IP addresses.
Additional info:
When you expose ports in a Docker container, Docker will create iptables rules to do the actual forwarding. See this. You can view these rules with:
iptables -n -L
iptables -t nat -n -L

Cannot connect to Go GRPC server running in local Docker container

I have a go grpc service. I'm developing on a mac, sierra. When running a grpc client against the service locally, all is well, but when running same client against same service in the docker container I get this error:
transport: http2Client.notifyError got notified that the client transport was broken EOF.
FATA[0000] rpc error: code = Internal desc = transport is closing
this is my docker file:
FROM golang:1.7.5
RUN mkdir -p /go/src/github.com/foo/bar
WORKDIR /go/src/github.com/foo/bar
COPY . /go/src/github.com/foo/bar
# ONBUILD RUN go-wrapper download
RUN go install
ENTRYPOINT /go/bin/bar
EXPOSE 51672
my command to build the image:
docker build -t bar .
my command to launch the docker container:
docker run -p 51672:51672 --name bar-container bar
Other info:
client program runs fine from within the docker container
connecting to a regular rest endpoint works fine (http2, grpc related?)
running the lsof command in OS X yields these results
$lsof -i | grep 51672
com.docke 984 oldDave 21u IPv4 0x72779547e3a32c89 0t0 TCP *:51672 (LISTEN)
com.docke 984 oldDave 22u IPv6 0x72779547cc0fd161 0t0 TCP localhost:51672 (LISTEN)
here's a snippet of my server code:
server := &Server{}
endpoint := "localhost:51672"
lis, err := net.Listen("tcp", endpoint)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer(grpc.Creds(creds))
pb.RegisterExpServiceServer(s, server)
// Register reflection service on gRPC server.
reflection.Register(s)
log.Info("Starting Exp server: ", endpoint)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
When you specify a hostname or IP address​ to listen on (in this case localhost which resolves to 127.0.0.1), then your server will only listen on that IP address.
Listening on localhost isn't a problem when you are outside of a Docker container. If your server only listens on 127.0.0.1:51672, then your client can easily connect to it since the connection is also made from 127.0.0.1.
When you run your server inside a Docker container, it'll only listen on 127.0.0.1:51672 as before. The 127.0.0.1 is a local loopback address and it not accessible outside the container.
When you fire up the docker container with "-p 51672:51672", it'll forward traffic heading to 127.0.0.1:51672 to the container's IP address, which in my case is 172.17.0.2.
The container gets an IP addresses within the docker0 network interface (which you can see with the "ip addr ls" command)
So, when your traffic gets forwarded to the container on 172.17.0.2:51672, there's nothing listening there and the connection attempt fails.
The fix:
The problem is with the listen endpoint:
endpoint := "localhost:51672"
To fix your problem, change it to
endpoint := ":51672"
That'll make your server listen on all it container's IP addresses.
Additional info:
When you expose ports in a Docker container, Docker will create iptables rules to do the actual forwarding. See this. You can view these rules
with:
iptables -n -L
iptables -t nat -n -L
If you use docker container to run grpc service,you should make sure grpc service and grpc client on ths same bridge
if you are using docker container, u can define network by IP and give this IP to your IP address(like: 178.20.0.5).

Resources