diff --git a/Dockerfile b/Dockerfile index 31feca2..a2383da 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,13 +4,25 @@ WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . -RUN go build -ldflags="-s -w" -o spotify-ws . +RUN go build -ldflags="-s -w" -o /app/spotify-ws . +RUN go build -ldflags="-s -w" -o /app/healthcheck ./healthcheck FROM gcr.io/distroless/static:nonroot +ARG BUILD_DATE +ARG VCS_REF +LABEL org.opencontainers.image.created=$BUILD_DATE +LABEL org.opencontainers.image.authors="skidoodle" +LABEL org.opencontainers.image.url="https://github.com/skidoodle/spotify-ws" +LABEL org.opencontainers.image.documentation="https://github.com/skidoodle/spotify-ws/blob/main/readme.md" +LABEL org.opencontainers.image.source="https://github.com/skidoodle/spotify-ws" +LABEL org.opencontainers.image.revision=$VCS_REF +LABEL org.opencontainers.image.title="spotify-ws" +LABEL org.opencontainers.image.description="A WebSocket server that relays the current Spotify playing track to connected clients." +LABEL org.opencontainers.image.licenses="AGPL-3.0" WORKDIR /app COPY --from=builder --chown=nonroot:nonroot /app/spotify-ws . - +COPY --from=builder --chown=nonroot:nonroot /app/healthcheck . EXPOSE 3000 -HEALTHCHECK --interval=30s --timeout=5s --start-period=5s CMD ["/spotify-ws", "-health"] +HEALTHCHECK --interval=30s --timeout=5s --start-period=5s CMD ["/app/healthcheck"] USER nonroot:nonroot -CMD ["/spotify-ws"] \ No newline at end of file +CMD ["/app/spotify-ws"] \ No newline at end of file diff --git a/compose.dev.yaml b/compose.dev.yaml new file mode 100644 index 0000000..4c47317 --- /dev/null +++ b/compose.dev.yaml @@ -0,0 +1,11 @@ +services: + spotify-ws: + build: + context: . + dockerfile: Dockerfile + container_name: spotify-ws + restart: unless-stopped + ports: + - "3000:3000" + env_file: + - .env diff --git a/docker-compose.yaml b/compose.yaml similarity index 100% rename from docker-compose.yaml rename to compose.yaml diff --git a/docker-compose.dev.yaml b/docker-compose.dev.yaml deleted file mode 100644 index 49382ed..0000000 --- a/docker-compose.dev.yaml +++ /dev/null @@ -1,17 +0,0 @@ -services: - spotify-ws: - build: - context: . - dockerfile: Dockerfile - container_name: spotify-ws - restart: unless-stopped - ports: - - "3000:3000" - environment: - - REFRESH_TOKEN=${REFRESH_TOKEN} - - CLIENT_SECRET=${CLIENT_SECRET} - - CLIENT_ID=${CLIENT_ID} - #- LOG_LEVEL=DEBUG - #- ALLOWED_ORIGINS=http://localhost:3000 - #- SERVER_PORT=3000 - #- RT=true diff --git a/healthcheck/healthcheck.go b/healthcheck/healthcheck.go new file mode 100644 index 0000000..2438d74 --- /dev/null +++ b/healthcheck/healthcheck.go @@ -0,0 +1,61 @@ +package main + +import ( + "context" + "fmt" + "io" + "net/http" + "os" + "time" +) + +const ( + defaultPort = "3000" + requestTimeout = 5 * time.Second +) + +func main() { + ctx, cancel := context.WithTimeout(context.Background(), requestTimeout) + defer cancel() + + if err := run(ctx); err != nil { + _, _ = fmt.Fprintf(os.Stderr, "health check failed: %v\n", err) + os.Exit(1) + } + + os.Exit(0) +} + +func run(ctx context.Context) error { + port := os.Getenv("SERVER_PORT") + if port == "" { + port = defaultPort + } + + url := fmt.Sprintf("http://localhost:%s/health", port) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return fmt.Errorf("could not create request: %w", err) + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return fmt.Errorf("request to %s failed: %w", url, err) + } + defer func() { + if closeErr := resp.Body.Close(); closeErr != nil { + _, _ = fmt.Fprintf(os.Stderr, "warning: failed to close response body: %v\n", closeErr) + } + }() + + if _, err := io.Copy(io.Discard, resp.Body); err != nil { + return fmt.Errorf("failed to discard response body: %w", err) + } + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("received non-200 status code: %d", resp.StatusCode) + } + + return nil +}