【发布时间】:2021-02-03 15:14:12
【问题描述】:
我目前正在 macOS 上使用 Golang 开发一个小应用程序,它可以在本地完美运行。
我从一个从头开始制作的 Dockerfile 制作了一个 docker 镜像。
我的问题是,当容器启动时它会无限期挂起,docker 没有绑定端口,但我仍然可以进入容器。
以下是容器内正在运行的进程:
/go/src/app # ps
PID USER TIME COMMAND
1 root 0:00 ./main
13 root 0:00 sh
23 root 0:00 ps
这是我的 docker-compose:
version: "3.3"
services:
dns:
build:
context: .
ports:
- "53:53"
这是我的 Dockerfile
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"]
来自 docker 尝试启动容器的日志:
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
它永远挂在“附加到 lighthouse_dns_1”处。
如果我通过这样做从容器中手动启动可执行文件:
docker exec -it <container id> /bin/sh
/go/src/app# ./main
这是项目结构:
.
└── project
├── main.go
└── vendor
└── services
├── dns.go
└── request.go
代码如下:
main.go(根文件夹)
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(供应商/服务文件夹)
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(供应商/服务文件夹)
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
}
它可以工作,一旦我退出容器,它就会终止可执行文件的执行(正常行为)
你们知道为什么吗?
【问题讨论】:
-
分享你的 dockerfile
-
请edit您的问题包含所需的信息(例如minimal reproducible example)。此外,将文本图像替换为实际文本。作为这里的新用户,也请带上tour并阅读How to Ask。
-
@UlrichEckhardt,感谢您的回复,我已经完善了帖子。我希望它足够理解。
-
Stdout 说
CMD ["./launch.sh"]你的 dockerfile 说CMD ["./main"]... 这是怎么回事?看起来那不是实际的 dockerfile,或者不是实际的输出,无论哪种方式我们都无法调试我们看不到的东西。 -
@mkopriva 是的,抱歉,我尝试使用 ./main 和 shell 脚本来检查它是否有任何区别,已更正
标签: docker go containers alpine