Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement object assignments in webhook #30

Merged
merged 14 commits into from
Nov 15, 2023
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
*.secret*
.envrc
hack/kind_kubeconfig.yaml
.gitguardian.yaml

# Binaries for programs and plugins
*.exe
Expand Down
16 changes: 16 additions & 0 deletions .run/shard (kind).run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="shard (kind)" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="kubernetes-controller-sharding" />
<working_directory value="$PROJECT_DIR$" />
<parameters value="--zap-log-level=debug --shard=shard-host" />
<envs>
<env name="LEADER_ELECT" value="false" />
<env name="KUBECONFIG" value="$PROJECT_DIR$/hack/kind_kubeconfig.yaml" />
</envs>
<kind value="PACKAGE" />
<package value="github.com/timebertt/kubernetes-controller-sharding/hack/cmd/shard" />
<directory value="$PROJECT_DIR$" />
<filePath value="$PROJECT_DIR$/webhosting-operator/cmd/experiment/main.go" />
<method v="2" />
</configuration>
</component>
3 changes: 2 additions & 1 deletion .run/sharder (kind).run.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<configuration default="false" name="sharder (kind)" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="kubernetes-controller-sharding" />
<working_directory value="$PROJECT_DIR$" />
<parameters value="--config=hack/config/sharder/host/config.yaml --zap-log-level=debug" />
<envs>
<env name="LEADER_ELECT" value="false" />
<env name="KUBECONFIG" value="$PROJECT_DIR$/hack/kind_kubeconfig.yaml" />
Expand All @@ -12,4 +13,4 @@
<filePath value="$PROJECT_DIR$/webhosting-operator/cmd/experiment/main.go" />
<method v="2" />
</configuration>
</component>
</component>
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,13 @@ clean-tools-bin: ## Empty the tools binary directory
modules: ## Runs go mod to ensure modules are up to date.
go mod tidy

.PHONY: generate
generate: $(CONTROLLER_GEN) modules ## Run all code generators
.PHONY: generate-fast
generate-fast: $(CONTROLLER_GEN) modules ## Run all fast code generators
$(CONTROLLER_GEN) rbac:roleName=sharder crd paths="./pkg/..." output:rbac:artifacts:config=config/rbac output:crd:artifacts:config=config/crds
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./pkg/..."

.PHONY: generate
generate: generate-fast modules ## Run all code generators
hack/update-codegen.sh

