Skip to content

SeaweedFS COSI provisioner permanently CrashLoops after one bad start (stale unix socket in emptyDir) #2429

Description

@TrijeetSethi

Summary

The seaweedfs-objectstorage-provisioner Deployment from the cozy-seaweedfs chart can enter an unrecoverable CrashLoopBackOff state after a single transient driver crash. The driver's Unix socket is created in an emptyDir shared between the seaweedfs-cosi-driver and seaweedfs-cosi-sidecar containers, and the driver does not remove the socket file on shutdown — so every subsequent restart fails with bind: address already in use. Since emptyDir survives container restarts (only pod deletion wipes it), a single bad start makes the socket unrecoverable for the lifetime of the pod.

Reproduction

Observed on Cozystack [email protected]+8ac248326acb (Cozystack v1.x, isp-full variant). The pod showed 72 driver restarts over 4d1h with no automatic recovery:

```
$ kubectl -n tenant-root get pod -l app.kubernetes.io/component=objectstorage-provisioner
NAME READY STATUS RESTARTS AGE
seaweedfs-objectstorage-provisioner-699cb8d657-j5tzz 0/2 CrashLoopBackOff 72 (21s ago) 4d1h

$ kubectl -n tenant-root logs -c seaweedfs-cosi-driver --previous
E0420 18:26:32.659118 1 server.go:51] "Failed to start server" err="listen unix /var/lib/cosi/cosi.sock: bind: address already in use"
E0420 18:26:32.659194 1 main.go:63] "driver exited with error" err="Failed to start server: listen unix /var/lib/cosi/cosi.sock: bind: address already in use"

$ kubectl -n tenant-root logs -c seaweedfs-cosi-sidecar --previous
I0420 18:26:16.646213 1 cmd.go:79] "Attempting connection to driver" address="unix:///var/lib/cosi/cosi.sock"
E0420 18:28:46.646647 1 provisioner.go:80] "Connection failed" err="context deadline exceeded" address="unix:///var/lib/cosi/cosi.sock"
```

The two containers share an emptyDir:

```yaml
volumeMounts:

  • mountPath: /var/lib/cosi
    name: socket
    volumes:
  • emptyDir: {}
    name: socket
    ```

Impact

  • BucketClaim reconciliation stops while the provisioner is down. New buckets can't be allocated.
  • The tenant-root/objectstore-system HelmRelease wedges in RollbackSucceeded/UpgradeFailed flap because Helm waits 10m for the provisioner Deployment to become available.
  • Existing buckets and the SeaweedFS S3 endpoints continue to function — the socket is only used by the COSI control plane, not the data plane.

Workaround

Manually delete the pod (which wipes emptyDir) and clear the stale leader Lease so the new pod can take over without waiting out the 150s lease:

```bash
kubectl -n tenant-root delete pod -l app.kubernetes.io/component=objectstorage-provisioner
kubectl -n tenant-root delete lease tenant-root-seaweedfs-objectstorage-k8s-io-cosi
```

Suggested fix

Add an init container to the provisioner Deployment that removes any stale socket before the driver starts:

```yaml
initContainers:

  • name: cleanup-stale-socket
    image: busybox:stable
    command: ["sh", "-c", "rm -f /var/lib/cosi/cosi.sock"]
    volumeMounts:
    • name: socket
      mountPath: /var/lib/cosi
      ```

Alternatively (or additionally), the upstream COSI driver in sigs.k8s.io/container-object-storage-interface should call os.Remove(path) before net.Listen("unix", path). Either fix alone resolves it; both are zero-risk.

Environment

  • Cozystack v1.x, isp-full variant
  • Talos v1.12.6 / Kubernetes 1.34.3
  • Chart: [email protected]+8ac248326acb

