Container details: {#if isEditing} { if (e.key === 'Enter') saveRename(); if (e.key === 'Escape') cancelEditing(); }} disabled={renaming} /> {:else} {displayName || containerId.slice(0, 12)} {/if} {@const composeStack = containerData?.Config?.Labels?.['com.docker.compose.project']} {#if composeStack && !loading}

Open stack "{composeStack}"

{/if} {#if containerData?.State?.Running && !loading} {isLiveConnected ? 'Live' : 'Offline'} {/if} {#if containerData && !loading} {/if}
{#if loading}
{:else if error}
{error}
{:else if containerData} showLogs = false}>Overview showLogs = true}>Logs showLogs = false}>Layers { showLogs = false; if (processesAutoRefresh) startProcessesCollection(); else fetchProcesses(); }}>Processes showLogs = false}>Network showLogs = false}>Mounts showLogs = false}>Files showLogs = false}>Environment showLogs = false}>Labels showLogs = false}>Security showLogs = false}>Resources showLogs = false}>Health {#if containerData.State?.Running}
CPU {currentStats?.cpuPercent?.toFixed(1) ?? '—'}%
{#if cpuHistory.length >= 2} {:else}
Loading...
{/if}
Memory {currentStats?.memoryPercent?.toFixed(1) ?? '—'}%
{#if memoryHistory.length >= 2} {:else}
Loading...
{/if}
{formatBytes(currentStats?.memoryUsage ?? 0)} / {formatBytes(currentStats?.memoryLimit ?? 0)}
Network I/O
RX: {formatBytes(currentStats?.networkRx ?? 0)}
TX: {formatBytes(currentStats?.networkTx ?? 0)}
Disk I/O
Read: {formatBytes(currentStats?.blockRead ?? 0)}
Write: {formatBytes(currentStats?.blockWrite ?? 0)}
Processes
{#if processesData?.Processes?.length} running in container {:else if processesLoading} {:else} — {/if}
{/if}

Status

State

{containerData.State?.Status || 'unknown'}

Restart Policy

{containerData.HostConfig?.RestartPolicy?.Name || 'no'}

Exit Code

{containerData.State?.ExitCode ?? 'N/A'}

Restart Count

{containerData.RestartCount ?? 0}

Basic information

ID

{containerData.Id?.slice(0, 12)}

Platform

{containerData.Platform || 'N/A'}

Created

{formatDate(containerData.Created)}

Started

{formatDate(containerData.State?.StartedAt)}

Image

{containerData.Config?.Image || 'N/A'}
{#if containerData.Path || containerData.Args}

Command

{containerData.Path || ''} {containerData.Args?.join(' ') || ''}
{/if}
{#if !containerData.State?.Running}
Container is not running
{:else if processesLoading}
{:else if processesError}
{processesError}
{:else if processesData && processesData.Processes?.length > 0}
{#each processesData.Titles as title} {/each} {#each processesData.Processes as process, i} {#each process as cell} {/each} {/each}
#{title}
{i + 1}{cell}
{processesData.Processes.length} process(es)
{:else}

No processes found

{/if}
showLogs = false} /> {#if containerData?.Image} {:else}

No image information available

{/if}

Network mode

{networkModeLabel}
{#if containerData.HostConfig?.Dns?.length > 0 || containerData.HostConfig?.DnsSearch?.length > 0 || containerData.HostConfig?.DnsOptions?.length > 0}

DNS configuration

{#if containerData.HostConfig?.Dns?.length > 0}

DNS Servers

{#each containerData.HostConfig.Dns as dns} {dns} {/each}
{/if} {#if containerData.HostConfig?.DnsSearch?.length > 0}

DNS Search

{#each containerData.HostConfig.DnsSearch as search} {search} {/each}
{/if} {#if containerData.HostConfig?.DnsOptions?.length > 0}

DNS Options

{#each containerData.HostConfig.DnsOptions as opt} {opt} {/each}
{/if}
{/if} {#if containerData.HostConfig?.ExtraHosts?.length > 0}

Extra hosts

{#each containerData.HostConfig.ExtraHosts as host}
{host}
{/each}
{/if}

Connected networks

{#if isSharedNetworkMode}

Network namespace is shared via {containerData.HostConfig?.NetworkMode} — additional networks cannot be attached.

{:else if containerData.NetworkSettings?.Networks && Object.keys(containerData.NetworkSettings.Networks).length > 0}
{#each Object.entries(containerData.NetworkSettings.Networks) as [networkName, networkData]} {@const netData = networkData as any}
{networkName} {netData.NetworkID?.slice(0, 12)}
{#if containerData.State?.Running} {/if}
{#if networkData.IPAddress}

IPv4

{networkData.IPAddress}
{/if} {#if networkData.GlobalIPv6Address}

IPv6

{networkData.GlobalIPv6Address}
{/if} {#if networkData.MacAddress}

MAC

{networkData.MacAddress}
{/if} {#if networkData.Gateway}

Gateway

{networkData.Gateway}
{/if} {#if networkData.Aliases?.length > 0}

Aliases

{networkData.Aliases.join(', ')}
{/if}
{/each}
{:else}

No networks connected.

{/if} {#if containerData.State?.Running && !isSharedNetworkMode}
{#if selectedNetwork} {@const net = unconnectedNetworks.find(n => n.id === selectedNetwork)} {net?.name || 'Unknown'} {net?.driver} {:else} {networksLoading ? 'Loading networks...' : unconnectedNetworks.length > 0 ? 'Join a network...' : 'No networks available'} {/if} {#each unconnectedNetworks as network} {network.name} {network.driver} {/each}
{/if}
{#if containerData.NetworkSettings?.Ports && Object.keys(containerData.NetworkSettings.Ports).length > 0} {@const inspectParsedUrl = parseCustomUrl(containerData.Config?.Labels?.['dockhand.url'])}

Port mappings

{#if inspectParsedUrl} {/if} {#each Object.entries(containerData.NetworkSettings.Ports) as [containerPort, hostBindings]} {#if hostBindings && hostBindings.length > 0} {#each hostBindings as binding} {@const portParsedOverride = parseCustomUrl(containerData.Config?.Labels?.[`dockhand.port.${binding.HostPort}.url`])} {@const url = portParsedOverride?.url || getPortUrl(parseInt(binding.HostPort))}
{#if url} {portParsedOverride?.name ?? `${binding.HostIp || '0.0.0.0'}:${binding.HostPort}`} {:else} {binding.HostIp || '0.0.0.0'}:{binding.HostPort} {/if} {containerPort}
{/each} {:else}
exposed {containerPort}
{/if} {/each}
{/if}
{#if containerData.Mounts && containerData.Mounts.length > 0}
{#each containerData.Mounts as mount}
{mount.Type} {mount.RW ? 'Read/Write' : 'Read-Only'}

Source

{mount.Source || mount.Name || 'N/A'}

Destination

{mount.Destination}
{#if mount.Driver}

Driver

{mount.Driver}
{/if} {#if mount.Propagation}

Propagation

{mount.Propagation}
{/if}
{/each}
{:else}

No mounts configured

{/if}
{#if containerData.State?.Running && !containerData.State?.Paused} {:else if containerData.State?.Paused}
Container is paused
{:else}
Container is not running
{/if}
{#if containerData.divergence?.env?.length > 0}
{containerData.divergence.env.length} env var{containerData.divergence.env.length === 1 ? '' : 's'} differ from the image: {containerData.divergence.env.join(', ')}. Values set by you at create time will stay. To reset to the image's current values, Remove & Deploy.
{/if} {#if containerData.Config?.Env && containerData.Config.Env.length > 0}
{#each [...containerData.Config.Env].sort((a, b) => a.split('=')[0].localeCompare(b.split('=')[0])) as envVar} {@const [key, ...valueParts] = envVar.split('=')} {@const value = valueParts.join('=')} {@const diverges = containerData.divergence?.env?.includes(key)}
{key} = {value}
{/each}
{:else}

No environment variables

{/if}
{#if containerData.divergence?.labels?.length > 0}
{containerData.divergence.labels.length} label{containerData.divergence.labels.length === 1 ? '' : 's'} differ from the image: {containerData.divergence.labels.join(', ')}. Values set by you at create time will stay. To reset to the image's current values, Remove & Deploy.
{/if} {#if containerData.Config?.Labels && Object.keys(containerData.Config.Labels).length > 0} {@const allLabels = Object.entries(containerData.Config.Labels).sort((a, b) => a[0].localeCompare(b[0]))} {@const filter = labelFilter.trim().toLowerCase()} {@const visibleLabels = filter ? allLabels.filter(([k, v]) => k.toLowerCase().includes(filter) || String(v).toLowerCase().includes(filter)) : allLabels}
{visibleLabels.length === allLabels.length ? `${allLabels.length} label${allLabels.length === 1 ? '' : 's'}` : `${visibleLabels.length} of ${allLabels.length}`}
{#if visibleLabels.length > 0}
{#each visibleLabels as [key, value]} {@const diverges = containerData.divergence?.labels?.includes(key)}
{key} = {value}
{/each}
{:else}

No labels match "{labelFilter}"

{/if} {:else}

No labels

{/if}

Privileged

{containerData.HostConfig?.Privileged ? 'Yes' : 'No'}

Read-only Root

{containerData.HostConfig?.ReadonlyRootfs ? 'Yes' : 'No'}

User

{containerData.Config?.User || 'root'}

User Namespace

{containerData.HostConfig?.UsernsMode || 'host'}
{#if containerData.HostConfig?.SecurityOpt?.length > 0}

Security options

{#each containerData.HostConfig.SecurityOpt as opt}
{opt}
{/each}
{/if}
{#if containerData.AppArmorProfile !== undefined}

AppArmor Profile

{containerData.AppArmorProfile || 'unconfined'}
{/if} {#if containerData.HostConfig?.SecurityOpt?.some((o: string) => o.startsWith('seccomp'))}

Seccomp

{containerData.HostConfig.SecurityOpt.find((o: string) => o.startsWith('seccomp'))?.split('=')[1] || 'default'}
{/if}
{#if containerData.HostConfig?.CapAdd?.length > 0}

Added capabilities

{#each containerData.HostConfig.CapAdd as cap} {cap} {/each}
{/if} {#if containerData.HostConfig?.CapDrop?.length > 0}

Dropped capabilities

{#each containerData.HostConfig.CapDrop as cap} {cap} {/each}
{/if}
{#if !containerData.HostConfig?.CapAdd?.length && !containerData.HostConfig?.CapDrop?.length && !containerData.HostConfig?.SecurityOpt?.length}

Default security settings

{/if}

Resource limits

CPU Shares

{containerData.HostConfig?.CpuShares || 'default'}

CPUs

{containerData.HostConfig?.NanoCpus ? (containerData.HostConfig.NanoCpus / 1e9).toFixed(2) : 'unlimited'}

Memory

{formatMemory(containerData.HostConfig?.Memory)}

Memory Swap

{formatMemory(containerData.HostConfig?.MemorySwap)}

Memory Reservation

{formatMemory(containerData.HostConfig?.MemoryReservation)}

PIDs Limit

{containerData.HostConfig?.PidsLimit ?? 'unlimited'}

OOM Kill

{containerData.HostConfig?.OomKillDisable ? 'Disabled' : 'Enabled'}

CPU Period/Quota

{containerData.HostConfig?.CpuPeriod || 0}/{containerData.HostConfig?.CpuQuota || 0}
{#if containerData.HostConfig?.Ulimits?.length > 0}

Ulimits

{#each containerData.HostConfig.Ulimits as ulimit}
{ulimit.Name} soft={ulimit.Soft} hard={ulimit.Hard}
{/each}
{/if} {#if containerData.HostConfig?.Devices?.length > 0}

Devices

{#each containerData.HostConfig.Devices as device}
{device.PathOnHost} {device.PathInContainer} {#if device.CgroupPermissions} {device.CgroupPermissions} {/if}
{/each}
{/if} {#if containerData.HostConfig?.DeviceRequests?.length > 0 || (containerData.HostConfig?.Runtime && containerData.HostConfig.Runtime !== 'runc')}

GPU

{#if containerData.HostConfig?.Runtime}

Runtime

{containerData.HostConfig.Runtime}
{/if} {#if containerData.HostConfig?.DeviceRequests?.length > 0} {@const req = containerData.HostConfig.DeviceRequests[0]}

Count

{req.Count === -1 ? 'All' : req.Count}
{#if req.Driver}

Driver

{req.Driver}
{/if} {#if req.DeviceIDs?.length > 0}

Device IDs

{#each req.DeviceIDs as id} {id} {/each}
{/if} {#if req.Capabilities?.length > 0}

Capabilities

{#each req.Capabilities.flat() as cap} {cap} {/each}
{/if} {/if}
{/if}

Cgroup settings

Cgroup

{containerData.HostConfig?.Cgroup || 'default'}

Cgroup Parent

{containerData.HostConfig?.CgroupParent || 'default'}

Cgroupns Mode

{containerData.HostConfig?.CgroupnsMode || 'host'}
{@const healthConfig = containerData.Config?.Healthcheck} {@const healthState = containerData.State?.Health} {@const formatNs = (ns: number) => ns ? `${ns / 1e9}s` : '-'} {#if healthConfig || healthState}
{#if healthConfig && healthConfig.Test && healthConfig.Test.length > 0}

Configuration

Command

{healthConfig.Test.join(' ')}

Interval

{formatNs(healthConfig.Interval)}

Timeout

{formatNs(healthConfig.Timeout)}

Retries

{healthConfig.Retries || '-'}

Start period

{formatNs(healthConfig.StartPeriod)}
{/if} {#if healthState}

Status

Current status

{healthState.Status}

Failing streak

{healthState.FailingStreak || 0}
{#if healthState.Log && healthState.Log.length > 0}

Health check log

{#each healthState.Log.slice(-5) as log}
Exit: {log.ExitCode} {formatDate(log.End)}
{#if log.Output} {log.Output.trim()} {/if}
{/each}
{/if} {:else if healthConfig}

Waiting for first health check to complete...

{/if}
{:else}

No health check configured

{/if}
{/if}
Inspect
{#each jsonLines as line, i} {/each}
{i + 1} {@html line || ' '}