diff --git a/Makefile b/Makefile index 9a33bc41..1b1e8be3 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # To re-generate a bundle for another specific version without changing the standard setup, you can: # - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2) # - use environment variables to overwrite this value (e.g export VERSION=0.0.2) -VERSION ?= 0.12.0-alpha.3 +VERSION ?= 0.12.0 # CHANNELS define the bundle channels used in the bundle. # Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable") diff --git a/README.md b/README.md index 95764e36..153850d7 100644 --- a/README.md +++ b/README.md @@ -27,19 +27,22 @@ Lighweight, CRD based Envoy control plane for Kubernetes: - [**Install using kustomize**](#install-using-kustomize) - [**Deploy a discovery service**](#deploy-a-discovery-service) - [**Next steps**](#next-steps) + - Walkthrough: [TLS offloading with Envoy sidecars](docs/walkthroughs/tls-offloading-sidecars.md) + - Walkthrough: [Path routing using Envoy in a Kubernetes Deployment](docs/walkthroughs/path-routing-envoydeployment.md) + - Walkthrough: [Validation of Envoy resources](docs/walkthroughs/configuration-validation.md) + - Walkthrough: [Self-Healing](docs/walkthroughs/self-healing.md) + - Walkthrough: [Connection draining with the shutdown manager](docs/walkthroughs/envoy-connection-draining-on-shutdown.md) - [**Configuration**](#configuration) - - [**API reference**](#api-reference) + - [**API reference**](docs/api-reference/reference.asciidoc) - [**EnvoyConfig custom resource**](#envoyconfig-custom-resource) - [**Secrets**](#secrets) - [**Sidecar injection configuration**](#sidecar-injection-configuration) -- [**Use cases**](#use-cases) - - [**Ratelimit**](#ratelimit) -- [**Design docs**](#design-docs) - - [**Discovery service**](#discovery-service) - - [**Sidecar injection**](#sidecar-injection) - - [**Operator**](#operator) -- [**Development**](#development) -- [**Release**](#release) +- **Design docs** + - [**Discovery service**](docs/design/discovery-service.md) + - [**Sidecar injection**](docs/design/sidecar-injection.md) + - [**Operator**](docs/design/operator.md) +- [**Development**](docs/development/README.md) +- [**Release**](docs/release.md) ## **Overview** @@ -164,49 +167,104 @@ spec: # nodeID. The nodeID of an Envoy proxy can be specified using the "--node-id" command # line flag nodeID: proxy - # Resources can be written either in json or in yaml, being json the default if - # not specified - serialization: json - # Resources can be written using Envoy API v3. - envoyAPI: v3 - # envoyResources is where users can write the different type of resources supported by MARIN3R - envoyResources: - # the "secrets" field holds references to Kubernetes Secrets. Only Secrets of type + # resources is where users can write the different type of resources supported by MARIN3R + resources: + # type "secret" field holds references to Kubernetes Secrets. Only Secrets of type # "kubernetes.io/tls" can be referenced. Any certificate referenced from another Envoy # resource (for example a listener or a cluster) needs to be present here so marin3r # knows where to get the certificate from. - secrets: - # name is the name of the kubernetes Secret that holds the certificate and by which it can be - # referenced to from other resources - - name: certificate - # Endpoints is a list of the Envoy ClusterLoadAssignment resource type. + - type: secret + # generateFromTlsSecret is the name of the kubernetes Secret that holds the certificate and by which it can be + # referenced to from other resources + generateFromTlsSecret: certificate + # use "tlsCertificate" to generate a secret for a tlsCertificate (https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/transport_sockets/tls/v3/common.proto#extensions-transport-sockets-tls-v3-tlscertificate) + # use "validationContext" to generate a secret for a validationContext (https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/transport_sockets/tls/v3/common.proto#extensions-transport-sockets-tls-v3-certificatevalidationcontext) + blueprint: tlsCertificate + + # type "endpoint" is an Envoy ClusterLoadAssignment resource type. # API V3 reference: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/endpoint/v3/endpoint.proto - endpoints: - - value: {"clusterName":"cluster1","endpoints":[{"lbEndpoints":[{"endpoint":{"address":{"socketAddress":{"address":"127.0.0.1","portValue":8080}}}}]}]} - # Clusters is a list of the Envoy Cluster resource type. + - type: endpoint + value: + clusterName: cluster + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 127.0.0.1 + portValue: 8080 + + # type "endpoint" also supports dynamic discovery of endpoints by watching EndpointSlice kubernetes resources. + - type: endpoint + generateFromEndpointSlices: + selector: + matchLabels: + kubernetes.io/service-name: my-service + clusterName: cluster + targetPort: http + + # type "cluster" is an Envoy Cluster resource type. # API V3 reference: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/cluster/v3/cluster.proto - clusters: - - value: {"name":"cluster1","type":"STRICT_DNS","connectTimeout":"2s","loadAssignment":{"clusterName":"cluster1","endpoints":[]}} - # Routes is a list of the Envoy Route resource type. + - type: cluster + value: + name: cluster + type: STRICT_DNS + connectTimeout: 2s + loadAssignment: + clusterName: cluster1 + endpoints: [] + + # type "route" is an Envoy Route resource type. # API V3 reference: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route.proto - routes: - - value: {"name":"route1","virtual_hosts":[{"name":"vhost","domains":["*"],"routes":[{"match":{"prefix":"/"},"direct_response":{"status":200}}]}]} - # ScopedRoutes is a list of the Envoy Scoped Route resource type. + - type: route + value: + name: route1 + virtual_hosts: + - name: vhost + domains: + - "*" + routes: + - match: + prefix: "/" + direct_response: + status: 200 + + # type "scopedRoutes" is an Envoy Scoped Route resource type. # API V3 reference: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/scoped_route.proto - scopedRoutes: - - value: {"name":"scoped_route1","route_configuration_name":"route1","key":{"fragments":[{"string_key":"test"}]}} - # Listeners is a list of the Envoy Listener resource type. + - type: scopedRoute + value: + name: scoped_route1 + route_configuration_name: route1 + key: + fragments: + - string_key: test + + # type "listener" is an Envoy Listener resource type. # API V3 reference: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/listener/v3/listener.proto - listeners: - - value: {"name":"listener1","address":{"socketAddress":{"address":"0.0.0.0","portValue":8443}}} - # Runtimes is a list of the Envoy Runtime resource type. + - type: listener + value: + name: listener1 + address: + socketAddress: + address: 0.0.0.0 + portValue: 8443 + + # type "runtime" is an Envoy Runtime resource type. # API V3 reference: https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/runtime/v3/rtds.proto - runtimes: - - value: {"name":"runtime1","layer":{"static_layer_0":"value"}} - # ExtensionConfigs is a list of the envoy ExtensionConfig resource type + - type: runtime + value: + name: runtime1 + layer: + static_layer_0: value + + # type "extensionConfig" is an Envoy ExtensionConfig resource type # API V3 reference: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/extension.proto - extensionConfigs: - - value: {"name":"http_filter1","typed_config":{"@type":"type.googleapis.com/envoy.extensions.filters.http.router.v3.Router","dynamic_stats":false}} + - type: extensionConfig + value: + name: http_filter1 + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + dynamic_stats: false ``` ### **Secrets** @@ -219,9 +277,10 @@ To use a certificate from a kubernetes Secret refer it like this from an EnvoyCo ```yaml spec: - envoyResources: - secrets: - - name: certificate + resources: + - type: secret + generateFromTlsSecret: certificate + blueprint: tlsCertificate ``` This certificate can then be referenced in an Envoy cluster/listener with the following snippet (check the kuard example): @@ -279,25 +338,3 @@ The `port` syntax is a comma-separated list of `name:port[:protocol]` as in `"en #### `marin3r.3scale.net/host-port-mappings` syntax The `host-port-mappings` syntax is a comma-separated list of `container-port-name:host-port-number` as in `"envoy-http:1080,envoy-https:1443"`. - -## **Use cases** - -### [**Ratelimit**](/docs/use-cases/ratelimit/README.md) - -## **Design docs** - -For an in-depth look at how MARIN3R works, check the [design docs](/docs/design). - -### [**Discovery service**](/docs/design/discovery-service.md) - -### [**Sidecar injection**](/docs/design/sidecar-injection.md) - -### [**Operator**](/docs/design/operator.md) - -## **Development** - -You can find development documentation [here](/docs/development/README.md). - -## **Release** - -You can find release process documentation [here](/docs/release.md). diff --git a/apis/marin3r/v1alpha1/resources.go b/apis/marin3r/v1alpha1/resources.go index c3e42b41..6e05bba2 100644 --- a/apis/marin3r/v1alpha1/resources.go +++ b/apis/marin3r/v1alpha1/resources.go @@ -21,7 +21,7 @@ const ( // TlsCertificate TlsCertificate Blueprint = "tlsCertificate" // TlsValidationContext - TlsValidationContext Blueprint = "tlsValidationContext" + TlsValidationContext Blueprint = "validationContext" ) const defaultBlueprint Blueprint = TlsCertificate diff --git a/bundle/manifests/marin3r.3scale.net_envoyconfigrevisions.yaml b/bundle/manifests/marin3r.3scale.net_envoyconfigrevisions.yaml index 9b656334..d84cbff0 100644 --- a/bundle/manifests/marin3r.3scale.net_envoyconfigrevisions.yaml +++ b/bundle/manifests/marin3r.3scale.net_envoyconfigrevisions.yaml @@ -243,14 +243,14 @@ spec: the same namespace can be referred. properties: name: - description: Name of the envoy resource. If ref is not set, - a Secret with this same name will be fetched from within - the namespace. + description: Name of the envoy tslCerticate secret resource. + The certificate will be fetched from a Kubernetes Secrets + of type 'kubernetes.io/tls' with this same name. type: string ref: - description: Ref is a reference to a Kubernetes Secret of - type "kubernetes.io/tls". The value of 'ref' cannot point - to a different namespace. + description: 'DEPRECATED: this field is deprecated and it''s + value will be ignored. The ''name'' of the Kubernetes + Secret must match the ''name'' field.' properties: name: description: name is unique within a namespace to reference diff --git a/bundle/manifests/marin3r.3scale.net_envoyconfigs.yaml b/bundle/manifests/marin3r.3scale.net_envoyconfigs.yaml index 5921f0a6..9ae3b556 100644 --- a/bundle/manifests/marin3r.3scale.net_envoyconfigs.yaml +++ b/bundle/manifests/marin3r.3scale.net_envoyconfigs.yaml @@ -236,14 +236,14 @@ spec: the same namespace can be referred. properties: name: - description: Name of the envoy resource. If ref is not set, - a Secret with this same name will be fetched from within - the namespace. + description: Name of the envoy tslCerticate secret resource. + The certificate will be fetched from a Kubernetes Secrets + of type 'kubernetes.io/tls' with this same name. type: string ref: - description: Ref is a reference to a Kubernetes Secret of - type "kubernetes.io/tls". The value of 'ref' cannot point - to a different namespace. + description: 'DEPRECATED: this field is deprecated and it''s + value will be ignored. The ''name'' of the Kubernetes + Secret must match the ''name'' field.' properties: name: description: name is unique within a namespace to reference @@ -373,7 +373,6 @@ spec: is used if unset. enum: - json - - b64json - yaml type: string required: diff --git a/bundle/manifests/marin3r.clusterserviceversion.yaml b/bundle/manifests/marin3r.clusterserviceversion.yaml index 23c6880b..2d82698f 100644 --- a/bundle/manifests/marin3r.clusterserviceversion.yaml +++ b/bundle/manifests/marin3r.clusterserviceversion.yaml @@ -12,31 +12,133 @@ metadata: "namespace": "my-namespace" }, "spec": { - "envoyAPI": "v3", - "envoyResources": { - "clusters": [ - { - "value": "name: example\nconnect_timeout: 10ms\ntype: STRICT_DNS\ndns_lookup_family: V4_ONLY\nlb_policy: ROUND_ROBIN\nload_assignment:\n cluster_name: example\n endpoints:\n - lb_endpoints:\n - endpoint:\n address:\n socket_address:\n address: example\n port_value: 8080\n" - } - ], - "listeners": [ - { - "value": "name: https\naddress:\n socket_address:\n address: 0.0.0.0\n port_value: 8443\nfilter_chains:\n - filters:\n - name: envoy.filters.network.http_connection_manager\n typed_config:\n \"@type\": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager\n access_log:\n - name: envoy.access_loggers.file\n typed_config:\n \"@type\": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog\n path: /dev/stdout\n stat_prefix: https\n rds: { route_config_name: \"local\", config_source: { ads: {}, resource_api_version: \"V3\" }}\n http_filters:\n - name: envoy.filters.http.router\n transport_socket:\n name: envoy.transport_sockets.tls\n typed_config:\n \"@type\": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext\n common_tls_context:\n tls_certificate_sds_secret_configs:\n - name: example.default.svc\n sds_config: { ads: {}, resource_api_version: \"V3\" }\n" + "nodeID": "example", + "resources": [ + { + "type": "cluster", + "value": { + "connect_timeout": "0.01s", + "dns_lookup_family": "V4_ONLY", + "lb_policy": "ROUND_ROBIN", + "load_assignment": { + "cluster_name": "example", + "endpoints": [ + { + "lb_endpoints": [ + { + "endpoint": { + "address": { + "socket_address": { + "address": "example", + "port_value": 8080 + } + } + } + } + ] + } + ] + }, + "name": "example", + "type": "STRICT_DNS" } - ], - "routes": [ - { - "value": "name: local\nvirtual_hosts:\n - name: all\n domains: [\"*\"]\n routes:\n - match:\n prefix: \"/\"\n route:\n cluster: example\n" + }, + { + "type": "route", + "value": { + "name": "local", + "virtual_hosts": [ + { + "domains": [ + "*" + ], + "name": "all", + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "example" + } + } + ] + } + ] } - ], - "secrets": [ - { - "name": "example.default.svc" + }, + { + "type": "listener", + "value": { + "address": { + "socket_address": { + "address": "0.0.0.0", + "port_value": 8443 + } + }, + "filter_chains": [ + { + "filters": [ + { + "name": "envoy.filters.network.http_connection_manager", + "typed_config": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", + "access_log": [ + { + "name": "envoy.access_loggers.file", + "typed_config": { + "@type": "type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog", + "path": "/dev/stdout" + } + } + ], + "http_filters": [ + { + "name": "envoy.filters.http.router", + "typed_config": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "rds": { + "config_source": { + "ads": {}, + "resource_api_version": "V3" + }, + "route_config_name": "local" + }, + "stat_prefix": "https" + } + } + ], + "transport_socket": { + "name": "envoy.transport_sockets.tls", + "typed_config": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "common_tls_context": { + "tls_certificate_sds_secret_configs": [ + { + "name": "example.default.svc", + "sds_config": { + "ads": {}, + "resource_api_version": "V3" + } + } + ] + } + } + } + } + ], + "name": "https" } - ] - }, - "nodeID": "example", - "serialization": "yaml" + }, + { + "blueprint": "tlsCertificate", + "generateFromTlsSecret": "example.default.svc", + "type": "secret" + } + ] } }, { @@ -71,14 +173,14 @@ metadata: categories: Networking certified: "false" containerImage: quay.io/3scale/marin3r - createdAt: "2023-05-10T14:02:27Z" + createdAt: "2023-05-22T14:59:28Z" description: Lighweight, CRD based Envoy control plane for Kubernetes operators.operatorframework.io/builder: operator-sdk-v1.28.0 operators.operatorframework.io/internal-objects: '["envoyconfigrevisions.marin3r.3scale.net","discoveryservicecertificates.operator.marin3r.3scale.net"]' operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: https://github.com/3scale-ops/marin3r support: Red Hat, Inc. - name: marin3r.v0.12.0-alpha.3 + name: marin3r.v0.12.0 namespace: placeholder spec: apiservicedefinitions: {} @@ -188,6 +290,13 @@ spec: path: pkiConfg.serverCertificate.duration - displayName: Secret Name path: pkiConfg.serverCertificate.secretName + - description: PriorityClass to assign the discovery service Pod to + displayName: Pod Priority Class + path: podPriorityClass + - description: ProbePort is the port where healthz endpoint is served. Defaults + to 8384. + displayName: Probe Port + path: probePort - description: Resources holds the Resource Requirements to use for the discovery service Deployment. When not set it defaults to no resource requests nor limits. CPU and Memory resources are supported. @@ -205,11 +314,6 @@ spec: to 18000. displayName: Xds Server Port path: xdsServerPort - statusDescriptors: - - description: Conditions represent the latest available observations of an - object's state - displayName: Conditions - path: conditions version: v1alpha1 - description: EnvoyConfigRevision is an internal resource that stores a specific version of an EnvoyConfig resource. EnvoyConfigRevisions are automatically @@ -320,12 +424,13 @@ spec: - description: Secrets is a list of references to Kubernetes Secret objects. displayName: Secrets path: envoyResources.secrets - - description: Name of the envoy resource. If ref is not set, a Secret with - this same name will be fetched from within the namespace. + - description: Name of the envoy tslCerticate secret resource. The certificate + will be fetched from a Kubernetes Secrets of type 'kubernetes.io/tls' with + this same name. displayName: Name path: envoyResources.secrets[0].name - - description: Ref is a reference to a Kubernetes Secret of type "kubernetes.io/tls". - The value of 'ref' cannot point to a different namespace. + - description: 'DEPRECATED: this field is deprecated and it''s value will be + ignored. The ''name'' of the Kubernetes Secret must match the ''name'' field.' displayName: Ref path: envoyResources.secrets[0].ref x-descriptors: @@ -501,12 +606,13 @@ spec: - description: Secrets is a list of references to Kubernetes Secret objects. displayName: Secrets path: envoyResources.secrets - - description: Name of the envoy resource. If ref is not set, a Secret with - this same name will be fetched from within the namespace. + - description: Name of the envoy tslCerticate secret resource. The certificate + will be fetched from a Kubernetes Secrets of type 'kubernetes.io/tls' with + this same name. displayName: Name path: envoyResources.secrets[0].name - - description: Ref is a reference to a Kubernetes Secret of type "kubernetes.io/tls". - The value of 'ref' cannot point to a different namespace. + - description: 'DEPRECATED: this field is deprecated and it''s value will be + ignored. The ''name'' of the Kubernetes Secret must match the ''name'' field.' displayName: Ref path: envoyResources.secrets[0].ref x-descriptors: @@ -813,7 +919,7 @@ spec: valueFrom: fieldRef: fieldPath: metadata.annotations['olm.targetNamespaces'] - image: quay.io/3scale/marin3r:v0.12.0-alpha.3 + image: quay.io/3scale/marin3r:v0.12.0 livenessProbe: httpGet: path: /healthz @@ -871,7 +977,7 @@ spec: valueFrom: fieldRef: fieldPath: metadata.annotations['olm.targetNamespaces'] - image: quay.io/3scale/marin3r:v0.12.0-alpha.3 + image: quay.io/3scale/marin3r:v0.12.0 livenessProbe: httpGet: path: /healthz @@ -999,6 +1105,14 @@ spec: - patch - update - watch + - apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - get + - list + - watch - apiGroups: - marin3r.3scale.net resources: @@ -1170,7 +1284,7 @@ spec: maturity: alpha provider: name: Red Hat - version: 0.12.0-alpha.3 + version: 0.12.0 webhookdefinitions: - admissionReviewVersions: - v1 diff --git a/bundle/manifests/operator.marin3r.3scale.net_discoveryservices.yaml b/bundle/manifests/operator.marin3r.3scale.net_discoveryservices.yaml index de2c6a19..807e5963 100644 --- a/bundle/manifests/operator.marin3r.3scale.net_discoveryservices.yaml +++ b/bundle/manifests/operator.marin3r.3scale.net_discoveryservices.yaml @@ -83,6 +83,14 @@ spec: - rootCertificateAuthority - serverCertificate type: object + podPriorityClass: + description: PriorityClass to assign the discovery service Pod to + type: string + probePort: + description: ProbePort is the port where healthz endpoint is served. + Defaults to 8384. + format: int32 + type: integer resources: description: Resources holds the Resource Requirements to use for the discovery service Deployment. When not set it defaults to no @@ -151,76 +159,86 @@ spec: status: description: DiscoveryServiceStatus defines the observed state of DiscoveryService properties: - conditions: - description: Conditions represent the latest available observations - of an object's state - 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 + deploymentName: + type: string + deploymentStatus: + description: DeploymentStatus is the most recently observed status + of the Deployment. + properties: + availableReplicas: + description: Total number of available pods (ready for at least + minReadySeconds) targeted by this deployment. + format: int32 + type: integer + collisionCount: + description: Count of hash collisions for the Deployment. The + Deployment controller uses this field as a collision avoidance + mechanism when it needs to create the name for the newest ReplicaSet. + format: int32 + type: integer + conditions: + description: Represents the latest available observations of a + deployment's current state. + items: + description: DeploymentCondition describes the state of a deployment + at a certain point. + properties: + lastTransitionTime: + description: Last time the condition transitioned from one + status to another. + format: date-time + type: string + lastUpdateTime: + description: The last time this condition was updated. + format: date-time + type: string + message: + description: A human readable message indicating details + about the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, + Unknown. + type: string + type: + description: Type of deployment condition. + type: string + required: + - status + - type + type: object + type: array + observedGeneration: + description: The generation observed by the deployment controller. + format: int64 + type: integer + readyReplicas: + description: readyReplicas is the number of pods targeted by this + Deployment with a Ready Condition. + format: int32 + type: integer + replicas: + description: Total number of non-terminated pods targeted by this + deployment (their labels match the selector). + format: int32 + type: integer + unavailableReplicas: + description: Total number of unavailable pods targeted by this + deployment. This is the total number of pods that are still + required for the deployment to have 100% available capacity. + They may either be pods that are running but not yet available + or pods that still have not been created. + format: int32 + type: integer + updatedReplicas: + description: Total number of non-terminated pods targeted by this + deployment that have the desired template spec. + format: int32 + type: integer + type: object type: object type: object served: true diff --git a/bundle/manifests/operator.marin3r.3scale.net_envoydeployments.yaml b/bundle/manifests/operator.marin3r.3scale.net_envoydeployments.yaml index f8f2bea6..1583ab17 100644 --- a/bundle/manifests/operator.marin3r.3scale.net_envoydeployments.yaml +++ b/bundle/manifests/operator.marin3r.3scale.net_envoydeployments.yaml @@ -1760,6 +1760,87 @@ spec: type: object status: description: EnvoyDeploymentStatus defines the observed state of EnvoyDeployment + properties: + deploymentName: + type: string + deploymentStatus: + description: DeploymentStatus is the most recently observed status + of the Deployment. + properties: + availableReplicas: + description: Total number of available pods (ready for at least + minReadySeconds) targeted by this deployment. + format: int32 + type: integer + collisionCount: + description: Count of hash collisions for the Deployment. The + Deployment controller uses this field as a collision avoidance + mechanism when it needs to create the name for the newest ReplicaSet. + format: int32 + type: integer + conditions: + description: Represents the latest available observations of a + deployment's current state. + items: + description: DeploymentCondition describes the state of a deployment + at a certain point. + properties: + lastTransitionTime: + description: Last time the condition transitioned from one + status to another. + format: date-time + type: string + lastUpdateTime: + description: The last time this condition was updated. + format: date-time + type: string + message: + description: A human readable message indicating details + about the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, + Unknown. + type: string + type: + description: Type of deployment condition. + type: string + required: + - status + - type + type: object + type: array + observedGeneration: + description: The generation observed by the deployment controller. + format: int64 + type: integer + readyReplicas: + description: readyReplicas is the number of pods targeted by this + Deployment with a Ready Condition. + format: int32 + type: integer + replicas: + description: Total number of non-terminated pods targeted by this + deployment (their labels match the selector). + format: int32 + type: integer + unavailableReplicas: + description: Total number of unavailable pods targeted by this + deployment. This is the total number of pods that are still + required for the deployment to have 100% available capacity. + They may either be pods that are running but not yet available + or pods that still have not been created. + format: int32 + type: integer + updatedReplicas: + description: Total number of non-terminated pods targeted by this + deployment that have the desired template spec. + format: int32 + type: integer + type: object type: object type: object served: true diff --git a/config/crd/bases/marin3r.3scale.net_envoyconfigrevisions.yaml b/config/crd/bases/marin3r.3scale.net_envoyconfigrevisions.yaml index ced4ac3e..0c4d3b8d 100644 --- a/config/crd/bases/marin3r.3scale.net_envoyconfigrevisions.yaml +++ b/config/crd/bases/marin3r.3scale.net_envoyconfigrevisions.yaml @@ -244,14 +244,14 @@ spec: the same namespace can be referred. properties: name: - description: Name of the envoy resource. If ref is not set, - a Secret with this same name will be fetched from within - the namespace. + description: Name of the envoy tslCerticate secret resource. + The certificate will be fetched from a Kubernetes Secrets + of type 'kubernetes.io/tls' with this same name. type: string ref: - description: Ref is a reference to a Kubernetes Secret of - type "kubernetes.io/tls". The value of 'ref' cannot point - to a different namespace. + description: 'DEPRECATED: this field is deprecated and it''s + value will be ignored. The ''name'' of the Kubernetes + Secret must match the ''name'' field.' properties: name: description: name is unique within a namespace to reference diff --git a/config/crd/bases/marin3r.3scale.net_envoyconfigs.yaml b/config/crd/bases/marin3r.3scale.net_envoyconfigs.yaml index 22d59189..6d65e529 100644 --- a/config/crd/bases/marin3r.3scale.net_envoyconfigs.yaml +++ b/config/crd/bases/marin3r.3scale.net_envoyconfigs.yaml @@ -237,14 +237,14 @@ spec: the same namespace can be referred. properties: name: - description: Name of the envoy resource. If ref is not set, - a Secret with this same name will be fetched from within - the namespace. + description: Name of the envoy tslCerticate secret resource. + The certificate will be fetched from a Kubernetes Secrets + of type 'kubernetes.io/tls' with this same name. type: string ref: - description: Ref is a reference to a Kubernetes Secret of - type "kubernetes.io/tls". The value of 'ref' cannot point - to a different namespace. + description: 'DEPRECATED: this field is deprecated and it''s + value will be ignored. The ''name'' of the Kubernetes + Secret must match the ''name'' field.' properties: name: description: name is unique within a namespace to reference diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 554d4a2a..99a93fbb 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -13,7 +13,7 @@ kind: Kustomization images: - name: controller newName: quay.io/3scale/marin3r - newTag: v0.12.0-alpha.3 + newTag: v0.12.0 patchesStrategicMerge: - custom/manager_patch.yaml diff --git a/config/manifests/bases/marin3r.clusterserviceversion.yaml b/config/manifests/bases/marin3r.clusterserviceversion.yaml index fd515a94..c6e89d9a 100644 --- a/config/manifests/bases/marin3r.clusterserviceversion.yaml +++ b/config/manifests/bases/marin3r.clusterserviceversion.yaml @@ -196,6 +196,13 @@ spec: path: pkiConfg.serverCertificate.duration - displayName: Secret Name path: pkiConfg.serverCertificate.secretName + - description: PriorityClass to assign the discovery service Pod to + displayName: Pod Priority Class + path: podPriorityClass + - description: ProbePort is the port where healthz endpoint is served. Defaults + to 8384. + displayName: Probe Port + path: probePort - description: Resources holds the Resource Requirements to use for the discovery service Deployment. When not set it defaults to no resource requests nor limits. CPU and Memory resources are supported. @@ -213,11 +220,6 @@ spec: to 18000. displayName: Xds Server Port path: xdsServerPort - statusDescriptors: - - description: Conditions represent the latest available observations of an - object's state - displayName: Conditions - path: conditions version: v1alpha1 - description: EnvoyConfigRevision is an internal resource that stores a specific version of an EnvoyConfig resource. EnvoyConfigRevisions are automatically @@ -328,12 +330,13 @@ spec: - description: Secrets is a list of references to Kubernetes Secret objects. displayName: Secrets path: envoyResources.secrets - - description: Name of the envoy resource. If ref is not set, a Secret with - this same name will be fetched from within the namespace. + - description: Name of the envoy tslCerticate secret resource. The certificate + will be fetched from a Kubernetes Secrets of type 'kubernetes.io/tls' with + this same name. displayName: Name path: envoyResources.secrets[0].name - - description: Ref is a reference to a Kubernetes Secret of type "kubernetes.io/tls". - The value of 'ref' cannot point to a different namespace. + - description: 'DEPRECATED: this field is deprecated and it''s value will be + ignored. The ''name'' of the Kubernetes Secret must match the ''name'' field.' displayName: Ref path: envoyResources.secrets[0].ref x-descriptors: @@ -509,12 +512,13 @@ spec: - description: Secrets is a list of references to Kubernetes Secret objects. displayName: Secrets path: envoyResources.secrets - - description: Name of the envoy resource. If ref is not set, a Secret with - this same name will be fetched from within the namespace. + - description: Name of the envoy tslCerticate secret resource. The certificate + will be fetched from a Kubernetes Secrets of type 'kubernetes.io/tls' with + this same name. displayName: Name path: envoyResources.secrets[0].name - - description: Ref is a reference to a Kubernetes Secret of type "kubernetes.io/tls". - The value of 'ref' cannot point to a different namespace. + - description: 'DEPRECATED: this field is deprecated and it''s value will be + ignored. The ''name'' of the Kubernetes Secret must match the ''name'' field.' displayName: Ref path: envoyResources.secrets[0].ref x-descriptors: diff --git a/config/samples/marin3r_v1alpha1_envoyconfig.yaml b/config/samples/marin3r_v1alpha1_envoyconfig.yaml index 3ac64380..0b81d75a 100644 --- a/config/samples/marin3r_v1alpha1_envoyconfig.yaml +++ b/config/samples/marin3r_v1alpha1_envoyconfig.yaml @@ -5,47 +5,43 @@ metadata: namespace: my-namespace spec: nodeID: example - serialization: yaml - envoyAPI: v3 - envoyResources: - secrets: - - name: example.default.svc - clusters: - - value: | - name: example - connect_timeout: 10ms - type: STRICT_DNS - dns_lookup_family: V4_ONLY - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: example - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: example - port_value: 8080 - routes: - - value: | - name: local - virtual_hosts: - - name: all - domains: ["*"] - routes: - - match: - prefix: "/" - route: - cluster: example - listeners: - - value: | - name: https - address: - socket_address: - address: 0.0.0.0 - port_value: 8443 - filter_chains: - - filters: + resources: + - type: cluster + value: + connect_timeout: 0.01s + dns_lookup_family: V4_ONLY + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: example + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: example + port_value: 8080 + name: example + type: STRICT_DNS + - type: route + value: + name: local + virtual_hosts: + - domains: + - "*" + name: all + routes: + - match: + prefix: / + route: + cluster: example + - type: listener + value: + address: + socket_address: + address: 0.0.0.0 + port_value: 8443 + filter_chains: + - filters: - name: envoy.filters.network.http_connection_manager typed_config: "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager @@ -54,16 +50,27 @@ spec: typed_config: "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog path: /dev/stdout - stat_prefix: https - rds: { route_config_name: "local", config_source: { ads: {}, resource_api_version: "V3" }} http_filters: - name: envoy.filters.http.router - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext - common_tls_context: - tls_certificate_sds_secret_configs: - - name: example.default.svc - sds_config: { ads: {}, resource_api_version: "V3" } - + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + rds: + config_source: + ads: {} + resource_api_version: V3 + route_config_name: local + stat_prefix: https + transport_socket: + name: envoy.transport_sockets.tls + typed_config: + "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext + common_tls_context: + tls_certificate_sds_secret_configs: + - name: example.default.svc + sds_config: + ads: {} + resource_api_version: V3 + name: https + - blueprint: tlsCertificate + generateFromTlsSecret: example.default.svc + type: secret diff --git a/config/test/manager_patch.yaml b/config/test/manager_patch.yaml index 3fa3d108..e8c1c97a 100644 --- a/config/test/manager_patch.yaml +++ b/config/test/manager_patch.yaml @@ -11,4 +11,7 @@ spec: args: - operator - --leader-elect - - --debug \ No newline at end of file + - --debug + env: + - name: MARIN3R_IMAGE + value: quay.io/3scale/marin3r:test \ No newline at end of file diff --git a/config/webhook/kustomization.yaml b/config/webhook/kustomization.yaml index e1304c7b..e666443b 100644 --- a/config/webhook/kustomization.yaml +++ b/config/webhook/kustomization.yaml @@ -10,7 +10,7 @@ kind: Kustomization images: - name: controller newName: quay.io/3scale/marin3r - newTag: v0.12.0-alpha.3 + newTag: v0.12.0 # [CUSTOM: pod mutating webhook config] This patch adds a label selector to the MutatingWebhookConfig patchesStrategicMerge: diff --git a/controllers/marin3r/envoyconfigrevision_controller.go b/controllers/marin3r/envoyconfigrevision_controller.go index 9800348a..f650ca36 100644 --- a/controllers/marin3r/envoyconfigrevision_controller.go +++ b/controllers/marin3r/envoyconfigrevision_controller.go @@ -132,9 +132,9 @@ func (r *EnvoyConfigRevisionReconciler) Reconcile(ctx context.Context, req ctrl. vt, err = cacheReconciler.Reconcile(ctx, req.NamespacedName, ecr.Spec.Resources, ecr.Spec.NodeID, ecr.Spec.Version) - // If a type errors.StatusError is returned it means that the config in spec.envoyResources is wrong + // If a type errors.StatusError is returned it means that the config in spec.resources is wrong // and cannot be written into the xDS cache. This is true for any error loading all types of resources - // except for Secrets. Secrets are dynamically loaded from the API and transient failures are possible, so + // except for Secrets and generated Endpoints, which are dynamically loaded from the k8s API. In those cases // setting a permanent taint could occur for a transient failure, which is not desirable. if err != nil { switch err.(type) { diff --git a/docs/api-reference/reference.asciidoc b/docs/api-reference/reference.asciidoc index 9b1f31fa..5abaf0d3 100644 --- a/docs/api-reference/reference.asciidoc +++ b/docs/api-reference/reference.asciidoc @@ -22,6 +22,18 @@ Package v1alpha1 contains API Schema definitions for the envoy v1alpha1 API grou +[id="{anchor_prefix}-github-com-3scale-ops-marin3r-apis-marin3r-v1alpha1-blueprint"] +==== Blueprint (string) + +Blueprint is an enum of the supported blueprints for generated resources + +.Appears In: +**** +- xref:{anchor_prefix}-github-com-3scale-ops-marin3r-apis-marin3r-v1alpha1-resource[$$Resource$$] +**** + + + [id="{anchor_prefix}-github-com-3scale-ops-marin3r-apis-marin3r-v1alpha1-configrevisionref"] ==== ConfigRevisionRef @@ -135,9 +147,10 @@ EnvoyConfigRevisionSpec defines the desired state of EnvoyConfigRevision | Field | Description | *`nodeID`* __string__ | NodeID holds the envoy identifier for the discovery service to know which set of resources to send to each of the envoy clients that connect to it. | *`version`* __string__ | Version is a hash of the EnvoyResources field -| *`envoyAPI`* __string__ | EnvoyAPI is the version of envoy's API to use. Defaults to v3. -| *`serialization`* __string__ | Serialization specicifies the serialization format used to describe the resources. "json" and "yaml" are supported. "json" is used if unset. +| *`envoyAPI`* __APIVersion__ | EnvoyAPI is the version of envoy's API to use. Defaults to v3. +| *`serialization`* __Serialization__ | Serialization specicifies the serialization format used to describe the resources. "json" and "yaml" are supported. "json" is used if unset. | *`envoyResources`* __xref:{anchor_prefix}-github-com-3scale-ops-marin3r-apis-marin3r-v1alpha1-envoyresources[$$EnvoyResources$$]__ | EnvoyResources holds the different types of resources suported by the envoy discovery service +| *`resources`* __xref:{anchor_prefix}-github-com-3scale-ops-marin3r-apis-marin3r-v1alpha1-resource[$$Resource$$] array__ | Resources holds the different types of resources suported by the envoy discovery service |=== @@ -176,9 +189,10 @@ EnvoyConfigSpec defines the desired state of EnvoyConfig |=== | Field | Description | *`nodeID`* __string__ | NodeID holds the envoy identifier for the discovery service to know which set of resources to send to each of the envoy clients that connect to it. -| *`serialization`* __string__ | Serialization specicifies the serialization format used to describe the resources. "json" and "yaml" are supported. "json" is used if unset. -| *`envoyAPI`* __string__ | EnvoyAPI is the version of envoy's API to use. Defaults to v3. -| *`envoyResources`* __xref:{anchor_prefix}-github-com-3scale-ops-marin3r-apis-marin3r-v1alpha1-envoyresources[$$EnvoyResources$$]__ | EnvoyResources holds the different types of resources suported by the envoy discovery service +| *`serialization`* __Serialization__ | Serialization specicifies the serialization format used to describe the resources. "json" and "yaml" are supported. "json" is used if unset. +| *`envoyAPI`* __APIVersion__ | EnvoyAPI is the version of envoy's API to use. Defaults to v3. +| *`envoyResources`* __xref:{anchor_prefix}-github-com-3scale-ops-marin3r-apis-marin3r-v1alpha1-envoyresources[$$EnvoyResources$$]__ | EnvoyResources holds the different types of resources suported by the envoy discovery service DEPRECATED. Use the `resources` field instead. +| *`resources`* __xref:{anchor_prefix}-github-com-3scale-ops-marin3r-apis-marin3r-v1alpha1-resource[$$Resource$$] array__ | Resources holds the different types of resources suported by the envoy discovery service |=== @@ -259,13 +273,54 @@ EnvoySecretResource holds a reference to a k8s Secret from where to take a secre [cols="25a,75a", options="header"] |=== | Field | Description -| *`name`* __string__ | Name of the envoy resource. If ref is not set, a Secret with this same name will be fetched from within the namespace. -| *`ref`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#secretreference-v1-core[$$SecretReference$$]__ | Ref is a reference to a Kubernetes Secret of type "kubernetes.io/tls". The value of 'ref' cannot point to a different namespace. +| *`name`* __string__ | Name of the envoy tslCerticate secret resource. The certificate will be fetched from a Kubernetes Secrets of type 'kubernetes.io/tls' with this same name. +| *`ref`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#secretreference-v1-core[$$SecretReference$$]__ | DEPRECATED: this field is deprecated and it's value will be ignored. The 'name' of the Kubernetes Secret must match the 'name' field. +|=== + + + + +[id="{anchor_prefix}-github-com-3scale-ops-marin3r-apis-marin3r-v1alpha1-generatefromendpointslices"] +==== GenerateFromEndpointSlices + + + +.Appears In: +**** +- xref:{anchor_prefix}-github-com-3scale-ops-marin3r-apis-marin3r-v1alpha1-resource[$$Resource$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`selector`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#labelselector-v1-meta[$$LabelSelector$$]__ | +| *`clusterName`* __string__ | +| *`targetPort`* __string__ | |=== +[id="{anchor_prefix}-github-com-3scale-ops-marin3r-apis-marin3r-v1alpha1-resource"] +==== Resource + +Resource holds serialized representation of an envoy resource + +.Appears In: +**** +- xref:{anchor_prefix}-github-com-3scale-ops-marin3r-apis-marin3r-v1alpha1-envoyconfigrevisionspec[$$EnvoyConfigRevisionSpec$$] +- xref:{anchor_prefix}-github-com-3scale-ops-marin3r-apis-marin3r-v1alpha1-envoyconfigspec[$$EnvoyConfigSpec$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`type`* __Type__ | Type is the type url for the protobuf message +| *`value`* __RawExtension__ | Value is the protobufer message that configures the resource. The proto must match the envoy configuration API v3 specification for the given resource type (https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol#resource-types) +| *`generateFromTlsSecret`* __string__ | The name of a Kubernetes Secret of type "kubernetes.io/tls" +| *`generateFromEndpointSlices`* __xref:{anchor_prefix}-github-com-3scale-ops-marin3r-apis-marin3r-v1alpha1-generatefromendpointslices[$$GenerateFromEndpointSlices$$]__ | Specifies a label selector to watch for EndpointSlices that will be used to generate the endpoint resource +| *`blueprint`* __xref:{anchor_prefix}-github-com-3scale-ops-marin3r-apis-marin3r-v1alpha1-blueprint[$$Blueprint$$]__ | Blueprint specifies a template to generate a configuration proto. It is currently only supported to generate secret configuration resources from k8s Secrets +|=== [id="{anchor_prefix}-github-com-3scale-ops-marin3r-apis-marin3r-v1alpha1-versiontracker"] @@ -541,7 +596,9 @@ DiscoveryServiceSpec defines the desired state of DiscoveryService | *`pkiConfg`* __xref:{anchor_prefix}-github-com-3scale-ops-marin3r-apis-operator-marin3r-v1alpha1-pkiconfig[$$PKIConfig$$]__ | PKIConfig has configuration for the PKI that marin3r manages for the different certificates it requires | *`xdsServerPort`* __integer__ | XdsServerPort is the port where the xDS server listens. Defaults to 18000. | *`metricsPort`* __integer__ | MetricsPort is the port where metrics are served. Defaults to 8383. +| *`probePort`* __integer__ | ProbePort is the port where healthz endpoint is served. Defaults to 8384. | *`serviceConfig`* __xref:{anchor_prefix}-github-com-3scale-ops-marin3r-apis-operator-marin3r-v1alpha1-serviceconfig[$$ServiceConfig$$]__ | ServiceConfig configures the way the DiscoveryService endpoints are exposed +| *`podPriorityClass`* __string__ | PriorityClass to assign the discovery service Pod to |=== @@ -558,7 +615,8 @@ DiscoveryServiceStatus defines the observed state of DiscoveryService [cols="25a,75a", options="header"] |=== | Field | Description -| *`conditions`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#condition-v1-meta[$$Condition$$] array__ | Conditions represent the latest available observations of an object's state +| *`deploymentName`* __string__ | +| *`deploymentStatus`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#deploymentstatus-v1-apps[$$DeploymentStatus$$]__ | |=== @@ -577,8 +635,8 @@ DiscoveryServiceStatus defines the observed state of DiscoveryService | Field | Description | *`minReplicas`* __integer__ | minReplicas is the lower limit for the number of replicas to which the autoscaler can scale down. It defaults to 1 pod. minReplicas is allowed to be 0 if the alpha feature gate HPAScaleToZero is enabled and at least one Object or External metric is configured. Scaling is active as long as at least one metric value is available. | *`maxReplicas`* __integer__ | maxReplicas is the upper limit for the number of replicas to which the autoscaler can scale up. It cannot be less that minReplicas. -| *`metrics`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#metricspec-v2beta2-autoscaling[$$MetricSpec$$] array__ | metrics contains the specifications for which to use to calculate the desired replica count (the maximum replica count across all metrics will be used). The desired replica count is calculated multiplying the ratio between the target value and the current value by the current number of pods. Ergo, metrics used must decrease as the pod count is increased, and vice-versa. See the individual metric source types for more information about how each type of metric must respond. If not set, the default metric will be set to 80% average CPU utilization. -| *`behavior`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#horizontalpodautoscalerbehavior-v2beta2-autoscaling[$$HorizontalPodAutoscalerBehavior$$]__ | behavior configures the scaling behavior of the target in both Up and Down directions (scaleUp and scaleDown fields respectively). If not set, the default HPAScalingRules for scale up and scale down are used. +| *`metrics`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#metricspec-v2-autoscaling[$$MetricSpec$$] array__ | metrics contains the specifications for which to use to calculate the desired replica count (the maximum replica count across all metrics will be used). The desired replica count is calculated multiplying the ratio between the target value and the current value by the current number of pods. Ergo, metrics used must decrease as the pod count is increased, and vice-versa. See the individual metric source types for more information about how each type of metric must respond. If not set, the default metric will be set to 80% average CPU utilization. +| *`behavior`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#horizontalpodautoscalerbehavior-v2-autoscaling[$$HorizontalPodAutoscalerBehavior$$]__ | behavior configures the scaling behavior of the target in both Up and Down directions (scaleUp and scaleDown fields respectively). If not set, the default HPAScalingRules for scale up and scale down are used. |=== @@ -655,6 +713,22 @@ EnvoyDeploymentSpec defines the desired state of EnvoyDeployment |=== +[id="{anchor_prefix}-github-com-3scale-ops-marin3r-apis-operator-marin3r-v1alpha1-envoydeploymentstatus"] +==== EnvoyDeploymentStatus + +EnvoyDeploymentStatus defines the observed state of EnvoyDeployment + +.Appears In: +**** +- xref:{anchor_prefix}-github-com-3scale-ops-marin3r-apis-operator-marin3r-v1alpha1-envoydeployment[$$EnvoyDeployment$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`deploymentName`* __string__ | +| *`deploymentStatus`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#deploymentstatus-v1-apps[$$DeploymentStatus$$]__ | +|=== [id="{anchor_prefix}-github-com-3scale-ops-marin3r-apis-operator-marin3r-v1alpha1-initmanager"] diff --git a/docs/design/discovery-service.md b/docs/design/discovery-service.md index 51a6b6dd..b29698d1 100644 --- a/docs/design/discovery-service.md +++ b/docs/design/discovery-service.md @@ -17,16 +17,16 @@ As of today, the discovery service runs in a single pod. The mechanism by which configurations get to the discovery service server and are then delivered to envoy proxies follows the follwing design: -- Users or other software/controllers create EnvoyConfig custom resources in the Kubernetes API. The EnvoyConfig controller watches these resources and generates owned EnvoyConfigRevision custom resources, one per version of the envoy resources contained in the EnvoyConfig custom resource (in the `spec.envoyResources` field), up to a maximum of 10. This is effectively a list of the config versions that have been applied to a set of envoy proxies over time. +- Users or other software/controllers create EnvoyConfig custom resources in the Kubernetes API. The EnvoyConfig controller watches these resources and generates owned EnvoyConfigRevision custom resources, one per version of the envoy resources contained in the EnvoyConfig custom resource (in the `spec.resources` field), up to a maximum of 10. This is effectively a list of the config versions that have been applied to a set of envoy proxies over time. - Only one of the EnvoyConfigRevisions holds the current version of the config. This is called the **published version** and is marked in the EnvoyConfigRevision with the `RevisionPublished` condition. It is the EnvoyConfig controller the one deciding which of its owned EnvoyConfigRevisions is the one actually published. The algorithm used to decide which is one it should be is: 1. EnvoyConfig controller keeps a list of EnvoyConfigRevision references in `status.configRevisions`, ordered by time of publication. The last published revision holds the highest array index position. - 2. Revisions are versioned by computing the hash of the `spec.envoyResources` field. + 2. Revisions are versioned by computing the hash of the `spec.resources` field. 3. The revision with the highest array index that is not marked with the `RevisionTainted` condition is marked with the `RevisionPublished` condition, effectively getting it published. 4. All other owned EnvoyConfigRevisions get the `RevisionPublished` condition set to `false`. -- When an EnvoyConfig resource gets updated, the hash of `spec.envoyResources` is recalculated and a new EnvoyConfigRevision for that hash is created. If an EnvoyConfigRevision already exists that matches the hash, the existing reference in `status.configRevisions` that points to that EnvoyConfigRevision gets moved to the array's highest index position, effectively triggering the publication of that revision. +- When an EnvoyConfig resource gets updated, the hash of `spec.resources` is recalculated and a new EnvoyConfigRevision for that hash is created. If an EnvoyConfigRevision already exists that matches the hash, the existing reference in `status.configRevisions` that points to that EnvoyConfigRevision gets moved to the array's highest index position, effectively triggering the publication of that revision. - The EnvoyConfigRevision controller watches events on EnvoyConfigRevision custom resources. Whenever it receives an event on one, it checks if the revision is marked as published. If so, loads the envoy resources from serizalized format into proto message objects and writes them to the xDS server in-memory cache. The xDS server will start delivering the new config to the envoy proxies as soon as it detects changes in the in-memory cache. @@ -63,7 +63,7 @@ The in-memory cache is built by the discovery service with the process described The discovery service can also deliver certificates to the envoy proxies. When an envoy configuration references an envoy secret resource to be used as a certificate (the secret type must be "kubernetes.io/tls"), this needs to be specified in the EnvoyConfig custom resource as a reference to a kubernetes Secret. -For example, in the following EnvoyConfig there is a listener configured for TLS termination. The TLS config of the listener specifies that the certificate needs to be retrieved from the discovery service, referencing it by name. This name needs to match the name given to the secret in the secret reference in `spec.envoyResources.secrets`. +For example, in the following EnvoyConfig there is a listener configured for TLS termination. The TLS config of the listener specifies that the certificate needs to be retrieved from the discovery service, referencing it by name. This name needs to match the name given to the secret in the secret reference in `spec.resources`. ```yaml apiVersion: marin3r.3scale.net/v1alpha1 @@ -73,40 +73,37 @@ metadata: spec: nodeID: my-proxy serialization: yaml - envoyResources: - secrets: - - name: my-certificate - ref: - name: my-certificate-secret-resource - namespace: default - listeners: - - name: https - value: | - name: https - address: { socket_address: { address: 0.0.0.0, port_value: 1443 }} - filter_chains: - - filters: - - name: envoy.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: my-proxy - domains: ["*"] - routes: - - match: { prefix: "/" } - direct_response: { status: 200, body: { inline_string: ok }} - http_filters: [ name: envoy.router ] - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": "type.googleapis.com/envoy.api.v2.auth.DownstreamTlsContext" - common_tls_context: - tls_certificate_sds_secret_configs: - - name: my-certificate - sds_config: { ads: {}} + resources: + - type: secret + generateFromTlsSecret: my-certificate + blueprint: tlsCertificate + - type: listener + value + name: https + address: { socket_address: { address: 0.0.0.0, port_value: 1443 }} + filter_chains: + - filters: + - name: envoy.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager + stat_prefix: ingress_http + route_config: + name: local_route + virtual_hosts: + - name: my-proxy + domains: ["*"] + routes: + - match: { prefix: "/" } + direct_response: { status: 200, body: { inline_string: ok }} + http_filters: [ name: envoy.router ] + transport_socket: + name: envoy.transport_sockets.tls + typed_config: + "@type": "type.googleapis.com/envoy.api.v2.auth.DownstreamTlsContext" + common_tls_context: + tls_certificate_sds_secret_configs: + - name: my-certificate + sds_config: { ads: {}} ``` Using references to kubernetes Secret resources avoids having to write sensitive information like the certificate's private key directly into the EnvoyConfig custom resource. This is a standard way to manage sensitive information inside Kubernetes and allows to safely keep the EnvoyConfig custom resources under version control. diff --git a/docs/walkthroughs/configuration-validation.md b/docs/walkthroughs/configuration-validation.md index 0cb550d5..7d150772 100644 --- a/docs/walkthroughs/configuration-validation.md +++ b/docs/walkthroughs/configuration-validation.md @@ -15,27 +15,25 @@ cat <<'EOF' | kubectl apply -f - apiVersion: marin3r.3scale.net/v1alpha1 kind: EnvoyConfig metadata: - name: kuard + name: example spec: - nodeID: kuard - serialization: yaml - envoyAPI: v3 - envoyResources: - secrets: - - name: kuard-certificate - clusters: - - value: | - name: kuard - connect_timeout: 10 miliseconds - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: kuard - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: { address: 127.0.0.1, port_value: 8080 } + nodeID: example + resources: + - type: cluster + value: + name: example + type: STRICT_DNS + connect_timeout: 10 miliseconds + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: example + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: 127.0.0.1 + port_value: 8080 EOF ``` diff --git a/docs/walkthroughs/envoy-connection-draining-on-shutdown.md b/docs/walkthroughs/envoy-connection-draining-on-shutdown.md index dfe636c0..34329174 100644 --- a/docs/walkthroughs/envoy-connection-draining-on-shutdown.md +++ b/docs/walkthroughs/envoy-connection-draining-on-shutdown.md @@ -24,26 +24,35 @@ spec: nodeID: envoy serialization: yaml envoyAPI: v3 - envoyResources: - listeners: - - value: | - name: http - address: { socket_address: { address: 0.0.0.0, port_value: 8080 } } - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - route_config: - name: route - virtual_hosts: - - name: any - domains: ["*"] - routes: - - {"match":{"prefix":"/"},"direct_response":{"status":200}} - http_filters: - - name: envoy.filters.http.router + resources: + - type: listener + value: + name: http + address: + socket_address: + address: 0.0.0.0 + port_value: 8080 + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + http_filters: + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + route_config: + name: route + virtual_hosts: + - domains: + - '*' + name: any + routes: + - direct_response: + status: 200 + match: + prefix: / + stat_prefix: ingress_http EOF ``` diff --git a/docs/walkthroughs/path-routing-envoydeployment.md b/docs/walkthroughs/path-routing-envoydeployment.md index 05bc5aa3..baf52922 100644 --- a/docs/walkthroughs/path-routing-envoydeployment.md +++ b/docs/walkthroughs/path-routing-envoydeployment.md @@ -106,41 +106,50 @@ metadata: name: envoy spec: nodeID: envoy - serialization: yaml - envoyAPI: v3 - envoyResources: - clusters: - - value: | - name: upstream-a - connect_timeout: 10ms - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: upstream-a - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: { address: upstream-a, port_value: 8080 } - listeners: - - value: | - name: http - address: { socket_address: { address: 0.0.0.0, port_value: 8080 } } - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - route_config: - name: route - virtual_hosts: - - name: any - domains: ["*"] - routes: - - { match: { prefix: "/a" }, route: { cluster: "upstream-a" } } - http_filters: - - name: envoy.filters.http.router + resources: + - type: cluster + value: + name: upstream-a + type: STRICT_DNS + connect_timeout: 0.01s + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: upstream-a + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: upstream-a + port_value: 8080 + - type: listener + value: + name: http + address: + socket_address: + address: 0.0.0.0 + port_value: 8080 + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + http_filters: + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + route_config: + name: route + virtual_hosts: + - domains: + - "*" + name: any + routes: + - match: + prefix: /a + route: + cluster: upstream-a + stat_prefix: ingress_http EOF ``` @@ -231,54 +240,69 @@ metadata: name: envoy spec: nodeID: envoy - serialization: yaml - envoyAPI: v3 - envoyResources: - clusters: - - value: | - name: upstream-a - connect_timeout: 10ms - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: upstream-a - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: { address: upstream-a, port_value: 8080 } - - value: | - name: upstream-b - connect_timeout: 10ms - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: upstream-b - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: { address: upstream-b, port_value: 8080 } - listeners: - - value: | - name: http - address: { socket_address: { address: 0.0.0.0, port_value: 8080 } } - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - route_config: - name: route - virtual_hosts: - - name: any - domains: ["*"] - routes: - - { match: { prefix: "/a" }, route: { cluster: "upstream-a" } } - - { match: { prefix: "/b" }, route: { cluster: "upstream-b" } } - http_filters: - - name: envoy.filters.http.router + resources: + - type: cluster + value: + name: upstream-a + type: STRICT_DNS + connect_timeout: 0.01s + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: upstream-a + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: upstream-a + port_value: 8080 + - type: cluster + value: + name: upstream-b + type: STRICT_DNS + connect_timeout: 0.01s + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: upstream-b + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: upstream-b + port_value: 8080 + - type: listener + value: + name: http + address: + socket_address: + address: 0.0.0.0 + port_value: 8080 + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + http_filters: + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + route_config: + name: route + virtual_hosts: + - domains: + - "*" + name: any + routes: + - match: + prefix: /a + route: + cluster: upstream-a + - match: + prefix: /b + route: + cluster: upstream-b + stat_prefix: ingress_http EOF ``` @@ -342,6 +366,6 @@ Execute the following commands to delete the resources created in this walkthoug ```bash kubectl delete envoydeployment envoy kubectl delete envoyconfig envoy -kubectl delete deployment upstream-a -kubectl delete deployment upstream-b +kubectl delete deployment upstream-a upstream-b +kubectl delete service upstream-a upstream-b ``` diff --git a/docs/walkthroughs/self-healing.md b/docs/walkthroughs/self-healing.md index b0090b92..9e2e7d32 100644 --- a/docs/walkthroughs/self-healing.md +++ b/docs/walkthroughs/self-healing.md @@ -50,39 +50,50 @@ spec: nodeID: kuard serialization: yaml envoyAPI: v3 - envoyResources: - clusters: - - value: | - name: kuard - connect_timeout: 10ms - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: kuard - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: { address: 127.0.0.1, port_value: 8080 } - listeners: - - value: | - name: http - address: { socket_address: { address: 0.0.0.0, port_value: 8081 } } - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_https - route_config: - name: local_route - virtual_hosts: - - name: any - domains: ["*"] - routes: - [{ match: { prefix: "/" }, route: { cluster: "kuard" } }] - http_filters: - - name: envoy.filters.http.router + resources: + - type: cluster + value: + name: kuard + type: STRICT_DNS + connect_timeout: 0.01s + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: kuard + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: 127.0.0.1 + port_value: 8080 + - type: listener + value: + name: http + address: + socket_address: + address: 0.0.0.0 + port_value: 8081 + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + http_filters: + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + route_config: + name: local_route + virtual_hosts: + - domains: + - "*" + name: any + routes: + - match: + prefix: / + route: + cluster: kuard + stat_prefix: ingress_https EOF ``` @@ -119,7 +130,7 @@ Check that the setup works using the following curl: ## **Modify the Envoy configuration** -Modify the EnvoyConfig resource to change the port that the http listener binds to. This is incorrect and the Envoy proxy will reject it because address changes are not allowed in listener resources (the correct way of doing this would be to add a new listener and then remove the old one). +Modify the EnvoyConfig resource to point the listener to an inexistent cluster. This is incorrect and the Envoy proxy will reject this configuration change. ```bash cat <<'EOF' | kubectl apply -f - @@ -129,42 +140,50 @@ metadata: name: kuard spec: nodeID: kuard - serialization: yaml - envoyAPI: v3 - envoyResources: - clusters: - - value: | - name: kuard - connect_timeout: 10ms - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: kuard - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: { address: 127.0.0.1, port_value: 8080 } - listeners: - - value: | - name: http - # Changed listener port from 8081 to 5000 - address: { socket_address: { address: 0.0.0.0, port_value: 5000 } } - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_https - route_config: - name: local_route - virtual_hosts: - - name: any - domains: ["*"] - routes: - [{ match: { prefix: "/" }, route: { cluster: "kuard" } }] - http_filters: - - name: envoy.filters.http.router + resources: + - type: cluster + value: + connect_timeout: 0.01s + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: kuard + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: 127.0.0.1 + port_value: 8080 + name: kuard + type: STRICT_DNS + - type: listener + value: + address: + socket_address: + address: 0.0.0.0 + port_value: 5000 + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + http_filters: + - name: envoy.filters.http.router + typed_config: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + route_config: + name: local_route + virtual_hosts: + - domains: + - '*' + name: any + routes: + - match: + prefix: / + route: + cluster: other + stat_prefix: ingress_https + name: http EOF ``` diff --git a/docs/walkthroughs/tls-offloading-sidecars.md b/docs/walkthroughs/tls-offloading-sidecars.md index bd17c832..185c4e67 100644 --- a/docs/walkthroughs/tls-offloading-sidecars.md +++ b/docs/walkthroughs/tls-offloading-sidecars.md @@ -82,51 +82,63 @@ metadata: name: kuard spec: nodeID: kuard - serialization: yaml - envoyAPI: v3 - envoyResources: - secrets: - - name: kuard-certificate - clusters: - - value: | - name: kuard - connect_timeout: 10ms - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: kuard - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: { address: 127.0.0.1, port_value: 8080 } - listeners: - - value: | - name: https - address: { socket_address: { address: 0.0.0.0, port_value: 8443 } } - filter_chains: - - transport_socket: - name: envoy.transport_sockets.tls + resources: + - type: secret + generateFromTlsSecret: kuard-certificate + blueprint: tlsCertificate + - type: cluster + value: + name: kuard + type: STRICT_DNS + connect_timeout: 0.01s + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: kuard + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: 127.0.0.1 + port_value: 8080 + - type: listener + value: + name: https + address: + socket_address: + address: 0.0.0.0 + port_value: 8443 + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext - common_tls_context: - tls_certificate_sds_secret_configs: - - name: kuard-certificate - sds_config: { ads: {}, resource_api_version: "V3" } - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_https - route_config: - name: local_route - virtual_hosts: - - name: kuard - domains: ["*"] - routes: - [{ match: { prefix: "/" }, route: { cluster: "kuard" } }] - http_filters: - - name: envoy.filters.http.router + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + http_filters: + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + route_config: + name: local_route + virtual_hosts: + - domains: + - "*" + name: kuard + routes: + - match: + prefix: / + route: + cluster: kuard + stat_prefix: ingress_https + transport_socket: + name: envoy.transport_sockets.tls + typed_config: + "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext + common_tls_context: + tls_certificate_sds_secret_configs: + - name: kuard-certificate + sds_config: + ads: {} + resource_api_version: V3 EOF ``` diff --git a/pkg/image/zz_generated.go b/pkg/image/zz_generated.go index dc61d700..9bc13c88 100644 --- a/pkg/image/zz_generated.go +++ b/pkg/image/zz_generated.go @@ -1,5 +1,5 @@ package image const ( - image string = "quay.io/3scale/marin3r:v0.12.0-alpha.3" + image string = "quay.io/3scale/marin3r:v0.12.0" ) diff --git a/pkg/version/zz_generated.go b/pkg/version/zz_generated.go index 89010374..fae3c599 100644 --- a/pkg/version/zz_generated.go +++ b/pkg/version/zz_generated.go @@ -1,5 +1,5 @@ package version const ( - version string = "v0.12.0-alpha.3" + version string = "v0.12.0" )