mirror of https://github.com/portainer/portainer
274 lines
14 KiB
HTML
274 lines
14 KiB
HTML
<page-header title="'Create container'" breadcrumbs="[{label:'Containers', link:'docker.containers'}, 'Add container']"> </page-header>
|
|
|
|
<information-panel title-text="Caution" ng-if="state.mode == 'duplicate'">
|
|
<span class="small">
|
|
<p class="text-muted">
|
|
<pr-icon icon="'alert-triangle'" mode="'warning'" class-name="'mr-0.5'"></pr-icon>
|
|
The new container may fail to start if the image is changed, and settings from the previous container aren't compatible. Common causes include entrypoint, cmd or
|
|
<a href="https://docs.portainer.io/user/docker/containers/advanced" target="_blank">other settings</a> set by an image.
|
|
</p>
|
|
</span>
|
|
</information-panel>
|
|
|
|
<div class="row">
|
|
<div class="col-lg-12 col-md-12 col-xs-12">
|
|
<rd-widget>
|
|
<rd-widget-body>
|
|
<form class="form-horizontal" autocomplete="off">
|
|
<!-- name-input -->
|
|
<div class="form-group">
|
|
<label for="container_name" class="col-sm-3 col-lg-2 control-label text-left">Name</label>
|
|
<div class="col-sm-8">
|
|
<input type="text" class="form-control" ng-model="config.name" id="container_name" placeholder="e.g. myContainer" />
|
|
</div>
|
|
</div>
|
|
<!-- !name-input -->
|
|
<div class="col-sm-12 form-section-title"> Image configuration </div>
|
|
<div ng-if="!formValues.RegistryModel.Registry && fromContainer">
|
|
<pr-icon icon="'alert-triangle'" mode="'warning'"></pr-icon>
|
|
<span class="small text-danger" style="margin-left: 5px">
|
|
The Docker registry for the <code>{{ config.Image }}</code> image is not registered inside Portainer, you will not be able to create a container. Please register that
|
|
registry first.
|
|
</span>
|
|
</div>
|
|
<div ng-if="formValues.RegistryModel.Registry || !fromContainer">
|
|
<!-- image-and-registry -->
|
|
<por-image-registry
|
|
model="formValues.RegistryModel"
|
|
ng-if="formValues.RegistryModel.Registry"
|
|
auto-complete="true"
|
|
endpoint="endpoint"
|
|
is-admin="isAdmin"
|
|
check-rate-limits="formValues.alwaysPull"
|
|
on-image-change="onImageNameChange()"
|
|
set-validity="setPullImageValidity"
|
|
>
|
|
<!-- always-pull -->
|
|
<div class="form-group">
|
|
<div class="col-sm-12">
|
|
<por-switch-field
|
|
name="'alwaysPull'"
|
|
label-class="'col-sm-2'"
|
|
checked="formValues.alwaysPull"
|
|
disabled="!state.pullImageValidity"
|
|
label="'Always pull the image'"
|
|
on-change="(onAlwaysPullChange)"
|
|
tooltip="'When enabled, Portainer will automatically try to pull the specified image before creating the container.'"
|
|
></por-switch-field>
|
|
</div>
|
|
</div>
|
|
<!-- !always-pull -->
|
|
</por-image-registry>
|
|
<!-- !image-and-registry -->
|
|
</div>
|
|
|
|
<!-- create-webhook -->
|
|
<div ng-if="isAdmin && applicationState.endpoint.type !== 4">
|
|
<div class="col-sm-12 form-section-title"> Webhooks </div>
|
|
<div class="form-group">
|
|
<div class="col-sm-12">
|
|
<por-switch-field
|
|
feature-id="'container-webhook'"
|
|
label-class="'col-sm-2'"
|
|
label="'Create a container webhook'"
|
|
tooltip="'Create a webhook (or callback URI) to automate the recreate 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.'"
|
|
></por-switch-field>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- !create-webhook -->
|
|
|
|
<div class="col-sm-12 form-section-title"> Network ports configuration </div>
|
|
<!-- publish-exposed-ports -->
|
|
<div class="form-group">
|
|
<div class="col-sm-12">
|
|
<por-switch-field
|
|
label-class="'col-sm-2'"
|
|
checked="config.HostConfig.PublishAllPorts"
|
|
label="'Publish all exposed network ports to random host ports'"
|
|
on-change="(handlePublishAllPortsChange)"
|
|
tooltip="'When enabled, Portainer will let Docker automatically map a random port on the host to each one defined in the image Dockerfile.'"
|
|
></por-switch-field>
|
|
</div>
|
|
</div>
|
|
<!-- !publish-exposed-ports -->
|
|
<!-- port-mapping -->
|
|
<div class="form-group">
|
|
<div class="col-sm-12">
|
|
<label class="control-label text-left">
|
|
Manual network port publishing
|
|
<portainer-tooltip
|
|
message="'When a range of ports on the host and a single port on the container is specified, Docker will randomly choose a single available port in the defined range and forward that to the container port.'"
|
|
></portainer-tooltip>
|
|
</label>
|
|
<span class="label label-default interactive" style="margin-left: 10px" ng-click="addPortBinding()">
|
|
<pr-icon icon="'plus'" mode="'alt'"></pr-icon> publish a new network port
|
|
</span>
|
|
</div>
|
|
<!-- port-mapping-input-list -->
|
|
<div class="col-sm-12 form-inline" style="margin-top: 10px">
|
|
<div ng-repeat="portBinding in config.HostConfig.PortBindings" style="margin-top: 2px">
|
|
<!-- host-port -->
|
|
<div class="input-group col-sm-4 input-group-sm">
|
|
<span class="input-group-addon">host</span>
|
|
<input type="text" class="form-control" ng-model="portBinding.hostPort" placeholder="e.g. 80, 80-88, ip:80 or ip:80-88 (optional)" />
|
|
</div>
|
|
<!-- !host-port -->
|
|
<span style="margin: 0 10px 0 10px">
|
|
<pr-icon icon="'arrow-right'"></pr-icon>
|
|
</span>
|
|
<!-- container-port -->
|
|
<div class="input-group col-sm-4 input-group-sm">
|
|
<span class="input-group-addon">container</span>
|
|
<input type="text" class="form-control" ng-model="portBinding.containerPort" placeholder="e.g. 80 or 80-88" />
|
|
</div>
|
|
<!-- !container-port -->
|
|
<!-- protocol-actions -->
|
|
<div class="input-group col-sm-3 input-group-sm">
|
|
<div class="btn-group btn-group-sm">
|
|
<label class="btn btn-light" ng-model="portBinding.protocol" uib-btn-radio="'tcp'">TCP</label>
|
|
<label class="btn btn-light" ng-model="portBinding.protocol" uib-btn-radio="'udp'">UDP</label>
|
|
</div>
|
|
<button class="btn btn-light" type="button" ng-click="removePortBinding($index)">
|
|
<pr-icon icon="'trash-2'" class-name="'icon-secondary icon-md'"></pr-icon>
|
|
</button>
|
|
</div>
|
|
<!-- !protocol-actions -->
|
|
</div>
|
|
</div>
|
|
<!-- !port-mapping-input-list -->
|
|
</div>
|
|
<!-- !port-mapping -->
|
|
<div ng-if="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'">
|
|
<div class="col-sm-12 form-section-title"> Deployment </div>
|
|
<!-- node-selection -->
|
|
<node-selector model="formValues.NodeName" endpoint-id="endpoint.Id"> </node-selector>
|
|
<!-- !node-selection -->
|
|
</div>
|
|
<!-- access-control -->
|
|
<por-access-control-form form-data="formValues.AccessControlData" resource-control="fromContainer.ResourceControl" ng-if="fromContainer"></por-access-control-form>
|
|
<!-- !access-control -->
|
|
<!-- actions -->
|
|
<div class="col-sm-12 form-section-title"> Actions </div>
|
|
<!-- autoremove -->
|
|
<div class="form-group">
|
|
<div class="col-sm-12">
|
|
<por-switch-field
|
|
label-class="'col-sm-2'"
|
|
checked="config.HostConfig.AutoRemove"
|
|
label="'Auto remove'"
|
|
on-change="(handleAutoRemoveChange)"
|
|
tooltip="'When enabled, Portainer will automatically remove the container when it exits. This is useful when you want to use the container only once.'"
|
|
></por-switch-field>
|
|
</div>
|
|
</div>
|
|
<!-- !autoremove -->
|
|
<div class="form-group">
|
|
<div class="col-sm-12">
|
|
<button
|
|
type="button"
|
|
class="btn btn-primary btn-sm !ml-0"
|
|
ng-disabled="state.actionInProgress || !formValues.RegistryModel.Image || (!formValues.RegistryModel.Registry && fromContainer)
|
|
|| (fromContainer.IsPortainer && fromContainer.Name === '/' + config.name)"
|
|
ng-click="create()"
|
|
button-spinner="state.actionInProgress"
|
|
>
|
|
<span ng-hide="state.actionInProgress">Deploy the container</span>
|
|
<span ng-show="state.actionInProgress">Deployment in progress...</span>
|
|
</button>
|
|
<span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px">{{ state.formValidationError }}</span>
|
|
</div>
|
|
</div>
|
|
<!-- !actions -->
|
|
</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="settings" title-text="Advanced container settings"></rd-widget-header>
|
|
<rd-widget-body>
|
|
<ul class="nav nav-pills nav-justified">
|
|
<li class="active interactive"><a data-target="#command" data-toggle="tab">Command & logging</a></li>
|
|
<li class="interactive"><a data-target="#volumes" data-toggle="tab">Volumes</a></li>
|
|
<li class="interactive"><a data-target="#network" data-toggle="tab">Network</a></li>
|
|
<li class="interactive"><a data-target="#env" data-toggle="tab">Env</a></li>
|
|
<li class="interactive"><a data-target="#labels" data-toggle="tab">Labels</a></li>
|
|
<li class="interactive"><a data-target="#restart-policy" data-toggle="tab">Restart policy</a></li>
|
|
<li class="interactive"><a data-target="#runtime-resources" ng-mouseup="refreshSlider()" data-toggle="tab">Runtime & Resources</a></li>
|
|
<li ng-if="areContainerCapabilitiesEnabled" class="interactive"><a data-target="#container-capabilities" data-toggle="tab">Capabilities</a></li>
|
|
</ul>
|
|
<div class="form-horizontal" ng-if="state.containerIsLoaded">
|
|
<!-- tab-content -->
|
|
<div class="tab-content">
|
|
<!-- tab-command -->
|
|
<div class="tab-pane active" id="command">
|
|
<docker-create-container-commands-tab
|
|
values="formValues.commands"
|
|
api-version="applicationState.endpoint.apiVersion"
|
|
on-change="(handleCommandsChange)"
|
|
></docker-create-container-commands-tab>
|
|
</div>
|
|
<!-- !tab-command -->
|
|
|
|
<div class="tab-pane" id="volumes">
|
|
<docker-create-container-volumes-tab ng-if="state.containerIsLoaded" values="formValues.volumes" on-change="(onVolumesChange)" allow-bind-mounts="allowBindMounts">
|
|
</docker-create-container-volumes-tab>
|
|
</div>
|
|
|
|
<div class="tab-pane" id="network">
|
|
<docker-create-container-network-tab values="formValues.network" on-change="(onNetworkChange)"> </docker-create-container-network-tab>
|
|
</div>
|
|
|
|
<div class="tab-pane" id="labels">
|
|
<docker-create-container-labels-tab values="formValues.labels" on-change="(onLabelsChange)"></docker-create-container-labels-tab>
|
|
</div>
|
|
|
|
<!-- tab-env -->
|
|
<div class="tab-pane" id="env">
|
|
<docker-create-container-env-vars-tab
|
|
ng-if="state.containerIsLoaded"
|
|
values="formValues.envVars"
|
|
on-change="(handleEnvVarsChange)"
|
|
></docker-create-container-env-vars-tab>
|
|
</div>
|
|
<!-- !tab-env -->
|
|
|
|
<div class="tab-pane" id="restart-policy">
|
|
<docker-create-container-restart-policy-tab values="formValues.restartPolicy" on-change="(onRestartPolicyChange)"></docker-create-container-restart-policy-tab>
|
|
</div>
|
|
|
|
<!-- tab-runtime-resources -->
|
|
<div class="tab-pane" id="runtime-resources">
|
|
<docker-create-container-resources-tab
|
|
values="formValues.resources"
|
|
on-change="(onResourcesChange)"
|
|
allow-privileged-mode="allowPrivilegedMode"
|
|
is-devices-field-visible="showDeviceMapping"
|
|
is-sysctl-field-visible="allowSysctl"
|
|
is-init-field-visible="applicationState.endpoint.apiVersion >= 1.37"
|
|
is-image-invalid="!formValues.RegistryModel.Image || (!formValues.RegistryModel.Registry && fromContainer)"
|
|
redeploy="(redeployUnlimitedResources)"
|
|
is-duplicate="state.mode == 'duplicate'"
|
|
validation-data="{
|
|
maxMemory: state.sliderMaxMemory,
|
|
maxCpu: state.sliderMaxCpu,
|
|
}"
|
|
></docker-create-container-resources-tab>
|
|
</div>
|
|
<!-- !tab-runtime-resources -->
|
|
<!-- tab-container-capabilities -->
|
|
<div class="tab-pane" id="container-capabilities">
|
|
<docker-create-container-capabilities-tab values="formValues.capabilities" on-change="(onCapabilitiesChange)"></docker-create-container-capabilities-tab>
|
|
</div>
|
|
<!-- !tab-container-capabilities -->
|
|
</div>
|
|
</div>
|
|
</rd-widget-body>
|
|
</rd-widget>
|
|
</div>
|
|
</div>
|