Add envoy connection balancing. (#14616)
Add envoy connection balancing config.
This commit is contained in:
parent
3eb708e964
commit
d9e42b0f1c
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:feature
|
||||||
|
connect: Add Envoy connection balancing configuration fields.
|
||||||
|
```
|
|
@ -53,6 +53,7 @@ func ComputeResolvedServiceConfig(
|
||||||
structs.NewServiceID(args.Name, &args.EnterpriseMeta),
|
structs.NewServiceID(args.Name, &args.EnterpriseMeta),
|
||||||
)
|
)
|
||||||
if serviceConf != nil {
|
if serviceConf != nil {
|
||||||
|
|
||||||
if serviceConf.Expose.Checks {
|
if serviceConf.Expose.Checks {
|
||||||
thisReply.Expose.Checks = true
|
thisReply.Expose.Checks = true
|
||||||
}
|
}
|
||||||
|
@ -62,12 +63,6 @@ func ComputeResolvedServiceConfig(
|
||||||
if serviceConf.MeshGateway.Mode != structs.MeshGatewayModeDefault {
|
if serviceConf.MeshGateway.Mode != structs.MeshGatewayModeDefault {
|
||||||
thisReply.MeshGateway.Mode = serviceConf.MeshGateway.Mode
|
thisReply.MeshGateway.Mode = serviceConf.MeshGateway.Mode
|
||||||
}
|
}
|
||||||
if serviceConf.Protocol != "" {
|
|
||||||
if thisReply.ProxyConfig == nil {
|
|
||||||
thisReply.ProxyConfig = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
thisReply.ProxyConfig["protocol"] = serviceConf.Protocol
|
|
||||||
}
|
|
||||||
if serviceConf.TransparentProxy.OutboundListenerPort != 0 {
|
if serviceConf.TransparentProxy.OutboundListenerPort != 0 {
|
||||||
thisReply.TransparentProxy.OutboundListenerPort = serviceConf.TransparentProxy.OutboundListenerPort
|
thisReply.TransparentProxy.OutboundListenerPort = serviceConf.TransparentProxy.OutboundListenerPort
|
||||||
}
|
}
|
||||||
|
@ -81,25 +76,29 @@ func ComputeResolvedServiceConfig(
|
||||||
thisReply.Destination = *serviceConf.Destination
|
thisReply.Destination = *serviceConf.Destination
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Populate values for the proxy config map
|
||||||
|
proxyConf := thisReply.ProxyConfig
|
||||||
|
if proxyConf == nil {
|
||||||
|
proxyConf = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
if serviceConf.Protocol != "" {
|
||||||
|
proxyConf["protocol"] = serviceConf.Protocol
|
||||||
|
}
|
||||||
|
if serviceConf.BalanceInboundConnections != "" {
|
||||||
|
proxyConf["balance_inbound_connections"] = serviceConf.BalanceInboundConnections
|
||||||
|
}
|
||||||
if serviceConf.MaxInboundConnections > 0 {
|
if serviceConf.MaxInboundConnections > 0 {
|
||||||
if thisReply.ProxyConfig == nil {
|
proxyConf["max_inbound_connections"] = serviceConf.MaxInboundConnections
|
||||||
thisReply.ProxyConfig = map[string]interface{}{}
|
|
||||||
}
|
|
||||||
thisReply.ProxyConfig["max_inbound_connections"] = serviceConf.MaxInboundConnections
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if serviceConf.LocalConnectTimeoutMs > 0 {
|
if serviceConf.LocalConnectTimeoutMs > 0 {
|
||||||
if thisReply.ProxyConfig == nil {
|
proxyConf["local_connect_timeout_ms"] = serviceConf.LocalConnectTimeoutMs
|
||||||
thisReply.ProxyConfig = map[string]interface{}{}
|
|
||||||
}
|
|
||||||
thisReply.ProxyConfig["local_connect_timeout_ms"] = serviceConf.LocalConnectTimeoutMs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if serviceConf.LocalRequestTimeoutMs > 0 {
|
if serviceConf.LocalRequestTimeoutMs > 0 {
|
||||||
if thisReply.ProxyConfig == nil {
|
proxyConf["local_request_timeout_ms"] = serviceConf.LocalRequestTimeoutMs
|
||||||
thisReply.ProxyConfig = map[string]interface{}{}
|
}
|
||||||
}
|
// Add the proxy conf to the response if any fields were populated
|
||||||
thisReply.ProxyConfig["local_request_timeout_ms"] = serviceConf.LocalRequestTimeoutMs
|
if len(proxyConf) > 0 {
|
||||||
|
thisReply.ProxyConfig = proxyConf
|
||||||
}
|
}
|
||||||
|
|
||||||
thisReply.Meta = serviceConf.Meta
|
thisReply.Meta = serviceConf.Meta
|
||||||
|
|
|
@ -24,6 +24,26 @@ func Test_ComputeResolvedServiceConfig(t *testing.T) {
|
||||||
args args
|
args args
|
||||||
want *structs.ServiceConfigResponse
|
want *structs.ServiceConfigResponse
|
||||||
}{
|
}{
|
||||||
|
{
|
||||||
|
name: "proxy with balanceinboundconnections",
|
||||||
|
args: args{
|
||||||
|
scReq: &structs.ServiceConfigRequest{
|
||||||
|
Name: "sid",
|
||||||
|
},
|
||||||
|
entries: &ResolvedServiceConfigSet{
|
||||||
|
ServiceDefaults: map[structs.ServiceID]*structs.ServiceConfigEntry{
|
||||||
|
sid: {
|
||||||
|
BalanceInboundConnections: "exact_balance",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &structs.ServiceConfigResponse{
|
||||||
|
ProxyConfig: map[string]interface{}{
|
||||||
|
"balance_inbound_connections": "exact_balance",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "proxy with maxinboundsconnections",
|
name: "proxy with maxinboundsconnections",
|
||||||
args: args{
|
args: args{
|
||||||
|
|
|
@ -38,6 +38,8 @@ const (
|
||||||
MeshConfigMesh string = "mesh"
|
MeshConfigMesh string = "mesh"
|
||||||
|
|
||||||
DefaultServiceProtocol = "tcp"
|
DefaultServiceProtocol = "tcp"
|
||||||
|
|
||||||
|
ConnectionExactBalance = "exact_balance"
|
||||||
)
|
)
|
||||||
|
|
||||||
var AllConfigEntryKinds = []string{
|
var AllConfigEntryKinds = []string{
|
||||||
|
@ -98,19 +100,20 @@ type WarningConfigEntry interface {
|
||||||
// ServiceConfiguration is the top-level struct for the configuration of a service
|
// ServiceConfiguration is the top-level struct for the configuration of a service
|
||||||
// across the entire cluster.
|
// across the entire cluster.
|
||||||
type ServiceConfigEntry struct {
|
type ServiceConfigEntry struct {
|
||||||
Kind string
|
Kind string
|
||||||
Name string
|
Name string
|
||||||
Protocol string
|
Protocol string
|
||||||
Mode ProxyMode `json:",omitempty"`
|
Mode ProxyMode `json:",omitempty"`
|
||||||
TransparentProxy TransparentProxyConfig `json:",omitempty" alias:"transparent_proxy"`
|
TransparentProxy TransparentProxyConfig `json:",omitempty" alias:"transparent_proxy"`
|
||||||
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
|
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
|
||||||
Expose ExposeConfig `json:",omitempty"`
|
Expose ExposeConfig `json:",omitempty"`
|
||||||
ExternalSNI string `json:",omitempty" alias:"external_sni"`
|
ExternalSNI string `json:",omitempty" alias:"external_sni"`
|
||||||
UpstreamConfig *UpstreamConfiguration `json:",omitempty" alias:"upstream_config"`
|
UpstreamConfig *UpstreamConfiguration `json:",omitempty" alias:"upstream_config"`
|
||||||
Destination *DestinationConfig `json:",omitempty"`
|
Destination *DestinationConfig `json:",omitempty"`
|
||||||
MaxInboundConnections int `json:",omitempty" alias:"max_inbound_connections"`
|
MaxInboundConnections int `json:",omitempty" alias:"max_inbound_connections"`
|
||||||
LocalConnectTimeoutMs int `json:",omitempty" alias:"local_connect_timeout_ms"`
|
LocalConnectTimeoutMs int `json:",omitempty" alias:"local_connect_timeout_ms"`
|
||||||
LocalRequestTimeoutMs int `json:",omitempty" alias:"local_request_timeout_ms"`
|
LocalRequestTimeoutMs int `json:",omitempty" alias:"local_request_timeout_ms"`
|
||||||
|
BalanceInboundConnections string `json:",omitempty" alias:"balance_inbound_connections"`
|
||||||
|
|
||||||
Meta map[string]string `json:",omitempty"`
|
Meta map[string]string `json:",omitempty"`
|
||||||
acl.EnterpriseMeta `hcl:",squash" mapstructure:",squash"`
|
acl.EnterpriseMeta `hcl:",squash" mapstructure:",squash"`
|
||||||
|
@ -183,6 +186,10 @@ func (e *ServiceConfigEntry) Validate() error {
|
||||||
|
|
||||||
validationErr := validateConfigEntryMeta(e.Meta)
|
validationErr := validateConfigEntryMeta(e.Meta)
|
||||||
|
|
||||||
|
if !isValidConnectionBalance(e.BalanceInboundConnections) {
|
||||||
|
validationErr = multierror.Append(validationErr, fmt.Errorf("invalid value for balance_inbound_connections: %v", e.BalanceInboundConnections))
|
||||||
|
}
|
||||||
|
|
||||||
// External endpoints are invalid with an existing service's upstream configuration
|
// External endpoints are invalid with an existing service's upstream configuration
|
||||||
if e.UpstreamConfig != nil && e.Destination != nil {
|
if e.UpstreamConfig != nil && e.Destination != nil {
|
||||||
validationErr = multierror.Append(validationErr, errors.New("UpstreamConfig and Destination are mutually exclusive for service defaults"))
|
validationErr = multierror.Append(validationErr, errors.New("UpstreamConfig and Destination are mutually exclusive for service defaults"))
|
||||||
|
@ -800,6 +807,10 @@ type UpstreamConfig struct {
|
||||||
|
|
||||||
// MeshGatewayConfig controls how Mesh Gateways are configured and used
|
// MeshGatewayConfig controls how Mesh Gateways are configured and used
|
||||||
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway" `
|
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway" `
|
||||||
|
|
||||||
|
// BalanceOutboundConnections indicates how the proxy should attempt to distribute
|
||||||
|
// connections across worker threads. Only used by envoy proxies.
|
||||||
|
BalanceOutboundConnections string `json:",omitempty" alias:"balance_outbound_connections"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg UpstreamConfig) Clone() UpstreamConfig {
|
func (cfg UpstreamConfig) Clone() UpstreamConfig {
|
||||||
|
@ -848,6 +859,9 @@ func (cfg UpstreamConfig) MergeInto(dst map[string]interface{}) {
|
||||||
if cfg.PassiveHealthCheck != nil {
|
if cfg.PassiveHealthCheck != nil {
|
||||||
dst["passive_health_check"] = cfg.PassiveHealthCheck
|
dst["passive_health_check"] = cfg.PassiveHealthCheck
|
||||||
}
|
}
|
||||||
|
if cfg.BalanceOutboundConnections != "" {
|
||||||
|
dst["balance_outbound_connections"] = cfg.BalanceOutboundConnections
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *UpstreamConfig) NormalizeWithoutName() error {
|
func (cfg *UpstreamConfig) NormalizeWithoutName() error {
|
||||||
|
@ -917,6 +931,10 @@ func (cfg UpstreamConfig) validate(named bool) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !isValidConnectionBalance(cfg.BalanceOutboundConnections) {
|
||||||
|
validationErr = multierror.Append(validationErr, fmt.Errorf("invalid value for balance_outbound_connections: %v", cfg.BalanceOutboundConnections))
|
||||||
|
}
|
||||||
|
|
||||||
return validationErr
|
return validationErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1222,3 +1240,7 @@ func validateConfigEntryMeta(meta map[string]string) error {
|
||||||
type ConfigEntryDeleteResponse struct {
|
type ConfigEntryDeleteResponse struct {
|
||||||
Deleted bool
|
Deleted bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isValidConnectionBalance(s string) bool {
|
||||||
|
return s == "" || s == ConnectionExactBalance
|
||||||
|
}
|
||||||
|
|
|
@ -340,6 +340,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
"moreconfig" {
|
"moreconfig" {
|
||||||
"moar" = "config"
|
"moar" = "config"
|
||||||
}
|
}
|
||||||
|
"balance_inbound_connections" = "exact_balance"
|
||||||
}
|
}
|
||||||
mesh_gateway {
|
mesh_gateway {
|
||||||
mode = "remote"
|
mode = "remote"
|
||||||
|
@ -358,6 +359,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
"moreconfig" {
|
"moreconfig" {
|
||||||
"moar" = "config"
|
"moar" = "config"
|
||||||
}
|
}
|
||||||
|
"balance_inbound_connections" = "exact_balance"
|
||||||
}
|
}
|
||||||
MeshGateway {
|
MeshGateway {
|
||||||
Mode = "remote"
|
Mode = "remote"
|
||||||
|
@ -376,6 +378,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
"moreconfig": map[string]interface{}{
|
"moreconfig": map[string]interface{}{
|
||||||
"moar": "config",
|
"moar": "config",
|
||||||
},
|
},
|
||||||
|
"balance_inbound_connections": "exact_balance",
|
||||||
},
|
},
|
||||||
MeshGateway: MeshGatewayConfig{
|
MeshGateway: MeshGatewayConfig{
|
||||||
Mode: MeshGatewayModeRemote,
|
Mode: MeshGatewayModeRemote,
|
||||||
|
@ -396,6 +399,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
mesh_gateway {
|
mesh_gateway {
|
||||||
mode = "remote"
|
mode = "remote"
|
||||||
}
|
}
|
||||||
|
balance_inbound_connections = "exact_balance"
|
||||||
upstream_config {
|
upstream_config {
|
||||||
overrides = [
|
overrides = [
|
||||||
{
|
{
|
||||||
|
@ -415,6 +419,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
defaults {
|
defaults {
|
||||||
connect_timeout_ms = 5
|
connect_timeout_ms = 5
|
||||||
protocol = "http"
|
protocol = "http"
|
||||||
|
balance_outbound_connections = "exact_balance"
|
||||||
envoy_listener_json = "foo"
|
envoy_listener_json = "foo"
|
||||||
envoy_cluster_json = "bar"
|
envoy_cluster_json = "bar"
|
||||||
limits {
|
limits {
|
||||||
|
@ -437,6 +442,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
MeshGateway {
|
MeshGateway {
|
||||||
Mode = "remote"
|
Mode = "remote"
|
||||||
}
|
}
|
||||||
|
BalanceInboundConnections = "exact_balance"
|
||||||
UpstreamConfig {
|
UpstreamConfig {
|
||||||
Overrides = [
|
Overrides = [
|
||||||
{
|
{
|
||||||
|
@ -463,6 +469,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
MaxPendingRequests = 4
|
MaxPendingRequests = 4
|
||||||
MaxConcurrentRequests = 5
|
MaxConcurrentRequests = 5
|
||||||
}
|
}
|
||||||
|
BalanceOutboundConnections = "exact_balance"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
@ -478,6 +485,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
MeshGateway: MeshGatewayConfig{
|
MeshGateway: MeshGatewayConfig{
|
||||||
Mode: MeshGatewayModeRemote,
|
Mode: MeshGatewayModeRemote,
|
||||||
},
|
},
|
||||||
|
BalanceInboundConnections: "exact_balance",
|
||||||
UpstreamConfig: &UpstreamConfiguration{
|
UpstreamConfig: &UpstreamConfiguration{
|
||||||
Overrides: []*UpstreamConfig{
|
Overrides: []*UpstreamConfig{
|
||||||
{
|
{
|
||||||
|
@ -502,6 +510,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
MaxPendingRequests: intPointer(4),
|
MaxPendingRequests: intPointer(4),
|
||||||
MaxConcurrentRequests: intPointer(5),
|
MaxConcurrentRequests: intPointer(5),
|
||||||
},
|
},
|
||||||
|
BalanceOutboundConnections: "exact_balance",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -2651,6 +2660,44 @@ func TestServiceConfigEntry(t *testing.T) {
|
||||||
},
|
},
|
||||||
validateErr: "Duplicate address",
|
validateErr: "Duplicate address",
|
||||||
},
|
},
|
||||||
|
"validate: invalid inbound connection balance": {
|
||||||
|
entry: &ServiceConfigEntry{
|
||||||
|
Kind: ServiceDefaults,
|
||||||
|
Name: "external",
|
||||||
|
Protocol: "http",
|
||||||
|
BalanceInboundConnections: "invalid",
|
||||||
|
},
|
||||||
|
validateErr: "invalid value for balance_inbound_connections",
|
||||||
|
},
|
||||||
|
"validate: invalid default outbound connection balance": {
|
||||||
|
entry: &ServiceConfigEntry{
|
||||||
|
Kind: ServiceDefaults,
|
||||||
|
Name: "external",
|
||||||
|
Protocol: "http",
|
||||||
|
UpstreamConfig: &UpstreamConfiguration{
|
||||||
|
Defaults: &UpstreamConfig{
|
||||||
|
BalanceOutboundConnections: "invalid",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
validateErr: "invalid value for balance_outbound_connections",
|
||||||
|
},
|
||||||
|
"validate: invalid override outbound connection balance": {
|
||||||
|
entry: &ServiceConfigEntry{
|
||||||
|
Kind: ServiceDefaults,
|
||||||
|
Name: "external",
|
||||||
|
Protocol: "http",
|
||||||
|
UpstreamConfig: &UpstreamConfiguration{
|
||||||
|
Overrides: []*UpstreamConfig{
|
||||||
|
{
|
||||||
|
Name: "upstream",
|
||||||
|
BalanceOutboundConnections: "invalid",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
validateErr: "invalid value for balance_outbound_connections",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
testConfigEntryNormalizeAndValidate(t, cases)
|
testConfigEntryNormalizeAndValidate(t, cases)
|
||||||
}
|
}
|
||||||
|
@ -2665,10 +2712,11 @@ func TestUpstreamConfig_MergeInto(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "kitchen sink",
|
name: "kitchen sink",
|
||||||
source: UpstreamConfig{
|
source: UpstreamConfig{
|
||||||
EnvoyListenerJSON: "foo",
|
BalanceOutboundConnections: "exact_balance",
|
||||||
EnvoyClusterJSON: "bar",
|
EnvoyListenerJSON: "foo",
|
||||||
ConnectTimeoutMs: 5,
|
EnvoyClusterJSON: "bar",
|
||||||
Protocol: "http",
|
ConnectTimeoutMs: 5,
|
||||||
|
Protocol: "http",
|
||||||
Limits: &UpstreamLimits{
|
Limits: &UpstreamLimits{
|
||||||
MaxConnections: intPointer(3),
|
MaxConnections: intPointer(3),
|
||||||
MaxPendingRequests: intPointer(4),
|
MaxPendingRequests: intPointer(4),
|
||||||
|
@ -2682,10 +2730,11 @@ func TestUpstreamConfig_MergeInto(t *testing.T) {
|
||||||
},
|
},
|
||||||
destination: make(map[string]interface{}),
|
destination: make(map[string]interface{}),
|
||||||
want: map[string]interface{}{
|
want: map[string]interface{}{
|
||||||
"envoy_listener_json": "foo",
|
"balance_outbound_connections": "exact_balance",
|
||||||
"envoy_cluster_json": "bar",
|
"envoy_listener_json": "foo",
|
||||||
"connect_timeout_ms": 5,
|
"envoy_cluster_json": "bar",
|
||||||
"protocol": "http",
|
"connect_timeout_ms": 5,
|
||||||
|
"protocol": "http",
|
||||||
"limits": &UpstreamLimits{
|
"limits": &UpstreamLimits{
|
||||||
MaxConnections: intPointer(3),
|
MaxConnections: intPointer(3),
|
||||||
MaxPendingRequests: intPointer(4),
|
MaxPendingRequests: intPointer(4),
|
||||||
|
@ -2701,10 +2750,11 @@ func TestUpstreamConfig_MergeInto(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "kitchen sink override of destination",
|
name: "kitchen sink override of destination",
|
||||||
source: UpstreamConfig{
|
source: UpstreamConfig{
|
||||||
EnvoyListenerJSON: "foo",
|
BalanceOutboundConnections: "exact_balance",
|
||||||
EnvoyClusterJSON: "bar",
|
EnvoyListenerJSON: "foo",
|
||||||
ConnectTimeoutMs: 5,
|
EnvoyClusterJSON: "bar",
|
||||||
Protocol: "http",
|
ConnectTimeoutMs: 5,
|
||||||
|
Protocol: "http",
|
||||||
Limits: &UpstreamLimits{
|
Limits: &UpstreamLimits{
|
||||||
MaxConnections: intPointer(3),
|
MaxConnections: intPointer(3),
|
||||||
MaxPendingRequests: intPointer(4),
|
MaxPendingRequests: intPointer(4),
|
||||||
|
@ -2717,10 +2767,11 @@ func TestUpstreamConfig_MergeInto(t *testing.T) {
|
||||||
MeshGateway: MeshGatewayConfig{Mode: MeshGatewayModeRemote},
|
MeshGateway: MeshGatewayConfig{Mode: MeshGatewayModeRemote},
|
||||||
},
|
},
|
||||||
destination: map[string]interface{}{
|
destination: map[string]interface{}{
|
||||||
"envoy_listener_json": "zip",
|
"balance_outbound_connections": "",
|
||||||
"envoy_cluster_json": "zap",
|
"envoy_listener_json": "zip",
|
||||||
"connect_timeout_ms": 10,
|
"envoy_cluster_json": "zap",
|
||||||
"protocol": "grpc",
|
"connect_timeout_ms": 10,
|
||||||
|
"protocol": "grpc",
|
||||||
"limits": &UpstreamLimits{
|
"limits": &UpstreamLimits{
|
||||||
MaxConnections: intPointer(10),
|
MaxConnections: intPointer(10),
|
||||||
MaxPendingRequests: intPointer(11),
|
MaxPendingRequests: intPointer(11),
|
||||||
|
@ -2733,10 +2784,11 @@ func TestUpstreamConfig_MergeInto(t *testing.T) {
|
||||||
"mesh_gateway": MeshGatewayConfig{Mode: MeshGatewayModeLocal},
|
"mesh_gateway": MeshGatewayConfig{Mode: MeshGatewayModeLocal},
|
||||||
},
|
},
|
||||||
want: map[string]interface{}{
|
want: map[string]interface{}{
|
||||||
"envoy_listener_json": "foo",
|
"balance_outbound_connections": "exact_balance",
|
||||||
"envoy_cluster_json": "bar",
|
"envoy_listener_json": "foo",
|
||||||
"connect_timeout_ms": 5,
|
"envoy_cluster_json": "bar",
|
||||||
"protocol": "http",
|
"connect_timeout_ms": 5,
|
||||||
|
"protocol": "http",
|
||||||
"limits": &UpstreamLimits{
|
"limits": &UpstreamLimits{
|
||||||
MaxConnections: intPointer(3),
|
MaxConnections: intPointer(3),
|
||||||
MaxPendingRequests: intPointer(4),
|
MaxPendingRequests: intPointer(4),
|
||||||
|
@ -2753,10 +2805,11 @@ func TestUpstreamConfig_MergeInto(t *testing.T) {
|
||||||
name: "empty source leaves destination intact",
|
name: "empty source leaves destination intact",
|
||||||
source: UpstreamConfig{},
|
source: UpstreamConfig{},
|
||||||
destination: map[string]interface{}{
|
destination: map[string]interface{}{
|
||||||
"envoy_listener_json": "zip",
|
"balance_outbound_connections": "exact_balance",
|
||||||
"envoy_cluster_json": "zap",
|
"envoy_listener_json": "zip",
|
||||||
"connect_timeout_ms": 10,
|
"envoy_cluster_json": "zap",
|
||||||
"protocol": "grpc",
|
"connect_timeout_ms": 10,
|
||||||
|
"protocol": "grpc",
|
||||||
"limits": &UpstreamLimits{
|
"limits": &UpstreamLimits{
|
||||||
MaxConnections: intPointer(10),
|
MaxConnections: intPointer(10),
|
||||||
MaxPendingRequests: intPointer(11),
|
MaxPendingRequests: intPointer(11),
|
||||||
|
@ -2770,10 +2823,11 @@ func TestUpstreamConfig_MergeInto(t *testing.T) {
|
||||||
"mesh_gateway": MeshGatewayConfig{Mode: MeshGatewayModeLocal},
|
"mesh_gateway": MeshGatewayConfig{Mode: MeshGatewayModeLocal},
|
||||||
},
|
},
|
||||||
want: map[string]interface{}{
|
want: map[string]interface{}{
|
||||||
"envoy_listener_json": "zip",
|
"balance_outbound_connections": "exact_balance",
|
||||||
"envoy_cluster_json": "zap",
|
"envoy_listener_json": "zip",
|
||||||
"connect_timeout_ms": 10,
|
"envoy_cluster_json": "zap",
|
||||||
"protocol": "grpc",
|
"connect_timeout_ms": 10,
|
||||||
|
"protocol": "grpc",
|
||||||
"limits": &UpstreamLimits{
|
"limits": &UpstreamLimits{
|
||||||
MaxConnections: intPointer(10),
|
MaxConnections: intPointer(10),
|
||||||
MaxPendingRequests: intPointer(11),
|
MaxPendingRequests: intPointer(11),
|
||||||
|
|
|
@ -68,6 +68,10 @@ type ProxyConfig struct {
|
||||||
// MaxInboundConnections is the maximum number of inbound connections to
|
// MaxInboundConnections is the maximum number of inbound connections to
|
||||||
// the proxy. If not set, the default is 0 (no limit).
|
// the proxy. If not set, the default is 0 (no limit).
|
||||||
MaxInboundConnections int `mapstructure:"max_inbound_connections"`
|
MaxInboundConnections int `mapstructure:"max_inbound_connections"`
|
||||||
|
|
||||||
|
// BalanceInboundConnections indicates how the proxy should attempt to distribute
|
||||||
|
// connections across worker threads. Only used by envoy proxies.
|
||||||
|
BalanceInboundConnections string `json:",omitempty" alias:"balance_inbound_connections"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseProxyConfig returns the ProxyConfig parsed from the an opaque map. If an
|
// ParseProxyConfig returns the ProxyConfig parsed from the an opaque map. If an
|
||||||
|
|
|
@ -157,6 +157,17 @@ func TestParseProxyConfig(t *testing.T) {
|
||||||
Protocol: "tcp",
|
Protocol: "tcp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "balance inbound connections override, string",
|
||||||
|
input: map[string]interface{}{
|
||||||
|
"balance_inbound_connections": "exact_balance",
|
||||||
|
},
|
||||||
|
want: ProxyConfig{
|
||||||
|
LocalConnectTimeoutMs: 5000,
|
||||||
|
Protocol: "tcp",
|
||||||
|
BalanceInboundConnections: "exact_balance",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
|
@ -190,6 +190,7 @@ func (s *ResourceGenerator) listenersFromSnapshotConnectProxy(cfgSnap *proxycfg.
|
||||||
}
|
}
|
||||||
|
|
||||||
upstreamListener := makeListener(uid.EnvoyID(), upstreamCfg, envoy_core_v3.TrafficDirection_OUTBOUND)
|
upstreamListener := makeListener(uid.EnvoyID(), upstreamCfg, envoy_core_v3.TrafficDirection_OUTBOUND)
|
||||||
|
s.injectConnectionBalanceConfig(cfg.BalanceOutboundConnections, upstreamListener)
|
||||||
upstreamListener.FilterChains = []*envoy_listener_v3.FilterChain{
|
upstreamListener.FilterChains = []*envoy_listener_v3.FilterChain{
|
||||||
filterChain,
|
filterChain,
|
||||||
}
|
}
|
||||||
|
@ -385,6 +386,8 @@ func (s *ResourceGenerator) listenersFromSnapshotConnectProxy(cfgSnap *proxycfg.
|
||||||
}
|
}
|
||||||
|
|
||||||
upstreamListener := makeListener(uid.EnvoyID(), upstreamCfg, envoy_core_v3.TrafficDirection_OUTBOUND)
|
upstreamListener := makeListener(uid.EnvoyID(), upstreamCfg, envoy_core_v3.TrafficDirection_OUTBOUND)
|
||||||
|
s.injectConnectionBalanceConfig(cfg.BalanceOutboundConnections, upstreamListener)
|
||||||
|
|
||||||
upstreamListener.FilterChains = []*envoy_listener_v3.FilterChain{
|
upstreamListener.FilterChains = []*envoy_listener_v3.FilterChain{
|
||||||
filterChain,
|
filterChain,
|
||||||
}
|
}
|
||||||
|
@ -559,6 +562,7 @@ func (s *ResourceGenerator) listenersFromSnapshotConnectProxy(cfgSnap *proxycfg.
|
||||||
}
|
}
|
||||||
|
|
||||||
upstreamListener := makeListener(uid.EnvoyID(), u, envoy_core_v3.TrafficDirection_OUTBOUND)
|
upstreamListener := makeListener(uid.EnvoyID(), u, envoy_core_v3.TrafficDirection_OUTBOUND)
|
||||||
|
s.injectConnectionBalanceConfig(cfg.BalanceOutboundConnections, upstreamListener)
|
||||||
|
|
||||||
filterChain, err := s.makeUpstreamFilterChain(filterChainOpts{
|
filterChain, err := s.makeUpstreamFilterChain(filterChainOpts{
|
||||||
// TODO (SNI partition) add partition for upstream SNI
|
// TODO (SNI partition) add partition for upstream SNI
|
||||||
|
@ -905,6 +909,19 @@ func makeListenerFromUserConfig(configJSON string) (*envoy_listener_v3.Listener,
|
||||||
return &l, nil
|
return &l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ResourceGenerator) injectConnectionBalanceConfig(balanceType string, listener *envoy_listener_v3.Listener) {
|
||||||
|
switch balanceType {
|
||||||
|
case "":
|
||||||
|
// Default with no balancing.
|
||||||
|
case structs.ConnectionExactBalance:
|
||||||
|
listener.ConnectionBalanceConfig = &envoy_listener_v3.Listener_ConnectionBalanceConfig{
|
||||||
|
BalanceType: &envoy_listener_v3.Listener_ConnectionBalanceConfig_ExactBalance_{},
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
s.Logger.Warn("ignoring invalid connection balance option", "value", balanceType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure that the first filter in each filter chain of a public listener is
|
// Ensure that the first filter in each filter chain of a public listener is
|
||||||
// the authz filter to prevent unauthorized access.
|
// the authz filter to prevent unauthorized access.
|
||||||
func (s *ResourceGenerator) injectConnectFilters(cfgSnap *proxycfg.ConfigSnapshot, listener *envoy_listener_v3.Listener) error {
|
func (s *ResourceGenerator) injectConnectFilters(cfgSnap *proxycfg.ConfigSnapshot, listener *envoy_listener_v3.Listener) error {
|
||||||
|
@ -1221,6 +1238,7 @@ func (s *ResourceGenerator) makeInboundListener(cfgSnap *proxycfg.ConfigSnapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
l = makePortListener(name, addr, port, envoy_core_v3.TrafficDirection_INBOUND)
|
l = makePortListener(name, addr, port, envoy_core_v3.TrafficDirection_INBOUND)
|
||||||
|
s.injectConnectionBalanceConfig(cfg.BalanceInboundConnections, l)
|
||||||
|
|
||||||
var tracing *envoy_http_v3.HttpConnectionManager_Tracing
|
var tracing *envoy_http_v3.HttpConnectionManager_Tracing
|
||||||
if cfg.ListenerTracingJSON != "" {
|
if cfg.ListenerTracingJSON != "" {
|
||||||
|
|
|
@ -160,6 +160,22 @@ func TestListenersFromSnapshot(t *testing.T) {
|
||||||
}, nil)
|
}, nil)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "listener-balance-inbound-connections",
|
||||||
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||||
|
return proxycfg.TestConfigSnapshot(t, func(ns *structs.NodeService) {
|
||||||
|
ns.Proxy.Config["balance_inbound_connections"] = "exact_balance"
|
||||||
|
}, nil)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "listener-balance-outbound-connections-bind-port",
|
||||||
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||||
|
return proxycfg.TestConfigSnapshot(t, func(ns *structs.NodeService) {
|
||||||
|
ns.Proxy.Upstreams[0].Config["balance_outbound_connections"] = "exact_balance"
|
||||||
|
}, nil)
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "http-public-listener",
|
name: "http-public-listener",
|
||||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||||
|
|
122
agent/xds/testdata/listeners/listener-balance-inbound-connections.latest.golden
vendored
Normal file
122
agent/xds/testdata/listeners/listener-balance-inbound-connections.latest.golden
vendored
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
{
|
||||||
|
"versionInfo": "00000001",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "db:127.0.0.1:9191",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "127.0.0.1",
|
||||||
|
"portValue": 9191
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.tcp_proxy",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||||
|
"statPrefix": "upstream.db.default.default.dc1",
|
||||||
|
"cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "OUTBOUND"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "prepared_query:geo-cache:127.10.10.10:8181",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "127.10.10.10",
|
||||||
|
"portValue": 8181
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.tcp_proxy",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||||
|
"statPrefix": "upstream.prepared_query_geo-cache",
|
||||||
|
"cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "OUTBOUND"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "public_listener:0.0.0.0:9999",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "0.0.0.0",
|
||||||
|
"portValue": 9999
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.rbac",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.rbac.v3.RBAC",
|
||||||
|
"rules": {
|
||||||
|
|
||||||
|
},
|
||||||
|
"statPrefix": "connect_authz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.tcp_proxy",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||||
|
"statPrefix": "public_listener",
|
||||||
|
"cluster": "local_app"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"transportSocket": {
|
||||||
|
"name": "tls",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
|
||||||
|
"commonTlsContext": {
|
||||||
|
"tlsParams": {
|
||||||
|
|
||||||
|
},
|
||||||
|
"tlsCertificates": [
|
||||||
|
{
|
||||||
|
"certificateChain": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requireClientCertificate": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "INBOUND",
|
||||||
|
"connectionBalanceConfig": {
|
||||||
|
"exactBalance": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"nonce": "00000001"
|
||||||
|
}
|
122
agent/xds/testdata/listeners/listener-balance-outbound-connections-bind-port.latest.golden
vendored
Normal file
122
agent/xds/testdata/listeners/listener-balance-outbound-connections-bind-port.latest.golden
vendored
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
{
|
||||||
|
"versionInfo": "00000001",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "db:127.0.0.1:9191",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "127.0.0.1",
|
||||||
|
"portValue": 9191
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.tcp_proxy",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||||
|
"statPrefix": "upstream.db.default.default.dc1",
|
||||||
|
"cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "OUTBOUND",
|
||||||
|
"connectionBalanceConfig": {
|
||||||
|
"exactBalance": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "prepared_query:geo-cache:127.10.10.10:8181",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "127.10.10.10",
|
||||||
|
"portValue": 8181
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.tcp_proxy",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||||
|
"statPrefix": "upstream.prepared_query_geo-cache",
|
||||||
|
"cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "OUTBOUND"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "public_listener:0.0.0.0:9999",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "0.0.0.0",
|
||||||
|
"portValue": 9999
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.rbac",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.rbac.v3.RBAC",
|
||||||
|
"rules": {
|
||||||
|
|
||||||
|
},
|
||||||
|
"statPrefix": "connect_authz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.tcp_proxy",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||||
|
"statPrefix": "public_listener",
|
||||||
|
"cluster": "local_app"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"transportSocket": {
|
||||||
|
"name": "tls",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
|
||||||
|
"commonTlsContext": {
|
||||||
|
"tlsParams": {
|
||||||
|
|
||||||
|
},
|
||||||
|
"tlsCertificates": [
|
||||||
|
{
|
||||||
|
"certificateChain": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requireClientCertificate": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "INBOUND"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"nonce": "00000001"
|
||||||
|
}
|
|
@ -177,6 +177,10 @@ type UpstreamConfig struct {
|
||||||
|
|
||||||
// MeshGatewayConfig controls how Mesh Gateways are configured and used
|
// MeshGatewayConfig controls how Mesh Gateways are configured and used
|
||||||
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway" `
|
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway" `
|
||||||
|
|
||||||
|
// BalanceOutboundConnections indicates that the proxy should attempt to evenly distribute
|
||||||
|
// outbound connections across worker threads. Only used by envoy proxies.
|
||||||
|
BalanceOutboundConnections string `json:",omitempty" alias:"balance_outbound_connections"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DestinationConfig represents a virtual service, i.e. one that is external to Consul
|
// DestinationConfig represents a virtual service, i.e. one that is external to Consul
|
||||||
|
@ -223,24 +227,25 @@ type UpstreamLimits struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceConfigEntry struct {
|
type ServiceConfigEntry struct {
|
||||||
Kind string
|
Kind string
|
||||||
Name string
|
Name string
|
||||||
Partition string `json:",omitempty"`
|
Partition string `json:",omitempty"`
|
||||||
Namespace string `json:",omitempty"`
|
Namespace string `json:",omitempty"`
|
||||||
Protocol string `json:",omitempty"`
|
Protocol string `json:",omitempty"`
|
||||||
Mode ProxyMode `json:",omitempty"`
|
Mode ProxyMode `json:",omitempty"`
|
||||||
TransparentProxy *TransparentProxyConfig `json:",omitempty" alias:"transparent_proxy"`
|
TransparentProxy *TransparentProxyConfig `json:",omitempty" alias:"transparent_proxy"`
|
||||||
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
|
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
|
||||||
Expose ExposeConfig `json:",omitempty"`
|
Expose ExposeConfig `json:",omitempty"`
|
||||||
ExternalSNI string `json:",omitempty" alias:"external_sni"`
|
ExternalSNI string `json:",omitempty" alias:"external_sni"`
|
||||||
UpstreamConfig *UpstreamConfiguration `json:",omitempty" alias:"upstream_config"`
|
UpstreamConfig *UpstreamConfiguration `json:",omitempty" alias:"upstream_config"`
|
||||||
Destination *DestinationConfig `json:",omitempty"`
|
Destination *DestinationConfig `json:",omitempty"`
|
||||||
MaxInboundConnections int `json:",omitempty" alias:"max_inbound_connections"`
|
MaxInboundConnections int `json:",omitempty" alias:"max_inbound_connections"`
|
||||||
LocalConnectTimeoutMs int `json:",omitempty" alias:"local_connect_timeout_ms"`
|
LocalConnectTimeoutMs int `json:",omitempty" alias:"local_connect_timeout_ms"`
|
||||||
LocalRequestTimeoutMs int `json:",omitempty" alias:"local_request_timeout_ms"`
|
LocalRequestTimeoutMs int `json:",omitempty" alias:"local_request_timeout_ms"`
|
||||||
Meta map[string]string `json:",omitempty"`
|
BalanceInboundConnections string `json:",omitempty" alias:"balance_inbound_connections"`
|
||||||
CreateIndex uint64
|
Meta map[string]string `json:",omitempty"`
|
||||||
ModifyIndex uint64
|
CreateIndex uint64
|
||||||
|
ModifyIndex uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceConfigEntry) GetKind() string { return s.Kind }
|
func (s *ServiceConfigEntry) GetKind() string { return s.Kind }
|
||||||
|
|
|
@ -104,9 +104,10 @@ func TestAPI_ConfigEntries(t *testing.T) {
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"gir": "zim",
|
"gir": "zim",
|
||||||
},
|
},
|
||||||
MaxInboundConnections: 5,
|
MaxInboundConnections: 5,
|
||||||
LocalConnectTimeoutMs: 5000,
|
BalanceInboundConnections: "exact_balance",
|
||||||
LocalRequestTimeoutMs: 7000,
|
LocalConnectTimeoutMs: 5000,
|
||||||
|
LocalRequestTimeoutMs: 7000,
|
||||||
}
|
}
|
||||||
|
|
||||||
dest := &DestinationConfig{
|
dest := &DestinationConfig{
|
||||||
|
@ -148,6 +149,7 @@ func TestAPI_ConfigEntries(t *testing.T) {
|
||||||
require.Equal(t, service.Meta, readService.Meta)
|
require.Equal(t, service.Meta, readService.Meta)
|
||||||
require.Equal(t, service.Meta, readService.GetMeta())
|
require.Equal(t, service.Meta, readService.GetMeta())
|
||||||
require.Equal(t, service.MaxInboundConnections, readService.MaxInboundConnections)
|
require.Equal(t, service.MaxInboundConnections, readService.MaxInboundConnections)
|
||||||
|
require.Equal(t, service.BalanceInboundConnections, readService.BalanceInboundConnections)
|
||||||
require.Equal(t, service.LocalConnectTimeoutMs, readService.LocalConnectTimeoutMs)
|
require.Equal(t, service.LocalConnectTimeoutMs, readService.LocalConnectTimeoutMs)
|
||||||
require.Equal(t, service.LocalRequestTimeoutMs, readService.LocalRequestTimeoutMs)
|
require.Equal(t, service.LocalRequestTimeoutMs, readService.LocalRequestTimeoutMs)
|
||||||
|
|
||||||
|
@ -446,6 +448,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
"OutboundListenerPort": 808,
|
"OutboundListenerPort": 808,
|
||||||
"DialedDirectly": true
|
"DialedDirectly": true
|
||||||
},
|
},
|
||||||
|
"BalanceInboundConnections": "exact_balance",
|
||||||
"UpstreamConfig": {
|
"UpstreamConfig": {
|
||||||
"Overrides": [
|
"Overrides": [
|
||||||
{
|
{
|
||||||
|
@ -454,7 +457,8 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
"MaxFailures": 3,
|
"MaxFailures": 3,
|
||||||
"Interval": "2s",
|
"Interval": "2s",
|
||||||
"EnforcingConsecutive5xx": 60
|
"EnforcingConsecutive5xx": 60
|
||||||
}
|
},
|
||||||
|
"BalanceOutboundConnections": "exact_balance"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "finance--billing",
|
"Name": "finance--billing",
|
||||||
|
@ -498,6 +502,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
OutboundListenerPort: 808,
|
OutboundListenerPort: 808,
|
||||||
DialedDirectly: true,
|
DialedDirectly: true,
|
||||||
},
|
},
|
||||||
|
BalanceInboundConnections: "exact_balance",
|
||||||
UpstreamConfig: &UpstreamConfiguration{
|
UpstreamConfig: &UpstreamConfiguration{
|
||||||
Overrides: []*UpstreamConfig{
|
Overrides: []*UpstreamConfig{
|
||||||
{
|
{
|
||||||
|
@ -507,6 +512,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
Interval: 2 * time.Second,
|
Interval: 2 * time.Second,
|
||||||
EnforcingConsecutive5xx: uint32Pointer(60),
|
EnforcingConsecutive5xx: uint32Pointer(60),
|
||||||
},
|
},
|
||||||
|
BalanceOutboundConnections: "exact_balance",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "finance--billing",
|
Name: "finance--billing",
|
||||||
|
|
|
@ -355,6 +355,15 @@ represents a location outside the Consul cluster. They can be dialed directly wh
|
||||||
[\`service-intentions\`](/docs/connect/config-entries/service-intentions).
|
[\`service-intentions\`](/docs/connect/config-entries/service-intentions).
|
||||||
Supported values are one of \`tcp\`, \`http\`, \`http2\`, or \`grpc\`.`,
|
Supported values are one of \`tcp\`, \`http\`, \`http2\`, or \`grpc\`.`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'BalanceInboundConnections',
|
||||||
|
type: `string: ""`,
|
||||||
|
description: `Sets the strategy for allocating inbound connections to the service across proxy threads.
|
||||||
|
The only supported value is \`exact_balance\`. By default, no connection balancing is used.
|
||||||
|
Refer to the
|
||||||
|
[Envoy Connection Balance config](https://cloudnative.to/envoy/api-v3/config/listener/v3/listener.proto.html#config-listener-v3-listener-connectionbalanceconfig)
|
||||||
|
for details.`
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'Mode',
|
name: 'Mode',
|
||||||
type: `string: ""`,
|
type: `string: ""`,
|
||||||
|
@ -445,6 +454,15 @@ represents a location outside the Consul cluster. They can be dialed directly wh
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'BalanceOutboundConnections',
|
||||||
|
type: `string: ""`,
|
||||||
|
description: `Sets the strategy for allocating outbound connections from the upstream across proxy threads.
|
||||||
|
The only supported value is \`exact_balance\`. By default, no connection balancing is used.
|
||||||
|
Refer to the
|
||||||
|
[Envoy Connection Balance config](https://cloudnative.to/envoy/api-v3/config/listener/v3/listener.proto.html#config-listener-v3-listener-connectionbalanceconfig)
|
||||||
|
for details.`
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'Limits',
|
name: 'Limits',
|
||||||
type: 'Limits: <optional>',
|
type: 'Limits: <optional>',
|
||||||
|
@ -587,6 +605,15 @@ represents a location outside the Consul cluster. They can be dialed directly wh
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'BalanceOutboundConnections',
|
||||||
|
type: `string: ""`,
|
||||||
|
description: `Sets the strategy for allocating outbound connections from the upstream across proxy threads.
|
||||||
|
The only supported value is \`exact_balance\`. By default, no connection balancing is used.
|
||||||
|
Refer to the
|
||||||
|
[Envoy Connection Balance config](https://cloudnative.to/envoy/api-v3/config/listener/v3/listener.proto.html#config-listener-v3-listener-connectionbalanceconfig)
|
||||||
|
for details.`
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'Limits',
|
name: 'Limits',
|
||||||
type: 'Limits: <optional>',
|
type: 'Limits: <optional>',
|
||||||
|
|
|
@ -254,6 +254,14 @@ defaults that are inherited by all services.
|
||||||
specified, inherits the Envoy default for route timeouts (15s). A value of 0 will
|
specified, inherits the Envoy default for route timeouts (15s). A value of 0 will
|
||||||
disable request timeouts.
|
disable request timeouts.
|
||||||
|
|
||||||
|
- `balance_inbound_connections` - The strategy used for balancing inbound connections
|
||||||
|
across Envoy worker threads. Consul service mesh Envoy integration supports the
|
||||||
|
following `balance_inbound_connections` values:
|
||||||
|
|
||||||
|
- `""` - Empty string (default). No connection balancing strategy is used. Consul does not balance inbound connections.
|
||||||
|
- `exact_balance` - Inbound connections to the service use the
|
||||||
|
[Envoy Exact Balance Strategy.](https://cloudnative.to/envoy/api-v3/config/listener/v3/listener.proto.html#config-listener-v3-listener-connectionbalanceconfig-exactbalance)
|
||||||
|
|
||||||
### Proxy Upstream Config Options
|
### Proxy Upstream Config Options
|
||||||
|
|
||||||
The following configuration items may be overridden directly in the
|
The following configuration items may be overridden directly in the
|
||||||
|
@ -313,6 +321,14 @@ definition](/docs/connect/registration/service-registration) or
|
||||||
- `enforcing_consecutive_5xx` - The % chance that a host will be actually ejected
|
- `enforcing_consecutive_5xx` - The % chance that a host will be actually ejected
|
||||||
when an outlier status is detected through consecutive 5xx.
|
when an outlier status is detected through consecutive 5xx.
|
||||||
|
|
||||||
|
- `balance_outbound_connections` - Specifies the strategy for balancing outbound connections
|
||||||
|
across Envoy worker threads. Consul service mesh Envoy integration supports the
|
||||||
|
following `balance_outbound_connections` values:
|
||||||
|
|
||||||
|
- `""` - Empty string (default). No connection balancing strategy is used. Consul does not balance outbound connections.
|
||||||
|
- `exact_balance` - Outbound connections from the upstream use the
|
||||||
|
[Envoy Exact Balance Strategy.](https://cloudnative.to/envoy/api-v3/config/listener/v3/listener.proto.html#config-listener-v3-listener-connectionbalanceconfig-exactbalance)
|
||||||
|
|
||||||
### Gateway Options
|
### Gateway Options
|
||||||
|
|
||||||
These fields may also be overridden explicitly in the [proxy service
|
These fields may also be overridden explicitly in the [proxy service
|
||||||
|
|
Loading…
Reference in New Issue