diff --git a/.goreleaser.yml b/.goreleaser.yml index 86c1d5671b..d48c87dc4c 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -66,13 +66,9 @@ milestones: snapshot: name_template: "edge" -before: - hooks: - - make crds-release-file - release: extra_files: - - glob: ./build/out/crds.yaml + - glob: ./deploy/crds.yaml - glob: ./deploy/manifests/nginx-gateway.yaml - glob: ./deploy/manifests/nginx-plus-gateway.yaml - glob: ./deploy/manifests/nginx-gateway-experimental.yaml diff --git a/.yamllint.yaml b/.yamllint.yaml index e0d0da447c..1160805b42 100644 --- a/.yamllint.yaml +++ b/.yamllint.yaml @@ -6,6 +6,7 @@ yaml-files: ignore: - charts/nginx-gateway-fabric - config/crd/bases/ + - deploy/crds.yaml - .github/workflows/ rules: diff --git a/Makefile b/Makefile index 1396373f6b..044a232814 100644 --- a/Makefile +++ b/Makefile @@ -101,6 +101,8 @@ generate: ## Run go generate .PHONY: generate-crds generate-crds: ## Generate CRDs and Go types using kubebuilder go run sigs.k8s.io/controller-tools/cmd/controller-gen crd object paths=./apis/... output:crd:artifacts:config=config/crd/bases + @kustomize version || (code=$$?; printf "\033[0;31mError\033[0m: there was a problem with kustomize, use 'brew install kustomize' to install it\n"; exit $$code) + kustomize build config/crd >deploy/crds.yaml .PHONY: generate-manifests generate-manifests: ## Generate manifests using Helm. @@ -113,10 +115,6 @@ generate-manifests: ## Generate manifests using Helm. helm template nginx-gateway $(CHART_DIR) $(HELM_TEMPLATE_COMMON_ARGS) --set service.annotations.'service\.beta\.kubernetes\.io\/aws-load-balancer-type'="nlb" -n nginx-gateway -s templates/service.yaml > $(strip $(MANIFEST_DIR))/service/loadbalancer-aws-nlb.yaml helm template nginx-gateway $(CHART_DIR) $(HELM_TEMPLATE_COMMON_ARGS) --set service.type=NodePort --set service.externalTrafficPolicy="" -n nginx-gateway -s templates/service.yaml > $(strip $(MANIFEST_DIR))/service/nodeport.yaml -.PHONY: crds-release-file -crds-release-file: ## Generate combined crds file for releases - scripts/combine-crds.sh - .PHONY: clean clean: ## Clean the build -rm -r $(OUT_DIR) diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml new file mode 100644 index 0000000000..873746dd82 --- /dev/null +++ b/config/crd/kustomization.yaml @@ -0,0 +1,5 @@ +resources: + - bases/gateway.nginx.org_clientsettingspolicies.yaml + - bases/gateway.nginx.org_nginxgateways.yaml + - bases/gateway.nginx.org_nginxproxies.yaml + - bases/gateway.nginx.org_observabilitypolicies.yaml diff --git a/conformance/Makefile b/conformance/Makefile index 1a3d7c482e..d426022009 100644 --- a/conformance/Makefile +++ b/conformance/Makefile @@ -11,7 +11,6 @@ KIND_KUBE_CONFIG=$${HOME}/.kube/kind/config CONFORMANCE_TAG = latest CONFORMANCE_PREFIX = conformance-test-runner NGF_MANIFEST=../deploy/manifests/nginx-gateway.yaml -CRDS=../deploy/manifests/crds/ STATIC_MANIFEST=provisioner/static-deployment.yaml PROVISIONER_MANIFEST=provisioner/provisioner.yaml INSTALL_WEBHOOK ?= false @@ -63,13 +62,13 @@ load-images-with-plus: ## Load NGF and NGINX Plus images on configured kind clus .PHONY: prepare-ngf-dependencies prepare-ngf-dependencies: update-ngf-manifest ## Install NGF dependencies on configured kind cluster ./scripts/install-gateway.sh $(GW_API_VERSION) $(INSTALL_WEBHOOK) $(ENABLE_EXPERIMENTAL) - kubectl apply -f $(CRDS) + kustomize build ../config/crd/bases | kubectl apply -f - kubectl apply -f $(NGF_MANIFEST) .PHONY: prepare-ngf-dependencies-with-plus prepare-ngf-dependencies-with-plus: update-ngf-manifest-with-plus ## Install NGF dependencies with Plus on configured kind cluster ./scripts/install-gateway.sh $(GW_API_VERSION) $(INSTALL_WEBHOOK) - kubectl apply -f $(CRDS) + kustomize build ../config/crd/bases | kubectl apply -f - kubectl apply -f $(NGF_MANIFEST) .PHONY: deploy-updated-provisioner diff --git a/deploy/crds.yaml b/deploy/crds.yaml new file mode 100644 index 0000000000..3505fd1917 --- /dev/null +++ b/deploy/crds.yaml @@ -0,0 +1,1309 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + gateway.networking.k8s.io/policy: inherited + name: clientsettingspolicies.gateway.nginx.org +spec: + group: gateway.nginx.org + names: + categories: + - nginx-gateway-fabric + kind: ClientSettingsPolicy + listKind: ClientSettingsPolicyList + plural: clientsettingspolicies + shortNames: + - cspolicy + singular: clientsettingspolicy + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + ClientSettingsPolicy is an Inherited Attached Policy. It provides a way to configure the behavior of the connection + between the client and NGINX Gateway Fabric. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of the ClientSettingsPolicy. + properties: + body: + description: Body defines the client request body settings. + properties: + maxSize: + description: |- + MaxSize sets the maximum allowed size of the client request body. + If the size in a request exceeds the configured value, + the 413 (Request Entity Too Large) error is returned to the client. + Setting size to 0 disables checking of client request body size. + Default: https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size. + pattern: ^\d{1,4}(k|m|g)?$ + type: string + timeout: + description: |- + Timeout defines a timeout for reading client request body. The timeout is set only for a period between + two successive read operations, not for the transmission of the whole request body. + If a client does not transmit anything within this time, the request is terminated with the + 408 (Request Time-out) error. + Default: https://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_timeout. + pattern: ^\d{1,4}(ms|s)?$ + type: string + type: object + keepAlive: + description: KeepAlive defines the keep-alive settings. + properties: + requests: + description: |- + Requests sets the maximum number of requests that can be served through one keep-alive connection. + After the maximum number of requests are made, the connection is closed. Closing connections periodically + is necessary to free per-connection memory allocations. Therefore, using too high maximum number of requests + is not recommended as it can lead to excessive memory usage. + Default: https://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_requests. + format: int32 + minimum: 0 + type: integer + time: + description: |- + Time defines the maximum time during which requests can be processed through one keep-alive connection. + After this time is reached, the connection is closed following the subsequent request processing. + Default: https://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_time. + pattern: ^\d{1,4}(ms|s)?$ + type: string + timeout: + description: Timeout defines the keep-alive timeouts for clients. + properties: + header: + description: 'Header sets the timeout in the "Keep-Alive: + timeout=time" response header field.' + pattern: ^\d{1,4}(ms|s)?$ + type: string + server: + description: |- + Server sets the timeout during which a keep-alive client connection will stay open on the server side. + Setting this value to 0 disables keep-alive client connections. + pattern: ^\d{1,4}(ms|s)?$ + type: string + type: object + type: object + targetRef: + description: |- + TargetRef identifies an API object to apply the policy to. + Object must be in the same namespace as the policy. + + + Support: Gateway, HTTPRoute + properties: + group: + description: Group is the group of the target resource. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the target resource. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the target resource. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, the local + namespace is inferred. Even when policy targets a resource in a different + namespace, it MUST only apply to traffic originating from the same + namespace as the policy. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + required: + - targetRef + type: object + status: + description: Status defines the state of the ClientSettingsPolicy. + properties: + ancestors: + description: |- + Ancestors is a list of ancestor resources (usually Gateways) that are + associated with the policy, and the status of the policy with respect to + each ancestor. When this policy attaches to a parent, the controller that + manages the parent and the ancestors MUST add an entry to this list when + the controller first sees the policy and SHOULD update the entry as + appropriate when the relevant ancestor is modified. + + + Note that choosing the relevant ancestor is left to the Policy designers; + an important part of Policy design is designing the right object level at + which to namespace this status. + + + Note also that implementations MUST ONLY populate ancestor status for + the Ancestor resources they are responsible for. Implementations MUST + use the ControllerName field to uniquely identify the entries in this list + that they are responsible for. + + + Note that to achieve this, the list of PolicyAncestorStatus structs + MUST be treated as a map with a composite key, made up of the AncestorRef + and ControllerName fields combined. + + + A maximum of 16 ancestors will be represented in this list. An empty list + means the Policy is not relevant for any ancestors. + + + If this slice is full, implementations MUST NOT add further entries. + Instead they MUST consider the policy unimplementable and signal that + on any related resources such as the ancestor that would be referenced + here. For example, if this list was full on BackendTLSPolicy, no + additional Gateways would be able to reference the Service targeted by + the BackendTLSPolicy. + items: + description: |- + PolicyAncestorStatus describes the status of a route with respect to an + associated Ancestor. + + + Ancestors refer to objects that are either the Target of a policy or above it + in terms of object hierarchy. For example, if a policy targets a Service, the + Policy's Ancestors are, in order, the Service, the HTTPRoute, the Gateway, and + the GatewayClass. Almost always, in this hierarchy, the Gateway will be the most + useful object to place Policy status on, so we recommend that implementations + SHOULD use Gateway as the PolicyAncestorStatus object unless the designers + have a _very_ good reason otherwise. + + + In the context of policy attachment, the Ancestor is used to distinguish which + resource results in a distinct application of this policy. For example, if a policy + targets a Service, it may have a distinct result per attached Gateway. + + + Policies targeting the same resource may have different effects depending on the + ancestors of those resources. For example, different Gateways targeting the same + Service may have different capabilities, especially if they have different underlying + implementations. + + + For example, in BackendTLSPolicy, the Policy attaches to a Service that is + used as a backend in a HTTPRoute that is itself attached to a Gateway. + In this case, the relevant object for status is the Gateway, and that is the + ancestor object referred to in this status. + + + Note that a parent is also an ancestor, so for objects where the parent is the + relevant object for status, this struct SHOULD still be used. + + + This struct is intended to be used in a slice that's effectively a map, + with a composite key made up of the AncestorRef and the ControllerName. + properties: + ancestorRef: + description: |- + AncestorRef corresponds with a ParentRef in the spec that this + PolicyAncestorStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + + There are two kinds of parent resources with "Core" support: + + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, experimental, ClusterIP Services only) + + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + + Support: Extended + + + + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + + * Gateway: Listener Name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port Name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. Note that attaching Routes to Services as Parents + is part of experimental Mesh support and is not supported for any other + purpose. + + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + conditions: + description: Conditions describes the status of the Policy with + respect to the given Ancestor. + items: + description: "Condition contains details for one aspect of + the current state of this API Resource.\n---\nThis struct + is intended for direct use as an array at the field path + .status.conditions. For example,\n\n\n\ttype FooStatus + struct{\n\t // Represents the observations of a foo's + current state.\n\t // Known .status.conditions.type are: + \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // + +listType=map\n\t // +listMapKey=type\n\t Conditions + []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" + patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + 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 + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: |- + ControllerName is a domain/path string that indicates the name of the + controller that wrote this status. This corresponds with the + controllerName field on GatewayClass. + + + Example: "example.net/gateway-controller". + + + The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are + valid Kubernetes names + (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + + + Controllers MUST populate this field when writing status. Controllers should ensure that + entries to status populated with their ControllerName are cleaned up when they are no + longer necessary. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + required: + - ancestorRef + - controllerName + type: object + maxItems: 16 + type: array + required: + - ancestors + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + name: nginxgateways.gateway.nginx.org +spec: + group: gateway.nginx.org + names: + categories: + - nginx-gateway-fabric + kind: NginxGateway + listKind: NginxGatewayList + plural: nginxgateways + singular: nginxgateway + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: NginxGateway represents the dynamic configuration for an NGINX + Gateway Fabric control plane. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: NginxGatewaySpec defines the desired state of the NginxGateway. + properties: + logging: + description: Logging defines logging related settings for the control + plane. + properties: + level: + default: info + description: Level defines the logging level. + enum: + - info + - debug + - error + type: string + type: object + type: object + status: + description: NginxGatewayStatus defines the state of the NginxGateway. + properties: + conditions: + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + 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 + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + name: nginxproxies.gateway.nginx.org +spec: + group: gateway.nginx.org + names: + categories: + - nginx-gateway-fabric + kind: NginxProxy + listKind: NginxProxyList + plural: nginxproxies + singular: nginxproxy + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + NginxProxy is a configuration object that is attached to a GatewayClass parametersRef. It provides a way + to configure global settings for all Gateways defined from the GatewayClass. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of the NginxProxy. + properties: + telemetry: + description: Telemetry specifies the OpenTelemetry configuration. + properties: + exporter: + description: Exporter specifies OpenTelemetry export parameters. + properties: + batchCount: + description: |- + BatchCount is the number of pending batches per worker, spans exceeding the limit are dropped. + Default: https://nginx.org/en/docs/ngx_otel_module.html#otel_exporter + format: int32 + minimum: 0 + type: integer + batchSize: + description: |- + BatchSize is the maximum number of spans to be sent in one batch per worker. + Default: https://nginx.org/en/docs/ngx_otel_module.html#otel_exporter + format: int32 + minimum: 0 + type: integer + endpoint: + description: |- + Endpoint is the address of OTLP/gRPC endpoint that will accept telemetry data. + Format: alphanumeric hostname with optional http scheme and optional port. + pattern: ^(?:http?:\/\/)?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*(?::\d{1,5})?$ + type: string + interval: + description: |- + Interval is the maximum interval between two exports. + Default: https://nginx.org/en/docs/ngx_otel_module.html#otel_exporter + pattern: ^\d{1,4}(ms|s)?$ + type: string + required: + - endpoint + type: object + serviceName: + description: |- + ServiceName is the "service.name" attribute of the OpenTelemetry resource. + Default is 'ngf::'. If a value is provided by the user, + then the default becomes a prefix to that value. + maxLength: 127 + pattern: ^[a-zA-Z0-9_-]+$ + type: string + spanAttributes: + description: SpanAttributes are custom key/value attributes that + are added to each span. + items: + description: SpanAttribute is a key value pair to be added to + a tracing span. + properties: + key: + description: |- + Key is the key for a span attribute. + Format: must have all '"' escaped and must not contain any '$' or end with an unescaped '\' + maxLength: 255 + minLength: 1 + pattern: ^([^"$\\]|\\[^$])*$ + type: string + value: + description: |- + Value is the value for a span attribute. + Format: must have all '"' escaped and must not contain any '$' or end with an unescaped '\' + maxLength: 255 + minLength: 1 + pattern: ^([^"$\\]|\\[^$])*$ + type: string + required: + - key + - value + type: object + maxItems: 64 + type: array + x-kubernetes-list-map-keys: + - key + x-kubernetes-list-type: map + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + gateway.networking.k8s.io/policy: direct + name: observabilitypolicies.gateway.nginx.org +spec: + group: gateway.nginx.org + names: + categories: + - nginx-gateway-fabric + kind: ObservabilityPolicy + listKind: ObservabilityPolicyList + plural: observabilitypolicies + singular: observabilitypolicy + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + ObservabilityPolicy is a Direct Attached Policy. It provides a way to configure observability settings for + the NGINX Gateway Fabric data plane. Used in conjunction with the NginxProxy CRD that is attached to the + GatewayClass parametersRef. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of the ObservabilityPolicy. + properties: + targetRef: + description: |- + TargetRef identifies an API object to apply the policy to. + Object must be in the same namespace as the policy. + + + Support: HTTPRoute + properties: + group: + description: Group is the group of the target resource. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the target resource. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the target resource. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, the local + namespace is inferred. Even when policy targets a resource in a different + namespace, it MUST only apply to traffic originating from the same + namespace as the policy. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + tracing: + description: Tracing allows for enabling and configuring tracing. + properties: + context: + description: |- + Context specifies how to propagate traceparent/tracestate headers. + Default: https://nginx.org/en/docs/ngx_otel_module.html#otel_trace_context + enum: + - extract + - inject + - propagate + - ignore + type: string + ratio: + description: |- + Ratio is the percentage of traffic that should be sampled. Integer from 0 to 100. + By default, 100% of http requests are traced. Not applicable for parent-based tracing. + format: int32 + maximum: 100 + minimum: 0 + type: integer + spanAttributes: + description: SpanAttributes are custom key/value attributes that + are added to each span. + items: + description: SpanAttribute is a key value pair to be added to + a tracing span. + properties: + key: + description: |- + Key is the key for a span attribute. + Format: must have all '"' escaped and must not contain any '$' or end with an unescaped '\' + maxLength: 255 + minLength: 1 + pattern: ^([^"$\\]|\\[^$])*$ + type: string + value: + description: |- + Value is the value for a span attribute. + Format: must have all '"' escaped and must not contain any '$' or end with an unescaped '\' + maxLength: 255 + minLength: 1 + pattern: ^([^"$\\]|\\[^$])*$ + type: string + required: + - key + - value + type: object + maxItems: 64 + type: array + x-kubernetes-list-map-keys: + - key + x-kubernetes-list-type: map + spanName: + description: |- + SpanName defines the name of the Otel span. By default is the name of the location for a request. + If specified, applies to all locations that are created for a route. + Format: must have all '"' escaped and must not contain any '$' or end with an unescaped '\' + Examples of invalid names: some-$value, quoted-"value"-name, unescaped\ + maxLength: 255 + minLength: 1 + pattern: ^([^"$\\]|\\[^$])*$ + type: string + strategy: + description: Strategy defines if tracing is ratio-based or parent-based. + enum: + - ratio + - parent + type: string + required: + - strategy + type: object + x-kubernetes-validations: + - message: ratio can only be specified if strategy is of type ratio + rule: '!(has(self.ratio) && self.strategy != ''ratio'')' + required: + - targetRef + type: object + status: + description: Status defines the state of the ObservabilityPolicy. + properties: + ancestors: + description: |- + Ancestors is a list of ancestor resources (usually Gateways) that are + associated with the policy, and the status of the policy with respect to + each ancestor. When this policy attaches to a parent, the controller that + manages the parent and the ancestors MUST add an entry to this list when + the controller first sees the policy and SHOULD update the entry as + appropriate when the relevant ancestor is modified. + + + Note that choosing the relevant ancestor is left to the Policy designers; + an important part of Policy design is designing the right object level at + which to namespace this status. + + + Note also that implementations MUST ONLY populate ancestor status for + the Ancestor resources they are responsible for. Implementations MUST + use the ControllerName field to uniquely identify the entries in this list + that they are responsible for. + + + Note that to achieve this, the list of PolicyAncestorStatus structs + MUST be treated as a map with a composite key, made up of the AncestorRef + and ControllerName fields combined. + + + A maximum of 16 ancestors will be represented in this list. An empty list + means the Policy is not relevant for any ancestors. + + + If this slice is full, implementations MUST NOT add further entries. + Instead they MUST consider the policy unimplementable and signal that + on any related resources such as the ancestor that would be referenced + here. For example, if this list was full on BackendTLSPolicy, no + additional Gateways would be able to reference the Service targeted by + the BackendTLSPolicy. + items: + description: |- + PolicyAncestorStatus describes the status of a route with respect to an + associated Ancestor. + + + Ancestors refer to objects that are either the Target of a policy or above it + in terms of object hierarchy. For example, if a policy targets a Service, the + Policy's Ancestors are, in order, the Service, the HTTPRoute, the Gateway, and + the GatewayClass. Almost always, in this hierarchy, the Gateway will be the most + useful object to place Policy status on, so we recommend that implementations + SHOULD use Gateway as the PolicyAncestorStatus object unless the designers + have a _very_ good reason otherwise. + + + In the context of policy attachment, the Ancestor is used to distinguish which + resource results in a distinct application of this policy. For example, if a policy + targets a Service, it may have a distinct result per attached Gateway. + + + Policies targeting the same resource may have different effects depending on the + ancestors of those resources. For example, different Gateways targeting the same + Service may have different capabilities, especially if they have different underlying + implementations. + + + For example, in BackendTLSPolicy, the Policy attaches to a Service that is + used as a backend in a HTTPRoute that is itself attached to a Gateway. + In this case, the relevant object for status is the Gateway, and that is the + ancestor object referred to in this status. + + + Note that a parent is also an ancestor, so for objects where the parent is the + relevant object for status, this struct SHOULD still be used. + + + This struct is intended to be used in a slice that's effectively a map, + with a composite key made up of the AncestorRef and the ControllerName. + properties: + ancestorRef: + description: |- + AncestorRef corresponds with a ParentRef in the spec that this + PolicyAncestorStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + + There are two kinds of parent resources with "Core" support: + + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, experimental, ClusterIP Services only) + + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + + Support: Extended + + + + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + + * Gateway: Listener Name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port Name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. Note that attaching Routes to Services as Parents + is part of experimental Mesh support and is not supported for any other + purpose. + + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + conditions: + description: Conditions describes the status of the Policy with + respect to the given Ancestor. + items: + description: "Condition contains details for one aspect of + the current state of this API Resource.\n---\nThis struct + is intended for direct use as an array at the field path + .status.conditions. For example,\n\n\n\ttype FooStatus + struct{\n\t // Represents the observations of a foo's + current state.\n\t // Known .status.conditions.type are: + \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // + +listType=map\n\t // +listMapKey=type\n\t Conditions + []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" + patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + 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 + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: |- + ControllerName is a domain/path string that indicates the name of the + controller that wrote this status. This corresponds with the + controllerName field on GatewayClass. + + + Example: "example.net/gateway-controller". + + + The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are + valid Kubernetes names + (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + + + Controllers MUST populate this field when writing status. Controllers should ensure that + entries to status populated with their ControllerName are cleaned up when they are no + longer necessary. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + required: + - ancestorRef + - controllerName + type: object + maxItems: 16 + type: array + required: + - ancestors + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/manifests/crds b/deploy/manifests/crds deleted file mode 120000 index dad8a5781a..0000000000 --- a/deploy/manifests/crds +++ /dev/null @@ -1 +0,0 @@ -../../config/crd/bases \ No newline at end of file diff --git a/docs/developer/quickstart.md b/docs/developer/quickstart.md index 5893143666..0e42834212 100644 --- a/docs/developer/quickstart.md +++ b/docs/developer/quickstart.md @@ -154,7 +154,7 @@ This will build the docker images `nginx-gateway-fabric:` and `nginx- ```shell make generate-manifests HELM_TEMPLATE_COMMON_ARGS="--set nginxGateway.image.repository=nginx-gateway-fabric --set nginxGateway.image.tag=$(whoami) --set nginxGateway.image.pullPolicy=Never --set nginx.image.repository=nginx-gateway-fabric/nginx --set nginx.image.tag=$(whoami) --set nginx.image.pullPolicy=Never" - kubectl apply -f deploy/manifests/crds + kubectl apply -f deploy/crds.yaml kubectl apply -f deploy/manifests/nginx-gateway.yaml kubectl apply -f deploy/manifests/service/nodeport.yaml ``` @@ -163,7 +163,7 @@ This will build the docker images `nginx-gateway-fabric:` and `nginx- ```shell make generate-manifests HELM_TEMPLATE_COMMON_ARGS="--set nginxGateway.image.repository=nginx-gateway-fabric --set nginxGateway.image.tag=$(whoami) --set nginxGateway.image.pullPolicy=Never --set nginx.image.repository=nginx-gateway-fabric/nginx-plus --set nginx.image.tag=$(whoami) --set nginx.image.pullPolicy=Never --set nginx.plus=true" - kubectl apply -f deploy/manifests/crds + kubectl apply -f deploy/crds.yaml kubectl apply -f deploy/manifests/nginx-gateway.yaml kubectl apply -f deploy/manifests/service/nodeport.yaml ``` @@ -172,7 +172,7 @@ This will build the docker images `nginx-gateway-fabric:` and `nginx- ```shell make generate-manifests HELM_TEMPLATE_COMMON_ARGS="--set nginxGateway.image.repository=nginx-gateway-fabric --set nginxGateway.image.tag=$(whoami) --set nginxGateway.image.pullPolicy=Never --set nginx.image.repository=nginx-gateway-fabric/nginx --set nginx.image.tag=$(whoami) --set nginx.image.pullPolicy=Never" - kubectl apply -f deploy/manifests/crds + kubectl apply -f deploy/crds.yaml kubectl apply -f deploy/manifests/nginx-gateway-experimental.yaml kubectl apply -f deploy/manifests/service/nodeport.yaml ``` diff --git a/scripts/combine-crds.sh b/scripts/combine-crds.sh deleted file mode 100755 index a05e5cb043..0000000000 --- a/scripts/combine-crds.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -mkdir -p build/out - -CRD_FILE=build/out/crds.yaml -echo "# NGINX Gateway API CustomResourceDefinitions" > ${CRD_FILE} - -for file in `ls deploy/manifests/crds/*.yaml`; do - echo "#" >> ${CRD_FILE} - echo "# $file" >> ${CRD_FILE} - echo "#" >> ${CRD_FILE} - cat $file >> ${CRD_FILE} -done diff --git a/site/content/installation/installing-ngf/manifests.md b/site/content/installation/installing-ngf/manifests.md index a50c585c98..fc9e444b81 100644 --- a/site/content/installation/installing-ngf/manifests.md +++ b/site/content/installation/installing-ngf/manifests.md @@ -33,18 +33,13 @@ Deploying NGINX Gateway Fabric with Kubernetes manifests takes only a few steps. #### Stable release ```shell - kubectl apply -f https://github.com/nginxinc/nginx-gateway-fabric/releases/download/v1.2.0/crds.yaml + kubectl apply -f https://raw.githubusercontent.com/nginxinc/nginx-gateway-fabric/v1.2.0/deploy/crds.yaml ``` #### Edge version ```shell - git clone https://github.com/nginxinc/nginx-gateway-fabric.git - cd nginx-gateway-fabric - ``` - - ```shell - kubectl apply -f deploy/manifests/crds + kubectl apply -f https://raw.githubusercontent.com/nginxinc/nginx-gateway-fabric/main/deploy/crds.yaml ``` ### 3. Deploy NGINX Gateway Fabric @@ -164,7 +159,7 @@ To upgrade NGINX Gateway Fabric and get the latest features and improvements, ta - To upgrade the Custom Resource Definitions (CRDs), run: ```shell - kubectl apply -f https://github.com/nginxinc/nginx-gateway-fabric/releases/download/v1.2.0/crds.yaml + kubectl apply -f https://raw.githubusercontent.com/nginxinc/nginx-gateway-fabric/v1.2.0/deploy/crds.yaml ``` 1. **Upgrade NGINX Gateway Fabric deployment:** @@ -238,7 +233,7 @@ Follow these steps to uninstall NGINX Gateway Fabric and Gateway API from your K ``` ```shell - kubectl delete -f https://github.com/nginxinc/nginx-gateway-fabric/releases/download/v1.2.0/crds.yaml + kubectl delete -f https://raw.githubusercontent.com/nginxinc/nginx-gateway-fabric/v1.2.0/deploy/crds.yaml ``` 1. **Remove the Gateway API resources:**