Pod logs, exec & status
logs() returns a pod’s log as one string; streamLogs() is a generator that yields it line by line — ideal for tailing a running container. With follow: true it runs until the container stops, or until client.stream_timeout seconds pass with no output — not the request timeout:
use RoundlyConsulting\KubernetesApi\DataTransferObjects\PodLogOptions;
$pod = $cluster->pods()->setNamespace('shop')->withName('checkout-5f7c9d8b6-x2kqj');
// Fetch logs as a string.
$logs = $pod->logs(new PodLogOptions(container: 'app', tailLines: 200, timestamps: true));
// The previous (crashed) instance of the container, last hour only.
$crash = $pod->logs(new PodLogOptions(container: 'app', previous: true, sinceSeconds: 3600));
// Stream logs line by line (tail). With follow: true it runs until the container stops
// (or client.stream_timeout seconds pass with no output), not the request timeout.
foreach ($pod->streamLogs(new PodLogOptions(container: 'app', follow: true)) as $line) {
echo $line.PHP_EOL;
}PodLogOptions
| Option | Type | Default | Effect |
|---|---|---|---|
container | ?string | null | Which container to read in a multi-container pod. |
follow | bool | false | Keep the stream open for new lines (streamLogs() defaults to true). |
tailLines | ?int | null | Only the last N lines. |
sinceSeconds | ?int | null | Only lines newer than N seconds. |
timestamps | bool | false | Prefix every line with its timestamp. |
previous | bool | false | The previous, terminated instance of the container — the crash log. |
limitBytes | ?int | null | Cap the number of bytes returned. |
Exec
exec() runs a command inside a container and returns an ExecResult with the captured stdout, stderr and exit code. It opens its own TLS WebSocket to the apiserver speaking the v4.channel.k8s.io subprotocol, with the client’s token, certificates and verification settings:
// Exec a command inside a pod (over a WebSocket; returns stdout, stderr, and exit code).
$result = $cluster->pods()
->setNamespace('shop')
->withName('checkout-5f7c9d8b6-x2kqj')
->exec(['php', 'artisan', 'cache:clear'], container: 'app');
$result->stdout; // captured standard output
$result->stderr; // captured standard error
$result->exitCode; // 0 (null if the stream ended before the command finished)
$result->successful(); // true only for exit code 0
$result->completed(); // false if the connection dropped or client.stream_timeout passed
// Need a shell? Ask for one explicitly.
$cluster->pods()->setNamespace('shop')->withName('checkout-5f7c9d8b6-x2kqj')
->exec(['sh', '-c', 'df -h /var/cache && echo done']);- Pass the command as an argument list — each element is sent as its own command parameter, so no shell quoting is involved. Wrap it in ['sh', '-c', '…'] when you need a shell.
- container selects the container in a multi-container pod; tty: true requests a TTY. stdin is never attached.
- The connection dials the cluster URL’s own scheme, host, port (443 when none is given) and path prefix, so a proxied apiserver (https://rancher.example/k8s/clusters/c-abc) works just like a direct one. Connecting has a 30-second timeout; connection and upgrade failures throw WebSocketException. Exec calls are not counted against the rate-limit budget.
- exec() waits for the apiserver to report the command’s exit status. If the stream ends first — a dropped connection or client.stream_timeout — exitCode is null, completed() and successful() are false: never a false success.
Pod and container status
Ask simple questions instead of decoding raw status — is the pod running, are its containers ready, why did one restart:
$pod = $cluster->pods()->setNamespace('shop')->withName('checkout-5f7c9d8b6-x2kqj')->find();
$pod->isRunning(); // status.phase === 'Running'
$pod->isSuccessful(); // 'Succeeded'
$pod->hasFailed(); // 'Failed'
$pod->containersReady(); // every container status is ready
$pod->initContainersReady();
$pod->getQos(); // status.qosClass, 'BestEffort' when absent
$pod->getStatusMessage();
$status = $pod->getContainerStatus('app'); // ?ContainerStatus
$status?->getState(); // 'running' | 'waiting' | 'terminated' | 'unknown'
$status?->getStateReason(); // e.g. 'CrashLoopBackOff'
$status?->restarts(); // restart count
$status?->isReady();
$status?->getStartedAt(); // ?CarbonShow your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.