Skip to content

Releases: fieldwork-ai/lighter

lighter 0.12.5

Choose a tag to compare

@rogersnm rogersnm released this 08 Oct 17:34
96f366e

lighter 0.12.5

LAN mode needs no sudo and no helper any more. Apple granted lighter its VM Networking entitlement, so lighter puts its machine on your network by itself.

What changed

  • LAN mode is one setting. lighter config --lan on, then lighter restart: the machine gets its own address on your network, with no sudo lighter lan enable first and no root process installed on your Mac. Until now a small helper, a root launchd daemon, started the bridged network card for lighter; macOS lets an app do that itself only with an entitlement Apple grants case by case, and Apple has granted it to lighter.
  • Everything else about LAN mode is the same: the same address from your router, the same discovery of devices by mDNS and SSDP, and the same rules for what your network can reach. Measured on the release build with no helper anywhere: an address by DHCP on Wi-Fi, 15 hosts answering a host-network container's mDNS query, and every reachability check of the LAN gate passing.
  • If you installed the helper, it can go: sudo lighter lan disable. Leaving it does no harm; lighter no longer uses it. lighter lan status says which applies.

Upgrading

brew upgrade lighter
lighter restart

Or lighter update download then lighter upgrade --restart if you installed with the install script.

Also

  • A build of your own from source still needs the helper for LAN mode (sudo lighter lan enable): the entitlement holds only in a release signed and notarized by Fieldwork.
  • Linux remains 6.18.52 (kernel f4dfc278). The data epoch remains 1.

Checksums

  • lighter-0.12.5-arm64.tar.gz: SHA256 73c196130d9cb40416a9f59d8d8287c4387a9f623448f0fb98e39fd52987d96c
  • lighter-0.12.5-arm64 (installer bootstrap): SHA256 2cae23c9811fd86c2b5ebb26527afff28b9135a98c435efa047dc6b3bb99088c
  • Kernel f4dfc278, rootfs 8431d8d0. Notarization 669c0a08 accepted.

lighter 0.12.4

Choose a tag to compare

@rogersnm rogersnm released this 08 Oct 08:14
5d45a65

lighter 0.12.4

Databases start with their data in a shared folder or on a drive, a container's nested mounts stay in place when the Mac changes the folders they sit in, and connections a server resets no longer pile up until containers cannot connect out.

What went wrong

