Skip to content

Commit 9962471

Browse files
Enable leader election on endpoints for controllers
Support the new upstream module for leader election via a new config field and command line flag (--lock-service-name). If specified, the new style election will be used. The legacy etcd election (triggered by controllerTTL > 0) will wait to verify no endpoint object exists before competing for the etcd lease, and will step down if it detects the endpoint object is created. With these changes, the controllers can now be run as static pods on the masters and talk only to the API. This will allow them to appear in the api and be scraped by prometheus.
1 parent 5468a46 commit 9962471

File tree

14 files changed

+319
-47
lines changed

14 files changed

+319
-47
lines changed

contrib/completions/bash/openshift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35173,6 +35173,8 @@ _openshift_start_master_controllers()
3517335173
local_nonpersistent_flags+=("--config=")
3517435174
flags+=("--listen=")
3517535175
local_nonpersistent_flags+=("--listen=")
35176+
flags+=("--lock-service-name=")
35177+
local_nonpersistent_flags+=("--lock-service-name=")
3517635178
flags+=("--azure-container-registry-config=")
3517735179
flags+=("--google-json-key=")
3517835180
flags+=("--log-flush-frequency=")

contrib/completions/zsh/openshift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35322,6 +35322,8 @@ _openshift_start_master_controllers()
3532235322
local_nonpersistent_flags+=("--config=")
3532335323
flags+=("--listen=")
3532435324
local_nonpersistent_flags+=("--listen=")
35325+
flags+=("--lock-service-name=")
35326+
local_nonpersistent_flags+=("--lock-service-name=")
3532535327
flags+=("--azure-container-registry-config=")
3532635328
flags+=("--google-json-key=")
3532735329
flags+=("--log-flush-frequency=")

contrib/kubernetes/controllers.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
apiVersion: v1
2+
kind: Pod
3+
metadata:
4+
name: controllers
5+
labels:
6+
master.openshift.io/controllers: 'true'
7+
spec:
8+
containers:
9+
- name: controller
10+
image: openshift/origin:latest
11+
args:
12+
- start
13+
- master
14+
- controllers
15+
- --listen=0.0.0.0:8444
16+
- --config=/etc/origin/master/master-config.yaml
17+
volumeMounts:
18+
- name: config
19+
mountPath: /etc/origin/master
20+
ports:
21+
- containerPort: 8444
22+
name: https
23+
volumes:
24+
- hostPath:
25+
path: /data/src/github.com/openshift/origin/openshift.local.test/master
26+
name: config

