Dockerfile:没有这个文件或目录。

huangapple go评论87阅读模式
英文:

Dockerfile : no such file or directory

问题

我做了一个Dockerfile来将我的开发环境部署到生产环境中。
然而,当我运行我的Docker时,出现了以下错误:

> http: panic serving xxx.xxx.xxx.xxx:xxxxx: open views/public/index.html: no such file or directory

我的错误在于Dockerfile中,但我不知道具体在哪里。。

我的Dockerfile:

FROM golang:alpine as builder
RUN apk update && apk add --no-cache git ca-certificates gcc g++ make && update-ca-certificates   
RUN adduser -D -g '' appuser   
WORKDIR /usr/src/app   
COPY . .   
RUN go mod download   
RUN go mod verify   
WORKDIR /usr/src/app/cmd/web   
RUN make docker    
FROM scratch   
WORKDIR /   
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/   
COPY --from=builder /etc/passwd /etc/passwd   
COPY --from=builder /usr/src/app/cmd/web/web /web   
USER appuser   
ENTRYPOINT ["./web"]   
CMD [":9000"] 

我的程序中路由"/"的示例:

func (s *server) handleIndex() http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        auth, _ := strconv.ParseBool(s.GetSessionValue(w, r, "authenticated"))
        files := []string{
            "views/public/index.html",
            "views/public/nav.html",
        }
        templates := template.Must(template.ParseFiles(files...))
        if err := templates.ExecuteTemplate(w, "index", authData{Authenticated: auth, NotAuthenticated: !auth}); err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
        }
    }
}

文件树:

ants-map/

┣ auth/  
┣ cmd/  
┃ ┗ web/  
┃   ┣ static/  
┃   ┣ views/ 这里是.html文件   
┃   ┣ Makefile  
┃   ┣ main.go  
┃   ┣ routes.go  
┃   ┣ routes_public.go  
┃   ┗ server.go  
┣ database/  
┣ .gitignore  
┣ Dockerfile  
┣ README.md  
┣ go.mod  
┗ go.sum
英文:

I do a Dockerfile to put my development in production.
However when I run my docker I have this following error :

> http: panic serving xxx.xxx.xxx.xxx:xxxxx: open views/public/index.html: no such file or directory

My mistake is in my Dockerfile but I don't see where..

My Dockerfile :

FROM golang:alpine as builder
RUN apk update && apk add --no-cache git ca-certificates gcc g++ make && update-ca-certificates   
RUN adduser -D -g '' appuser   
WORKDIR /usr/src/app   
COPY . .   
RUN go mod download   
RUN go mod verify   
WORKDIR /usr/src/app/cmd/web   
RUN make docker    
FROM scratch   
WORKDIR /   
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/   
COPY --from=builder /etc/passwd /etc/passwd   
COPY --from=builder /usr/src/app/cmd/web/web /web   
USER appuser   
ENTRYPOINT ["./web"]   
CMD [":9000"] 

Example for routes "/" in my program :

func (s *server) handleIndex() http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        auth, _ := strconv.ParseBool(s.GetSessionValue(w, r, "authenticated"))
        files := []string{
            "views/public/index.html",
            "views/public/nav.html",
        }
        templates := template.Must(template.ParseFiles(files...))
        if err := templates.ExecuteTemplate(w, "index", authData{Authenticated: auth, NotAuthenticated: !auth}); err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
        }
    }
}

File Tree :

ants-map/

┣ auth/  
┣ cmd/  
┃ ┗ web/  
┃   ┣ static/  
┃   ┣ views/ .html file here   
┃   ┣ Makefile  
┃   ┣ main.go  
┃   ┣ routes.go  
┃   ┣ routes_public.go  
┃   ┗ server.go  
┣ database/  
┣ .gitignore  
┣ Dockerfile  
┣ README.md  
┣ go.mod  
┗ go.sum 

答案1

得分: 1

你需要将静态文件和视图目录添加到最终的镜像中,在USER appuser之前添加以下两行代码:

COPY --from=builder /usr/src/app/cmd/web/views /web/views
COPY --from=builder /usr/src/app/cmd/web/static /web/static
英文:

You need to add the static and views directory to your final image, for that add the following 2 line before USER appuser:

COPY --from=builder /usr/src/app/cmd/web/views /web/views
COPY --from-builder /usr/src/app/cmd/web/static /web/static

答案2

得分: 1

正如其他人指出的那样,HTML文件没有被复制到最终的镜像中。你可以添加这个复制命令就可以了,但是这样你仍然需要管理可执行文件和可能的许多其他文件,甚至是几个目录的多个文件!有一种更好的方法。

当构建一个Go可执行文件时,只包括实际的Go代码本身及其依赖项。其他静态文件,如HTML文件,不会包含在Go二进制文件中。然而,从Go 1.16开始,现在有了一个解决方案,即Go Embed

处理静态文件的现代方法是将它们嵌入到Go程序中。例如,如果你在与另一个HTML文件目录相同的目录中有一个Go文件,那么你可以像这样嵌入整个HTML目录:

//go:embed html/*
var htmlFS embed.FS

然后,当你实际需要使用一个文件时,你可以通过名称查找它:

htmlBytes, err := htmlFS.ReadFile("html/index.html")

这将以字节形式给你该文件的内容。然后,你可以将这个文件作为字节发送到你的响应中。

嵌入不仅给你带来了真正的单文件程序的体验,而且由于文件的内容在内存中,相对于每次发送时都需要读取文件到内存中,它还具有更好的性能。

更新:在上面的示例中,你可以使用template.ParseFS而不是template.ParseFiles,并将embed.FS对象作为额外的第一个参数传递进去。请不要在每个API调用时直接从操作系统中读取所有模板文件。

英文:

As others have pointed out, the HTML files are not being copied over to the final image. You could just add this copy command and be done but then you are still managing the executable and potentially lots of other files or even several directories of several files! There is a better way.

When building a Go executable only the actual Go code itself and its dependencies are included. Other static files such as HTML are not included in a Go binary. However, as of Go 1.16, there is now a solution for this, which is Go Embed.

The modern way to handle static files is to embed them into your Go program. For example, if you have a Go file in the same directory as another directory of HTML files, then you could embed the whole HTML directory like this:

//go:embed html/*
var htmlFS embed.FS

Then, when you actually need to use a file you can look it up by name:

htmlBytes, err := htmlFS.ReadFile("html/index.html")

This will give you the contents of that file as bytes. Then, you can just send this file as bytes in your response.

Embedding not only gives you that experience of a true one-file program but it is also more performant since the file's contents are in memory versus having to read the file into memory each time you want to send it.

UPDATE: In the OP's example above, instead of template.ParseFiles, with a file system you can use template.ParseFS and pass the embed.FS object in there as the extra first argument. Please don't read all your template files directly from the OS on every API call.

huangapple
  • 本文由 发表于 2021年6月23日 21:59:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/68101331.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定