Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

kubeid

Kubernetes-native distributed ID generator based on the Twitter Snowflake algorithm.

  • Configurable epoch (KUBEID_EPOCH_MS)
  • gRPC + HTTP APIs
  • Kubernetes-native node ID via StatefulSet ordinal or Lease allocation
  • Go SDK at github.com/launchpad001/kubeid/sdk

Requires Go 1.26.0+.

Snowflake layout

+--------------------------------------------------------------------------+
| 1 bit unused | 41 bit timestamp | 10 bit node | 12 bit sequence          |
+--------------------------------------------------------------------------+
Field Bits Range
Timestamp 41 ms since configured epoch
Node ID 10 0 – 1023 (configurable)
Sequence 12 0 – 4095 per ms per node

node_bits and step_bits are configurable as long as their sum is ≤ 22 and each is > 0.

Epoch (important)

All replicas must share the same epoch. Changing the epoch after IDs have been issued breaks ordering and uniqueness assumptions.

Default epoch: 1767196800000 (2026-01-01 00:00:00 UTC+8).

export KUBEID_EPOCH_MS=1609459200000  # 2021-01-01 00:00:00 UTC

Quick start (local)

make proto tidy build

# static node id for local run
KUBEID_NODE_ID_MODE=static KUBEID_NODE_ID=1 ./bin/kubeid
# HTTP
curl -s http://127.0.0.1:8080/v1/id | jq
curl -s 'http://127.0.0.1:8080/v1/ids?count=5' | jq
curl -s http://127.0.0.1:8080/v1/info | jq