MariaDB could not start with its data in a shared folder or on a drive (#69, Borg Backup Server). lighter read the open flags a container passes in the wrong numbering: O_DIRECT, which MariaDB's storage engine opens its files with, reached the Mac as "open a directory", which the Mac refuses. The database could not create its files, and the container restarted forever: ten times in its first 75 seconds. A file preallocated straight after it was created also failed, with "Stale file handle".

On exFAT and FAT drives, as most drives are sold, a container's chmod did not stick. Those drives keep no permissions, and the Mac reports every file on them as its owner's alone (rwx------). A service whose user has to reach a directory another user owns could not, and a rename that must not replace a file, which ClickHouse uses, failed there with "Operation not supported".

A container lost the bind mounts nested inside another while it ran (#70), when the Mac touched a directory they sit in or changed its extended attributes. docker inspect still listed them; the container saw empty directories, and what it wrote went to the Mac's folder underneath.

After a restart, every owner a container had set in the home folder or on a drive read as root, until some container ran chown again. A database whose image checks its data directory's owner before changing it could refuse to start after lighter restart. The ownership was kept all along; lighter looked for it only once a chown had happened since it started.

Every outbound connection its server reset kept two descriptors in lighter's machine (#63). On a home server running Home Assistant, Frigate and Zigbee2MQTT, lighter's proxy ran out of all 65,536 in about six hours, and containers' connections out were refused until a restart.

What changed

  • O_DIRECT opens work. MariaDB initializes and runs with its data in a shared folder. Borg Backup Server, which failed to start on 0.12.3, starts and serves its web interface with its data in the home folder and on an exFAT drive.
  • On exFAT and FAT drives, a container's chmod is kept, in the record lighter already keeps for a container's chown, and every container sees it, after a restart too. The drive itself is untouched, and new files start as the Mac reports them. A rename that must not replace works there, as it does with Linux's own exFAT driver.
  • Owners a container sets are kept across restarts, in the home folder and on drives alike.
  • A change on the Mac never takes a container's mounts away. What the Mac removes, renames or creates is still seen at once.
  • A connection its server resets is let go. After 32 of them, lighter's proxy holds the 10 descriptors it held before; 0.12.3 held 74.

Upgrading

brew upgrade lighter
lighter restart

Or lighter update download then lighter upgrade --restart if you installed with the install script.

Also

  • The Mac's own disk and exFAT drives treat names that differ only in case as one, so a container that writes two such names into a shared folder finds a single file. ClickHouse does, inside Borg Backup Server, which then runs with its catalog features off. That is the drive, with lighter as with Docker Desktop: keep such data in a Docker volume, or on a case-sensitive APFS volume, where Borg Backup Server runs in full.
  • Linux remains 6.18.52 (kernel f4dfc278). The data epoch remains 1.

Checksums

  • lighter-0.12.4-arm64.tar.gz: SHA256 0f1bfcbdfa0d4fa546cf34231c4e16708fae2a2838d6d82a239e410f9bbb5baa
  • lighter-0.12.4-arm64 (installer bootstrap): SHA256 0138ff386bf77137bbb2b0793d1360a6223e428a0808d93af5aec592ecd34f41
  • Kernel f4dfc278, rootfs 8431d8d0. Notarization 9bdb41ab accepted.

lighter 0.12.3

Choose a tag to compare

@rogersnm rogersnm released this 07 Oct 19:43
6b2c93c

lighter 0.12.3

A network drive on the Mac that stops answering no longer freezes lighter's machine, and a device that calls a published UDP port over an IPv6 link-local address (fe80::) now gets an answer.

What went wrong

A hung network drive froze part of the machine. lighter answers a file request on the CPU that asked for it when nothing else is waiting, which is faster than handing it to a worker. A request on a network drive (SMB, NFS, AFP, WebDAV) that had stopped answering then stopped that CPU for as long as the drive did: with a NAS hung for 48 seconds, three of the machine's CPUs stopped, one for 40 seconds, and any container on them stopped too, whatever it was doing. And with enough requests waiting on that drive at once, every worker of the shared folder it was in was waiting too, so even files on the Mac's own disk in the same folder went unanswered: 38.7 seconds in one test.

A link-local IPv6 caller got no answer over UDP. lighter passes each caller's own address to a published port, so a DNS server such as Pi-hole or Technitium sees which device is asking. A link-local IPv6 address cannot be passed on: it only means something on the Mac's own network, and a container's reply to it would never leave the container. Over TCP such a caller was shown as lighter's own address, as a caller on the Mac itself is. Over UDP it was not shown at all: the datagram was dropped, and the caller got no answer.

What changed

  • Only requests on the Mac's own disks are answered on the CPU that asked. A request on a network drive goes to a worker, and at most a quarter of a shared folder's workers wait on such drives at once, so a drive that hangs holds up only what is waiting for it: with the same NAS hung for 48 seconds, no CPU stopped, and a file on the Mac's own disk in the same folder still answered at once. Requests on the Mac's own disks are as fast as before.
  • A link-local IPv6 caller is answered over UDP as well as TCP, and shown as lighter's own address, as a caller on the Mac itself is. Callers on IPv4 and on global IPv6 addresses are shown as themselves, as before.

Upgrading

brew upgrade lighter
lighter restart

Or lighter update download then lighter upgrade --restart if you installed with the install script.

Also

  • Linux remains 6.18.52 (kernel f4dfc278). The data epoch remains 1.

Checksums

  • lighter-0.12.3-arm64.tar.gz: SHA256 0a0c88211a89b69293c7f46a12e68af8fb58f60a31cf0dedf648178e451853c2
  • lighter-0.12.3-arm64 (installer bootstrap): SHA256 05e77c133b2baf741c2f3798a667aae3774d8310d05d3ce17d168e3c05f30dce
  • Kernel f4dfc278, rootfs 8dbbd78f. Notarization 6274c29c accepted.

lighter 0.12.2

Choose a tag to compare

@rogersnm rogersnm released this 07 Oct 15:44
ea0e926

lighter 0.12.2

A port published on one of your Mac's own addresses (-p 192.168.1.20:9000:9000, or a Tailscale address) now works, as it does with Docker Desktop and OrbStack.

What went wrong

Docker runs inside lighter's Linux machine, and binds a published port on the address you name. Name one of the Mac's addresses rather than 0.0.0.0 or 127.0.0.1, and Docker could not bind it, because the machine does not have that address: the container did not start ("cannot assign requested address"). A Compose file that keeps MinIO, a database or an admin UI on one network, or only on Tailscale, could not be used.

What changed

  • A port published on a Mac address is served on exactly that address. lighter binds it on the Mac, and the container answers there and nowhere else: not on localhost, and not on the Mac's other addresses. TCP and UDP, IPv4 and IPv6.
  • Containers still reach the Mac on that address. A container talking to a service running on the Mac itself, at the same address, still reaches the Mac.
  • If the address is not there when the port is opened (Tailscale disconnected, Wi-Fi on another network), lighter status lists the port as not forwarded, with the reason, and lighter keeps trying, as for any port the Mac cannot open.

Upgrading

brew upgrade lighter
lighter restart

Or lighter update download then lighter upgrade --restart if you installed with the install script.

Also

  • Linux remains 6.18.52 (kernel f4dfc278). The data epoch remains 1.

Checksums

  • lighter-0.12.2-arm64.tar.gz: SHA256 f35d2cca7c8555611974c78cd5b2ff4fae80c796c025219a477d805ae6778fe2
  • lighter-0.12.2-arm64 (installer bootstrap): SHA256 a5c49993ba69a1cfdba0266bf424c328261b5c660883d30a6f01849c3b4b0478
  • Kernel f4dfc278, rootfs 8c5ffa06. Notarization 09ecb373 accepted.

lighter 0.12.1

Choose a tag to compare

@rogersnm rogersnm released this 07 Oct 10:45
7a81aa6

lighter 0.12.1

A container that uses a USB stick, such as Zigbee2MQTT or Z-Wave JS, now comes back by itself after lighter restart or an upgrade.

What went wrong

When lighter restarts, Docker starts every container with a restart policy as soon as it is up, and the Mac attaches the USB devices you hold with lighter usb attach a few seconds later. A container that names a stick with devices: (/dev/serial/by-id/...) therefore started before the stick was there, failed with "no such file or directory", and stayed stopped: Docker never retries a container that failed to start, whatever its restart policy. Zigbee2MQTT was down after every restart until it was started by hand.

What changed

  • The machine waits for your USB devices before it starts any container. At boot, lighter tells the machine which held devices are plugged in, and the machine waits until each is attached and has its /dev/serial/by-id name before Docker starts. A container naming one comes back with it, as it would on a Linux machine with the stick plugged in. Measured on a Home Assistant Connect ZBT-2: the stick was there 2.4 to 4.7 seconds into boot, and boot waited exactly that long.
  • Nothing waits for a device that is not coming. Only devices plugged into the Mac are waited for, and never for more than fifteen seconds; a machine with no USB devices starts as before.

Upgrading

brew upgrade lighter
lighter restart

Or lighter update download then lighter upgrade --restart if you installed with the install script.

Also

  • Linux remains 6.18.52 (kernel f4dfc278). The data epoch remains 1.

Checksums

  • lighter-0.12.1-arm64.tar.gz: SHA256 ee55079d925ed016d9ab75bd349a71793873e90863eac07876e4616f08ab837d
  • lighter-0.12.1-arm64 (installer bootstrap): SHA256 72fa141986ad059a26e96ee11654953a9e0de261dfd3a16b1ecbfb438a62f75f
  • Kernel f4dfc278, rootfs fe7f5cdc. Notarization 2e5317eb accepted.

lighter 0.12.0

Choose a tag to compare

@rogersnm rogersnm released this 07 Oct 08:04
8d8f85a

lighter 0.12.0

network_mode: host works from the Mac, and a container can be on your network: Home Assistant, in host mode, discovers your devices and is discovered by them, as it would be on a Linux machine (#60). A reverse proxy such as Nginx Proxy Manager or Caddy in front of a host-network container now reaches it (#61).

What went wrong

lighter connects containers to your network through the Mac rather than putting them on it. That keeps your VPN and proxy settings in force for every container, and it meant two things never worked:

  • network_mode: host: a host-network container shares lighter's own network, not the Mac's, and Docker has no port bindings to report for it, so nothing it listened on was reachable from the Mac.
  • Discovery: Home Assistant, Plex, Jellyfin and the like find devices with mDNS, SSDP and DHCP, which only reach devices on the same network, so they found nothing on their own, in either mode.

What changed

  • What a host-network container listens on is reachable from the Mac, and from other containers through host.docker.internal, TCP and UDP, on localhost and, as lighter config --publish says, on the Mac's network, exactly as a port you publish with -p is: within milliseconds of the server starting to listen, gone when it stops, and the container sees who is calling. A server bound to 127.0.0.1 is on the Mac's loopback only.

  • LAN mode puts the machine on your network, with a network card and an address of its own:

    sudo lighter lan enable      # once: installs lighter's network helper
    lighter config --lan on
    lighter restart
    lighter status               #   lan        192.168.50.85/24 on Wi-Fi en1
    

    A host-network container then discovers and is discovered as on a Linux machine: Home Assistant picks the LAN address as its own and advertises it, and its integrations find what announces itself over mDNS or SSDP: on a home network, a Hue bridge, a printer, a NAS and the router within ten seconds of starting, against nothing without LAN mode. The machine gets its address from your router; on Wi-Fi, where a router may lease it nothing (the Mac's Wi-Fi carries one MAC), name one with lighter config --lan-address 192.168.50.240.

    Only what needs your network uses it. Everything bound for the internet still leaves through the Mac, so your VPN and proxy settings still apply, and containers on Docker's own networks reach your devices as they always have. Your network can reach only the ports host-network containers listen on, and the ports you publish when --publish is lan: never lighter's own.

    LAN mode needs a small system helper, because macOS lets only the system put a virtual machine on a network. It serves only lighter, and only the users who enabled it, and sudo lighter lan disable removes it. lighter has asked Apple for the entitlement that will make the helper unnecessary.

Upgrading

brew upgrade lighter
lighter restart

Or lighter update download then lighter upgrade --restart if you installed with the install script. Containers with a restart policy come back by themselves; start the others again, as after any restart. LAN mode is off until you turn it on.

Also

  • A container that uses the GPU or Neural Engine as soon as it starts is no longer turned away. Docker starts a container's process a moment before it lists the container as running, and lighter checks that list before letting a container reach an accelerator: a client that connected at once, as llama-bench does, could be refused as not running. lighter now waits out that moment, without holding up any other connection, and still refuses a container that did not ask for the device.
  • The machine gives memory back to a Mac that swapped long ago. A Mac with a lot of swap in use was treated as short of memory for as long as the swap stayed, which can be days after whatever caused it, so the machine held on to memory it had finished with. Swap now counts only while the Mac is still swapping.
  • Linux remains 6.18.52, with one more option built in, UDP socket diagnostics, which is how lighter finds a host-network UDP service (kernel f4dfc278). The data epoch remains 1.
  • A machine has room for more devices: 32 instead of 16, so LAN mode and several shared folders of your own fit together.

Checksums

  • lighter-0.12.0-arm64.tar.gz: SHA256 2f628b90f01e7d5d69abb49ec30d4ba824c5a2ca27df27002ce12de5633e27be
  • lighter-0.12.0-arm64 (installer bootstrap): SHA256 eb9448a57a96948d943746b4c21af0820a5e58984069d6e166f718f67bb346c8
  • Kernel f4dfc278, rootfs 6e7d8ae6. Notarization 76414229 accepted.

lighter 0.11.7

Choose a tag to compare

@rogersnm rogersnm released this 06 Oct 09:43
c50f88a

lighter 0.11.7

Containers no longer lose their outbound connections after a long run (#57), containers running as different users can work in the same shared folder (#55), and a non-root container can remove its own files from a sticky directory.

What went wrong

  • Outbound connections stopped working after hours (#57). When a container closed a connection to something that never closes its own end, as many devices and servers do with idle connections, lighter kept carrying it forever, holding four of its descriptors. A Home Assistant polling such a device used them all up overnight, and from then on every new outbound connection from every container was refused until lighter restarted.
  • One container user was locked out of what another made (#55). What a container running as a non-root user created in a shared folder was recorded as that user's, so a container running as anyone else got only the "other" permission bits: a build container running as you and a sandbox running as 1000 each found the other's directories read-only. Neither Docker Desktop nor OrbStack does this.
  • Sticky directories refused their own files. A non-root container could not delete a file it owned, or a Mac file, from a directory with the sticky bit (chmod 1777), because Linux still saw such files as root's.
  • Piping lighter's output crashed it. lighter status | head -1 ended in a panic.

What changed

  • A connection whose container side has gone is let go. lighter checks a container's side of each connection once it has been quiet for 30 seconds, and closes the connection as soon as that side no longer exists. A container that has only finished sending, and is waiting for a reply, keeps its connection for as long as the reply takes.
  • When lighter does run out of room for connections, it serves the ones it has before refusing more, and says why in its log. This part is from @ParalaXEngineering's pull request #56.
  • What a container creates belongs to whoever asks, as a file made on the Mac already does: every container user sees it as its own and can write it. A chown inside a container is still recorded and kept, so images that hand their data folders to a service user, such as Frigate and Postgres, work as before.
  • Sticky directories, and the protections Linux applies inside them, treat a file that belongs to whoever asks as the caller's. This takes a change to the guest's Linux kernel.
  • lighter's output into a pipe that closes early is dropped quietly, and the command carries on.

Upgrading

brew upgrade lighter
lighter restart

Or lighter update download then lighter upgrade --restart if you installed with the install script. Containers with a restart policy come back by themselves; start the others again, as after any restart.

A file a container created before this release is still recorded as its creator's. To make a folder's contents belong to whoever asks again, run docker run --rm -v "$PWD/<folder>:/f" alpine chown -R 0:0 /f from the folder's parent.

Also

  • Linux remains 6.18.52, with one new patch (kernel 3ed15e47). The data epoch remains 1.

Checksums

  • lighter-0.11.7-arm64.tar.gz: SHA256 2d2240c121506d3ae4712e01d47a2ded1cda5b5b4a38a1b0d18d6cb53de99fdc
  • lighter-0.11.7-arm64 (installer bootstrap): SHA256 1909e51a701dd3a018bc172acec70cb2b1f3061c0f98a5577dc1bc70eab63ae5
  • Kernel 3ed15e47, rootfs bed8289c. Notarization 94a3fff1 accepted.

lighter 0.11.6

Choose a tag to compare

@rogersnm rogersnm released this 05 Oct 21:13
b885b3e

lighter 0.11.6

Containers can bind from external drives, and from the Mac's temporary folders, at the same paths as on the Mac (#52). Extended attributes work on files on SMB shares and on drives formatted exFAT or FAT (#53). A bind from a folder lighter does not share is no longer silently empty.

What went wrong

lighter shared your home folder and nothing else. A bind from anywhere outside it, such as -v /Volumes/T9/media:/media, gave the container an empty folder that dockerd had made inside the machine, with no error anywhere: the container started and found nothing. The same happened with $TMPDIR, which on the Mac is under /var/folders, and so with any tool that binds a temporary directory. Sharing more meant editing config.json by hand, and a shared drive that was not connected stopped the machine from starting.

What changed

  • /Users, /Volumes and /var/folders are shared, at the same paths as on the Mac. These are Docker Desktop's defaults, without /tmp. An existing configuration that shares the home folder now reads as these, keeping any other folder it lists.
  • A drive is there whenever it is connected, including one plugged in while the machine runs, APFS or exFAT.
  • A drive ejects while the machine runs, from Finder, diskutil eject or hdiutil detach. lighter keeps files open on the Mac on the guest's behalf, and macOS refuses to eject a volume while anything has a file on it open; lighter now closes what it holds on a volume when macOS asks to eject it. A container still using the drive finds it gone, as it would on a Linux machine whose disk was unplugged.
  • Extended attributes work on SMB shares and exFAT or FAT drives (#53). lighter names a file on the Mac by its identity (/.vol/<device>/<inode>) where the volume supports that, and decided whether it did once, for the shared folder's own disk. A volume mounted inside a shared folder that has no identity paths, as SMB, exFAT and FAT do not, was given paths that did not exist, so every getfattr, setfattr and listing failed with "No such file or directory" on a file that was plainly there. Moving a file between two SMB shares keeping its metadata, as Sonarr does when it imports a download, failed the same way. Each volume now answers for itself.
  • A file a short-lived container wrote is no longer left open on the Mac. If the guest forgot the file before lighter had finished creating it, which is ordinary when the container exits straight away, lighter held it open until 2,048 others had taken its place.
  • lighter config --share <path> and --unshare <path> change what is shared, then lighter restart.
  • A shared folder that is not there, such as a drive that is unplugged, is left out when the machine starts instead of stopping it, and lighter doctor names it.
  • lighter status and lighter doctor name every bind mount from a folder on the Mac that isn't shared, with the container and the fix. /tmp is the machine's own rather than the Mac's, so for a bind from it they suggest your home folder or $TMPDIR.
  • lighter config --metal and --video are applied. Before, they were accepted and ignored.
  • All of a machine's shares draw on one budget of open files on the Mac. Each share used to keep its own, so more shares could have held more of the Mac's open files than one machine should.

Upgrading

brew upgrade lighter
lighter restart

Or lighter update download then lighter upgrade --restart if you installed with the install script. Containers with a restart policy come back by themselves; start the others again, as after any restart.

Also

  • Linux remains 6.18.52 (kernel 6225825f, unchanged). The data epoch remains 1.
  • Docker still starts a container whose bind lighter cannot serve. Refusing the start, as Docker Desktop does, means lighter answering Docker's API itself, and is a change for another release.

Checksums

  • lighter-0.11.6-arm64.tar.gz: SHA256 9bd7937258171928fc77b20c534e983a5cdf6fb30aa37f39624c6521dccc3830
  • lighter-0.11.6-arm64 (installer bootstrap): SHA256 c97eea92a292cdd33a2b77e47c3eb395025492a9e72f5485c4b4a0b4efc7a5cd
  • Kernel 6225825f, rootfs 02f57561. Notarization ec09f48e accepted.

lighter 0.11.5

Choose a tag to compare

@rogersnm rogersnm released this 05 Oct 14:52
50b2999

lighter 0.11.5

A port a container publishes that the Mac will not give lighter is no longer half open, no longer stays closed after the Mac lets go of it, and no longer fails without telling you.

What went wrong

When a container publishes a port, lighter opens it on the Mac on IPv4 (0.0.0.0) and IPv6 ([::]) separately. macOS refuses lighter a port that another user's program already holds on one of the Mac's addresses, whatever lighter asks for: Tailscale Serve sharing port 9000 on the Mac's tailnet address is one example. When that happened:

  • One half opened anyway. The container answered on localhost, which reaches IPv6, but not on 127.0.0.1, and not to other containers through host.docker.internal, which is far harder to diagnose than a port that is simply closed.
  • Only a log file said so. docker run and compose up succeeded, docker ps listed the port as published, and the container reported healthy.
  • Nothing tried again. Once the other program let go, the port stayed closed until some unrelated container happened to start or stop.

What changed

  • A port is opened on every address it was published on, or on none. If the Mac refuses one, lighter closes the other rather than leave it half open.
  • lighter tries again by itself, after a second at first and then less often, up to every 30 seconds, so the port opens shortly after whatever held it lets go.
  • It tells you. lighter status lists each published port it could not open and why, and lighter doctor warns about them. The log records the failure once, not on every attempt.

The refusal itself is macOS's, and every Docker runtime for the Mac meets it. If something on your Mac needs the same port, give one of them a different port.

Upgrading

brew upgrade lighter
lighter restart

Or lighter update download then lighter upgrade --restart if you installed with the install script. Containers with a restart policy come back by themselves; start the others again, as after any restart.

Also

  • Linux remains 6.18.52 (kernel 6225825f, unchanged). The data epoch remains 1.
  • Docker still reports success when it starts such a container. Failing the start, as Docker Desktop does, means lighter answering Docker's API itself, and is a change for another release.

Checksums

  • lighter-0.11.5-arm64.tar.gz: SHA256 33f926b3b1ef227acd3ba9f6445b183f38cdf73fc1f051df59069107b3a4df8e
  • lighter-0.11.5-arm64 (installer bootstrap): SHA256 5d96fcf2f01d2432a26adaceb465a55d0a2037d278db7e86ea58e615631c72d0
  • Kernel 6225825f, rootfs a38cbd65. Notarization 241f1f06 accepted.

lighter 0.11.4

Choose a tag to compare

@rogersnm rogersnm released this 05 Oct 11:46
ddef916

lighter 0.11.4

Two fixes reported against 0.11.3: a container running as a user other than root can create read-only files and directories in a shared folder, so git works there, and file watchers are no longer capped at the watch limit of a 2 GiB machine.

What changed

  • Read-only files and directories can be created as a non-root user (#48). In a folder shared from the Mac, a container running as a user other than root could not create a file without write permission for its owner (0444, 0555, 0400) or such a directory (mkdir -m 555): the create failed with "Permission denied" after the file had already appeared on the Mac, and trying again said it already existed. git writes every object it stores that way, so git add and git commit failed in a repository on the share and left empty tmp_obj files behind. cp of a read-only file failed the same way, as did chown of a read-only file even as root. All of these now work, and a create that fails leaves nothing behind.
  • File watchers are no longer limited by the memory the machine starts with (#49). Linux sets how many files can be watched from the memory it boots with, and with resources: cooperative lighter's machine boots small and grows later, so the limit stayed at about 15,800 watches however much memory the machine had. Two Next.js dev servers on a monorepo used all of it, and the next one failed with "OS file watch limit reached". The machine now allows 524,288 watches and 1,024 watchers on every boot. A watch costs memory only once something makes it.

Upgrading

brew upgrade lighter
lighter restart

Or lighter update download then lighter upgrade --restart if you installed with the install script. Containers with a restart policy come back by themselves; start the others again, as after any restart.

Also

  • Linux remains 6.18.52 (kernel 6225825f, unchanged from 0.11.3). The data epoch remains 1.

Checksums

  • lighter-0.11.4-arm64.tar.gz: SHA256 779d4e3f52d0db93793645c105cf2714fd06ad3d64dcfc61f5deb80eced83fee
  • lighter-0.11.4-arm64 (installer bootstrap): SHA256 977be56a693b7145eb5ebf2c19e2d5612b5a9bee3065a814789d699970ce4e40
  • Kernel 6225825f, rootfs 09dfdf03. Notarization 5eb27dfd accepted.