'Can't connect to Go Server in Docker container

I am trying to run a an HTTP Server written in Golang inside of a docker container and I keep getting connection refused. Everything is being run inside of an Ubuntu 20.04 Server VM running on my Windows 10 machine.

The Go server code:

package main

import "github.com/lkelly93/scheduler/internal/server"

func main() {
    server := server.NewHTTPServer()
    server.Start(3000)
}
package server

import (
    "context"
    "fmt"
    "net/http"
)

type HTTPServer interface {
    Start(port int) error

    Stop() error
}

func NewHTTPServer() HTTPServer {
    return &httpServer{}
}

type httpServer struct {
    server *http.Server
}

func (server *httpServer) Start(port int) error {
    serveMux := newServeMux()
    server.server = &http.Server {
        Addr: fmt.Sprintf(":%d", port),
        Handler: serveMux,
    }
    return server.server.ListenAndServe()
}

func (server *httpServer) Stop() error {
    return server.server.Shutdown(context.Background())
}

My Dockerfile:

FROM ubuntu:20.04

RUN apt-get update -y

#Install needed packages
RUN apt-get install software-properties-common -y
RUN apt-get install python3 -y
RUN apt-get update -y 
RUN apt-get install python3-pip -y
RUN apt-get install default-jre -y

#Install language dependacies
    #Python
    RUN pip3 install numpy

#Reduce VM size
# RUN rm -rf /var/lib/apt/lists/*

#Setup working DIRs
RUN mkdir secure
RUN mkdir secure/runner_files

COPY scheduler /secure
WORKDIR /secure

EXPOSE 3000

CMD ["./scheduler"] <-- The go server is compiled into a binary called scheduler

I build the given Dockerfile and then run:

docker run -d --name scheduler -p 3000:3000 scheduler:latest

Then I grab the container's address with:

docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' scheduler
->172.17.0.2

Finally I use cURL to send an http request:

curl http://172.17.0.2:3000/execute/python --data '{"Code":"print(\"Hello\")"}'

I am getting

curl: (7) Failed to connect to 172.17.0.2 port 3000: Connection refused

but should be getting

{"Stdout":"Hello\n"}%

If I run the Go server on the Ubuntu VM I have no issues calling it from my Win10 machine but I can't seem to call the Go server when it exists inside of a docker container from the Ubuntu machine.

The Go code is more complicated then just that but it's too much to post everything here, feel free to look at the whole repo at https://github.com/lkelly93/scheduler.

Eventually it will be the backend to a website I want to make that runs code. Something like LeetCode or Repl.it.

Thanks!

Edit:

docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
2a56a973040f        scheduler:latest    "./scheduler"       37 seconds ago      Up 36 seconds       0.0.0.0:3000->3000/tcp   scheduler

docker container logs 2a56a973040f gave no output.

Edit 2:

docker run -it --net container:2a56a973040f nicolaka/netshoot ss -lnt
State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0      4096               *:3000            *:*

Edit 3:

After reading through the man pages I found that if I had the tag --network=host to my image and then run.

curl http://localhost:3000/execute/python --data '{"Code":"print(\"Hello\")"}'

I get the correct output. While this works, I would like to have multiple docker images running side by side. So I would prefer to use IP address to address them all. So I don't think this is a permanent fix.



Solution 1:[1]

After doing more googling I followed this guide and created my own "user-defined bridge network".

If I launch my container and attach it to this network then it works! I would love it if someone could explain why though!

Solution 2:[2]

You've published the port, which forwards the port from the docker host to the container. Therefore you want to connect to http://localhost:3000. Connecting to container IP may fail with desktop installs since docker runs inside of a VM and those private IP's are only visible in the VM.

If you happen to be running docker-machine (this is the case with older docker toolbox installs), then you'll need to get the IP of the VM. Run echo $DOCKER_HOST to see the IP address and adjust the port to port 3000.

Solution 3:[3]

To fix this on my server I set the IP address to 0.0.0.0:4000. I'm using gin so the example would look lik:

r := gin.Default()
r.run("0.0.0.0:4000")

After this I was finally able to access it through my browser.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Luke Kelly
Solution 2 BMitch
Solution 3 Tj Gienger