Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@ jobs:
ci:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
- name: GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
version: latest
args: release --snapshot --clean --skip ko
env:
KO_DOCKER_REPO: "dummy"
- name: Checkout
uses: actions/checkout@v5
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.24"
- name: GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
version: latest
args: release --snapshot --clean --skip ko
env:
KO_DOCKER_REPO: "dummy"
40 changes: 20 additions & 20 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,32 @@ name: release
on:
push:
tags:
- 'v*.*.*'
- "v*.*.*"

permissions:
permissions:
contents: write
packages: write

jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
with:
fetch-depth: 0
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
cache: false
- name: Checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: "1.24"
cache: false

- name: Binary builds with GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
KO_DOCKER_REPO: "ghcr.io/${{ github.repository }}"
- name: Binary builds with GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
KO_DOCKER_REPO: "ghcr.io/${{ github.repository }}"
130 changes: 65 additions & 65 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,28 +48,28 @@ Installing from source (not recommended):
## Using the gRPC Health Checking Protocol

To make use of the `grpc_health_probe`, your application must implement the
[gRPC Health Checking Protocol v1][hc]. This means you must to register the
[gRPC Health Checking Protocol v1][hc]. This means you must register the
`Health` service and implement the `rpc Check` that returns a `SERVING` status.

Since the Health Checking protocol is part of the gRPC core, it has
packages/libraries available for the languages supported by gRPC:

