dockergodockerfilechromedp

Dockerfile for Go and chromedp


I'm trying to implement a Dockerfile to contain both my go binary and also chromedp. I manage to build the image and I can run the image and the go binary runs as expected, all but chromedp.

Thanks in advance!

Error message i recieve:
Error exec: "google-chrome": executable file not found in $PATH running chromedp

Dockerfile

# syntax=docker/dockerfile:1


##
## Build
##
FROM golang:1.17-bullseye as build

WORKDIR /app
COPY . ./

RUN go mod download

COPY *.go ./

RUN go build -o /docker-scraper

EXPOSE 8080

FROM chromedp/headless-shell:latest

CMD ["/docker-scraper"]

##
## Deploy
##
FROM gcr.io/distroless/base-debian11

WORKDIR /

COPY --from=build /docker-scraper /docker-scraper

EXPOSE 8080

USER nonroot:nonroot

ENTRYPOINT ["/docker-scraper"]

Solution

  • Error exec: "google-chrome": executable file not found in $PATH running chromedp

    This is because you did not run your go program in chromedp/headless-shell. You define multi-stage builds, but with this, only the last stage will be act as the base image of final image.

    This means your go program in fact runs in gcr.io/distroless/base-debian11, not headless-shell.

    To learn how to run your own program in headless-shell, you could refers to its official document:

    When using chromedp/headless-shell as a base image to build an image that runs your own program, You could experience zombie process problem. To reap zombie processeses, use dumb-init or tini on your Dockerfile's ENTRYPOINT

    FROM chromedp/headless-shell:latest
    ...
    # Install dumb-init or tini
    RUN apt install dumb-init
    # or RUN apt install tini
    ...
    ENTRYPOINT ["dumb-init", "--"]
    # or ENTRYPOINT ["tini", "--"]
    CMD ["/path/to/your/program"]
    

    A minimal workable example as next.

    main.go:

    package main
    
    import (
            "context"
            "log"
            "fmt"
            "time"
    
            "github.com/chromedp/chromedp"
    )
    
    func main() {
            ctx, cancel := chromedp.NewContext(
                    context.Background(),
                    chromedp.WithLogf(log.Printf),
            )
            defer cancel()
    
            ctx, cancel = context.WithTimeout(ctx, 15*time.Second)
            defer cancel()
    
            err := chromedp.Run(ctx,
                    chromedp.Navigate(`https://golang.org/pkg/time/`),
            )
            if err != nil {
                fmt.Println(err)
            }
            fmt.Println("done")
    }
    

    Dockerfile:

    FROM golang:latest as build
    
    WORKDIR /go/src/app
    COPY ./main.go .
    RUN go mod init docker-scraper; go mod tidy
    RUN go build
    
    FROM chromedp/headless-shell:latest
    RUN apt-get update; apt install dumb-init -y
    ENTRYPOINT ["dumb-init", "--"]
    COPY --from=build /go/src/app/docker-scraper /tmp
    CMD ["/tmp/docker-scraper"]
    

    docker-compose.yaml:

    version: '3'
    services:
      goservice:
        build: .
    

    Execution:

    $ docker-compose up
    Recreating chromedp-docker_goservice_1 ... done
    Attaching to chromedp-docker_goservice_1
    goservice_1  | done
    chromedp-docker_goservice_1 exited with code 0
    

    You could see no error about google-chrome now.