猿问

如何在 Docker 中部署包含静态文件的 Web 应用?

我构建了一个带有回声的Web应用程序。一些来源是server.go


package main


import ...


type TemplateRenderer struct {

    templates *template.Template

}


func (t *TemplateRenderer) Render(w io.Writer, name string, data interface{}, c echo.Context) error {

    if viewContext, isMap := data.(map[string]interface{}); isMap {

        viewContext["reverse"] = c.Echo().Reverse

    }


    return t.templates.ExecuteTemplate(w, name, data)

}


func main() {

    e := echo.New()

    e.Static("/static", "static")


    renderer := &TemplateRenderer{

        templates: template.Must(template.ParseGlob("public/views/*.html")),

    }

    e.Renderer = renderer


    e.GET("/", func(c echo.Context) error {

        return c.Render(http.StatusOK, "index.html", map[string]interface{}{})

    })


    e.Logger.Fatal(e.Start(":8080"))

}

项目树


├── helper

│   └── string.go

└─── site

    ├── Dockerfile

    ├── go.mod

    ├── go.sum

    ├── server.go

    ├── public

    │   └── views

    │       └── index.html

    └── static

我可以运行启动服务器,一切正常。但是如果用docker运行它,就会出错。go run server.go


Dockerfile


FROM golang:1.15.2-alpine3.12 AS builder

WORKDIR /app

COPY . .

WORKDIR /app/site

RUN CGO_ENABLED=0 GOOS=linux go build -o server


FROM alpine:3.12

COPY --from=builder /app/site /bin/.

ENTRYPOINT [ "server" ]

通过以下方式构建了一个 docker 映像


docker build -t gcr.io/${PROJECT_ID}/myapp -f site/Dockerfile .

在泊坞窗中运行应用


docker run --rm -p 8080:8080 gcr.io/${PROJECT_ID}/myapp

panic: html/template: pattern matches no files: `public/views/*.html`


goroutine 1 [running]:

html/template.Must(...)

    /usr/local/go/src/html/template/template.go:372

main.main()

    /app/site/server.go:76 +0x2af

该文件夹似乎未复制到映像中。但是在构建映像时没有任何错误。怎么了?public


海绵宝宝撒
浏览 157回答 2
2回答

心有法竹

首先,您使用的是多阶段 Docker 构建,它非常适合仅将编译的二进制文件复制到最终映像。但是,在 Dockerfile 中,您将复制整个构建目录 - 二进制文件以及所有源代码。server其次,您的主要问题是当图像作为容器运行时,默认工作目录是 - 因此服务器中的任何路径都找不到中的html文件。//bin/public如果你需要调试一个 docker 镜像 - 特别是如果它是一个基于 linux 发行版(如 alpine)的镜像 - 只需:docker run -it myimage /bin/sh无论如何,对您的docker的2个简单修复:FROM golang:1.15.2-alpine3.12 AS builderWORKDIR /appCOPY . .WORKDIR /app/siteRUN CGO_ENABLED=0 GOOS=linux go build -o serverFROM alpine:3.12COPY --from=builder /app/site/server /binCOPY --from=builder /app/site/public /publicENTRYPOINT [ "/bin/server" ]

慕沐林林

在Go 1.16中,您可以将这些文件编译成二进制文件本身。因此,您需要升级主机系统上的 Go 工具链,以及 Dockerfile 中构建阶段的行。Go 1.16 添加了嵌入包和一个新指令来支持这一点。FROM//go:embed首先,您需要告诉编译器嵌入模板文件,构建一个文件系统对象:import "embed"// templateFiles contains the raw text of the template files.//go:embed public/views/*.htmlvar templateFiles embed.FS然后,当你去使用它时,Go 1.16还会添加一个相应的(“html/template”)。解析FS函数:renderer := &TemplateRenderer{    templates: template.Must(template.ParseFS(templateFiles)),}现在所有文件都嵌入在二进制文件本身中,您不应该收到“找不到文件”类型错误。您可以考虑仅将已编译的二进制文件复制到最终映像中,而不将任何其他内容复制到最终映像中。# Upgrade to Go 1.16FROM golang:1.16-alpine3.12 AS builder# Unchanged from originalWORKDIR /appCOPY . .WORKDIR /app/siteRUN CGO_ENABLED=0 GOOS=linux go build -o serverFROM alpine:3.12# Only copy the compiled binary and not the source treeCOPY --from=builder /app/site/server /bin# Generally prefer CMD to ENTRYPOINTCMD [ "server" ]
随时随地看视频慕课网APP

相关分类

Go
我要回答