# parse — prefer id_str (see note below)
ID=$(curl -s http://127.0.0.1:8080/v1/id | jq -r .id_str)
curl -s "http://127.0.0.1:8080/v1/id/${ID}/parse" | jq

JavaScript / TypeScript clients: always use id_str. The numeric id field exceeds Number.MAX_SAFE_INTEGER and will be corrupted if parsed as a JSON number.

HTTP API

Method Path Description
GET /v1/id Generate one ID
GET /v1/ids?count=N Generate N IDs (count 1..1000; omit → 1)
POST /v1/ids Body {"count":N} (count 1..1000; omit → 1)
GET /v1/id/{id}/parse Parse an ID
GET /v1/info Generator metadata
GET /healthz Liveness
GET /readyz Readiness (false when lease ownership is lost)

Non-positive count is rejected with HTTP 400 on all batch endpoints. Transient clock-rollback errors return HTTP 503.

gRPC API

See api/proto/kubeid/v1/kubeid.proto.

Service: kubeid.v1.IDGenerator

  • Generate / GenerateBatch / Parse / Info
  • gRPC health + reflection enabled
  • GenerateBatch.count must be 1..1000 (no silent default)
  • Parse accepts id=0 (valid first ID at epoch on node 0)

Default listen: :9090.

HTTP/gRPC are trusted-network APIs (no auth). Keep them on ClusterIP / mesh-internal networks; do not expose the Service publicly without additional protection.

Go SDK

package main

import (
	"context"
	"fmt"
	"log"

	kubeid "github.com/launchpad001/kubeid/sdk"
)

func main() {
	// HTTP
	httpClient, err := kubeid.New(kubeid.WithHTTPEndpoint("http://kubeid.kubeid.svc:8080"))
	if err != nil {
		log.Fatal(err)
	}
	id, err := httpClient.Generate(context.Background())
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(id.Value, id.String)

	// gRPC
	grpcClient, err := kubeid.New(kubeid.WithGRPCEndpoint("kubeid.kubeid.svc:9090"))
	if err != nil {
		log.Fatal(err)
	}
	defer grpcClient.Close()

	ids, err := grpcClient.GenerateBatch(context.Background(), 10)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(len(ids))
}

When both HTTP and gRPC endpoints are set, the last endpoint option wins. Use WithProtocol(...) after the endpoint options to force a transport.

Generate retries transient failures automatically (default: 2 retries → 3 attempts, 50ms base backoff), including when a node is not ready (HTTP 503 / gRPC Unavailable / ErrNotReady, e.g. lease loss):

client, err := kubeid.New(
	kubeid.WithHTTPEndpoint("http://kubeid.kubeid.svc:8080"),
	kubeid.WithMaxRetries(5),                      // total attempts = 6
	kubeid.WithRetryBackoff(100*time.Millisecond), // optional
)
// WithMaxRetries(0) disables retries.
// Permanent 4xx / InvalidArgument fail fast (no retry).

GenerateBatch / Parse / Info are not retried by the SDK.

Container image

Images are published to GHCR on pushes to the default branch and on version tags:

ghcr.io/launchpad001/kubeid:latest
ghcr.io/launchpad001/kubeid:sha-<short>
ghcr.io/launchpad001/kubeid:vX.Y.Z   # from git tags
# local build
make docker
# or
make docker IMAGE=ghcr.io/launchpad001/kubeid TAG=dev

Kubernetes deployment

Deploy manifests use ghcr.io/launchpad001/kubeid:latest. After the first release, ensure the package is public (or configure an imagePullSecret) under the repo’s Packages settings.

Mode A — StatefulSet ordinal (recommended, simplest)

Node ID = pod ordinal (kubeid-0 → 0).

Replicas must be ≤ 2^node_bits (default 1024). Scaling beyond that causes pods with ordinals outside the bit layout to fail at resolve time.

kubectl apply -f deploy/statefulset.yaml

Mode B — Deployment + Lease

Each pod claims a free node ID via coordination.k8s.io/Lease.

  • Leases are renewed at ~1/3 of KUBEID_LEASE_DURATION.
  • Transient renew failures are retried with backoff for up to ~½ lease TTL; permanent loss of ownership (holder changed) fails immediately.
  • On terminal renew failure the process marks itself not ready (HTTP /readyz + gRPC health), refuses further Generate calls, then exits so Kubernetes restarts it.
  • Graceful shutdown (SIGTERM) releases the lease (with conflict retries) and does not treat a concurrent renew error as fatal.
  • Take-over of “expired” leases applies a skew safety margin (~2s, capped at ⅓ TTL). Run NTP (or equivalent) on all nodes so lease RenewTime remains meaningful.
kubectl apply -f deploy/rbac.yaml
kubectl apply -f deploy/deployment-lease.yaml

Configuration (env / ConfigMap)

Variable Default Description
KUBEID_EPOCH_MS 1767196800000 Snowflake epoch (Unix ms)
KUBEID_NODE_BITS 10 Bits for node ID (must be > 0)
KUBEID_STEP_BITS 12 Bits for sequence (must be > 0)
KUBEID_NODE_ID_MODE statefulset static | statefulset | lease
KUBEID_NODE_ID Required for static mode
POD_NAME Downward API (statefulset / lease)
POD_NAMESPACE default Downward API (lease)
KUBEID_LEASE_PREFIX kubeid-node Lease name prefix
KUBEID_LEASE_DURATION 15s Lease TTL (≥ 1s)
KUBEID_MAX_NODES 2^node_bits-1 Inclusive max node id for lease pool
KUBEID_HTTP_ADDR :8080 HTTP listen address
KUBEID_GRPC_ADDR :9090 gRPC listen address
KUBEID_LOG_LEVEL info debug | info | warn | error

Project layout

api/proto/          Protobuf definitions
api/gen/            Generated gRPC/protobuf code
cmd/kubeid/         Server entrypoint
internal/snowflake/ Core ID generator (configurable epoch)
internal/nodeid/    K8s node ID resolution
internal/server/    HTTP + gRPC handlers
internal/config/    Env-based configuration
sdk/                Go client SDK
deploy/             Kubernetes manifests

Build & test

make proto   # requires protoc, protoc-gen-go, protoc-gen-go-grpc
make tidy
make test
make build

License

Apache-2.0

About

Kubernetes-native distributed ID generator based on the Twitter Snowflake algorithm.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages