Documentation
¶
Overview ¶
Package grpcclient — горизонтальный cross-cutting helper для client-side gRPC keepalive. Единая точка истины для keepalive-параметров inter-service dial-сайтов (compute dialPeer, iam subject-drainer, vpc-sdk).
Проблема: bare-dial-сайты (`grpc.NewClient(addr, …)` без keepalive) держат conn'ы, которые между всплесками трафика простаивают и становятся half-open; первый RPC всплеска висит ~30с на переустановке TCP/HTTP2. keepalive-пинги проактивно обнаруживают мертвый conn и переустанавливают его.
Серверная сторона, принимающая idle keepalive (PermitWithoutStream=true), должна разрешать частые пинги — см. grpcsrv.DefaultKeepaliveEnforcement.
Package grpcclient — tls.go: opt-in mTLS client-credentials helper.
TLSClientCreds is the single source of truth for assembling client-side TLS transport credentials for inter-service gRPC dials, by analogy with the keepalive dial-option helper.
Behavior contract:
- enable=false → insecure transport-credentials (current plaintext dial, dev backward-compat); cert files are NOT read.
- enable=true → mTLS: presents client-cert (cert_file/key_file), verifies the server-cert against ca_files, and checks server_name against the server-cert SAN (client-cert + server-CA + server-name).
- enable=true + empty cert_file AND key_file → one-way TLS: NO client-cert is presented (still verifies server-cert via ca_files + server_name). This is not a normal production edge — it exists so a require-and-verify server correctly rejects a cert-less client → Unavailable.
- enable=true + unreadable/garbage cert / empty ca_files / empty server_name → error (fail-closed; never a silent insecure fallback).
Cert files are read once at startup; rotation = pod restart.
Index ¶
- Constants
- func DialPeer(opts PeerDialOptions) (*grpc.ClientConn, error)
- func KeepaliveDialOption(permitWithoutStream bool) grpc.DialOption
- func KeepaliveParams(permitWithoutStream bool) keepalive.ClientParameters
- func PeerConnectParams(dialTimeout time.Duration) grpc.ConnectParams
- func PeerServiceConfigJSON(retries uint, roundRobin bool) string
- func PeerTarget(endpoint string, roundRobin bool) string
- func TLSClientCreds(cfg TLSClient) (grpc.DialOption, error)
- func TLSClientTransportCreds(cfg TLSClient) (credentials.TransportCredentials, error)
- type PeerDialOptions
- type TLSClient
Constants ¶
const ( // DefaultKeepaliveTime — интервал ping'а: агрессивный 10s, чтобы поймать // half-open до следующего всплеска в kind, где idle-flow умирает быстрее 30s. DefaultKeepaliveTime = 10 * time.Second // DefaultKeepaliveTimeout — ack-deadline = треть интервала (инвариант // «таймаут = треть Time»). DefaultKeepaliveTimeout = DefaultKeepaliveTime / 3 )
Variables ¶
This section is empty.
Functions ¶
func DialPeer ¶
func DialPeer(opts PeerDialOptions) (*grpc.ClientConn, error)
DialPeer — соединение с соседом. Не набирает: `grpc.NewClient` откладывает соединение до первого вызова, поэтому отказ здесь означает негодные параметры, а не недоступность соседа.
func KeepaliveDialOption ¶
func KeepaliveDialOption(permitWithoutStream bool) grpc.DialOption
KeepaliveDialOption — grpc.DialOption с дефолтными keepalive-параметрами.
func KeepaliveParams ¶
func KeepaliveParams(permitWithoutStream bool) keepalive.ClientParameters
KeepaliveParams — стандартные client keepalive-параметры.
permitWithoutStream=true для преимущественно-idle conn'ов (authz, drainer): пинги держат conn теплым даже без активных стримов — прямо лечит half-open-столл. Для активно используемых conn'ов — false (там всегда есть трафик).
func PeerConnectParams ¶
func PeerConnectParams(dialTimeout time.Duration) grpc.ConnectParams
PeerConnectParams — отступ переподключения. Величины дословно те же, что у снятого строителя.
func PeerServiceConfigJSON ¶
PeerServiceConfigJSON — конфигурация службы: политика повтора и, по просьбе, распределение. Пустая строка означает «объявлять нечего» — а не «объявлено пустое»: повтор без попыток и балансировщик без адресов суть разные вещи.
func PeerTarget ¶
PeerTarget — адрес в форме, которую понимает резолвер gRPC. Схема пишется явно; разбор разобран в шапке файла.
func TLSClientCreds ¶
func TLSClientCreds(cfg TLSClient) (grpc.DialOption, error)
TLSClientCreds returns the grpc.DialOption carrying the transport credentials for this config. See package doc for the behavior contract.
func TLSClientTransportCreds ¶
func TLSClientTransportCreds(cfg TLSClient) (credentials.TransportCredentials, error)
TLSClientTransportCreds returns the raw credentials.TransportCredentials for this config — the same building block TLSClientCreds wraps into a DialOption. Callers that dial through a builder taking TransportCredentials (rather than a DialOption) use this directly, keeping a single source of truth for the behavior contract.
Types ¶
type PeerDialOptions ¶
type PeerDialOptions struct {
// Endpoint — адрес соседа: `host:port`, либо адрес, сам назвавший резолвер.
Endpoint string
// Creds — транспортные учётные данные. nil → insecure.
Creds credentials.TransportCredentials
// Retries — сколько раз повторить вызов сверх исходной попытки. 0 → без повтора.
Retries uint
// DialTimeout — цель отступа переподключения.
DialTimeout time.Duration
// KeepAliveTime — интервал опроса. 0 → без keepalive.
KeepAliveTime time.Duration
// UserAgent — представление клиента.
UserAgent string
// RoundRobin — распределять вызовы по ВСЕМ адресам имени. Требует резолвера
// dns: passthrough отдаёт один адрес.
RoundRobin bool
}
PeerDialOptions — параметры соединения с соседним сервисом.
type TLSClient ¶
type TLSClient struct {
// Enable toggles mTLS for this dial. Zero-value false ⇒ insecure.
Enable bool
// CertFile is the PEM client-certificate presented to the server.
CertFile string
// KeyFile is the PEM private key for CertFile.
KeyFile string
// CAFiles are PEM CA bundles used to verify the server-cert.
CAFiles []string
// ServerName is checked against the server-cert SAN.
ServerName string
}
TLSClient is a HORIZONTAL, per-edge client-side TLS value-struct. It is a plain value struct with no process-wide TLS singleton: every dial-site receives its own TLSClientCreds argument (no global singletons outside cmd/).
It carries NO absolute envconfig tags ON PURPOSE. This struct is embedded by every service under its own per-edge (per-peer) dial config field; an absolute tag (e.g. KACHO_COMPUTE_TLS_CLIENT_ENABLE) would collapse every dial-edge onto the same env names and break per-edge independence. Instead the env name is derived from the hierarchy of field names: the SERVICE owns the edge name by choosing the parent field and loading with config.LoadPrefixed("KACHO_<DOMAIN>", &cfg).
Example — a service that dials two peers:
type Config struct {
IAM grpcclient.TLSClient // → KACHO_COMPUTE_IAM_ENABLE, ..._CAFILES, ...
VPC grpcclient.TLSClient // → KACHO_COMPUTE_VPC_ENABLE, ..._CAFILES, ...
}
_ = config.LoadPrefixed("KACHO_COMPUTE", &cfg) // each dial-edge independent
This yields the KACHO_<DOMAIN>_<EDGE>_<NAME> convention with true per-edge prefixing: distinct dial-edges in one process resolve to distinct env blocks (one process may run an mTLS client and an insecure server simultaneously).