pkg/cmd/server/api/serialization_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ func fuzzInternalObject(t *testing.T, forVersion schema.GroupVersion, item runti
4343
if len(obj.Controllers) == 0 {
4444
obj.Controllers = configapi.ControllersAll
4545
}
46+
if election := obj.ControllerConfig.Election; election != nil {
47+
if len(election.LockNamespace) == 0 {
48+
election.LockNamespace = "kube-system"
49+
}
50+
if len(election.LockResource.Group) == 0 && len(election.LockResource.Resource) == 0 {
51+
election.LockResource.Resource = "endpoints"
52+
}
53+
}
4654
if obj.ServingInfo.RequestTimeoutSeconds == 0 {
4755
obj.ServingInfo.RequestTimeoutSeconds = 60 * 60
4856
}

pkg/cmd/server/api/types.go

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -334,12 +334,14 @@ type MasterConfig struct {
334334
Controllers string
335335
// PauseControllers instructs the master to not automatically start controllers, but instead
336336
// to wait until a notification to the server is received before launching them.
337-
// TODO: will be disabled in function for 1.1.
337+
// Deprecated: Will be removed in 3.7.
338338
PauseControllers bool
339-
// ControllerLeaseTTL enables controller election, instructing the master to attempt to acquire
340-
// a lease before controllers start and renewing it within a number of seconds defined by this value.
341-
// Setting this value non-negative forces pauseControllers=true. This value defaults off (0, or
339+
// ControllerLeaseTTL enables controller election against etcd, instructing the master to attempt to
340+
// acquire a lease before controllers start and renewing it within a number of seconds defined by this
341+
// value. Setting this value non-negative forces pauseControllers=true. This value defaults off (0, or
342342
// omitted) and controller election can be disabled with -1.
343+
// Deprecated: use controllerConfig.lockServiceName to force leader election via config, and the
344+
// appropriate leader election flags in controllerArguments. Will be removed in 3.9.
343345
ControllerLeaseTTL int
344346
// TODO: the next field added to controllers must be added to a new controllers struct
345347

@@ -1393,11 +1395,37 @@ type AdmissionConfig struct {
13931395

13941396
// ControllerConfig holds configuration values for controllers
13951397
type ControllerConfig struct {
1398+
// Election defines the configuration for electing a controller instance to make changes to
1399+
// the cluster. If unspecified, the ControllerTTL value is checked to determine whether the
1400+
// legacy direct etcd election code will be used.
1401+
Election *ControllerElectionConfig
13961402
// ServiceServingCert holds configuration for service serving cert signer which creates cert/key pairs for
13971403
// pods fulfilling a service to serve with.
13981404
ServiceServingCert ServiceServingCert
13991405
}
14001406

1407+
// ControllerElectionConfig contains configuration values for deciding how a controller
1408+
// will be elected to act as leader.
1409+
type ControllerElectionConfig struct {
1410+
// LockName is the resource name used to act as the lock for determining which controller
1411+
// instance should lead.
1412+
LockName string
1413+
// LockNamespace is the resource namespace used to act as the lock for determining which
1414+
// controller instance should lead. It defaults to "kube-system"
1415+
LockNamespace string
1416+
// LockResource is the group and resource name to use to coordinate for the controller lock.
1417+
// If unset, defaults to "endpoints".
1418+
LockResource GroupResource
1419+
}
1420+
1421+
// GroupResource points to a resource by its name and API group.
1422+
type GroupResource struct {
1423+
// Group is the name of an API group
1424+
Group string
1425+
// Resource is the name of a resource.
1426+
Resource string
1427+
}
1428+
14011429
// ServiceServingCert holds configuration for service serving cert signer which creates cert/key pairs for
14021430
// pods fulfilling a service to serve with.
14031431
type ServiceServingCert struct {

pkg/cmd/server/api/v1/conversions.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error {
2020
if len(obj.Controllers) == 0 {
2121
obj.Controllers = ControllersAll
2222
}
23+
if election := obj.ControllerConfig.Election; election != nil {
24+
if len(election.LockNamespace) == 0 {
25+
election.LockNamespace = "kube-system"
26+
}
27+
if len(election.LockResource.Group) == 0 && len(election.LockResource.Resource) == 0 {
28+
election.LockResource.Resource = "endpoints"
29+
}
30+
}
2331
if obj.ServingInfo.RequestTimeoutSeconds == 0 {
2432
obj.ServingInfo.RequestTimeoutSeconds = 60 * 60
2533
}

pkg/cmd/server/api/v1/swagger_doc.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,25 @@ func (ClientConnectionOverrides) SwaggerDoc() map[string]string {
133133

134134
var map_ControllerConfig = map[string]string{
135135
"": "ControllerConfig holds configuration values for controllers",
136+
"election": "Election defines the configuration for electing a controller instance to make changes to the cluster. If unspecified, the ControllerTTL value is checked to determine whether the legacy direct etcd election code will be used.",
136137
"serviceServingCert": "ServiceServingCert holds configuration for service serving cert signer which creates cert/key pairs for pods fulfilling a service to serve with.",
137138
}
138139

139140
func (ControllerConfig) SwaggerDoc() map[string]string {
140141
return map_ControllerConfig
141142
}
142143

144+
var map_ControllerElectionConfig = map[string]string{
145+
"": "ControllerElectionConfig contains configuration values for deciding how a controller will be elected to act as leader.",
146+
"lockName": "LockName is the resource name used to act as the lock for determining which controller instance should lead.",
147+
"lockNamespace": "LockNamespace is the resource namespace used to act as the lock for determining which controller instance should lead. It defaults to \"kube-system\"",
148+
"lockResource": "LockResource is the group and resource name to use to coordinate for the controller lock. If unset, defaults to \"Endpoints\".",
149+
}
150+
151+
func (ControllerElectionConfig) SwaggerDoc() map[string]string {
152+
return map_ControllerElectionConfig
153+
}
154+
143155
var map_DNSConfig = map[string]string{
144156
"": "DNSConfig holds the necessary configuration options for DNS",
145157
"bindAddress": "BindAddress is the ip:port to serve DNS on",
@@ -259,6 +271,16 @@ func (GrantConfig) SwaggerDoc() map[string]string {
259271
return map_GrantConfig
260272
}
261273

274+
var map_GroupResource = map[string]string{
275+
"": "GroupResource points to a resource by its name and API group.",
276+
"group": "Group is the name of an API group",
277+
"resource": "Resource is the name of a resource.",
278+
}
279+
280+
func (GroupResource) SwaggerDoc() map[string]string {
281+
return map_GroupResource
282+
}
283+
262284
var map_HTPasswdPasswordIdentityProvider = map[string]string{
263285
"": "HTPasswdPasswordIdentityProvider provides identities for users authenticating using htpasswd credentials",
264286
"file": "File is a reference to your htpasswd file",
@@ -463,8 +485,8 @@ var map_MasterConfig = map[string]string{
463485
"apiLevels": "APILevels is a list of API levels that should be enabled on startup: v1 as examples",
464486
"masterPublicURL": "MasterPublicURL is how clients can access the OpenShift API server",
465487
"controllers": "Controllers is a list of the controllers that should be started. If set to \"none\", no controllers will start automatically. The default value is \"*\" which will start all controllers. When using \"*\", you may exclude controllers by prepending a \"-\" in front of their name. No other values are recognized at this time.",
466-
"pauseControllers": "PauseControllers instructs the master to not automatically start controllers, but instead to wait until a notification to the server is received before launching them.",
467-
"controllerLeaseTTL": "ControllerLeaseTTL enables controller election, instructing the master to attempt to acquire a lease before controllers start and renewing it within a number of seconds defined by this value. Setting this value non-negative forces pauseControllers=true. This value defaults off (0, or omitted) and controller election can be disabled with -1.",
488+
"pauseControllers": "PauseControllers instructs the master to not automatically start controllers, but instead to wait until a notification to the server is received before launching them. This field is ignored if controllerConfig.lockServiceName is specified. Deprecated: Will be removed in 3.7.",
489+
"controllerLeaseTTL": "ControllerLeaseTTL enables controller election against etcd, instructing the master to attempt to acquire a lease before controllers start and renewing it within a number of seconds defined by this value. Setting this value non-negative forces pauseControllers=true. This value defaults off (0, or omitted) and controller election can be disabled with -1. This field is ignored if controllerConfig.lockServiceName is specified. Deprecated: use controllerConfig.lockServiceName to force leader election via config, and the\n appropriate leader election flags in controllerArguments. Will be removed in 3.9.",
468490
"admissionConfig": "AdmissionConfig contains admission control plugin configuration.",
469491
"controllerConfig": "ControllerConfig holds configuration values for controllers",
470492
"disabledFeatures": "DisabledFeatures is a list of features that should not be started. We omitempty here because its very unlikely that anyone will want to manually disable features and we don't want to encourage it.",

pkg/cmd/server/api/v1/types.go

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,12 +197,17 @@ type MasterConfig struct {
197197
// values are recognized at this time.
198198
Controllers string `json:"controllers"`
199199
// PauseControllers instructs the master to not automatically start controllers, but instead
200-
// to wait until a notification to the server is received before launching them.
200+
// to wait until a notification to the server is received before launching them. This field is
201+
// ignored if controllerConfig.lockServiceName is specified.
202+
// Deprecated: Will be removed in 3.7.
201203
PauseControllers bool `json:"pauseControllers"`
202-
// ControllerLeaseTTL enables controller election, instructing the master to attempt to acquire
203-
// a lease before controllers start and renewing it within a number of seconds defined by this value.
204-
// Setting this value non-negative forces pauseControllers=true. This value defaults off (0, or
205-
// omitted) and controller election can be disabled with -1.
204+
// ControllerLeaseTTL enables controller election against etcd, instructing the master to attempt to
205+
// acquire a lease before controllers start and renewing it within a number of seconds defined by this
206+
// value. Setting this value non-negative forces pauseControllers=true. This value defaults off (0, or
207+
// omitted) and controller election can be disabled with -1. This field is ignored if
208+
// controllerConfig.lockServiceName is specified.
209+
// Deprecated: use controllerConfig.lockServiceName to force leader election via config, and the
210+
// appropriate leader election flags in controllerArguments. Will be removed in 3.9.
206211
ControllerLeaseTTL int `json:"controllerLeaseTTL"`
207212

208213
// AdmissionConfig contains admission control plugin configuration.
@@ -1327,11 +1332,37 @@ type AdmissionConfig struct {
13271332

13281333
// ControllerConfig holds configuration values for controllers
13291334
type ControllerConfig struct {
1335+
// Election defines the configuration for electing a controller instance to make changes to
1336+
// the cluster. If unspecified, the ControllerTTL value is checked to determine whether the
1337+
// legacy direct etcd election code will be used.
1338+
Election *ControllerElectionConfig `json:"election"`
13301339
// ServiceServingCert holds configuration for service serving cert signer which creates cert/key pairs for
13311340
// pods fulfilling a service to serve with.
13321341
ServiceServingCert ServiceServingCert `json:"serviceServingCert"`
13331342
}
13341343

1344+
// ControllerElectionConfig contains configuration values for deciding how a controller
1345+
// will be elected to act as leader.
1346+
type ControllerElectionConfig struct {
1347+
// LockName is the resource name used to act as the lock for determining which controller
1348+
// instance should lead.
1349+
LockName string `json:"lockName"`
1350+
// LockNamespace is the resource namespace used to act as the lock for determining which
1351+
// controller instance should lead. It defaults to "kube-system"
1352+
LockNamespace string `json:"lockNamespace"`
1353+
// LockResource is the group and resource name to use to coordinate for the controller lock.
1354+
// If unset, defaults to "Endpoints".
1355+
LockResource GroupResource `json:"lockResource"`
1356+
}
1357+
1358+
// GroupResource points to a resource by its name and API group.
1359+
type GroupResource struct {
1360+
// Group is the name of an API group
1361+
Group string `json:"group"`
1362+
// Resource is the name of a resource.
1363+
Resource string `json:"resource"`
1364+
}
1365+
13351366
// ServiceServingCert holds configuration for service serving cert signer which creates cert/key pairs for
13361367
// pods fulfilling a service to serve with.
13371368
type ServiceServingCert struct {

pkg/cmd/server/api/v1/types_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ auditConfig:
118118
authConfig:
119119
requestHeader: null
120120
controllerConfig:
121+
election: null
121122
serviceServingCert:
122123
signer: null
123124
controllerLeaseTTL: 0

pkg/cmd/server/api/validation/master.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,23 @@ func ValidateAuditConfig(config api.AuditConfig, fldPath *field.Path) Validation
249249
func ValidateControllerConfig(config api.ControllerConfig, fldPath *field.Path) ValidationResults {
250250
validationResults := ValidationResults{}
251251

252+
if election := config.Election; election != nil {
253+
if len(election.LockName) == 0 {
254+
validationResults.AddErrors(field.Invalid(fldPath.Child("election", "lockName"), election.LockName, "may not be empty"))
255+
}
256+
for _, msg := range kvalidation.ValidateServiceName(election.LockName, false) {
257+
validationResults.AddErrors(field.Invalid(fldPath.Child("election", "lockName"), election.LockName, msg))
258+
}
259+
if len(election.LockNamespace) == 0 {
260+
validationResults.AddErrors(field.Invalid(fldPath.Child("election", "lockNamespace"), election.LockNamespace, "may not be empty"))
261+
}
262+
for _, msg := range kvalidation.ValidateNamespaceName(election.LockNamespace, false) {
263+
validationResults.AddErrors(field.Invalid(fldPath.Child("election", "lockNamespace"), election.LockNamespace, msg))
264+
}
265+
if len(election.LockResource.Resource) == 0 {
266+
validationResults.AddErrors(field.Invalid(fldPath.Child("election", "lockResource", "resource"), election.LockResource.Resource, "may not be empty"))
267+
}
268+
}
252269
if config.ServiceServingCert.Signer != nil {
253270
validationResults.AddErrors(ValidateCertInfo(*config.ServiceServingCert.Signer, true, fldPath.Child("serviceServingCert.signer"))...)
254271
}

0 commit comments

Comments
 (0)