How to Force Kill a Container in Apple's Open Source Framework
To force kill a container immediately, use the container kill command which sends SIGKILL by default, bypassing graceful shutdown mechanisms and terminating the process directly through the kernel.
The Apple container repository provides a specialized kill subcommand that targets running containers with POSIX signals. Unlike a standard stop operation that allows cleanup time, the force kill mechanism guarantees immediate termination by transmitting SIGKILL to the container's init process. This functionality is implemented across four distinct architectural layers, from CLI parsing to low-level runtime execution inside the virtual machine.
Basic Force Kill Commands
The simplest way to force kill a container uses the default KILL signal:
# Force kill a specific container by name or ID
container kill my-container
Because the default signal is KILL (SIGKILL), this command immediately terminates the container without allowing the process to catch or ignore the signal.
To kill all running containers simultaneously:
# Force kill every running container
container kill --all
This expands internally to target all active container IDs before dispatching individual kill requests.
Implementation Architecture
The force kill operation flows through four specific layers in the codebase, ensuring the signal reaches the correct process inside the virtualized environment.
CLI Layer: ContainerKill.swift
The entry point resides in Sources/ContainerCommands/Container/ContainerKill.swift. This file parses command-line arguments including --signal and --all, then iterates over the target container list.
let client = ContainerClient()
for container in containers {
try await client.kill(id: container, signal: signal)
}
The implementation (lines 55-73) validates the signal type and expands the --all flag into an array of running container identifiers before invoking the client API.
Client Communication: ContainerClient.swift
The ContainerClient class in Sources/Services/ContainerAPIService/Client/ContainerClient.swift encodes the kill request into an XPC message. The kill(id:signal:) method forwards the request to the container-side API server using a gRPC-style interface.
Server Handling: ContainersService.swift
The server implementation in Sources/Services/ContainerAPIService/Server/Containers/ContainersService.swift receives the request and resolves the target's runtime client. At lines 69-100, the service executes client.kill(processID, signal:) after looking up the appropriate runtime connection.
When the signal equals KILL and the processID matches the container's init process ID, the server additionally triggers handleContainerExit to perform standard cleanup operations typically associated with a graceful stop.
Runtime Execution: RuntimeService.swift
The final signal delivery occurs in Sources/Services/RuntimeLinux/Server/RuntimeService.swift. Here, the runtime service executes the actual proc.kill(signal) call inside the VM. When the signal is SIGKILL (lines 62-98), the service blocks until the VM reports the container's exit, ensuring synchronous termination confirmation.
Advanced Usage Examples
Specifying Alternative Signals
While the default KILL signal provides immediate termination, you can send other POSIX signals for different termination behaviors:
# Send SIGTERM for graceful shutdown attempt
container kill --signal TERM web-app
# Send SIGINT (equivalent to Ctrl+C)
container kill --signal INT web-app
Programmatic Force Kill in Swift
For applications integrating directly with the framework:
import ContainerAPIClient
let client = ContainerClient()
// Force kill by container ID
try await client.kill(id: "my-container-id", signal: "KILL")
This bypasses the CLI entirely and uses the same XPC communication channel that underlies the command-line tool.
Summary
container killis the primary command for force killing containers, defaulting to SIGKILL.- The
--allflag targets every running container simultaneously. - The implementation spans four layers: CLI parsing (
ContainerKill.swift), client messaging (ContainerClient.swift), server coordination (ContainersService.swift), and runtime execution (RuntimeService.swift). - When killing the init process with SIGKILL, the system still executes cleanup routines via
handleContainerExitto maintain state consistency. - The runtime blocks on SIGKILL operations until the VM confirms the container has exited, providing reliable termination status.
Frequently Asked Questions
What is the difference between container stop and container kill?
container stop attempts a graceful shutdown by sending SIGTERM and allowing a timeout period for the container to exit cleanly. container kill sends SIGKILL immediately by default, which the kernel handles directly without allowing the process to intercept or delay termination. According to the source code, container kill is the only method that guarantees immediate termination when a container is unresponsive.
Can a container process ignore the container kill command?
No. When using the default KILL signal (or explicitly specifying SIGKILL), the signal cannot be caught, blocked, or ignored by the target process. The kernel terminates the process immediately, making this the most reliable method for stopping stuck or zombie containers.
Why does the force kill command block until the container exits?
In Sources/Services/RuntimeLinux/Server/RuntimeService.swift, when the signal is KILL, the runtime service waits for the VM to report the container's exit before returning. This ensures the caller receives accurate status confirmation and prevents race conditions where subsequent commands might attempt to interact with a container that is still in the process of terminating.
Does killing a container require root privileges?
The container framework uses XPC communication between the client and server components. While the CLI itself may not require root if the user has appropriate container permissions, the actual signal delivery at the runtime layer executes with the necessary privileges to terminate processes within the virtualized environment. The framework handles privilege escalation internally through its service architecture.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →