mirror of https://github.com/portainer/portainer
382 lines
16 KiB
HTML
382 lines
16 KiB
HTML
<page-header title="'Container details'" breadcrumbs="[{label:'Containers', link:'docker.containers'}, (container.Name | trimcontainername)]"> </page-header>
|
|
|
|
<div
|
|
class="row"
|
|
authorization="DockerContainerStart, DockerContainerStop, DockerContainerKill, DockerContainerRestart, DockerContainerPause, DockerContainerUnpause, DockerContainerDelete, DockerContainerCreate"
|
|
>
|
|
<div class="col-lg-12 col-md-12 col-xs-12">
|
|
<rd-widget>
|
|
<rd-widget-header icon="settings" feather-icon="true" title-text="Actions"></rd-widget-header>
|
|
<rd-widget-body classes="padding">
|
|
<div class="btn-group" role="group" aria-label="...">
|
|
<button authorization="DockerContainerStart" class="btn btn-light btn-sm" ng-click="start()" ng-disabled="container.State.Running || container.IsPortainer">
|
|
<pr-icon icon="'play'" feather="true" class-name="'feather'"></pr-icon>
|
|
Start
|
|
</button>
|
|
<button authorization="DockerContainerStop" class="btn btn-light btn-sm" ng-click="stop()" ng-disabled="!container.State.Running || container.IsPortainer">
|
|
<pr-icon icon="'square'" feather="true"></pr-icon>
|
|
Stop
|
|
</button>
|
|
<button authorization="DockerContainerKill" class="btn btn-light btn-sm" ng-click="kill()" ng-disabled="!container.State.Running || container.IsPortainer">
|
|
<i class="fa fa-bomb space-right" aria-hidden="true"></i>Kill
|
|
</button>
|
|
<button authorization="DockerContainerRestart" class="btn btn-light btn-sm" ng-click="restart()" ng-disabled="!container.State.Running || container.IsPortainer"
|
|
><i class="fa fa-sync space-right" aria-hidden="true"></i>Restart</button
|
|
>
|
|
<button
|
|
authorization="DockerContainerPause"
|
|
class="btn btn-light btn-sm"
|
|
ng-click="pause()"
|
|
ng-disabled="!container.State.Running || container.State.Paused || container.IsPortainer"
|
|
><i class="fa fa-pause space-right" aria-hidden="true"></i>Pause</button
|
|
>
|
|
<button authorization="DockerContainerUnpause" class="btn btn-light btn-sm" ng-click="unpause()" ng-disabled="!container.State.Paused || container.IsPortainer"
|
|
><i class="fa fa-play space-right" aria-hidden="true"></i>Resume</button
|
|
>
|
|
<button authorization="DockerContainerDelete" class="btn btn-dangerlight btn-sm" ng-click="confirmRemove()" ng-disabled="container.IsPortainer"
|
|
><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Remove</button
|
|
>
|
|
</div>
|
|
<div class="btn-group" role="group" aria-label="..." ng-if="displayRecreateButton" authorization="DockerContainerCreate">
|
|
<button
|
|
type="button"
|
|
class="btn btn-danger btn-sm"
|
|
ng-disabled="state.recreateContainerInProgress || container.IsPortainer"
|
|
ng-click="recreate()"
|
|
button-spinner="state.recreateContainerInProgress"
|
|
>
|
|
<span ng-hide="state.recreateContainerInProgress"><i class="fa fa-sync space-right" aria-hidden="true"></i>Recreate</span>
|
|
<span ng-show="state.recreateContainerInProgress">Recreation in progress...</span>
|
|
</button>
|
|
<a class="btn btn-light btn-sm" type="button" ui-sref="docker.containers.new({ from: container.Id, nodeName: nodeName })" ng-disabled="container.IsPortainer"
|
|
><i class="fa fa-copy space-right" aria-hidden="true"></i>Duplicate/Edit</a
|
|
>
|
|
</div>
|
|
</rd-widget-body>
|
|
</rd-widget>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-lg-12 col-md-12 col-xs-12">
|
|
<rd-widget>
|
|
<rd-widget-header icon="box" feather-icon="true" title-text="Container status"></rd-widget-header>
|
|
<rd-widget-body classes="no-padding">
|
|
<table class="table">
|
|
<tbody>
|
|
<tr>
|
|
<td>ID</td>
|
|
<td>{{ container.Id }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Name</td>
|
|
<td ng-if="!container.edit">
|
|
{{ container.Name | trimcontainername }}
|
|
<a authorization="DockerContainerRename" href="" data-toggle="tooltip" title="Edit container name" ng-click="container.edit = true;"><i class="fa fa-edit"></i></a>
|
|
</td>
|
|
<td ng-if="container.edit">
|
|
<form ng-submit="renameContainer()">
|
|
<input type="text" class="containerNameInput" ng-model="container.newContainerName" />
|
|
<a href="" ng-click="container.edit = false;"><i class="fa fa-times"></i></a>
|
|
<a href="" ng-click="renameContainer()"><i class="fa fa-check-square"></i></a>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="container.NetworkSettings.IPAddress">
|
|
<td>IP address</td>
|
|
<td>{{ container.NetworkSettings.IPAddress }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Status</td>
|
|
<td>
|
|
<i class="fa fa-heartbeat space-right green-icon" ng-if="container.State.Running"></i>
|
|
<i class="fa fa-heartbeat space-right red-icon" ng-if="!container.State.Running && container.State.Status !== 'created'"></i>
|
|
{{ container.State | getstatetext }} for {{ activityTime
|
|
}}<span ng-if="!container.State.Running && container.State.Status !== 'created'"> with exit code {{ container.State.ExitCode }}</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Created</td>
|
|
<td>{{ container.Created | getisodate }}</td>
|
|
</tr>
|
|
<tr ng-if="container.State.Running">
|
|
<td>Start time</td>
|
|
<td>{{ container.State.StartedAt | getisodate }}</td>
|
|
</tr>
|
|
<tr ng-if="!container.State.Running && container.State.Status !== 'created'">
|
|
<td>Finished</td>
|
|
<td>{{ container.State.FinishedAt | getisodate }}</td>
|
|
</tr>
|
|
<tr ng-if="isAdmin && displayCreateWebhookButton && applicationState.endpoint.type !== 4">
|
|
<td colspan="6">
|
|
<div class="form-group">
|
|
<div class="col-sm-12">
|
|
<por-switch-field
|
|
tooltip="'Webhook (or callback URI) used to automate the recreation of this container. Sending a POST request to this callback URI (without requiring any authentication) will pull the most up-to-date version of the associated image and recreate this container.'"
|
|
label-class="'col-sm-2'"
|
|
label="'Container webhook'"
|
|
feature-id="'container-webhook'"
|
|
></por-switch-field>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr authorization="DockerContainerLogs, DockerContainerInspect, DockerContainerStats, DockerExecStart">
|
|
<td colspan="2">
|
|
<div class="btn-group" role="group" aria-label="...">
|
|
<a authorization="DockerContainerLogs" class="btn" type="button" ui-sref="docker.containers.container.logs({ id: container.Id })"
|
|
><i class="fa fa-file-alt space-right" aria-hidden="true"></i>Logs</a
|
|
>
|
|
<a authorization="DockerContainerInspect" class="btn" type="button" ui-sref="docker.containers.container.inspect({ id: container.Id })"
|
|
><i class="fa fa-info-circle space-right" aria-hidden="true"></i>Inspect</a
|
|
>
|
|
<a authorization="DockerContainerStats" class="btn" type="button" ui-sref="docker.containers.container.stats({ id: container.Id })"
|
|
><i class="fa fa-chart-area space-right" aria-hidden="true"></i>Stats</a
|
|
>
|
|
<a authorization="DockerExecStart" class="btn" type="button" ui-sref="docker.containers.container.exec({ id: container.Id })"
|
|
><i class="fa fa-terminal space-right" aria-hidden="true"></i>Console</a
|
|
>
|
|
<a authorization="DockerContainerAttach" class="btn" type="button" ui-sref="docker.containers.container.attach({ id: container.Id })"
|
|
><i class="fa fa-plug space-right" aria-hidden="true"></i>Attach</a
|
|
>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</rd-widget-body>
|
|
</rd-widget>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- access-control-panel -->
|
|
<access-control-panel
|
|
ng-if="container"
|
|
resource-id="container.Id"
|
|
resource-control="container.ResourceControl"
|
|
resource-type="resourceType"
|
|
on-update-success="(onUpdateResourceControlSuccess)"
|
|
>
|
|
</access-control-panel>
|
|
<!-- !access-control-panel -->
|
|
|
|
<div ng-if="container.State.Health" class="row">
|
|
<div class="col-lg-12 col-md-12 col-xs-12">
|
|
<rd-widget>
|
|
<rd-widget-header icon="fa-server" title-text="Container health"></rd-widget-header>
|
|
<rd-widget-body classes="no-padding">
|
|
<table class="table">
|
|
<tbody>
|
|
<tr>
|
|
<td>Status</td>
|
|
<td>
|
|
<i
|
|
ng-class="
|
|
{ healthy: 'fa fa-heartbeat space-right green-icon', unhealthy: 'fa fa-heartbeat space-right red-icon', starting: 'fa fa-heartbeat space-right orange-icon' }[
|
|
container.State.Health.Status
|
|
]
|
|
"
|
|
></i>
|
|
{{ container.State.Health.Status }}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Failure count</td>
|
|
<td>{{ container.State.Health.FailingStreak }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Last output</td>
|
|
<td>{{ container.State.Health.Log[container.State.Health.Log.length - 1].Output }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</rd-widget-body>
|
|
</rd-widget>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row" authorization="DockerImageCreate">
|
|
<div class="col-lg-12 col-md-12 col-xs-12">
|
|
<rd-widget>
|
|
<rd-widget-header icon="list" feather-icon="true" title-text="Create image"></rd-widget-header>
|
|
<rd-widget-body>
|
|
<form class="form-horizontal">
|
|
<!-- tag-description -->
|
|
<div class="form-group">
|
|
<div class="col-sm-12">
|
|
<span class="small text-muted">
|
|
You can create an image from this container, this allows you to backup important data or save helpful configurations. You'll be able to spin up another container
|
|
based on this image afterward.
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<!-- !tag-description -->
|
|
<!-- image-and-registry -->
|
|
<por-image-registry
|
|
model="config.RegistryModel"
|
|
auto-complete="true"
|
|
label-class="col-sm-1"
|
|
input-class="col-sm-11"
|
|
endpoint="endpoint"
|
|
is-admin="isAdmin"
|
|
set-validity="setPullImageValidity"
|
|
check-rate-limits="true"
|
|
></por-image-registry>
|
|
<!-- !image-and-registry -->
|
|
<!-- tag-note -->
|
|
<div class="form-group">
|
|
<div class="col-sm-12">
|
|
<span class="small text-muted">Note: if you don't specify the tag in the image name, <span class="label label-default">latest</span> will be used.</span>
|
|
</div>
|
|
</div>
|
|
<!-- !tag-note -->
|
|
<div class="form-group">
|
|
<div class="col-sm-12">
|
|
<button
|
|
type="button"
|
|
class="btn btn-primary btn-sm"
|
|
ng-disabled="!state.pullImageValidity || !config.RegistryModel.Image || config.commitInProgress"
|
|
ng-click="commit()"
|
|
>
|
|
Create
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</rd-widget-body>
|
|
</rd-widget>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-lg-12 col-md-12 col-xs-12">
|
|
<rd-widget>
|
|
<rd-widget-header icon="list" feather-icon="true" title-text="Container details"></rd-widget-header>
|
|
<rd-widget-body classes="no-padding">
|
|
<table class="table container-details-table">
|
|
<tbody>
|
|
<tr>
|
|
<td>Image</td>
|
|
<td
|
|
><a ui-sref="docker.images.image({ id: container.Image, nodeName: nodeName })">{{ container.Config.Image }}@{{ container.Image }}</a></td
|
|
>
|
|
</tr>
|
|
<tr ng-if="portBindings.length > 0">
|
|
<td>Port configuration</td>
|
|
<td>
|
|
<div ng-repeat="portMapping in portBindings"> {{ portMapping.host }} <i class="fa fa-long-arrow-alt-right"></i> {{ portMapping.container }} </div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>CMD</td>
|
|
<td
|
|
><code>{{ container.Config.Cmd | command }}</code></td
|
|
>
|
|
</tr>
|
|
<tr>
|
|
<td>ENTRYPOINT</td>
|
|
<td
|
|
><code>{{ container.Config.Entrypoint ? (container.Config.Entrypoint | command) : 'null' }}</code></td
|
|
>
|
|
</tr>
|
|
<tr>
|
|
<td>ENV</td>
|
|
<td>
|
|
<table class="table table-bordered table-condensed">
|
|
<tr ng-repeat="var in container.Config.Env track by $index">
|
|
<td>{{ var|key: '=' }}</td>
|
|
<td>{{ var|value: '=' }}</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="!(container.Config.Labels | emptyobject)">
|
|
<td>Labels</td>
|
|
<td>
|
|
<table class="table table-bordered table-condensed">
|
|
<tr ng-repeat="(k, v) in container.Config.Labels">
|
|
<td>{{ k }}</td>
|
|
<td>{{ v }}</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Restart policies</td>
|
|
<td>
|
|
<container-restart-policy
|
|
ng-if="container"
|
|
name="container.HostConfig.RestartPolicy.Name"
|
|
maximum-retry-count="container.HostConfig.RestartPolicy.MaximumRetryCount"
|
|
update-restart-policy="updateRestartPolicy(name, maximumRetryCount)"
|
|
>
|
|
</container-restart-policy>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="!(container.HostConfig.Sysctls | emptyobject)">
|
|
<td>Sysctls</td>
|
|
<td>
|
|
<table class="table table-bordered table-condensed">
|
|
<tr ng-repeat="(k, v) in container.HostConfig.Sysctls">
|
|
<td>{{ k }}</td>
|
|
<td>{{ v }}</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="container.HostConfig.DeviceRequests.length">
|
|
<td>GPUS</td>
|
|
<td>{{ computeDockerGPUCommand() }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</rd-widget-body>
|
|
</rd-widget>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row" ng-if="container.Mounts.length > 0">
|
|
<div class="col-lg-12 col-md-12 col-xs-12">
|
|
<rd-widget>
|
|
<rd-widget-header icon="database" feather-icon="true" title-text="Volumes"></rd-widget-header>
|
|
<rd-widget-body classes="no-padding">
|
|
<table class="table">
|
|
<thead>
|
|
<tr>
|
|
<th>Host/volume</th>
|
|
<th>Path in container</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr ng-repeat="vol in container.Mounts">
|
|
<td ng-if="vol.Type === 'bind'">{{ vol.Source }}</td>
|
|
<td ng-if="vol.Type === 'volume'"
|
|
><a ui-sref="docker.volumes.volume({ id: vol.Name, nodeName: nodeName })">{{ vol.Name }}</a></td
|
|
>
|
|
<td>{{ vol.Destination }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</rd-widget-body>
|
|
</rd-widget>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-sm-12">
|
|
<container-networks-datatable
|
|
ng-if="container.NetworkSettings.Networks"
|
|
title-text="Connected networks"
|
|
title-icon="share-2"
|
|
dataset="container.NetworkSettings.Networks"
|
|
table-key="container-networks"
|
|
container="container"
|
|
available-networks="availableNetworks"
|
|
join-network-action="containerJoinNetwork"
|
|
join-network-action-in-progress="state.joinNetworkInProgress"
|
|
leave-network-action="containerLeaveNetwork"
|
|
leave-network-action-in-progress="state.leaveNetworkInProgress"
|
|
node-name="nodeName"
|
|
></container-networks-datatable>
|
|
</div>
|
|
</div>
|