Activity

  1. added
    kind/bugCategorizes issue or PR as related to a bug
    on Apr 20, 2026
  2. added
    area/storageIssues or PRs related to storage (linstor, seaweedfs, bucket, velero, harbor)
    priority/important-soonMust be staffed and worked on either currently, or very soon, ideally in time for the next release
    triage/acceptedIndicates an issue is ready to be actively worked on
    on Apr 27, 2026
  3. lexfrei commented on Jun 2, 2026

    @lexfrei
    Contributor

    Confirming this is still present on a newer build and a different variant, plus two additions.

    Environment (reproduced)

    • Cozystack from main (dev build); objectstorage-controller and objectstorage-sidecar v1.4.0-rc.2; seaweedfs-cosi-driver v0.3.0; seaweedfs chrislusf/seaweedfs:4.05.
    • k3s v1.36.1+k3s1, isp-full-generic variant (non-Talos) — so this is not Talos-specific.
    • The socket emptyDir at /var/lib/cosi shared by both containers is present exactly as described.

    Addition 1 — the stale Lease gates recovery independently of the socket. Even when the provisioner pod is recreated with a fresh emptyDir (0 restarts, both containers Running/Ready, no bind: address already in use), reconciliation stays dead: the Lease tenant-root-seaweedfs-objectstorage-k8s-io-cosi remains held by the previous (now-deleted) pod, and the fresh pod does not take leadership for several minutes while that stale Lease (leaseDurationSeconds: 150) persists. So "delete the pod (wipes emptyDir)" does not restore service on its own — when pods are recreated rather than restarted in place, the Lease is the dominant blocker and must be cleared (or leadership handed over faster). The init-container socket cleanup is necessary but not sufficient for the recreate path.

    Addition 2 — silent false-success / data-integrity symptom (possibly a related controller-status bug). While the control plane is wedged, a Bucket created via the cozystack Bucket app (with spec.users) lands in a misleading state: the COSI Bucket (objectstorage.k8s.io) reports status.bucketReady: true with a bucketID while the bucket was never created in SeaweedFS — the filer has no buckets path, the granted identity's ListBuckets returns empty, and every object op returns NoSuchBucket. Meanwhile the matching BucketClaim.status.bucketReady stays false, so the driver refuses the BucketAccess (BucketAccess can't be granted to Bucket not in Ready state) and no credentials are issued. If the claim status is force-set to ready, credentials are then issued but are useless — they authenticate, yet every operation returns NoSuchBucket/AccessDenied. Net effect: a consumer can see a "Ready" Bucket without a usable bucket behind it.

    Recovery confirms the fix direction. A full teardown of the S3 stack recovers cleanly: disable seaweedfs on the tenant, delete the stale Lease plus any orphaned COSI Bucket/BucketClaim/BucketAccess (force-clearing finalizers) and the seaweedfs PVCs, then re-enable. A fresh provisioner then reconciles a new Bucket and an S3 PUT/GET round-trip succeeds — so the SeaweedFS data plane is fine and the problem is entirely the COSI control plane. The failure recurs after the next provisioner pod recreation, so recovery is not automatic.

    +1 on the suggested init-container socket cleanup; please also consider the lease/leaderelection path so a recreated pod takes over without the multi-minute stall.

  4. androndo commented on Aug 3, 2026

    @androndo
    Contributor

    Fixed. Closing after verifying against main (04b742670) — all three reported symptoms, including both additions in the thread.

    The socket half was fixed upstream in the driver, in the exact image main pins. packages/system/seaweedfs/values.yaml and packages/extra/seaweedfs/images/seaweedfs-cosi-driver.tag both pin ghcr.io/seaweedfs/seaweedfs-cosi-driver:v0.3.1; at that tag cmd/seaweedfs-cosi-driver/main.go stats the endpoint, refuses to touch anything that is not a socket, dials it first so a live listener is left alone, and only then removes the path before binding (upstream PR seaweedfs/seaweedfs-cosi-driver#8). The reports here were all on v0.3.0, which unconditionally bound and so wedged forever on a leftover socket in the emptyDir.

    Addition 1, the ~150s leader-election stall after a pod recreate: packages/system/objectstorage-controller/images/objectstorage/patches/93-shorten-leaderelection-lease.diff cuts LeaseDuration 150s to 15s, RenewDeadline 120s to 10s and RetryPeriod 60s to 2s, so a recreated pod resumes reconciliation in about 15s.

    Addition 2, a Bucket reported Ready with no bucket behind it: packages/system/objectstorage-controller/images/objectstorage/patches/92-bucketclaim-propagate-ready.diff.

    One thing from the discussion was deliberately not done: the chart-side init-container that would clean the socket before start. The cosi.initContainers hook exists in the vendored chart but cozystack never sets it, and the client-topology deployment still mounts a bare emptyDir. That is belt-and-braces now that the driver self-cleans, so it is not worth keeping this open — file it fresh if the driver ever regresses.

    Found during an audit of all open backup issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/storageIssues or PRs related to storage (linstor, seaweedfs, bucket, velero, harbor)kind/bugCategorizes issue or PR as related to a bugpriority/important-soonMust be staffed and worked on either currently, or very soon, ideally in time for the next releasetriage/acceptedIndicates an issue is ready to be actively worked on

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions