gpt4 book ai didi

docker - 为什么执行 Golang 可执行文件的 docker 容器在启动后立即挂起?

转载 作者:行者123 更新时间:2023-12-02 21:31:04 26 4
gpt4 key购买 nike

关闭。这个问题需要debugging details .它目前不接受答案。












想改进这个问题?将问题更新为 on-topic对于堆栈溢出。

1年前关闭。




Improve this question




我目前正在 macOS 上使用 Golang 开发一个小应用程序,它可以在本地完美运行。
我从一个从头开始制作的 Dockerfile 制作了一个 docker 镜像。
我的问题是,当容器启动时,它会无限期挂起,docker 不会绑定(bind)端口,但我仍然可以进入容器内部。
以下是容器内正在运行的进程:

/go/src/app # ps
PID USER TIME COMMAND
1 root 0:00 ./main
13 root 0:00 sh
23 root 0:00 ps
这是我的 docker 撰写:
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( vendor/服务文件夹)
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/服务文件夹)
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
}
它可以工作,一旦我退出容器,它就会终止可执行文件的执行(正常行为)
你们知道为什么吗?

最佳答案

我在自己的环境中部署了它,服务器已启动并监听端口 53:

Removing intermediate container 9ca44a8e9e1c
---> 50ac6085b9d6
Step 10/10 : CMD ["./main"]
---> Running in f031cb3bb632
Removing intermediate container f031cb3bb632
---> 61f8a889d84d

Successfully built 61f8a889d84d
Successfully tagged test-64451146:latest
Recreating 64451146_dns_1 ... done

$ docker run -it --rm --net container:64451146_dns_1 nicolaka/netshoot bash
bash-5.0# ss -lnu
State Recv-Q Send-Q Local Address:Port Peer Address:Port
UNCONN 0 0 127.0.0.11:45648 0.0.0.0:*
UNCONN 0 0 *:53 *:*
我可以用 nslookup 打它,然后挖掘并接收响应。我怀疑你的问题是因为你没有看到 Starting server 消息,为此你只需要添加一个换行符。否则,该缓冲区仅在容器停止时刷新:
fmt.Print("Starting server\n")
您将看到的另一个可能的错误是对 localhost 的网络请求:
url := fmt.Sprintf("http://localhost:3000/dns/domain/%s/type/%d", strings.TrimSuffix(domain, "."), entryType)
在容器内部,localhost 是容器,而不是运行容器的主机。网络在 docker 中命名空间,类似于文件系统和 pid 的命名空间。这就是为什么我使用上面的 --net container: 语法来运行具有相同命名空间的第二个容器并查看监听端口。因此,您需要将 URL 更改为可以从容器内部访问的内容,如果这取决于您运行它的位置,那么我经常将其作为变量(CLI arg 或环境变量)从容器外部注入(inject),而不是硬编码到程序中。

关于docker - 为什么执行 Golang 可执行文件的 docker 容器在启动后立即挂起?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64451146/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com