From bbf93430b7b8a34ce870f36f9444cac0b15b324a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Guillot?= Date: Sat, 20 Feb 2021 12:42:15 -0800 Subject: [PATCH] Add more extensive healthcheck support - Add new cli argument: -healthcheck - Add HEALTHCHECK instruction to Dockerfile - Update Docker Compose examples --- cli/cli.go | 8 +++++++ cli/health_check.go | 34 ++++++++++++++++++++++++++++++ contrib/docker-compose/basic.yml | 9 +++++++- contrib/docker-compose/caddy.yml | 7 +++++- contrib/docker-compose/traefik.yml | 7 +++++- miniflux.1 | 9 +++++++- packaging/docker/Dockerfile | 2 +- 7 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 cli/health_check.go diff --git a/cli/cli.go b/cli/cli.go index 5b100eb4..826f0f42 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -28,6 +28,7 @@ const ( flagDebugModeHelp = "Show debug logs" flagConfigFileHelp = "Load configuration file" flagConfigDumpHelp = "Print parsed configuration values" + flagHealthCheckHelp = `Perform a health check on the given endpoint (the value "auto" try to guess the health check endpoint).` ) // Parse parses command line arguments. @@ -44,6 +45,7 @@ func Parse() { flagDebugMode bool flagConfigFile string flagConfigDump bool + flagHealthCheck string ) flag.BoolVar(&flagInfo, "info", false, flagInfoHelp) @@ -59,6 +61,7 @@ func Parse() { flag.StringVar(&flagConfigFile, "config-file", "", flagConfigFileHelp) flag.StringVar(&flagConfigFile, "c", "", flagConfigFileHelp) flag.BoolVar(&flagConfigDump, "config-dump", false, flagConfigDumpHelp) + flag.StringVar(&flagHealthCheck, "healthcheck", "", flagHealthCheckHelp) flag.Parse() cfg := config.NewParser() @@ -88,6 +91,11 @@ func Parse() { logger.EnableDebug() } + if flagHealthCheck != "" { + doHealthCheck(flagHealthCheck) + return + } + if flagInfo { info() return diff --git a/cli/health_check.go b/cli/health_check.go new file mode 100644 index 00000000..8e6a4e85 --- /dev/null +++ b/cli/health_check.go @@ -0,0 +1,34 @@ +// Copyright 2021 Frédéric Guillot. All rights reserved. +// Use of this source code is governed by the Apache 2.0 +// license that can be found in the LICENSE file. + +package cli // import "miniflux.app/cli" + +import ( + "net/http" + "time" + + "miniflux.app/config" + "miniflux.app/logger" +) + +func doHealthCheck(healthCheckEndpoint string) { + if healthCheckEndpoint == "auto" { + healthCheckEndpoint = "http://" + config.Opts.ListenAddr() + config.Opts.BasePath() + "/healthcheck" + } + + logger.Debug(`Executing health check on %s`, healthCheckEndpoint) + + client := &http.Client{Timeout: 3 * time.Second} + resp, err := client.Get(healthCheckEndpoint) + if err != nil { + logger.Fatal(`Health check failure: %v`, err) + } + defer resp.Body.Close() + + if resp.StatusCode != 200 { + logger.Fatal(`Health check failed with status code %d`, resp.StatusCode) + } + + logger.Debug(`Health check is OK`) +} diff --git a/contrib/docker-compose/basic.yml b/contrib/docker-compose/basic.yml index acc8b0af..a90f01e6 100644 --- a/contrib/docker-compose/basic.yml +++ b/contrib/docker-compose/basic.yml @@ -3,16 +3,19 @@ services: miniflux: image: miniflux/miniflux:latest container_name: miniflux + restart: always ports: - "80:8080" depends_on: - - db + db: + condition: service_healthy environment: - DATABASE_URL=postgres://miniflux:secret@db/miniflux?sslmode=disable - RUN_MIGRATIONS=1 - CREATE_ADMIN=1 - ADMIN_USERNAME=admin - ADMIN_PASSWORD=test123 + - DEBUG=1 db: image: postgres:latest container_name: postgres @@ -21,5 +24,9 @@ services: - POSTGRES_PASSWORD=secret volumes: - miniflux-db:/var/lib/postgresql/data + healthcheck: + test: ["CMD", "pg_isready", "-U", "miniflux"] + interval: 10s + start_period: 30s volumes: miniflux-db: \ No newline at end of file diff --git a/contrib/docker-compose/caddy.yml b/contrib/docker-compose/caddy.yml index c9f16596..63c07c08 100644 --- a/contrib/docker-compose/caddy.yml +++ b/contrib/docker-compose/caddy.yml @@ -16,7 +16,8 @@ services: image: miniflux/miniflux:latest container_name: miniflux depends_on: - - db + db: + condition: service_healthy environment: - DATABASE_URL=postgres://miniflux:secret@db/miniflux?sslmode=disable - RUN_MIGRATIONS=1 @@ -32,6 +33,10 @@ services: - POSTGRES_PASSWORD=secret volumes: - miniflux-db:/var/lib/postgresql/data + healthcheck: + test: ["CMD", "pg_isready", "-U", "miniflux"] + interval: 10s + start_period: 30s volumes: miniflux-db: caddy_data: diff --git a/contrib/docker-compose/traefik.yml b/contrib/docker-compose/traefik.yml index a06a519e..05977cab 100644 --- a/contrib/docker-compose/traefik.yml +++ b/contrib/docker-compose/traefik.yml @@ -21,7 +21,8 @@ services: image: miniflux/miniflux:latest container_name: miniflux depends_on: - - db + db: + condition: service_healthy expose: - "8080" environment: @@ -44,5 +45,9 @@ services: - POSTGRES_PASSWORD=secret volumes: - miniflux-db:/var/lib/postgresql/data + healthcheck: + test: ["CMD", "pg_isready", "-U", "miniflux"] + interval: 10s + start_period: 30s volumes: miniflux-db: diff --git a/miniflux.1 b/miniflux.1 index c8c710f7..7de208d2 100644 --- a/miniflux.1 +++ b/miniflux.1 @@ -1,5 +1,5 @@ .\" Manpage for miniflux. -.TH "MINIFLUX" "1" "September 28, 2020" "\ \&" "\ \&" +.TH "MINIFLUX" "1" "February 20, 2021" "\ \&" "\ \&" .SH NAME miniflux \- Minimalist and opinionated feed reader @@ -43,6 +43,13 @@ Show debug logs\&. Flush all sessions (disconnect users)\&. .RE .PP +.B \-healthcheck +.RS 4 +Perform a health check on the given endpoint\&. +.br +The value "auto" try to guess the health check endpoint\&. +.RE +.PP .B \-i .RS 4 Show application information\&. diff --git a/packaging/docker/Dockerfile b/packaging/docker/Dockerfile index 34554d89..0653e362 100644 --- a/packaging/docker/Dockerfile +++ b/packaging/docker/Dockerfile @@ -20,7 +20,7 @@ LABEL org.opencontainers.image.documentation=https://miniflux.app/docs/ EXPOSE 8080 ENV LISTEN_ADDR 0.0.0.0:8080 - +HEALTHCHECK --start-period=30s CMD ["/usr/bin/miniflux", "-healthcheck", "auto"] RUN apk --no-cache add ca-certificates tzdata COPY --from=build /go/src/app/miniflux /usr/bin/miniflux USER nobody