Skip to content

Upjet leaks orphan external resources upon provider pod crash/restart #305

Description

@arfevrier

What problem are you facing?

Hello, I'm working on project requiring to manage in GCP thousands of objects. I wanted to test Crossplane's behaviour with this large number of objects created.
In k8s, pods have no guarantee to run to completion and may be interrupted at any time, including graceful K8S node shutdown. I have observed that when the provider's pod is terminated while a crossplane MR reconciles and an external resource is being created, we have no information to be able to recover manually. This lack of information is problematic when you have to manage a large number of objects.
I made a benchmark on the GCP provider benchmark_gcp_18-10-2023. The project contains installation and configuration code.

Details of the infrastructure:

  • Date: 18/10/2023
  • Platform: Google Cloud Platform (GCP), GKE Cluster Standard
  • Version: K8s: 1.27.3-gke.100, Crossplane: v1.13, provider-gcp-dns:v0.37.0
  • Setting: Default, with Crossplane ControllerConfig: --debug and --enable-management-policies
  • Compute Machine type: e2-highcpu-16 (16vCPU/16Go)

On the run I have called Run N°5: 4000 RecordSets: Service interruption during resource creation I have terminated the GCP provider pod during the deployment of 4000 RecordSets.

image
Top diagram: Number of log received from the provider. Botton diagram: Number of API calls reveiced by GCP for the DNS API endpoints.

After provider restart some resources are already created. As the provider was unable to complete the creation of the object in K8s, in the state of the K8s cluster the object does not exist. It will then try to start creating it again. The provider tries in loop to create the resources but fails because the name of the RecordSet already exist.

image
The provider tries to create in loop the resource recordset/benchmarkeight339 but Terraform fails in loop with 409 error.

Log details (exported from GCP Logs Explorer):

In the case of GCP RecordSet, two external resources cannot have the same name. But if we use resources referenced by their ID, the resource will then be orphaned.
By default no information about creation in progress is printed. In the GCP provider we need to start the pod with the --debug option.

How could Upjet help solve your problem?

The provider could give more information in order to reconciliate manually the situation. For exemple:

  • By default, the provider log could contain information about the creation status of an object. Without the need to rely on the --debug option.

  • The MR resource can block on Status.Conditions.Reason "Creating". If the provider start and see MR resource in "Creating" it mean something have not been done properly. The object is put in error to warn the human operator about potential orphan resource in GCP (e.g.: "The provider restarted during resource creation"). This is the way Terraform has chosen: The .tfstate is lock at startup. In case of a crash, the lock is not release. Terraform cannot be started up again without an operator manually releasing the lock.

  • I don't know if this is possible: Create an object on the cloud provider in a transactional way. In order to perform failure recovery. Undoubtedly complicated if we go by Terraform.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions