docker service create
| Descripción | Crea un nuevo servicio |
|---|---|
| Uso | docker service create [OPTIONS] IMAGE [COMMAND] [ARG...] |
Swarm Este comando funciona con el orquestador de Swarm.
Descripción
Crea un servicio según lo descrito por los parámetros especificados.
NoteEste es un comando de gestión de clústeres y debe ejecutarse en un nodo administrador de Swarm (manager node). Para obtener más información sobre administradores y trabajadores, consulta la sección del modo Swarm en la documentación.
Opciones
| Opción | Predeterminado | Descripción |
|---|---|---|
--cap-add | API 1.41+ Añade capacidades de Linux | |
--cap-drop | API 1.41+ Elimina capacidades de Linux | |
--config | API 1.30+ Especifica las configuraciones que se expondrán al servicio | |
--constraint | Restricciones de ubicación | |
--container-label | Etiquetas del contenedor | |
--credential-spec | API 1.29+ Especificación de credenciales para cuenta de servicio administrada (solo Windows) | |
-d, --detach | API 1.29+ Sale inmediatamente en lugar de esperar a que el servicio converja | |
--dns | API 1.25+ Establece servidores DNS personalizados | |
--dns-option | API 1.25+ Establece opciones de DNS | |
--dns-search | API 1.25+ Establece dominios de búsqueda DNS personalizados | |
--endpoint-mode | vip | Modo de endpoint (vip o dnsrr) |
--entrypoint | Sobrescribe el ENTRYPOINT por defecto de la imagen | |
-e, --env | Establece variables de entorno | |
--env-file | Lee un archivo de variables de entorno | |
--generic-resource | Recursos definidos por el usuario | |
--group | API 1.25+ Establece uno o más grupos de usuarios suplementarios para el contenedor | |
--health-cmd | API 1.25+ Comando a ejecutar para comprobar el estado de salud | |
--health-interval | API 1.25+ Tiempo entre ejecuciones de la comprobación (ms|s|m|h) | |
--health-retries | API 1.25+ Fallos consecutivos necesarios para reportar un estado insalubre | |
--health-start-interval | API 1.44+ Tiempo entre ejecuciones de la comprobación durante el período de inicio (ms|s|m|h) | |
--health-start-period | API 1.29+
Período de inicio para que el contenedor se inicialice antes de comenzar la cuenta regresiva de reintentos de salud (ms|s|m|h) | |
--health-timeout | API 1.25+ Tiempo máximo permitido para que se ejecute una comprobación (ms|s|m|h) | |
--host | API 1.25+ Establece una o más asociaciones de host a IP personalizadas (host:ip) | |
--hostname | API 1.25+ Nombre de host del contenedor | |
--init | API 1.37+
Utiliza un proceso init dentro de cada contenedor del servicio para reenviar señales y adoptar procesos huérfanos | |
--isolation | API 1.35+ Modo de aislamiento del contenedor del servicio | |
-l, --label | Etiquetas del servicio | |
--limit-cpu | Limita las CPUs | |
--limit-memory | Limita la memoria | |
--limit-pids | API 1.41+ Limita el número máximo de procesos (por defecto 0 = ilimitado) | |
--log-driver | Controlador de registro para el servicio | |
--log-opt | Opciones del controlador de registro | |
--max-concurrent | API 1.41+
Número de tareas de trabajo a ejecutar simultáneamente (por defecto es igual a --replicas) | |
--memory-swap | API 1.52+ Bytes de intercambio (swap) (-1 para ilimitado) | |
--memory-swappiness | -1 | API 1.52+ Ajusta la tendencia al intercambio (swappiness) de memoria (0-100), -1 para restablecer al valor predeterminado |
--mode | replicated | Modo de servicio (replicated, global, replicated-job, global-job) |
--mount | Acopla un montaje de sistema de archivos al servicio | |
--name | Nombre del servicio | |
--network | Conexiones de red | |
--no-healthcheck | API 1.25+ Deshabilita cualquier HEALTHCHECK especificado por el contenedor | |
--no-resolve-image | API 1.30+
No consulta el registro para resolver el digest de la imagen y las plataformas compatibles | |
--oom-score-adj | API 1.46+ Ajusta las preferencias OOM del host (-1000 a 1000) | |
--placement-pref | API 1.28+ Añade una preferencia de ubicación | |
-p, --publish | Publica un puerto como puerto de nodo | |
-q, --quiet | Suprime la salida del progreso | |
--read-only | API 1.28+ Monta el sistema de archivos raíz del contenedor como de solo lectura | |
--replicas | Número de tareas | |
--replicas-max-per-node | API 1.40+ Número máximo de tareas por nodo (por defecto 0 = ilimitado) | |
--reserve-cpu | Reserva CPUs | |
--reserve-memory | Reserva memoria | |
--restart-condition | Reinicia cuando se cumple la condición (none, on-failure, any) (por defecto any) | |
--restart-delay | Retraso entre intentos de reinicio (ns|us|ms|s|m|h) (por defecto 5s) | |
--restart-max-attempts | Número máximo de reinicios antes de darse por vencido | |
--restart-window | Ventana de tiempo utilizada para evaluar la política de reinicio (ns|us|ms|s|m|h) | |
--rollback-delay | API 1.28+ Retraso entre reversiones (rollbacks) de tareas (ns|us|ms|s|m|h) (por defecto 0s) | |
--rollback-failure-action | API 1.28+
Acción ante un fallo en la reversión (rollback) (pause, continue) (por defecto pause) | |
--rollback-max-failure-ratio | API 1.28+ Tasa de fallos tolerada durante una reversión (rollback) (por defecto 0) | |
--rollback-monitor | API 1.28+
Duración después de cada reversión (rollback) de tarea para monitorear fallos (ns|us|ms|s|m|h) (por defecto 5s) | |
--rollback-order | API 1.29+
Orden de reversión (rollback) (start-first, stop-first) (por defecto stop-first) | |
--rollback-parallelism | 1 | API 1.28+
Número máximo de tareas revertidas (rolled back) simultáneamente (0 para revertir todas a la vez) |
--secret | API 1.25+ Especifica secretos que se expondrán al servicio | |
--stop-grace-period | Tiempo a esperar antes de forzar la finalización de un contenedor (ns|us|ms|s|m|h) (por defecto 10s) | |
--stop-signal | API 1.28+ Señal para detener el contenedor | |
--sysctl | API 1.40+ Opciones de sysctl | |
-t, --tty | API 1.25+ Asigna un pseudo-TTY | |
--ulimit | API 1.41+ Opciones de ulimit | |
--update-delay | Retraso entre actualizaciones (ns|us|ms|s|m|h) (por defecto 0s) | |
--update-failure-action | Acción ante un fallo en la actualización (pause, continue, rollback) (por defecto pause) | |
--update-max-failure-ratio | API 1.25+ Tasa de fallos tolerada durante una actualización (por defecto 0) | |
--update-monitor | API 1.25+
Duración después de cada actualización de tarea para monitorear fallos (ns|us|ms|s|m|h) (por defecto 5s) | |
--update-order | API 1.29+
Orden de actualización (start-first, stop-first) (por defecto stop-first) | |
--update-parallelism | 1 | Número máximo de tareas actualizadas simultáneamente (0 para actualizar todas a la vez) |
-u, --user | Nombre de usuario o UID (formato: <nombre|uid>[:<grupo|gid>]) | |
--with-registry-auth | Envía detalles de autenticación del registro a los agentes de swarm | |
-w, --workdir | Directorio de trabajo dentro del contenedor |
Ejemplos
Crear un servicio
$ docker service create --name redis redis:7.4.1
dmu1ept4cxcfe8k8lhtux3ro3
$ docker service create --mode global --name redis2 redis:7.4.1
a8q9dasaafudfs8q8w32udass
$ docker service ls
ID NAME MODE REPLICAS IMAGE
dmu1ept4cxcf redis replicated 1/1 redis:7.4.1
a8q9dasaafud redis2 global 1/1 redis:7.4.1
Crear un servicio utilizando una imagen de un registro privado (--with-registry-auth)
Si tu imagen está disponible en un registro privado que requiere iniciar sesión, utiliza el
flag --with-registry-auth con docker service create, después de haber iniciado sesión. Si
tu imagen está almacenada en registry.example.com, que es un registro privado, utiliza
un comando como el siguiente:
$ docker login registry.example.com
$ docker service create \
--with-registry-auth \
--name my_service \
registry.example.com/acme/my_image:latest
Esto pasa el token de inicio de sesión desde tu cliente local a los nodos de swarm donde se despliega el servicio, utilizando los registros WAL cifrados. Con esta información, los nodos pueden iniciar sesión en el registro y descargar la imagen.
Crear un servicio con 5 tareas réplica (--replicas)
Utiliza el flag --replicas para establecer el número de tareas réplica para un servicio
replicado. El siguiente comando crea un servicio redis con 5 tareas réplica:
$ docker service create --name redis --replicas=5 redis:7.4.1
4cdgfyky7ozwh3htjfw0d12qv
El comando anterior establece el número deseado de tareas para el servicio. Aunque
el comando devuelve la salida inmediatamente, el escalado real del servicio puede tomar
algún tiempo. La columna REPLICAS muestra tanto el número real como el deseado
de tareas réplica para el servicio.
En el siguiente ejemplo, el estado deseado es de 5 réplicas, pero el número
actual de tareas RUNNING (en ejecución) es 3:
$ docker service ls
ID NAME MODE REPLICAS IMAGE
4cdgfyky7ozw redis replicated 3/5 redis:7.4.1
Una vez creadas todas las tareas y en estado RUNNING, el número real de tareas es
igual al deseado:
$ docker service ls
ID NAME MODE REPLICAS IMAGE
4cdgfyky7ozw redis replicated 5/5 redis:7.4.1
Crear un servicio con secretos (--secret)
Utiliza el flag --secret para dar acceso a un contenedor a un
secreto.
Crea un servicio especificando un secreto:
$ docker service create --name redis --secret secret.json redis:7.4.1
4cdgfyky7ozwh3htjfw0d12qv
Crea un servicio especificando el secreto, el destino, el ID de usuario/grupo y el modo:
$ docker service create --name redis \
--secret source=ssh-key,target=ssh \
--secret source=app-key,target=app,uid=1000,gid=1001,mode=0400 \
redis:7.4.1
4cdgfyky7ozwh3htjfw0d12qv
Para conceder acceso a un servicio a múltiples secretos, utiliza múltiples flags --secret.
Los secretos se encuentran en /run/secrets en el contenedor si no se especifica ningún destino.
Si no se especifica ningún destino, el nombre del secreto se utiliza como el archivo en memoria
en el contenedor. Si se especifica un destino, este se utiliza como nombre de archivo. En el
ejemplo anterior, se crean dos archivos: /run/secrets/ssh y
/run/secrets/app para cada uno de los destinos de secreto especificados.
Crear un servicio con configuraciones (--config)
Utiliza el flag --config para dar acceso a un contenedor a una
configuración.
Crea un servicio con una configuración. La configuración se montará en redis-config,
será propiedad del usuario que ejecuta el comando dentro del contenedor (a menudo root),
y tendrá el modo de archivo 0444 (legible para todos). Puedes especificar el uid y el gid
como IDs numéricos o nombres. Cuando utilices nombres, los nombres de grupo/usuario proporcionados
deben existir previamente en el contenedor. El mode se especifica como una secuencia de 4 números,
como 0755.
$ docker service create --name=redis --config redis-conf redis:7.4.1
Crea un servicio con una configuración y especifica la ubicación de destino y el modo de archivo:
$ docker service create --name redis \
--config source=redis-conf,target=/etc/redis/redis.conf,mode=0400 redis:7.4.1
Para conceder acceso a un servicio a múltiples configuraciones, utiliza múltiples flags --config.
Las configuraciones se encuentran en / en el contenedor si no se especifica ningún destino. Si no
se especifica ningún destino, el nombre de la configuración se utiliza como el nombre del archivo en
el contenedor. Si se especifica un destino, este se utiliza como nombre de archivo.
Crear un servicio con una política de actualización continua (rolling update)
$ docker service create \
--replicas 10 \
--name redis \
--update-delay 10s \
--update-parallelism 2 \
redis:7.4.1
Al ejecutar una
actualización del servicio, el planificador actualiza un
máximo de 2 tareas a la vez, con un intervalo de 10s entre actualizaciones. Para obtener más información,
consulta el
tutorial de actualizaciones continuas.
Establecer variables de entorno (-e, --env)
Esto establece una variable de entorno para todas las tareas de un servicio. Por ejemplo:
$ docker service create \
--name redis_2 \
--replicas 5 \
--env MYVAR=foo \
redis:7.4.1
Para especificar múltiples variables de entorno, especifica múltiples flags --env, cada uno
con un par clave-valor independiente.
$ docker service create \
--name redis_2 \
--replicas 5 \
--env MYVAR=foo \
--env MYVAR2=bar \
redis:7.4.1
Crear un servicio con un nombre de host específico (--hostname)
Esta opción establece el nombre de host (hostname) de los contenedores del servicio Docker en una cadena específica. Por ejemplo:
$ docker service create --name redis --hostname myredis redis:7.4.1
Establecer metadatos en un servicio (-l, --label)
Una etiqueta (label) es un par clave=valor que aplica metadatos a un servicio. Para etiquetar un
servicio con dos etiquetas:
$ docker service create \
--name redis_2 \
--label com.example.foo="bar" \
--label bar=baz \
redis:7.4.1
Para obtener más información sobre las etiquetas, consulta aplicar metadatos personalizados.
Añadir montajes vinculados (bind mounts), volúmenes o sistemas de archivos en memoria (--mount)
Docker admite tres tipos diferentes de montajes, que permiten a los contenedores leer o escribir en archivos o directorios, ya sea en el sistema operativo del host o en sistemas de archivos en memoria. Estos tipos son volúmenes de datos (a menudo llamados simplemente volúmenes), montajes vinculados (bind mounts), tmpfs y tuberías con nombre (named pipes).
Un montaje vinculado (bind mount) hace que un archivo o directorio del host esté disponible para el
contenedor en el que está montado. Un montaje vinculado puede ser de solo lectura o
de lectura y escritura. Por ejemplo, un contenedor podría compartir la información DNS de su host mediante
un montaje vinculado del archivo /etc/resolv.conf del host, o un contenedor podría
escribir registros en el directorio /var/log/myContainerLogs de su host. Si utilizas
montajes vinculados y tu host y contenedores tienen diferentes nociones de permisos,
controles de acceso u otros detalles similares, te encontrarás con problemas de portabilidad.
Un volumen con nombre (named volume) es un mecanismo para desacoplar los datos persistentes que necesita tu contenedor de la imagen utilizada para crearlo y de la máquina host. Los volúmenes con nombre son creados y gestionados por Docker, y persisten incluso cuando ningún contenedor los está utilizando actualmente. Los datos en los volúmenes con nombre se pueden compartir entre un contenedor y la máquina host, así como entre múltiples contenedores. Docker utiliza un controlador de volumen (volume driver) para crear, gestionar y montar volúmenes. Puedes hacer copias de seguridad o restaurar volúmenes utilizando comandos de Docker.
Un tmpfs monta un sistema de archivos tmpfs dentro de un contenedor para datos volátiles.
Un npipe monta una tubería con nombre (named pipe) desde el host en el contenedor.
Considera una situación en la que tu imagen inicia un servidor web ligero. Podrías utilizar esa imagen como imagen base, copiar los archivos HTML de tu sitio web y empaquetar eso en otra imagen. Cada vez que cambie tu sitio web, tendrías que actualizar la nueva imagen y volver a desplegar todos los contenedores que sirven a tu sitio web. Una mejor solución es almacenar el sitio web en un volumen con nombre que se conecte a cada uno de tus contenedores de servidor web cuando se inicien. Para actualizar el sitio web, solo tienes que actualizar el volumen con nombre.
Para obtener más información sobre los volúmenes con nombre, consulta Volúmenes de datos.
La siguiente tabla describe las opciones que se aplican tanto a los montajes vinculados como a los volúmenes con nombre en un servicio:
| Opción | Requerido | Descripción |
|---|---|---|
| type | El tipo de montaje, puede ser el de volume, bind, tmpfs o npipe. Por defecto es volume si no se especifica el tipo.
| |
| src o source | para type=bind y type=npipe |
|
dst o destination o target | sí | Ruta de montaje dentro del contenedor, por ejemplo /some/path/in/container/. Si la ruta no existe en el sistema de archivos del contenedor, Engine crea un directorio en la ubicación especificada antes de montar el volumen o el montaje vinculado. |
readonly o ro | Engine monta los enlaces y volúmenes como read-write a menos que se indique la opción readonly al montar el enlace o volumen. Ten en cuenta que establecer readonly para un montaje vinculado podría no hacer que sus submontajes sean de solo lectura según la versión del kernel. Consulta también bind-recursive.
|
Opciones para montajes vinculados (bind mounts)
Las siguientes opciones solo se pueden utilizar para montajes vinculados (type=bind):
| Opción | Descripción |
|---|---|
| bind-propagation | Consulta la sección de propagación de montaje. |
| consistency | Los requisitos de consistencia para el montaje; uno de
|
| bind-recursive | Por defecto, los submontajes también se montan de forma vinculada recursivamente. Sin embargo, este comportamiento puede resultar confuso cuando un
montaje vinculado se configura con la opción readonly, porque los submontajes podrían no montarse como de solo lectura,
dependiendo de la versión del kernel.
Establece bind-recursive para controlar el comportamiento del montaje vinculado recursivo. El valor es uno de:
|
| bind-create-src | Por defecto, los montajes vinculados requieren que la ruta de origen exista en el host del demonio. Esta es una diferencia significativa
con respecto al flag -v, que crea la ruta de origen si no existe. Establece bind-create-src para crear la ruta de origen en el host del demonio si no existe. El valor es opcional:
|
Propagación de montaje (bind propagation)
La propagación de montaje se refiere a si los montajes creados dentro de un montaje
vinculado o volumen con nombre dado se pueden propagar a las réplicas de ese montaje o no. Considera
un punto de montaje /mnt, que también está montado en /tmp. Los ajustes de propagación
controlan si un montaje en /tmp/a también estaría disponible en /mnt/a. Cada
ajuste de propagación tiene una contraparte recursiva. En el caso de recursividad,
considera que /tmp/a también está montado como /foo. Los ajustes de propagación
controlan si /mnt/a y/o /tmp/a existirían.
La opción bind-propagation se establece de forma predeterminada en rprivate tanto para montajes vinculados como para
montajes de volumen, y solo se puede configurar para montajes vinculados. En otras palabras, los volúmenes con nombre
no admiten la propagación de montaje.
shared: Los submontajes del montaje original se exponen a los montajes réplica, y los submontajes de los montajes réplica también se propagan al montaje original.slave: similar a un montaje compartido, pero solo en una dirección. Si el montaje original expone un submontaje, el montaje réplica puede verlo. Sin embargo, si el montaje réplica expone un submontaje, el montaje original no puede verlo.private: El montaje es privado. Los submontajes dentro de él no se exponen a los montajes réplica, y los submontajes de los montajes réplica no se exponen al montaje original.rshared: Lo mismo que shared, pero la propagación también se extiende hacia y desde los puntos de montaje anidados dentro de cualquiera de los puntos de montaje originales o réplicas.rslave: Lo mismo queslave, pero la propagación también se extiende hacia y desde los puntos de montaje anidados dentro de cualquiera de los puntos de montaje originales o réplicas.rprivate: El predeterminado. Lo mismo queprivate, lo que significa que ningún punto de montaje en ningún lugar dentro de los puntos de montaje originales o réplicas se propaga en ninguna dirección.
Para obtener más información sobre la propagación de montaje, consulta la documentación del kernel de Linux para subárboles compartidos (shared subtree).
Opciones para volúmenes con nombre
Las siguientes opciones solo se pueden utilizar para volúmenes con nombre (type=volume):
| Opción | Descripción |
|---|---|
| volume-driver | Nombre del plugin del controlador de volumen (volume-driver) a utilizar para el volumen. Por defecto es "local", para utilizar el controlador de volumen local para crear el volumen si este no existe. |
| volume-label | Uno o más metadatos personalizados ("etiquetas") para aplicar al volumen en el momento de su creación. Por ejemplo, volume-label=mylabel=hello-world,my-other-label=hello-mars. Para obtener más información sobre las etiquetas, consulta aplicar metadatos personalizados. |
| volume-nocopy | Por defecto, si conectas un volumen vacío a un contenedor y ya existían archivos o
directorios en la ruta de montaje en el contenedor (dst),
Engine copia esos archivos y directorios en el volumen, permitiendo
que el host acceda a ellos. Establece volume-nocopy para deshabilitar la copia de archivos
desde el sistema de archivos del contenedor al volumen y montar el volumen vacío. El valor es opcional:
|
| volume-opt | Opciones específicas para un controlador de volumen dado, que se pasarán al controlador al crear el volumen. Las opciones se proporcionan como una lista separada por comas de pares clave/valor, por ejemplo, volume-opt=some-option=some-value,volume-opt=some-other-option=some-other-value. Para conocer las opciones disponibles para un controlador dado, consulta la documentación de ese controlador. |
Opciones para tmpfs
Las siguientes opciones solo se pueden utilizar para montajes tmpfs (type=tmpfs):
| Opción | Descripción |
|---|---|
| tmpfs-size | Tamaño del montaje tmpfs en bytes. Sin límite por defecto en Linux. |
| tmpfs-mode | Modo de archivo del tmpfs en octal (por ejemplo, "700" o "0700"). Por defecto es "1777" en Linux. |
Diferencias entre "--mount" y "--volume"
El flag --mount admite la mayoría de las opciones que admite el flag -v
o --volume para docker run, con algunas excepciones importantes:
El flag
--mountte permite especificar un controlador de volumen y opciones del controlador de volumen por volumen, sin tener que crear los volúmenes con antelación. En cambio,docker runte permite especificar un único controlador de volumen que comparten todos los volúmenes, utilizando el flag--volume-driver.El flag
--mountte permite especificar metadatos personalizados ("etiquetas") para un volumen, antes de que se cree el volumen.Cuando utilizas
--mountcontype=bind, la ruta del host debe hacer referencia a una ruta existente en el host. La ruta no se creará por ti y el servicio fallará con un error si la ruta no existe. Puedes utilizarbind-create-srcpara crear la ruta del host si no existe.El flag
--mountno te permite volver a etiquetar un volumen con los flagsZoz, que se utilizan para el etiquetado deselinux.
Crear un servicio utilizando un volumen con nombre
El siguiente ejemplo crea un servicio que utiliza un volumen con nombre:
$ docker service create \
--name my-service \
--replicas 3 \
--mount type=volume,source=my-volume,destination=/path/in/container,volume-label="color=red",volume-label="shape=round" \
nginx:alpine
Para cada réplica del servicio, Engine solicita un volumen llamado "my-volume" al controlador de volumen predeterminado ("local") donde se despliega la tarea. Si el volumen no existe, Engine crea un nuevo volumen y aplica las etiquetas "color" y "shape".
Cuando se inicia la tarea, el volumen se monta en /path/in/container/ dentro
del contenedor.
Ten en cuenta que el volumen predeterminado ("local") es un controlador de volumen de alcance local. Esto significa que, dependiendo de dónde se despliegue una tarea, esta tarea obtendrá un nuevo volumen llamado "my-volume", o compartirá el mismo "my-volume" con otras tareas del mismo servicio. Varios contenedores escribiendo en un mismo volumen compartido puede causar corrupción de datos si el software que se ejecuta dentro del contenedor no está diseñado para manejar procesos simultáneos escribiendo en la misma ubicación. Ten también en cuenta que los contenedores pueden ser reprogramados por el orquestador de Swarm y desplegarse en un nodo diferente.
Crear un servicio que utiliza un volumen anónimo
El siguiente comando crea un servicio con tres réplicas con un volumen anónimo
en /path/in/container:
$ docker service create \
--name my-service \
--replicas 3 \
--mount type=volume,destination=/path/in/container \
nginx:alpine
En este ejemplo, no se especifica ningún nombre (source) para el volumen, por lo que se crea
un nuevo volumen para cada tarea. Esto garantiza que cada tarea obtenga su propio volumen
y que los volúmenes no se compartan entre tareas. Los volúmenes anónimos se eliminan después
de que finalice la tarea que los utiliza.
Crear un servicio que utiliza un directorio del host montado de forma vinculada (bind-mounted)
El siguiente ejemplo monta de forma vinculada (bind-mounts) un directorio del host en /path/in/container en
los contenedores que respaldan el servicio:
$ docker service create \
--name my-service \
--mount type=bind,source=/path/on/host,destination=/path/in/container \
nginx:alpine
Establecer el modo de servicio (--mode)
El modo de servicio determina si se trata de un servicio replicado (replicated) o de un servicio global (global). Un servicio replicado ejecuta tantas tareas como se especifiquen, mientras que un servicio global se ejecuta en cada nodo activo en el swarm.
El siguiente comando crea un servicio global:
$ docker service create \
--name redis_2 \
--mode global \
redis:7.4.1
Especificar restricciones de servicio (--constraint)
Puedes limitar el conjunto de nodos donde se puede planificar una tarea definiendo
expresiones de restricción. Las expresiones de restricción pueden utilizar una regla de
coincidencia (==) o de exclusión (!=). Múltiples restricciones buscan nodos que cumplan con cada
expresión (coincidencia AND). Las restricciones pueden coincidir con etiquetas del nodo o de Engine como
se detalla a continuación:
| atributo del nodo | coincide con | ejemplo |
|---|---|---|
node.id | ID del nodo | node.id==2ivku8v2gvtg4 |
node.hostname | Nombre de host del nodo | node.hostname!=node-2 |
node.role | Rol del nodo (manager/worker) | node.role==manager |
node.platform.os | Sistema operativo del nodo | node.platform.os==windows |
node.platform.arch | Arquitectura del nodo | node.platform.arch==x86_64 |
node.labels | Etiquetas del nodo definidas por el usuario | node.labels.security==high |
engine.labels | Etiquetas del demonio de Docker (Docker Engine) | engine.labels.operatingsystem==ubuntu-24.04 |
Las etiquetas engine.labels se aplican a las etiquetas de Docker Engine, como el sistema operativo, los controladores,
etc. Los administradores de Swarm añaden node.labels para fines operativos utilizando
el comando
docker node update.
Por ejemplo, el siguiente comando limita las tareas del servicio redis a los nodos donde la etiqueta de tipo de nodo es igual a queue:
$ docker service create \
--name redis_2 \
--constraint node.platform.os==linux \
--constraint node.labels.type==queue \
redis:7.4.1
Si las restricciones del servicio excluyen a todos los nodos del clúster, se muestra un mensaje indicando que no se ha encontrado ningún nodo adecuado, pero el planificador iniciará un bucle de conciliación y desplegará el servicio una vez que haya disponible un nodo adecuado.
En el ejemplo de abajo, no se encontró ningún nodo que cumpliera con la restricción, lo que provocó que el servicio no conciliara con el estado deseado:
$ docker service create \
--name web \
--constraint node.labels.region==east \
nginx:alpine
lx1wrhhpmbbu0wuk0ybws30bc
overall progress: 0 out of 1 tasks
1/1: no suitable node (scheduling constraints not satisfied on 5 nodes)
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
b6lww17hrr4e web replicated 0/1 nginx:alpine
Después de añadir la etiqueta region=east a un nodo del clúster, el servicio
se concilia y se despliega el número deseado de réplicas:
$ docker node update --label-add region=east yswe2dm4c5fdgtsrli1e8ya5l
yswe2dm4c5fdgtsrli1e8ya5l
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
b6lww17hrr4e web replicated 1/1 nginx:alpine
Especificar preferencias de ubicación del servicio (--placement-pref)
Puedes configurar el servicio para dividir las tareas de manera uniforme entre diferentes categorías de nodos. Un ejemplo en el que esto puede ser útil es equilibrar las tareas en un conjunto de centros de datos o zonas de disponibilidad. El siguiente ejemplo ilustra esto:
$ docker service create \
--replicas 9 \
--name redis_2 \
--placement-pref spread=node.labels.datacenter \
redis:7.4.1
Esto utiliza --placement-pref con una estrategia de distribución spread (actualmente la única
estrategia admitida) para distribuir las tareas de manera uniforme según los valores de la etiqueta
de nodo datacenter. En este ejemplo, asumimos que cada nodo tiene una etiqueta de nodo
datacenter asignada. Si hay tres valores diferentes para esta etiqueta entre los
nodos del swarm, un tercio de las tareas se ubicará en los nodos
asociados con cada valor. Esto es así incluso si hay más nodos con un
valor que con otro. Por ejemplo, considera el siguiente conjunto de nodos:
- Tres nodos con
node.labels.datacenter=east - Dos nodos con
node.labels.datacenter=south - Un nodo con
node.labels.datacenter=west
Dado que estamos distribuyendo sobre los valores de la etiqueta datacenter y el
servicio tiene 9 réplicas, terminarán 3 réplicas en cada centro de datos. Hay
tres nodos asociados con el valor east, por lo que cada uno recibirá una de las
tres réplicas reservadas para este valor. Hay dos nodos con el valor
south, y las tres réplicas para este valor se dividirán entre ellos,
recibiendo uno dos réplicas y el otro solo una. Por último, west
tiene un único nodo que recibirá las tres réplicas reservadas para west.
Si los nodos de una categoría (por ejemplo, aquellos con
node.labels.datacenter=south) no pueden manejar su parte equitativa de tareas debido a
restricciones o limitaciones de recursos, las tareas adicionales se asignarán a otros
nodos en su lugar, si es posible.
Las preferencias de ubicación admiten tanto etiquetas de Engine como etiquetas de nodo. El
ejemplo anterior utiliza una etiqueta de nodo, porque se hace referencia a la etiqueta con
node.labels.datacenter. Para distribuir sobre los valores de una etiqueta de Engine, utiliza
--placement-pref spread=engine.labels.<nombre_etiqueta>.
Es posible añadir múltiples preferencias de ubicación a un servicio. Esto
establece una jerarquía de preferencias, de modo que las tareas se dividen primero sobre
una categoría y luego se dividen aún más sobre categorías adicionales. Un ejemplo
de dónde puede ser útil esto es dividir las tareas equitativamente entre centros de datos y
luego dividir las tareas dentro de cada centro de datos entre una selección de racks. Para añadir
múltiples preferencias de ubicación, especifica el flag --placement-pref varias
veces. El orden es importante, y las preferencias de ubicación se aplicarán
en el orden indicado al tomar las decisiones de planificación.
El siguiente ejemplo configura un servicio con múltiples preferencias de ubicación. Las tareas se distribuyen primero entre los distintos centros de datos y luego entre los racks (según lo indican las etiquetas respectivas):
$ docker service create \
--replicas 9 \
--name redis_2 \
--placement-pref 'spread=node.labels.datacenter' \
--placement-pref 'spread=node.labels.rack' \
redis:7.4.1
Al actualizar un servicio con docker service update, --placement-pref-add
añade una nueva preferencia de ubicación después de todas las preferencias de ubicación existentes.
--placement-pref-rm elimina una preferencia de ubicación existente que coincida con el
argumento.
Especificar requisitos y restricciones de memoria para un servicio (--reserve-memory y --limit-memory)
Si tu servicio necesita una cantidad mínima de memoria para funcionar correctamente,
puedes utilizar --reserve-memory para especificar que el servicio solo se
planifique en un nodo que tenga esta cantidad de memoria disponible para reservar. Si no hay ningún nodo
disponible que cumpla con los criterios, la tarea no se planifica, sino que permanece en estado
pendiente.
El siguiente ejemplo requiere que haya 4 GB de memoria disponibles y reservables en un nodo determinado antes de planificar la ejecución del servicio en ese nodo.
$ docker service create --reserve-memory=4GB --name=too-big nginx:alpine
Los administradores no planificarán un conjunto de contenedores en un solo nodo cuyas reservas combinadas superen la memoria disponible en ese nodo.
Una vez que una tarea está planificada y ejecutándose, --reserve-memory no impone un
límite de memoria. Utiliza --limit-memory para asegurar que una tarea no use más de una
cantidad determinada de memoria en un nodo. Este ejemplo limita la cantidad de memoria utilizada
por la tarea a 4 GB. La tarea se planificará incluso si cada uno de tus nodos tiene
solo 2 GB de memoria, porque --limit-memory es un límite superior.
$ docker service create --limit-memory=4GB --name=too-big nginx:alpine
El uso de --reserve-memory y --limit-memory no garantiza que Docker
no vaya a utilizar más memoria en tu host de la que deseas. Por ejemplo, podrías
crear muchos servicios, cuya suma de uso de memoria podría agotar la memoria disponible.
Puedes evitar que este escenario agote la memoria disponible teniendo en cuenta también
otro software (no contenedorizado) que se ejecuta en el host. Si
--reserve-memory es mayor o igual que --limit-memory, Docker no
planificará un servicio en un host que no tenga suficiente memoria. --limit-memory
limitará la memoria del servicio para mantenerse dentro de ese límite, por lo que si cada servicio
tiene una reserva y un límite de memoria configurados, los servicios de Docker tendrán menos probabilidades de
saturar el host. Otros contenedores que no son servicios o las aplicaciones que se ejecutan directamente
en el host de Docker aún podrían agotar la memoria.
Esta estrategia tiene un inconveniente. Reservar memoria también significa que podrías no estar haciendo un uso óptimo de la memoria disponible en el nodo. Considera un servicio que en circunstancias normales utiliza 100 MB de memoria, pero que dependiendo de la carga puede tener picos de hasta 500 MB. Reservar 500 MB para ese servicio (para garantizar que pueda disponer de 500 MB en esos picos) hace que se desperdicien 400 MB de memoria la mayor parte del tiempo.
En resumen, puedes adoptar un enfoque más conservador o más flexible:
Conservador: reservar 500 MB y limitar a 500 MB. Básicamente, ahora estás tratando los contenedores de servicio como máquinas virtuales, y podrías estar perdiendo una gran ventaja de los contenedores, que es una mayor densidad de servicios por host.
Flexible: limitar a 500 MB en la asunción de que si el servicio requiere más de 500 MB, está funcionando mal. Reserva una cantidad intermedia entre el requisito "normal" de 100 MB y el requisito de "pico" de 500 MB. Esto asume que cuando este servicio esté en su punto máximo, otros servicios o cargas de trabajo no contenedorizadas probablemente no lo estarán.
El enfoque que adoptes depende en gran medida de los patrones de uso de memoria de tus cargas de trabajo. Debes realizar pruebas en condiciones normales y de pico antes de decidirte por un enfoque.
On Linux, también puedes limitar la huella de memoria general de un servicio en un host determinado
a nivel del sistema operativo del host, utilizando cgroups u otras herramientas relevantes
del sistema operativo.
Especificar el número máximo de réplicas por nodo (--replicas-max-per-node)
Utiliza el flag --replicas-max-per-node para establecer el número máximo de tareas réplica que se pueden ejecutar en un nodo.
El siguiente comando crea un servicio nginx con 2 tareas réplica pero solo una tarea réplica por nodo.
Un ejemplo en el que esto puede ser útil es equilibrar las tareas en un conjunto de centros de datos junto con --placement-pref
y dejar que el ajuste --replicas-max-per-node se asegure de que las réplicas no se migren a otro centro de datos durante
las tareas de mantenimiento o ante un fallo en un centro de datos.
El siguiente ejemplo ilustra esto:
$ docker service create \
--name nginx \
--replicas 2 \
--replicas-max-per-node 1 \
--placement-pref 'spread=node.labels.datacenter' \
nginx
Conectar un servicio a una red existente (--network)
Puedes utilizar redes superpuestas (overlay networks) para conectar uno o más servicios dentro del swarm.
Primero, crea una red superpuesta en un nodo administrador utilizando el comando docker network create:
$ docker network create --driver overlay my-network
etjpu59cykrptrgw0z0hk5snf
Después de crear una red superpuesta en el modo swarm, todos los nodos administradores tienen acceso a la red.
Cuando creas un servicio y pasas el flag --network para conectar el servicio a
la red superpuesta:
$ docker service create \
--replicas 3 \
--network my-network \
--name my-web \
nginx
716thylsndqma81j6kkkb5aus
El swarm extiende my-network a cada nodo que ejecuta el servicio.
Los contenedores en la misma red pueden acceder entre sí mediante el descubrimiento de servicios.
La sintaxis en formato largo de --network permite especificar una lista de alias y opciones del controlador:
--network name=my-network,alias=web1,driver-opt=field1=value1
Publicar puertos de servicio externamente al swarm (-p, --publish)
Puedes publicar puertos de servicio para que estén disponibles externamente al swarm
utilizando el flag --publish. El flag --publish puede tomar dos estilos diferentes
de argumentos. La versión corta es posicional y te permite especificar el
puerto publicado y el puerto de destino separados por dos puntos (:).
$ docker service create --name my_web --replicas 3 --publish 8080:80 nginx
También existe un formato largo, que es más fácil de leer y te permite especificar más opciones. Se prefiere el formato largo. No puedes especificar el modo del servicio cuando utilizas el formato corto. A continuación se muestra un ejemplo del uso del formato largo para el mismo servicio que el anterior:
$ docker service create --name my_web --replicas 3 --publish published=8080,target=80 nginx
Las opciones que puedes especificar son:
| Opción | Sintaxis corta | Sintaxis larga | Descripción |
|---|---|---|---|
| puerto publicado y puerto de destino | --publish 8080:80 | --publish published=8080,target=80 | El puerto de destino dentro del contenedor y el puerto al que se asigna en los nodos, utilizando la malla de enrutamiento (ingress) o redes a nivel de host. Hay más opciones disponibles, más adelante en esta tabla. Se prefiere la sintaxis de clave-valor, porque se autodocumenta en cierta medida. |
| modo | No es posible establecer usando la sintaxis corta. | --publish published=8080,target=80,mode=host | El modo a utilizar para vincular el puerto, ya sea ingress o host. Por defecto es ingress para utilizar la malla de enrutamiento. |
| protocolo | --publish 8080:80/tcp | --publish published=8080,target=80,protocol=tcp | El protocolo a utilizar, tcp , udp o sctp. Por defecto es tcp. Para vincular un puerto para ambos protocolos, especifica el flag -p o --publish dos veces. |
Cuando publicas un puerto de servicio usando el modo ingress, la malla de enrutamiento de Swarm
hace que el servicio sea accesible en el puerto publicado en cada nodo, independientemente de si
hay una tarea para el servicio ejecutándose en ese nodo. Si utilizas el modo host,
el puerto solo se vincula en los nodos donde se ejecuta el servicio, y un puerto determinado
en un nodo solo se puede vincular una vez. Solo puedes establecer el modo de publicación utilizando
la sintaxis larga. Para obtener más información, consulta
Utilizar la malla de enrutamiento del modo swarm.
Proporcionar especificaciones de credenciales para cuentas de servicio administradas (--credentials-spec)
Esta opción solo se utiliza para servicios que emplean contenedores de Windows. La opción
--credential-spec debe tener el formato file://<nombre_archivo> o
registry://<nombre_valor>.
Cuando se utiliza el formato file://<nombre_archivo>, el archivo al que se hace referencia debe estar
presente en el subdirectorio CredentialSpecs del directorio de datos de docker,
que por defecto es C:\ProgramData\Docker\ en Windows. Por ejemplo,
especificar file://spec.json carga C:\ProgramData\Docker\CredentialSpecs\spec.json.
Cuando se utiliza el formato registry://<nombre_valor>, la especificación de credenciales se
lee desde el registro de Windows en el host del demonio. El valor de registro especificado
debe estar ubicado en:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\Containers\CredentialSpecs
Crear servicios utilizando plantillas
Puedes utilizar plantillas para algunos flags de service create, utilizando la sintaxis
proporcionada por el paquete text/template de Go.
Los flags compatibles son los siguientes:
--hostname--mount--env
Los marcadores de posición válidos para la plantilla Go son los siguientes:
| Marcador de posición | Descripción |
|---|---|
| .Service.ID | ID del servicio |
| .Service.Name | Nombre del servicio |
| .Service.Labels | Etiquetas del servicio |
| .Node.ID | ID del nodo |
| .Node.Hostname | Nombre de host del nodo |
| .Task.ID | ID de la tarea |
| .Task.Name | Nombre de la tarea |
| .Task.Slot | Ranura (slot) de la tarea |
Ejemplo de plantilla
En este ejemplo, vamos a configurar la plantilla de los contenedores creados basándonos en el nombre del servicio, el ID del nodo y el nombre de host donde se encuentra.
$ docker service create \
--name hosttempl \
--hostname="{{.Node.Hostname}}-{{.Node.ID}}-{{.Service.Name}}"\
busybox top
va8ew30grofhjoychbr6iot8c
$ docker service ps va8ew30grofhjoychbr6iot8c
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
wo41w8hg8qan hosttempl.1 busybox:latest@sha256:29f5d56d12684887bdfa50dcd29fc31eea4aaf4ad3bec43daf19026a7ce69912 2e7a8a9c4da2 Running Running about a minute ago
$ docker inspect --format="{{.Config.Hostname}}" 2e7a8a9c4da2-wo41w8hg8qanxwjwsg4kxpprj-hosttempl
x3ti0erg11rjpg64m75kej2mz-hosttempl
Especificar el modo de aislamiento en Windows (--isolation)
Por defecto, las tareas planificadas en nodos de Windows se ejecutan utilizando el modo de aislamiento predeterminado
configurado para ese nodo en particular. Para forzar un modo de aislamiento específico, puedes utilizar
el flag --isolation:
$ docker service create --name myservice --isolation=process microsoft/nanoserver
Los modos de aislamiento compatibles en Windows son:
default: utiliza los ajustes predeterminados especificados en el nodo que ejecuta la tareaprocess: utiliza aislamiento de proceso (solo Windows Server)hyperv: utiliza aislamiento de Hyper-V
Crear servicios solicitando recursos genéricos (--generic-resources)
Puedes limitar el tipo de nodos en los que puede terminar tu tarea utilizando el
flag --generic-resource (si los nodos anuncian estos recursos):
$ docker service create \
--name cuda \
--generic-resource "NVIDIA-GPU=2" \
--generic-resource "SSD=1" \
nvidia/cuda
Ejecutar como un trabajo (job)
Los trabajos (jobs) son un tipo especial de servicio diseñado para ejecutar una operación hasta su finalización y luego detenerse, a diferencia de los demonios de ejecución prolongada. Cuando una tarea (Task) que pertenece a un trabajo finaliza correctamente (valor de retorno 0), la tarea se marca como "Completada" (Completed) y no se vuelve a ejecutar.
Los trabajos se inician utilizando uno de los dos modos siguientes: replicated-job o global-job
$ docker service create --name myjob \
--mode replicated-job \
bash "true"
Este comando ejecutará una tarea que, utilizando la imagen bash, ejecutará el
comando true, el cual devolverá 0 y luego finalizará.
Aunque los trabajos son en última instancia un tipo de servicio diferente, presentan un par de advertencias en comparación con otros servicios:
- Ninguna de las opciones de configuración de actualización (update) o reversión (rollback) es válida. Los trabajos se pueden actualizar, pero no se pueden implementar ni revertir progresivamente, lo que hace que estas opciones de configuración sean irrelevantes.
- Los trabajos nunca se reinician al alcanzar el estado
Complete. Esto significa que, para los trabajos, establecer--restart-conditionenanyes lo mismo que establecerlo enon-failure.
Los trabajos están disponibles tanto en modo replicado como global.
Trabajos replicados (Replicated Jobs)
Un trabajo replicado es como un servicio replicado. Establecer el flag --replicas
especificará el número total de iteraciones de un trabajo a ejecutar.
Por defecto, todas las réplicas de un trabajo replicado se iniciarán a la vez. Para controlar
el número total de réplicas que se ejecutan simultáneamente en cualquier momento dado,
se puede utilizar el flag --max-concurrent:
$ docker service create \
--name mythrottledjob \
--mode replicated-job \
--replicas 10 \
--max-concurrent 2 \
bash "true"
El comando anterior ejecutará 10 tareas en total, pero solo 2 de ellas se ejecutarán en un momento dado.
Global Jobs
Los trabajos globales son como los servicios globales, en el sentido de que se ejecuta una tarea una vez en cada nodo
que cumpla con las restricciones de ubicación. Los trabajos globales están representados por el modo global-job.
Ten en cuenta que después de crear un trabajo global, cualquier nodo nuevo que se añada al clúster tendrá una tarea de ese trabajo iniciada en él. El trabajo global en su conjunto no tiene un estado de "finalizado", excepto en la medida en que cada nodo que cumple con las restricciones del trabajo tiene una tarea completada (Completed).