Golang+chromedp Docker部署报错:google-chrome不在$PATH中
问题与解决方案
问题描述
使用chromedp连接Chrome的Golang代码,搭配包含Chrome安装步骤的Dockerfile构建镜像成功,但运行镜像时出现exec: "google-chrome": executable file not found in $PATH错误。
相关代码
Golang代码
package main import ( "context" "fmt" "log" "os" "time" "github.com/chromedp/chromedp" "github.com/gin-gonic/gin" ) func main() { Api := gin.Default() Api.GET("api/jwt", func(c *gin.Context) { opts := append(chromedp.DefaultExecAllocatorOptions[:], chromedp.Flag("headless", false), chromedp.Flag("disable-gpu", true), chromedp.Flag("no-sandbox", true), chromedp.Flag("disable-dev-shm-usage", true), chromedp.Flag("disable-browser-side-navigation", true), chromedp.Flag("disable-infobars", true), chromedp.Flag("disable-extensions", true), chromedp.Flag("disable-notifications", true), chromedp.Flag("disable-default-apps", true), chromedp.Flag("disable-background-timer-throttling", true), chromedp.Flag("disable-backgrounding-occluded-windows", true), chromedp.Flag("disable-renderer-backgrounding", true), ) allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...) defer cancel() ctx, cancel := chromedp.NewContext(allocCtx) defer cancel() var localStorageData string // Declaração da variável localStorageData err := chromedp.Run(ctx, chromedp.Navigate("https://csonlinetenant.b2clogin.com/csonlinetenant.onmicrosoft.com/oauth2/v2.0/authorize"), chromedp.Sleep(5*time.Second), chromedp.WaitVisible(`#fgh`), chromedp.SendKeys(`#fghfg`, "fghfgh"), chromedp.SendKeys(`#xcvxcv`, "xcxcvcxv"), chromedp.Click(`#thgh`, chromedp.ByID), chromedp.Sleep(5*time.Second), chromedp.Click(`dfgd`, chromedp.ByID), chromedp.Sleep(15*time.Second), chromedp.EvaluateAsDevTools(`localStorage.getItem('c')`, &localStorageData), ) if err != nil { log.Printf("Error: %v", err) return } fmt.Println("Bearer", localStorageData) // Restante do código... c.JSON(200, gin.H{ "Success": localStorageData, }) }) listenAddr := os.Getenv("LISTEN") if val, ok := os.LookupEnv("FUNCTIONS_CUSTOMHANDLER_PORT"); ok { listenAddr = ":" + val } if listenAddr == "" { listenAddr = ":8080" } Api.Run(listenAddr) }
Dockerfile
FROM golang:1.20 AS build-stage WORKDIR /app # Instale as dependências do Chrome RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ && echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list RUN apt-get update && apt-get -y install google-chrome-stable RUN chrome & COPY go.mod go.sum ./ RUN go mod download COPY *.go ./ RUN CGO_ENABLED=0 GOOS=linux go build -o /dockergo # Run the tests in the container FROM build-stage AS run-test-stage RUN go test -v ./... # Deploy the application binary into a lean image FROM gcr.io/distroless/base-debian11 AS build-release-stage WORKDIR / COPY --from=build-stage /dockergo /dockergo EXPOSE 8080 USER nonroot:nonroot ENTRYPOINT ["/dockergo"]
错误信息
Error: exec: "google-chrome": executable file not found in $PATH
错误含义与解决方法
错误含义
该错误表示chromedp尝试调用google-chrome可执行文件,但当前运行的容器系统中,$PATH环境变量下找不到这个程序。不是Chrome未运行,是Chrome根本没有安装在最终运行的镜像里。
原因分析
- Docker采用多阶段构建,最终运行的
gcr.io/distroless/base-debian11是极简镜像,仅包含最基础的系统组件,没有复制build-stage阶段安装的Google Chrome及相关依赖。 - build-stage中的
RUN chrome &完全无效:构建阶段启动的进程在构建完成后会立即终止,且该命令本身可能因缺少终端环境导致构建警告或失败。
解决方法
方案一:改用包含Chrome的基础镜像(推荐,操作简单)
放弃distroless极简镜像,直接使用已安装Chrome的build-stage镜像作为最终运行环境,修改Dockerfile的build-release-stage部分:
FROM golang:1.20 AS build-stage WORKDIR /app # 安装Chrome依赖 RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ && echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list RUN apt-get update && apt-get -y install google-chrome-stable COPY go.mod go.sum ./ RUN go mod download COPY *.go ./ RUN CGO_ENABLED=0 GOOS=linux go build -o /dockergo # 测试阶段 FROM build-stage AS run-test-stage RUN go test -v ./... # 最终运行镜像,复用已安装Chrome的build-stage环境 FROM build-stage AS build-release-stage WORKDIR / COPY --from=build-stage /dockergo /dockergo EXPOSE 8080 USER nonroot:nonroot ENTRYPOINT ["/dockergo"]
方案二:将Chrome及依赖复制到distroless镜像(保持镜像精简,操作复杂)
如果坚持使用distroless镜像,需要手动复制Chrome可执行文件和必要的系统依赖库到最终镜像:
FROM golang:1.20 AS build-stage WORKDIR /app RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ && echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list RUN apt-get update && apt-get -y install google-chrome-stable COPY go.mod go.sum ./ RUN go mod download COPY *.go ./ RUN CGO_ENABLED=0 GOOS=linux go build -o /dockergo FROM gcr.io/distroless/base-debian11 AS build-release-stage WORKDIR / # 复制Chrome可执行文件和安装目录 COPY --from=build-stage /usr/bin/google-chrome /usr/bin/google-chrome COPY --from=build-stage /opt/google /opt/google # 复制Chrome运行必需的系统依赖库(根据实际运行情况补充) COPY --from=build-stage /lib/x86_64-linux-gnu/libnss3.so /lib/x86_64-linux-gnu/libnss3.so COPY --from=build-stage /lib/x86_64-linux-gnu/libnssutil3.so /lib/x86_64-linux-gnu/libnssutil3.so COPY --from=build-stage /lib/x86_64-linux-gnu/libsmime3.so /lib/x86_64-linux-gnu/libsmime3.so COPY --from=build-stage /lib/x86_64-linux-gnu/libssl3.so /lib/x86_64-linux-gnu/libssl3.so COPY --from=build-stage /lib/x86_64-linux-gnu/libcrypto.so.1.1 /lib/x86_64-linux-gnu/libcrypto.so.1.1 COPY --from=build-stage /lib/x86_64-linux-gnu/libglib-2.0.so.0 /lib/x86_64-linux-gnu/libglib-2.0.so.0 COPY --from=build-stage /dockergo /dockergo EXPOSE 8080 USER nonroot:nonroot ENTRYPOINT ["/dockergo"]
额外优化建议
容器环境下不适合运行非无头模式的Chrome,建议将Golang代码中的headless参数改为true:
chromedp.Flag("headless", true),
内容的提问来源于stack exchange,提问作者Guilherme Rodrigues
相关产品推荐
相关产品推荐

