Référence Spécification de service¶
La spécification Snowpark Container Services se trouve dans YAML (https://yaml.org/spec/). Elle donne à Snowflake les informations nécessaires pour configurer et exécuter votre service ou votre tâche.
La syntaxe générale est la suivante :
spec:
containers: # container list
- name: <name>
image: <image-name>
command: # optional list of strings
- <cmd>
- <arg1>
args: # optional list of strings
- <arg2>
- <arg3>
- ...
env: # optional
<key>: <value>
<key>: <value>
...
readinessProbe: # optional
port: <TCP port-num>
path: <http-path>
volumeMounts: # optional list
- name: <volume-name>
mountPath: <mount-path>
- name: <volume-name>
...
resources: # optional
requests:
memory: <memory-reserved>
nvidia.com/gpu: <count>
cpu: <cpu-units>
limits:
memory: <memory-reserved>
nvidia.com/gpu: <count>
cpu: <cpu-units>
secrets: # optional list
- snowflakeSecret:
secretKeyRef:
envVarName: # specify this or directoryPath
directoryPath: # specify this or envVarName
endpoints: # optional endpoint list
- name: <name>
port: <TCP port-num>
public: <true / false>
protocol : < TCP / HTTP / HTTPS >
- name: <name>
...
volumes: # optional volume list
- name: <name>
source: local | @<stagename> | memory
size: <amount-of-memory> # specify if memory is the volume source
- name: <name>
source: local | @<stagename> | memory
size: <amount-of-memory> # specify if memory is the volume source
...
logExporters:
eventTableConfig:
logLevel: <INFO | ERROR | NONE>
Lignes directrices générales¶
Une spécification de service/tâche comporte ces champs spec
de premier niveau :
spec.containers
(obligatoire) : une liste d’un ou plusieurs conteneurs d’application. Votre application conteneurisée doit avoir au moins un conteneur.spec.endpoints
(facultatif) : une liste de points de terminaison que le service expose. Vous pouvez choisir un point de terminaison public, permettant l’accès au service par le réseau.spec.volumes
(facultatif) : une liste de volumes de stockage à utiliser par les conteneurs.spec.logExporters
(facultatif) : ce champ permet de gérer le niveau des journaux de conteneurs exportés vers la table d’événements de votre compte.
Les règles de format suivantes s’appliquent aux champs name
(noms de conteneurs, de points de terminaison et de volumes) :
Peut contenir jusqu’à 63 caractères
Peut contenir une séquence de caractères alphanumériques minuscules ou « - ».
Doit commencer par un caractère alphabétique
Doit se terminer par un caractère alphanumérique
Attention
Les clients doivent s’assurer qu’aucune donnée personnelle (autre que pour un objet utilisateur), donnée sensible, donnée à exportation contrôlée ou autre donnée réglementée n’est saisie comme métadonnée dans le fichier de spécification. Pour plus d’informations, voir Champs de métadonnées dans Snowflake.
Les sections suivantes expliquent chacun des champs spec
de premier niveau.
Champ spec.containers
(obligatoire)¶
Le champ containers
est une liste de conteneurs OCI dans votre application. Pour chaque conteneur, seuls name
et image
sont des champs obligatoires. Le champ image
fait référence au nom de l’image que vous avez chargée dans un référentiel d’images Snowflake dans votre compte Snowflake. Par exemple :
spec:
containers:
- name: echo
image: /tutorial_db/data_schema/tutorial_repository/echo_service:dev
Lorsque vous créez un service (ou une tâche), Snowflake exécute ces conteneurs sur un seul nœud dans le pool de calcul spécifié, en partageant la même interface réseau. Vous pouvez exécuter plusieurs instances de service ; dans ce cas, chaque ensemble de ces conteneurs en cours d’exécution est appelé Instance de service.
Note
Actuellement, Snowpark Container Services nécessite des images de plateforme linux/amd64.
Les sections suivantes expliquent les types de champs containers
.
Champs containers.command
et containers.args
.¶
Utilisez ces champs facultatifs pour remplacer le point d’entrée du conteneur (la commande que le conteneur exécute avec tous les paramètres) défini dans le Dockerfile
(partie de votre image d’application) sans avoir à recréer votre image d’application :
containers.command
remplace leENTRYPOINT
Dockerfile
. Cela vous permet d’exécuter un exécutable différent dans le conteneur.containers.args
remplace leCMD
Dockerfile
. Cela vous permet de fournir différents arguments à la commande (l’exécutable).
Exemple
Votre Dockerfile
comprend le code suivant :
ENTRYPOINT ["python3", "main.py"]
CMD ["Bob"]
Ces entrées Dockerfile
exécutent la commande python3
et transmettent deux arguments : main.py
et Bob
. Vous pouvez remplacer ces valeurs dans le fichier de spécification de la manière suivante :
Pour remplacer le ENTRYPOINT, ajoutez le champ
containers.command
dans le fichier de spécification :spec: containers: - name: echo image: <image_name> command: - python3.9 - main.py
Pour remplacer l’argument « Bob », ajoutez le champ
containers.args
dans le fichier de spécification :spec: containers: - name: echo image: <image_name> args: - Alice
champ containers.env
¶
Utilisez le champ containers.env
pour spécifier les variables d’environnement qui sont transmises à tous les processus de votre conteneur :
spec:
containers:
- name: <name>
image: <image_name>
env:
ENV_VARIABLE_1: <value1>
ENV_VARIABLE_2: <value2>
…
…
Exemple
Dans le tutoriel 1, le code de l’application (echo_service.py
) lit les variables d’environnement avec les valeurs par défaut, si la valeur n’est pas explicitement définie.
CHARACTER_NAME = os.getenv('CHARACTER_NAME', 'I')
SERVER_PORT = os.getenv('SERVER_PORT', 8080)
CHARACTER_NAME
: lorsque le service echo reçoit une requête HTTP POST avec une chaîne (par exemple, « Hello »), le service renvoie « I said Hello ». Vous pouvez remplacer cette valeur par défaut dans le fichier de spécification. Par exemple, définissez la valeur « Bob » ; le service echo renvoie une réponse « Bob said Hello ».SERVER_PORT
: dans cette configuration par défaut, le service echo écoute sur le port 8080. Vous pouvez remplacer la valeur par défaut et spécifier un autre port.
Le fichier de spécification suivant remplace ces deux valeurs de variables d’environnement :
spec:
containers:
- name: echo
image: <image_name>
env:
CHARACTER_NAME: Bob
SERVER_PORT: 8085
endpoints:
- name: echo-endpoint
port: 8085
Notez que, parce que vous avez modifié le numéro de port sur lequel votre service écoute, la spécification a également mis à jour le point de terminaison (valeur du champ endpoints.port
).
champ containers.readinessProbe
¶
Utilisez l’objet containers.readinessProbe
pour donner à Snowflake une probe readiness dans votre application. Snowflake appelle cette sonde pour déterminer quand votre application est prête à servir des requêtes.
Snowflake envoie une requête HTTP GET à la probe readiness spécifiée, au port et au chemin spécifiés, et attend que votre service renvoie un statut HTTP 200 OK pour s’assurer que seuls les conteneurs sains servent le trafic.
Utilisez les champs suivants pour fournir les informations requises :
port
: le port réseau sur lequel le service écoute les probe readiness de disponibilité. Il n’est pas nécessaire de déclarer ce port comme point de terminaison.path
: Snowflake envoie des requêtes HTTP GET au service avec ce chemin.
Exemple
Dans le tutoriel 1, le code d’application (echo_python.py
) met en œuvre la probe readiness :
@app.get("/healthcheck")
def readiness_probe():
En conséquence, le fichier de spécification comprend le champ containers.readinessProbe
:
spec:
containers:
- name: echo
image: <image_name>
env:
SERVER_PORT: 8088
CHARACTER_NAME: Bob
readinessProbe:
port: 8088
path: /healthcheck
endpoints:
- name: echo-endpoint
port: 8088
Le port spécifié par la probe readiness ne doit pas nécessairement être un point de terminaison configuré. Votre service pourrait écouter sur un port différent uniquement pour la probe readiness.
champ containers.volumeMounts
¶
Les champs spec.volumes
et spec.containers.volumeMounts
fonctionnant ensemble, ils sont expliqués dans une même section. Pour plus d’informations, voir Champ spec.volumes (facultatif).
champ containers.resources
¶
Snowflake détermine comment utiliser les ressources de pools de calcul disponibles pour exécuter votre application. Il est recommandé d’indiquer explicitement les besoins en ressources de vos instances de service et de définir les limites appropriées dans la spécification. Notez que les ressources que vous spécifiez sont limitées par la famille d’instances des nœuds de votre pool de calcul. Pour plus d’informations, voir CREATE COMPUTE POOL.
Snowflake s’assure que les ressources spécifiées par containers.resources.requests
sont fournies et empêche également le service d’utiliser plus que les containers.resources.limits
indiquées. Vous pouvez spécifier des requêtes et des limites pour les ressources suivantes :
memory
: il s’agit de la mémoire requise pour votre conteneur d’application. Vous pouvez utiliser des unités décimales ou binaires pour exprimer les valeurs. Par exemple, 2G représente une requête de 2 000 000 000 octets. Pour plus d’informations, voir À propos des unités.cpu
: il s’agit d’unités de noyaux virtuels (vCPU). Par exemple, l’unité CPU 1 est équivalente à 1 vCPU. Les requêtes fractionnaires sont autorisées, telles que 0,5, qui peut également être exprimé sous la forme 500m. Pour plus d’informations, voir À propos des unités.nvidia.com/gpu
: si des GPUs sont nécessaires, ils doivent être demandés, et il doit également y avoir unelimit
spécifiée pour la même quantité. Si votre conteneur ne spécifie pas de requêtes et de limites pour la capacité GPU, il ne peut accéder à aucun GPUs. Le nombre de GPUs que vous pouvez demander est limité par le nombre maximum de GPUs pris en charge par leINSTANCE_TYPE
que vous choisissez lors de la création d’un pool de calcul. Pour plus d’informations, voir CREATE COMPUTE POOL.
Si Snowflake ne peut pas allouer les ressources incluses explicitement dans le fichier de spécification, vous pouvez créer les services (en utilisant CREATE SERVICE), mais le statut du service indiquera que le service ne peut pas être planifié en raison de ressources insuffisantes.
Exemple 1
Dans la spécification suivante, le champ containers.resources
décrit les exigences en matière de ressources pour le conteneur :
spec:
containers:
- name: resource-test-gpu
image: ...
resources:
requests:
memory: 2G
cpu: 0.5
nvidia.com/gpu: 1
limits:
memory: 4G
nvidia.com/gpu: 1
Dans cet exemple, il est demandé à Snowflake d’allouer au moins 2 GB de mémoire, un GPU et un demi-cœur de CPU pour le conteneur. En même temps, le conteneur n’est pas autorisé à utiliser plus de 4 GB de mémoire et un GPU.
Exemple 2
Vous créez un pool de calcul composé de deux nœuds ; chaque nœud dispose de 16 GB de mémoire et d’un GPU :
CREATE COMPUTE POOL tutorial_compute_pool MIN_NODES = 2 MAX_NODES = 2 INSTANCE_FAMILY = gpu_nv_s
Vous créez un service qui demande à Snowflake d’exécuter deux instances du service :
CREATE SERVICE echo_service MIN_INSTANCES=2 MAX_INSTANCES=2 IN COMPUTE POOL tutorial_compute_pool FROM @<stage_path> SPEC=<spec-file-stage-path>;
MIN_INSTANCES
etMAX_INSTANCES
sont tous deux définis sur 2. Par conséquent, Snowflake exécutera deux instances du service.
Si vous n’incluez pas explicitement les besoins en ressources dans la spécification de votre application, Snowflake décide d’exécuter ces instances sur le même nœud ou sur différents nœuds du pool de calcul.
Vous indiquez les besoins en ressources et demandez 10 GB de mémoire pour le conteneur :
- name: resource-test image: ... resources: requests: memory: 10G
Votre nœud de pool de calcul a 16 GB de mémoire, et Snowflake ne peut pas exécuter deux conteneurs sur le même nœud. Snowflake exécutera les deux instances de service sur des nœuds distincts dans le pool de calcul.
Demander 1 GB de mémoire et un GPU pour le conteneur :
spec: containers: - name: resource-test-gpu image: ... resources: requests: memory: 2G nvidia.com/gpu: 1 limits: nvidia.com/gpu: 1
Vous demandez un GPU par conteneur, et chaque nœud n’a qu’un GPU. Dans ce cas, bien que la mémoire ne soit pas un problème, Snowflake ne peut pas planifier les deux services sur un seul nœud. Cette exigence oblige Snowflake à exécuter les deux instances de service sur deux nœuds de pool de calcul distincts.
champ containers.secrets
¶
secrets: # optional list
- snowflakeSecret:
secretKeyRef:
envVarName: # specify this or directoryPath
directoryPath: # specify this or envVarName
Utilisez containers.secrets
pour donner des objets secrets à Snowflake que le conteneur peut utiliser pour s’authentifier lorsqu’un service ou une tâche communique avec des points de terminaison externes (en dehors de Snowflake). Pour plus d’informations, voir Utilisation des secrets Snowflake pour transmettre des identifiants de connexion à un conteneur.
snowflakeSecret
(obligatoire) : un nom d’objet Snowflake secret.secretKeyRef
: nom de la clé dans le secret. Lorsque ce champ est renseigné, Snowflake transmet la valeur associée à cette clé au conteneur. Requis pour les secrets d’authentification de base montés en tant que variables d’environnement. Vous ne spécifiez ce champ que lorsque vous transmettez des secrets à des variables d’environnement dans des conteneurs.envVarName
: nom de la variable d’environnement qui contient le secret. Ce champ ou le champdirectoryPath
est obligatoire.directoryPath
: le chemin du répertoire dans le conteneur où vous voulez copier les secrets. Snowflake remplit un fichier pour chaque clé secrète dans le répertoire spécifié. Lorsque vous spécifiezdirectoryPath
, ne spécifiez passecretKeyRef
. Ce champ ou le champenvVarName
est obligatoire.
Pour plus d’informations, voir Transmission de secrets Snowflake à un conteneur.
Champ spec.endpoints
(facultatif)¶
Utilisez le champ spec.endpoints
pour spécifier une liste de noms pour les ports réseau TCP que votre application expose. Snowpark Container Services peut exposer zéro à de nombreux points de terminaison. Utilisez les champs suivants pour décrire un point de terminaison :
name
: nom unique du point de terminaison. Lorsque vous faites référence au point de terminaison dans une fonction de service, vous spécifiez ce nom.port
: le port réseau sur lequel votre application écoute.protocol
: protocole pris en charge par le point de terminaison. Les valeurs prises en charge sont TCP, HTTP et HTTPS. Par défaut, le protocole est HTTP. Le protocole doit être HTTP ou HTTPS lorsque ce point de terminaison est public ou la cible d’une fonction de service (voir Utilisation d’un service).public
: si vous souhaitez que ce point de terminaison soit accessible depuis Internet, définissez ce champ surtrue
.
Note
Snowflake effectue des contrôles d’authentification et d’autorisation pour l’accès public qui permettent uniquement aux utilisateurs de Snowflake qui ont la permission d’utiliser le service.
Exemple
Voici la spécification de l’application utilisée dans le tutoriel 1 :
spec:
container:
- name: echo
image: <image-name>
env:
SERVER_PORT: 8000
CHARACTER_NAME: Bob
readinessProbe:
port: 8000
path: /healthcheck
endpoint:
- name: echoendpoint
port: 8000
public: true
Ce conteneur d’application expose un point de terminaison. Il comprend également le champ facultatif public
pour permettre l’accès au point de terminaison depuis l’extérieur de Snowflake (accès Internet). Par défaut, public
est false
.
Champ spec.volumes
(facultatif)¶
Cette section explique les champs spec.volumes
et spec.containers.volumeMounts
. volumes
définit un système de fichiers partagé. Un volumeMount
définit l’endroit où un volume apparaît dans un conteneur. Plusieurs conteneurs peuvent partager le même volume. Par conséquent, volumes
est un champ de niveau spec
, et volumeMount
fait partie d’une spécification de conteneur.
Utilisez ces champs pour décrire les volumes et les montages de volumes.
Utilisez
spec.volumes
pour spécifier les volumes disponibles pour vos conteneurs.volumes
est une liste. En d’autres termes, il peut y avoir plusieurs volumes. Utilisez les champs suivants pour décrire un volume :name
: nom unique du volume. Il est désigné parspec.containers.volumeMounts.name
.source
: il peut s’agir delocal
,memory
ou"@<stagename>"
.uid
: pour un volume de zone de préparation Snowflake, il s’agit de l’uid du fichier monté.gid
: pour un volume de zone de préparation Snowflake, il s’agit du gid du fichier monté.size
: pour un volume de mémoire, il s’agit de la taille du volume.
Utilisez
spec.containers.volumeMounts
pour indiquer où les volumes spécifiés sont montés dans le système de fichiers du conteneur.containers.volumeMounts
est également une liste. En d’autres termes, chaque conteneur peut avoir plusieurs montages de volumes. Utilisez les champs suivants pour décrire un montage de volume :name
: nom du volume à monter. Un même conteneur peut faire plusieurs fois référence au même volume.mountPath
: le chemin d’accès au fichier où le volume du conteneur doit être monté.
Snowflake prend en charge les types de volumes suivants pour les conteneurs d’application : volumes locaux, mémoire et zone de préparation Snowflake.
Volume local : les conteneurs d’une instance de service peuvent utiliser un disque local pour partager des fichiers. Par exemple, si votre application comporte deux conteneurs, un conteneur d’application et un analyseur de journaux, l’application peut écrire des journaux sur le volume local et l’analyseur de journaux peut lire les journaux.
Notez que, si vous exécutez plusieurs instances d’un service, seuls les conteneurs appartenant à une instance de service peuvent partager des volumes. Les conteneurs qui appartiennent à des instances de service différentes ne partagent pas de volumes.
Mémoire : vous pouvez utiliser un système de fichiers RAM pour les conteneurs.
Zone de préparation Snowflake : vous pouvez créer une zone de préparation Snowflake et donner aux conteneurs un accès pratique aux fichiers en zone de préparation. Les conditions suivantes s’appliquent lorsque vous montez une zone de préparation Snowflake :
Les zones de préparation externes ne sont pas prises en charge. Seuls les zones de préparation internes Snowflake avec un chiffrement SSE (voir Paramètres de zones de préparation internes) sont prises en charge. Utilisez CREATE STAGE pour créer une telle zone de préparation :
CREATE STAGE my_stage ENCRYPTION = (type = 'SNOWFLAKE_SSE');
Vous pouvez monter une zone de préparation ou un sous-répertoire, par exemple
@my_stage
,@my_stage/folder
, dans une zone de préparation. Vous ne pouvez pas monter un fichier, par exemple@my_stage/folder/file
, dans une zone de préparation.Le rôle de service détermine les permissions accordées aux conteneurs pour accéder à une zone de préparation montée. Le rôle de service est le rôle utilisé pour créer le service/la tâche. C’est également le rôle que le service/la tâche utilise pour toutes les interactions avec Snowflake.
Par exemple, si le rôle de service n’a pas le privilège WRITE sur une zone de préparation, le montage de cette zone de préparation sera en lecture seule. En d’autres termes, les conteneurs ne peuvent lire que les fichiers de la zone de préparation. Si le rôle de service dispose du privilège WRITE sur une zone de préparation, le montage de cette zone de préparation prendra en charge la lecture et l’écriture. Snowflake télécharge les mises à jour de fichiers de manière asynchrone.
Un conteneur qui monte une zone de préparation Snowflake s’exécute généralement en tant qu’utilisateur root. Cependant, il peut arriver que votre conteneur s’exécute en tant qu’utilisateur non root. Par exemple :
Si votre application utilise une bibliothèque tierce, celle-ci utilise un utilisateur non root pour exécuter le code de l’application à l’intérieur du conteneur.
Pour d’autres raisons, telles que la sécurité, vous pouvez exécuter votre application en tant qu’utilisateur non root à l’intérieur du conteneur.
Afin d’éviter les erreurs potentielles liées aux autorisations des utilisateurs de fichiers, il est important de définir les UID (Utilisateur ID) et GID (Groupe ID) du conteneur dans le cadre de la spécification. Ceci est particulièrement important pour les conteneurs qui utilisent un utilisateur et un groupe spécifiques pour lancer ou exécuter l’application dans le conteneur. En définissant les paramètres UID et GID appropriés, vous pouvez utiliser un conteneur fonctionnant en tant qu’utilisateur non root. Par exemple :
spec: ... volumes: - name: stagemount source: "@test" uid: <UID-value> gid: <GID-value>
Snowflake utilise ces informations pour monter la zone de préparation avec les permissions appropriées.
Obtenir les UID et GID du conteneur :
Exécutez le conteneur localement en utilisant
docker run
.Recherchez l’ID du conteneur à l’aide de la commande
docker container list
. Exemple de sortie partielle :CONTAINER ID IMAGE COMMAND —---------------------------------------------------------- a6a1f1fe204d tutorial-image "/usr/local/bin/entr…"
Exécutez la commande
docker id
à l’intérieur du conteneur pour obtenir les UID et GID :docker exec -it <container-id> id
Exemple de sortie :
uid=0(root) gid=0(root) groups=0(root)
Exemple
Votre application de machine learning comprend les deux conteneurs suivants :
Un conteneur
app
pour l’application principaleUn conteneur
logger-agent
qui collecte les journaux et les charge sur Amazon S3
Ces conteneurs utilisent les deux volumes suivants :
Volume
local
: cette application écrit les journaux que l’agent de journalisation lit.Zone de préparation Snowflake,
@model_stage
: l’application principale lit les fichiers de cette zone de préparation.
Dans l’exemple de spécification suivant, le conteneur app
monte les volumes logs
et models
, et le conteneur logging-agent
ne monte que le volume logs
:
spec: containers: - name: app image: <image1-name> volumeMounts: - name: logs mountPath: /opt/app/logs - name: models mountPath: /opt/models - name: logging-agent image: <image2-name> volumeMounts: - name: logs mountPath: /opt/logs volumes: - name: logs source: local - name: models source: "@model_stage"
Si plusieurs instances du service sont en cours d’exécution, les conteneurs logging-agent
et app
d’une instance de service partagent le volume logs
. Le volume logs
n’est pas partagé entre les instances de service.
Si, en plus de ces volumes, votre conteneur app
utilise également un volume de mémoire à 2 GB, vérifiez la spécification pour inclure le volume dans la liste volumes
et ajoutez également un autre montage de volume dans la liste volumeMounts
des conteneurs app
:
spec: containers: - name: app image: <image1-name> volumeMounts: - name: logs mountPath: /opt/app/logs - name: models mountPath: /opt/models - name: my-mem-volume mountPath: /dev/shm - name: logging-agent image: <image2-name> volumeMounts: - name: logs mountPath: /opt/logs volumes: - name: logs source: local - name: models source: "@model_stage" - name: "my-mem-volume" source: memory size: 2G
Notez que lorsque vous spécifiez memory
comme étant la source
du volume, vous devez également spécifier le champ volumes.size
pour indiquer la taille de la mémoire. Pour plus d’informations sur les unités de taille de mémoire que vous pouvez spécifier, voir À propos des unités.
Champ spec.logExporters
(facultatif)¶
Utilisez spec.logExporters
pour configurer la façon dont Snowflake collecte vos journaux d’application. Snowflake collecte la sortie de votre code dans votre conteneur d’application vers la sortie standard ou l’erreur standard.
Snowflake exporte ces journaux vers une table d’événements dans votre compte. Pour plus d’informations, voir Accès aux journaux des conteneurs locaux. Utilisez les spec.logExporters.eventTableConfig
pour indiquer les journaux que vous souhaitez enregistrer dans la table d’événements :
logExporters:
eventTableConfig:
logLevel: < INFO | ERROR | NONE >
Les valeurs logLevel
prises en charge sont les suivantes :
INFO
: exporter tous les journaux des utilisateurs.ERROR
: exporter uniquement les journaux d’erreurs. Snowflake n’exporte que les journaux du flux stderr.NONE
(par défaut) : ne pas exporter les journaux dans la table d’événements.
À propos des unités¶
Une spécification de service prend des valeurs numériques à plusieurs endroits. Snowpark Container Services prend en charge une variété d’unités pour exprimer ces valeurs. Pour les grandes et les petites valeurs, vous pouvez utiliser les unités binaires et décimales comme indiqué. Dans la liste suivante, « # » représente une valeur entière.
Unités binaires :
numberKi
signifienumber*1024
. Par exemple,memory: 4Ki
est équivalent àmemory: 4096
.numberMi
signifienumber*1024^2
.numberGi
signifienumber*1024^3
.
Unités décimales :
numberk
signifienumber*10^3
. Par exemple,memory: 4k
est équivalent àmemory: 4000
.numberM
signifienumber*10^6
.numberG
signifienumber*10^9
Unités fractionnaires :
numberm
signifienumber*0.001
. Par exemple,cpu: 500m
est équivalent àcpu: 0.5
.