I'am currently developing a small app with Golang on macOS and it works perfectly locally.
I have made a docker image from a Dockerfile made from scratch.
My issue is that when container is being launched it hangs indefinitely, docker does not bind ports but I can still go inside the container.
Here are the running processes inside the container:
/go/src/app # ps
PID USER TIME COMMAND
1 root 0:00 ./main
13 root 0:00 sh
23 root 0:00 ps
Here is my docker-compose:
version: "3.3"
services:
dns:
build:
context: .
ports:
- "53:53"
Here is my Dokerfile
FROM golang:alpine
RUN apk add git
WORKDIR /go/src/app
COPY . .
RUN go get -d -v
RUN go build main.go
RUN chmod +x main
EXPOSE 53/udp
EXPOSE 53/tcp
CMD ["./main"]
Logs from docker trying to launch the container:
Building dns
Step 1/10 : FROM golang:alpine
---> 813e7bfc1890
Step 2/10 : RUN apk add git
---> Using cache
---> b796ecde3d09
Step 3/10 : WORKDIR /go/src/app
---> Using cache
---> cf5226146d6c
Step 4/10 : COPY . .
---> e5fd26e9ade8
Step 5/10 : RUN go get -d -v
---> Running in ac4c1fe7dd41
github.com/gojektech/heimdall (download)
github.com/gojektech/valkyrie (download)
github.com/pkg/errors (download)
github.com/stretchr/testify (download)
github.com/davecgh/go-spew (download)
github.com/pmezard/go-difflib (download)
github.com/stretchr/objx (download)
get "gopkg.in/yaml.v3": found meta tag get.metaImport{Prefix:"gopkg.in/yaml.v3", VCS:"git", RepoRoot:"https://gopkg.in/yaml.v3"} at //gopkg.in/yaml.v3?go-get=1
gopkg.in/yaml.v3 (download)
github.com/miekg/dns (download)
get "golang.org/x/crypto/ed25519": found meta tag get.metaImport{Prefix:"golang.org/x/crypto", VCS:"git", RepoRoot:"https://go.googlesource.com/crypto"} at //golang.org/x/crypto/ed25519?go-get=1
get "golang.org/x/crypto/ed25519": verifying non-authoritative meta tag
golang.org/x/crypto (download)
get "golang.org/x/net/ipv4": found meta tag get.metaImport{Prefix:"golang.org/x/net", VCS:"git", RepoRoot:"https://go.googlesource.com/net"} at //golang.org/x/net/ipv4?go-get=1
get "golang.org/x/net/ipv4": verifying non-authoritative meta tag
golang.org/x/net (download)
get "golang.org/x/sys/unix": found meta tag get.metaImport{Prefix:"golang.org/x/sys", VCS:"git", RepoRoot:"https://go.googlesource.com/sys"} at //golang.org/x/sys/unix?go-get=1
get "golang.org/x/sys/unix": verifying non-authoritative meta tag
golang.org/x/sys (download)
get "golang.org/x/net/ipv6": found meta tag get.metaImport{Prefix:"golang.org/x/net", VCS:"git", RepoRoot:"https://go.googlesource.com/net"} at //golang.org/x/net/ipv6?go-get=1
get "golang.org/x/net/ipv6": verifying non-authoritative meta tag
Removing intermediate container ac4c1fe7dd41
---> b9d7f7dfbd1a
Step 6/10 : RUN CGO_ENABLED=0 go build main.go
---> Running in f1e34c2b4ff5
Removing intermediate container f1e34c2b4ff5
---> 948947d5834f
Step 7/10 : RUN chmod +x main
---> Running in f747d80c1784
Removing intermediate container f747d80c1784
---> 48d77cb64ede
Step 8/10 : EXPOSE 53/udp
---> Running in 154f55021335
Removing intermediate container 154f55021335
---> 43fec258b5b7
Step 9/10 : EXPOSE 53/tcp
---> Running in 793767d87201
Removing intermediate container 793767d87201
---> 5304e6d90c07
Step 10/10 : CMD ["./main"]
---> Running in 0d6644f390d2
Removing intermediate container 0d6644f390d2
---> 7fc32c2c2e27
Successfully built 7fc32c2c2e27
Successfully tagged lighthouse_dns:latest
Recreating lighthouse_dns_1 ... done
Attaching to lighthouse_dns_1
It hangs at "Attaching to lighthouse_dns_1" for an eternity.
and if I manually launch the executable from the container by doing this:
docker exec -it <container id> /bin/sh
/go/src/app# ./main
Here is the project structure:
.
└── project
├── main.go
└── vendor
└── services
├── dns.go
└── request.go
Here is the code:
main.go (root folder)
package main
import (
"flag"
"fmt"
"services"
)
func main() {
dnsPort := flag.Int("Port", 53, "Exposed running port")
flag.Parse()
fmt.Print("Starting server")
dnsService := services.Service{
Port: *dnsPort,
AccessKey: "hot-dog",
}
dnsService.Launch()
}
dns.go (vendor/services folder)
package services
import (
"log"
"net"
"strconv"
"github.com/miekg/dns"
)
type u struct {
AccessKey string
}
// ServeDNS ...
func (service *u) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
sdk := InternalSDK{}
msg := dns.Msg{}
msg.SetReply(r)
switch r.Question[0].Qtype {
case dns.TypeA:
msg.Authoritative = true
domain := msg.Question[0].Name
records, getDomainsError := sdk.GetDomainRecordsByType(domain, dns.TypeA)
if getDomainsError == nil {
for _, record := range records {
msg.Answer = append(msg.Answer, &dns.A{
Hdr: dns.RR_Header{Name: domain, Rrtype: record.Type, Class: record.Class, Ttl: record.TTL},
A: net.ParseIP(record.Data),
})
}
} else {
// todo: log error
}
}
w.WriteMsg(&msg)
}
type Service struct {
Port int
AccessKey string
}
// LaunchDNSService ...
func (service *Service) Launch() {
// make a new response chan
srv := &dns.Server{Addr: ":" + strconv.Itoa(service.Port), Net: "udp"}
srv.Handler = &u{}
if err := srv.ListenAndServe(); err != nil {
log.Fatalf("Failed to set udp listener %s\n", err.Error())
}
}
request.go (vendor/services folder)
package services
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
"github.com/gojektech/heimdall/httpclient"
)
type InternalSDK struct {
Timeout uint
Host string
Port uint32
AccessKey string
}
type DomainRecord struct {
Domain string `json:"domain"`
Type uint16 `json:"type"`
Class uint16 `json:"class"`
TTL uint32 `json:"ttl"`
Data string `json:"data"`
}
// New ...
// GetDomainInformations ...
func (call *InternalSDK) GetDomainRecordsByType(domain string, entryType uint16) ([]DomainRecord, error) {
// Use the clients GET method to create and execute the request
url := fmt.Sprintf("http://localhost:3000/dns/domain/%s/type/%d", strings.TrimSuffix(domain, "."), entryType)
timeout := 1000 * time.Millisecond
client := httpclient.NewClient(httpclient.WithHTTPTimeout(timeout))
// Use the clients GET method to create and execute the request
headers := http.Header{}
headers.Add("hug", "hh")
res, err := client.Get(url, headers)
if err != nil {
return nil, err
}
// Heimdall returns the standard *http.Response object
body, err := ioutil.ReadAll(res.Body)
var domainRecord []DomainRecord
json.Unmarshal([]byte(string(body)), &domainRecord)
return domainRecord, nil
}
It works and as soon as I quit the container it kills the executable execution (normal behaviour)
Do you guys have any idea why ?