.PHONY: fmt
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,10 @@ Read chapter 4 of the full [thesis](https://github.com/timebertt/thesis-controll

- [docs](docs):
- [getting started with controller sharding](docs/getting-started.md)
- [sharder](cmd/sharder): the main sharding component orchestrating sharding
- [shard](hack/cmd/shard): a simple dummy controller that implements the requirements for sharded controllers (used for development and testing purposes)
- [webhosting-operator](webhosting-operator): a sample operator for demonstrating and evaluating the implemented sharding design for Kubernetes controllers
- [samples-generator](webhosting-operator/cmd/samples-generator): a tool for generating a given amount of random `Website` objects
- [samples-generator](webhosting-operator/cmd/samples-generator): a tool for generating a given number of random `Website` objects
- [monitoring setup](hack/config/monitoring): a setup for monitoring and measuring load test experiments for the sample operator
- includes [kube-prometheus](https://github.com/prometheus-operator/kube-prometheus)
- [sharding-exporter](config/monitoring/sharding-exporter): (based on the [kube-state-metrics](https://github.com/kubernetes/kube-state-metrics) [custom resource metrics feature](https://github.com/kubernetes/kube-state-metrics/blob/main/docs/customresourcestate-metrics.md)) for metrics on the state of shards
Expand Down
5 changes: 4 additions & 1 deletion cmd/sharder/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/manager"

"github.com/timebertt/kubernetes-controller-sharding/pkg/controller"
"github.com/timebertt/kubernetes-controller-sharding/pkg/sharding/ring"
healthzutils "github.com/timebertt/kubernetes-controller-sharding/pkg/utils/healthz"
"github.com/timebertt/kubernetes-controller-sharding/pkg/webhook"
)
Expand Down Expand Up @@ -104,13 +105,15 @@ func run(ctx context.Context, log logr.Logger, opts *options) error {
return err
}

ringCache := ring.NewCache()

log.Info("Adding controllers to manager")
if err := controller.AddToManager(ctx, mgr, opts.config); err != nil {
return fmt.Errorf("failed adding controllers to manager: %w", err)
}

log.Info("Adding webhooks to manager")
if err := webhook.AddToManager(ctx, mgr, opts.config); err != nil {
if err := webhook.AddToManager(ctx, mgr, ringCache, opts.config); err != nil {
return fmt.Errorf("failed adding webhooks to manager: %w", err)
}

Expand Down
9 changes: 9 additions & 0 deletions cmd/sharder/app/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
"sigs.k8s.io/controller-runtime/pkg/webhook"

configv1alpha1 "github.com/timebertt/kubernetes-controller-sharding/pkg/apis/config/v1alpha1"
shardingv1alpha1 "github.com/timebertt/kubernetes-controller-sharding/pkg/apis/sharding/v1alpha1"
Expand Down Expand Up @@ -171,6 +172,14 @@ func (o *options) applyConfigToManagerOptions() {
}
}

webhookOptions := webhook.Options{}
if serverConfig := o.config.Webhook.Server; serverConfig != nil {
webhookOptions.CertDir = ptr.Deref(serverConfig.CertDir, "")
webhookOptions.CertName = ptr.Deref(serverConfig.CertName, "")
webhookOptions.KeyName = ptr.Deref(serverConfig.KeyName, "")
}
o.managerOptions.WebhookServer = webhook.NewServer(webhookOptions)

o.managerOptions.GracefulShutdownTimeout = ptr.To(o.config.GracefulShutdownTimeout.Duration)
}

Expand Down
13 changes: 13 additions & 0 deletions config/certificate/certificate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: webhook-server
spec:
issuerRef:
name: selfsigned
commonName: sharding:sharder:webhook
dnsNames:
- sharder.sharding-system
- sharder.sharding-system.svc
- sharder.sharding-system.svc.cluster.local
secretName: webhook-server
6 changes: 6 additions & 0 deletions config/certificate/issuer.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned
spec:
selfSigned: {}
26 changes: 26 additions & 0 deletions config/certificate/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component

resources:
- certificate.yaml
- issuer.yaml

patches:
- patch: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: sharder
namespace: sharding-system
spec:
template:
spec:
containers:
- name: sharder
volumeMounts:
- name: cert
mountPath: /tmp/k8s-webhook-server/serving-certs
volumes:
- name: cert
secret:
secretName: webhook-server
138 changes: 110 additions & 28 deletions config/crds/sharding.timebertt.dev_clusterrings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ spec:
scope: Cluster
versions:
- additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type == "Ready")].status
name: Ready
type: string
- jsonPath: .status.availableShards
name: Available
type: string
Expand Down Expand Up @@ -47,49 +50,54 @@ spec:
description: Spec contains the specification of the desired behavior of
the ClusterRing.
properties:
kinds:
description: Kinds specifies the list of object kinds that are distributed
resources:
description: Resources specifies the list of resources that are distributed
across shards in this ClusterRing.
items:
description: ClusterRingKind specifies an object kind that is distributed
across shards in the ClusterRing. This kind is the controller's
main kind, i.e., the kind of which it updates the object status.
description: RingResource specifies a resource along with controlled
resources that is distributed across shards in a ring.
properties:
apiGroup:
description: APIGroup is the API group of the object. Specify
"" for the core API group.
type: string
controlledKinds:
description: ControlledKinds are additional object kinds that
are distributed across shards in the ClusterRing. These kinds
are controlled by the controller's main kind, i.e., they have
an owner reference with controller=true back to the object
kind of this ClusterRingKind. Typically, the controller also
watches objects of this kind and enqueues the owning object
(of the main kind) whenever the status of a controlled object
controlledResources:
description: ControlledResources are additional resources that
are distributed across shards in the ClusterRing. These resources
are controlled by the controller's main resource, i.e., they
have an owner reference with controller=true back to the GroupResource
of this RingResource. Typically, the controller also watches
objects of this resource and enqueues the owning object (of
the main resource) whenever the status of a controlled object
changes.
items:
description: ObjectKind specifies an object kind that is distributed
across shards in the ClusterRing.
description: GroupResource specifies a Group and a Resource,
but does not force a version. This is useful for identifying
concepts during lookup stages without having partially valid
types
properties:
apiGroup:
description: APIGroup is the API group of the object.
Specify "" for the core API group.
group:
type: string
kind:
description: Kind is the kind of the object.
resource:
type: string
required:
- kind
- group
- resource
type: object
type: array
kind:
description: Kind is the kind of the object.
x-kubernetes-list-map-keys:
- group
- resource
x-kubernetes-list-type: map
group:
type: string
resource:
type: string
required:
- kind
- group
- resource
type: object
type: array
x-kubernetes-list-map-keys:
- group
- resource
x-kubernetes-list-type: map
type: object
status:
description: Status contains the most recently observed status of the
Expand All @@ -100,6 +108,80 @@ spec:
of this ring.
format: int32
type: integer
conditions:
description: 'Conditions represents the observations of a foo''s current
state. Known .status.conditions.type are: "Available", "Progressing",
and "Degraded"'
items:
description: "Condition contains details for one aspect of the current
state of this API Resource. --- This struct is intended for direct
use as an array at the field path .status.conditions. For example,
\n type FooStatus struct{ // Represents the observations of a
foo's current state. // Known .status.conditions.type are: \"Available\",
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
// +listType=map // +listMapKey=type Conditions []metav1.Condition
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
properties:
lastTransitionTime:
description: lastTransitionTime is the last time the condition
transitioned from one status to another. This should be when
the underlying condition changed. If that is not known, then
using the time when the API field changed is acceptable.
format: date-time
type: string
message:
description: message is a human readable message indicating
details about the transition. This may be an empty string.
maxLength: 32768
type: string
observedGeneration:
description: observedGeneration represents the .metadata.generation
that the condition was set based upon. For instance, if .metadata.generation
is currently 12, but the .status.conditions[x].observedGeneration
is 9, the condition is out of date with respect to the current
state of the instance.
format: int64
minimum: 0
type: integer
reason:
description: reason contains a programmatic identifier indicating
the reason for the condition's last transition. Producers
of specific condition types may define expected values and
meanings for this field, and whether the values are considered
a guaranteed API. The value should be a CamelCase string.
This field may not be empty.
maxLength: 1024
minLength: 1
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
type: string
status:
description: status of the condition, one of True, False, Unknown.
enum:
- "True"
- "False"
- Unknown
type: string
type:
description: type of condition in CamelCase or in foo.example.com/CamelCase.
--- Many .condition.type values are consistent across resources
like Available, but because arbitrary conditions can be useful
(see .node.status.conditions), the ability to deconflict is
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
type: string
required:
- lastTransitionTime
- message
- reason
- status
- type
type: object
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
observedGeneration:
description: The generation observed by the ClusterRing controller.
format: int64
Expand Down
4 changes: 4 additions & 0 deletions config/default/config.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
apiVersion: config.sharding.timebertt.dev/v1alpha1
kind: SharderConfig
webhook:
config:
annotations:
cert-manager.io/inject-ca-from: sharding-system/webhook-server
3 changes: 3 additions & 0 deletions config/default/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ spec:
- name: DISABLE_HTTP2
value: "true"
ports:
- name: webhook
containerPort: 9443
protocol: TCP
- name: metrics
containerPort: 8080
protocol: TCP
Expand Down
3 changes: 3 additions & 0 deletions config/default/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ resources:
- ../rbac
- ../crds

components:
- ../certificate

configMapGenerator:
- name: sharder-config
options:
Expand Down
4 changes: 4 additions & 0 deletions config/default/service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ spec:
selector:
app.kubernetes.io/component: sharder
ports:
- port: 443
name: webhook
protocol: TCP
targetPort: webhook
- port: 8080
name: metrics
protocol: TCP
Expand Down
14 changes: 14 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ kind: ClusterRole
metadata:
name: sharder
rules:
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- admissionregistration.k8s.io
resources:
- mutatingwebhookconfigurations
verbs:
- create
- patch
- apiGroups:
- coordination.k8s.io
resources:
Expand Down
Loading