mirror of
https://github.com/karust/openserp.git
synced 2026-08-05 08:50:23 +08:00
feat: refactor docker setup, use chromedp/headless
This commit is contained in:
14
.dockerignore
Normal file
14
.dockerignore
Normal file
@@ -0,0 +1,14 @@
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
.release/
|
||||
docs/*.md
|
||||
*.md
|
||||
testdata/
|
||||
|
||||
openserp
|
||||
openserp.exe
|
||||
bin/
|
||||
dist/
|
||||
*.tgz
|
||||
*.tar
|
||||
41
Dockerfile
41
Dockerfile
@@ -1,28 +1,41 @@
|
||||
# Build
|
||||
FROM golang:alpine as builder
|
||||
|
||||
LABEL stage=gobuilder
|
||||
RUN apk update --no-cache && apk add --no-cache tzdata
|
||||
FROM --platform=$BUILDPLATFORM golang:1.24.6-bookworm@sha256:ab1d1823abb55a9504d2e3e003b75b36dbeb1cbcc4c92593d85a84ee46becc6c AS builder
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
ADD go.mod .
|
||||
ADD go.sum .
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
RUN go build -o /app/openserp .
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH:-amd64} go build -trimpath -ldflags="-s -w" -o /app/openserp .
|
||||
|
||||
|
||||
FROM zenika/alpine-chrome:with-chromedriver
|
||||
# `chromedp/headless-shell:stable` also works here
|
||||
FROM chromedp/headless-shell:stable@sha256:aac539266027f91cf47610da1129dce360d23f45f8f150683cca94223fa2f1e2
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY --from=builder /app/openserp /usr/local/bin/openserp
|
||||
COPY config.yaml ./config.yaml
|
||||
# wget: used by HEALTHCHECK (localhost, no TLS, so ca-certificates not required).
|
||||
# dumb-init: already provided by `docker run --init` / compose `init: true`, so we do NOT add tini here — the PID1 reaper is supplied by the runtime.
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends wget \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& getent passwd chrome >/dev/null 2>&1 || useradd --create-home --uid 1001 --shell /bin/bash chrome \
|
||||
&& chown chrome:chrome /usr/src/app
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:7000/health || exit 1
|
||||
COPY --from=builder /app/openserp /usr/local/bin/openserp
|
||||
COPY --chown=chrome:chrome config.yaml ./config.yaml
|
||||
|
||||
# Rod's launcher.LookPath does not know about /headless-shell/headless-shell.
|
||||
# Viper auto-binds OPENSERP_APP_BROWSER_PATH to app.browser_path, so this pins the binary and avoids Rod's runtime chromium auto-download (which would fail in this non-root, network-restricted image).
|
||||
ENV OPENSERP_APP_BROWSER_PATH=/headless-shell/headless-shell \
|
||||
OPENSERP_SERVER_HOST=0.0.0.0 \
|
||||
OPENSERP_SERVER_PORT=7000
|
||||
|
||||
USER chrome
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
||||
CMD wget --quiet --tries=1 --spider "http://127.0.0.1:${OPENSERP_SERVER_PORT}/health" || exit 1
|
||||
|
||||
ENTRYPOINT ["openserp"]
|
||||
|
||||
|
||||
59
core/browser_unit_test.go
Normal file
59
core/browser_unit_test.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestResolveBrowserBinaryPathPrefersExplicit(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
bin := filepath.Join(dir, "chromium")
|
||||
if err := os.WriteFile(bin, []byte("test"), 0o755); err != nil {
|
||||
t.Fatalf("write temp browser binary: %v", err)
|
||||
}
|
||||
|
||||
path, err := resolveBrowserBinaryPath(bin, func() (string, bool) {
|
||||
return "/should/not/be/used", true
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("resolve browser path: %v", err)
|
||||
}
|
||||
if path != bin {
|
||||
t.Fatalf("expected explicit browser path %q, got %q", bin, path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveBrowserBinaryPathFallsBackToLookPath(t *testing.T) {
|
||||
want := "/usr/bin/chromium"
|
||||
path, err := resolveBrowserBinaryPath("", func() (string, bool) {
|
||||
return want, true
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("resolve browser path: %v", err)
|
||||
}
|
||||
if path != want {
|
||||
t.Fatalf("expected lookPath result %q, got %q", want, path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveBrowserBinaryPathReturnsEmptyWhenNothingResolved(t *testing.T) {
|
||||
path, err := resolveBrowserBinaryPath("", func() (string, bool) {
|
||||
return "", false
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("resolve browser path: %v", err)
|
||||
}
|
||||
if path != "" {
|
||||
t.Fatalf("expected empty path, got %q", path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveBrowserBinaryPathRejectsInvalidExplicit(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
if _, err := resolveBrowserBinaryPath(dir, func() (string, bool) {
|
||||
return "", false
|
||||
}); err == nil {
|
||||
t.Fatalf("expected error when explicit browser_path points to a directory")
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,9 @@ version: '3'
|
||||
services:
|
||||
openserp:
|
||||
container_name: serp
|
||||
init: true
|
||||
# Chrome crashes with "Out of memory" on page loads when /dev/shm is the default 64MB. Prefer an enlarged shm over `ipc:host` to keep the container isolated from the host IPC namespace.
|
||||
shm_size: 2gb
|
||||
build:
|
||||
context: .
|
||||
ports:
|
||||
|
||||
Reference in New Issue
Block a user