[[health.proto](https://github.com/grpc/grpc/blob/master/src/proto/grpc/health/v1/health.proto)]
[[Go](https://godoc.org/google.golang.org/grpc/health/grpc_health_v1)]
[[Go](https://pkg.go.dev/google.golang.org/grpc/health/grpc_health_v1)]
[[Java](https://github.com/grpc/grpc-java/blob/master/services/src/generated/main/grpc/io/grpc/health/v1/HealthGrpc.java)]
[[Python](https://github.com/grpc/grpc/tree/master/src/python/grpcio_health_checking)]
[[C#](https://github.com/grpc/grpc/tree/master/src/csharp/Grpc.HealthCheck)/[NuGet](https://www.nuget.org/packages/Grpc.HealthCheck/)]
[[Ruby](https://www.rubydoc.info/gems/grpc/Grpc/Health/Checker)] ...

Most of the languages listed above provide helper functions that hides
Most of the languages listed above provide helper functions that hide
implementation details. This eliminates the need for you to implement the
`Check` rpc yourself.

## Example: gRPC health checking on Kubernetes

Kubernetes now supports [gRPC health checking][k8s]. If your cluster is running a version that supports gRPC health checking, you can define a gRPC liveness probe in your Pod specification. For more information on how to define a gRPC liveness probe in Kubernetes, see the [Kubernetes documentation][k8s-new].

However, if your Kubernetes version does not support gRPC health checking or if you want to use some advanced features that Kubernetes does not support, you can use `grpc_health_probe` to health-check your gRPC server. As a solution,
However, if your Kubernetes version does not support gRPC health checking or if you want to use some advanced features that Kubernetes does not support, you can use `grpc_health_probe` to health-check your gRPC server. As a solution,
`grpc_health_probe` [can be used for Kubernetes][k8s] to health-check gRPC
servers running in the Pod.

Expand All @@ -81,7 +81,7 @@ image. Choose a [binary release][rel] and download it in your Dockerfile:

```bash
ARG TARGETOS TARGETARCH
RUN GRPC_HEALTH_PROBE_VERSION=v0.4.38 && \
RUN GRPC_HEALTH_PROBE_VERSION=<git tag> && \
wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-${TARGETOS}-${TARGETARCH} && \
chmod +x /bin/grpc_health_probe
```
Expand All @@ -98,21 +98,21 @@ In your Kubernetes Pod specification manifest, specify a `livenessProbe` and/or
```yaml
spec:
containers:
- name: server
image: "[YOUR-DOCKER-IMAGE]"
ports:
- containerPort: 5000
readinessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:5000"]
initialDelaySeconds: 5
livenessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:5000"]
initialDelaySeconds: 10
- name: server
image: "[YOUR-DOCKER-IMAGE]"
ports:
- containerPort: 5000
readinessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:5000"]
initialDelaySeconds: 5
livenessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:5000"]
initialDelaySeconds: 10
```

This approach provide proper readiness/liveness checking to your applications
This approach provides proper readiness/liveness checking to your applications
that implement the [gRPC Health Checking Protocol][hc].

## Health Checking TLS Servers
Expand All @@ -121,77 +121,77 @@ If a gRPC server is serving traffic over TLS, or uses TLS client authentication
to authorize clients, you can still use `grpc_health_probe` to check health
with command-line options:

| Option | Description |
|:------------|-------------|
| **`-tls`** | use TLS (default: false) |
| **`-tls-ca-cert`** | path to file containing CA certificates (to override system root CAs) |
| **`-tls-client-cert`** | client certificate for authenticating to the server |
| **`-tls-client-key`** | private key for for authenticating to the server |
| **`-tls-no-verify`** | use TLS, but do not verify the certificate presented by the server (INSECURE) (default: false) |
| **`-tls-server-name`** | override the hostname used to verify the server certificate |
| Option | Description |
| :--------------------- | ---------------------------------------------------------------------------------------------- |
| **`-tls`** | use TLS (default: false) |
| **`-tls-ca-cert`** | path to file containing CA certificates (to override system root CAs) |
| **`-tls-client-cert`** | client certificate for authenticating to the server |
| **`-tls-client-key`** | private key for for authenticating to the server |
| **`-tls-no-verify`** | use TLS, but do not verify the certificate presented by the server (INSECURE) (default: false) |
| **`-tls-server-name`** | override the hostname used to verify the server certificate |

## Health checking TLS Servers with SPIFFE issued credentials

If your gRPC server requires authentication, you can use the following command line options and set the
If your gRPC server requires authentication, you can use the following command line options and set the
[SPIFFE_ENDPOINT_SOCKET][spiffe-socket]
environment variable.

| Option | Description |
|:------------|-------------|
| Option | Description |
| :------------ | ------------------------------------------------------------------------------ |
| **`-spiffe`** | use [SPIFFE Workload API][spiffe] to retrieve TLS credentials (default: false) |

## Other Available Flags

| Option | Description |
|:------------|-------------|
| **`-v`** | verbose logs (default: false) |
| **`-connect-timeout`** | timeout for establishing connection |
| **`-rpc-timeout`** | timeout for health check rpc |
| **`-rpc-header`** | sends metadata in the RPC request context (default: empty map) |
| **`-user-agent`** | user-agent header value of health check requests (default: grpc_health_probe) |
| **`-service`** | service name to check (default: "") - empty string is convention for server health |
| **`-gzip`** | use GZIPCompressor for requests and GZIPDecompressor for response (default: false) |
| **`-version`** | print the probe version and exit |
| Option | Description |
| :--------------------- | ---------------------------------------------------------------------------------- |
| **`-v`** | verbose logs (default: false) |
| **`-connect-timeout`** | timeout for establishing connection |
| **`-rpc-timeout`** | timeout for health check rpc |
| **`-rpc-header`** | sends metadata in the RPC request context (default: empty map) |
| **`-user-agent`** | user-agent header value of health check requests (default: grpc_health_probe) |
| **`-service`** | service name to check (default: "") - empty string is convention for server health |
| **`-gzip`** | use GZIPCompressor for requests and GZIPDecompressor for response (default: false) |
| **`-version`** | print the probe version and exit |

**Example:**

1. Start the `route_guide` [example
server](https://github.com/grpc/grpc-go/tree/be59908d40f00be3573a50284c3863f1a37b8528/examples/route_guide)
with TLS by running:
1. Start the `route_guide` [example
server](https://github.com/grpc/grpc-go/tree/be59908d40f00be3573a50284c3863f1a37b8528/examples/route_guide)
with TLS by running:

go run server/server.go -tls
go run server/server.go -tls

2. Run `grpc_client_probe` with the [CA
certificate](https://github.com/grpc/grpc-go/blob/be59908d40f00be3573a50284c3863f1a37b8528/testdata/ca.pem)
(in the `testdata/` directory) and hostname override the
[cert](https://github.com/grpc/grpc-go/blob/be59908d40f00be3573a50284c3863f1a37b8528/testdata/server1.pem) is signed for:
2. Run `grpc_client_probe` with the [CA
certificate](https://github.com/grpc/grpc-go/blob/be59908d40f00be3573a50284c3863f1a37b8528/testdata/ca.pem)
(in the `testdata/` directory) and hostname override the
[cert](https://github.com/grpc/grpc-go/blob/be59908d40f00be3573a50284c3863f1a37b8528/testdata/server1.pem) is signed for:

```sh
$ grpc_health_probe -addr 127.0.0.1:10000 \
-tls \
-tls-ca-cert /path/to/testdata/ca.pem \
-tls-server-name=example.com \
-rpc-header=foo:bar \
-rpc-header=foo2:bar2
```sh
$ grpc_health_probe -addr 127.0.0.1:10000 \
-tls \
-tls-ca-cert /path/to/testdata/ca.pem \
-tls-server-name=example.com \
-rpc-header=foo:bar \
-rpc-header=foo2:bar2

status: SERVING
```
status: SERVING
```

## Exit codes

It is not recommended to rely on specific exit statuses. Any failure will be
a non-zero exit code.

| Exit Code | Description |
|:-----------:|-------------|
| **0** | success: rpc response is `SERVING`. |
| **1** | failure: invalid command-line arguments |
| **2** | failure: connection failed or timed out |
| **3** | failure: rpc failed or timed out |
| **4** | failure: rpc successful, but the response is not `SERVING` |
| **20** | failure: could not retrieve TLS credentials using the [SPIFFE Workload API][spiffe] |
| Exit Code | Description |
| :-------: | ----------------------------------------------------------------------------------- |
| **0** | success: rpc response is `SERVING`. |
| **1** | failure: invalid command-line arguments |
| **2** | failure: connection failed or timed out |
| **3** | failure: rpc failed or timed out |
| **4** | failure: rpc successful, but the response is not `SERVING` |
| **20** | failure: could not retrieve TLS credentials using the [SPIFFE Workload API][spiffe] |

----
---

This is not an official Google project.

Expand Down
22 changes: 10 additions & 12 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
module github.com/grpc-ecosystem/grpc-health-probe

go 1.24.4

require (
github.com/spiffe/go-spiffe/v2 v2.5.0
golang.org/x/crypto v0.38.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/sys v0.33.0 // indirect
google.golang.org/grpc v1.74.2
)

require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/go-jose/go-jose/v4 v4.1.2 // indirect
github.com/zeebo/errs v1.4.0 // indirect
golang.org/x/sync v0.14.0 // indirect
golang.org/x/text v0.25.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
google.golang.org/protobuf v1.36.6 // indirect
golang.org/x/crypto v0.41.0 // indirect
golang.org/x/net v0.43.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/text v0.28.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a // indirect
google.golang.org/protobuf v1.36.7 // indirect
)

go 1.23.0

toolchain go1.24.4
32 changes: 16 additions & 16 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
github.com/go-jose/go-jose/v4 v4.1.2 h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI=
github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
Expand Down Expand Up @@ -34,21 +34,21 @@ go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFw
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a h1:tPE/Kp+x9dMSwUm/uM0JKK0IfdiJkwAbSMSeZBXXJXc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo=
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading