Dockerfile : 没有这样的文件或目录

时间:2021-06-23 13:59:04

标签: docker go dockerfile

我做了一个 Dockerfile 来将我的开发投入生产。 但是,当我运行 docker 时出现以下错误:

<块引用>

http: panic services 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 file here   
┃   ┣ Makefile  
┃   ┣ main.go  
┃   ┣ routes.go  
┃   ┣ routes_public.go  
┃   ┗ server.go  
┣ database/  
┣ .gitignore  
┣ Dockerfile  
┣ README.md  
┣ go.mod  
┗ go.sum 

2 个答案:

答案 0 :(得分:1)

您需要将静态和视图目录添加到最终图像中,为此在 USER appuser 之前添加以下 2 行:

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

答案 1 :(得分:1)

正如其他人指出的那样,HTML 文件不会被复制到最终图像中。您可以添加此复制命令并完成,但是您仍然在管理可执行文件和潜在的许多其他文件,甚至是多个文件的多个目录!有更好的方法。

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

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

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

然后,当您确实需要使用文件时,您可以按名称查找:

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

这将以字节的形式为您提供该文件的内容。然后,您可以在响应中将此文件作为字节发送。

嵌入不仅为您提供真正的单文件程序体验,而且由于文件的内容在内存中,而不是每次发送文件时都必须将文件读入内存,因此它的性能也更高。

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