Conception d'une VUI - Interface utilisateur vocale
Conception De L'interface Utilisateur
Avec l'avènement d'outils comme Docker , Conteneurs Linux , et d'autres, il est devenu très facile d'isoler les processus Linux dans leurs propres petits environnements système. Cela permet d'exécuter toute une gamme d'applications sur une seule vraie machine Linux et de garantir qu'aucune d'entre elles ne puisse interférer l'une avec l'autre, sans avoir à recourir à des machines virtuelles. Ces outils ont été une énorme aubaine pour PaaS fournisseurs. Mais que se passe-t-il exactement sous le capot?
Ces outils reposent sur un certain nombre de fonctionnalités et de composants du noyau Linux. Certaines de ces fonctionnalités ont été introduites assez récemment, tandis que d'autres nécessitent encore de patcher le noyau lui-même. Mais l'un des composants clés, utilisant les espaces de noms Linux, est une fonctionnalité de Linux depuis la sortie de la version 2.6.24 en 2008.
Quiconque connaît chroot
a déjà une idée de base de ce que les espaces de noms Linux peuvent faire et comment utiliser l'espace de noms en général. Tout comme chroot
permet aux processus de voir n'importe quel répertoire arbitraire comme racine du système (indépendamment du reste des processus), les espaces de noms Linux permettent également à d'autres aspects du système d'exploitation d'être modifiés indépendamment. Cela comprend l'arborescence des processus, les interfaces réseau, les points de montage, les ressources de communication inter-processus, etc.
kubernetes est conçu pour fonctionner avec n'importe quel produit de conteneurisation
Dans un ordinateur mono-utilisateur, un environnement système unique peut convenir. Mais sur un serveur, où vous souhaitez exécuter plusieurs services, il est essentiel pour la sécurité et la stabilité que les services soient aussi isolés que possible les uns des autres. Imaginez un serveur exécutant plusieurs services, dont l'un est compromis par un intrus. Dans un tel cas, l'intrus peut être en mesure d'exploiter ce service et de se diriger vers les autres services, et peut même être en mesure de compromettre l'ensemble du serveur. L'isolation de l'espace de noms peut fournir un environnement sécurisé pour éliminer ce risque.
Par exemple, en utilisant l'espacement des noms, il est possible d'exécuter en toute sécurité des programmes arbitraires ou inconnus sur votre serveur. Récemment, il y a eu un nombre croissant de concours de programmation et de plates-formes de «hackathon», comme HackerRank , TopCoder , Codeforces , et beaucoup plus. Beaucoup d'entre eux utilisent des pipelines automatisés pour exécuter et valider les programmes soumis par les candidats. Il est souvent impossible de connaître à l’avance la véritable nature des programmes des candidats, et certains peuvent même contenir des éléments malveillants. En exécutant ces programmes avec un espace de nom complètement isolé du reste du système, le logiciel peut être testé et validé sans mettre en danger le reste de la machine. De même, les services d'intégration continue en ligne, tels que Drone.io , récupérez automatiquement votre référentiel de code et exécutez les scripts de test sur leurs propres serveurs. Encore une fois, l'isolation des espaces de noms est ce qui permet de fournir ces services en toute sécurité.
Les outils d'espacement de noms tels que Docker permettent également un meilleur contrôle de l'utilisation des ressources système par les processus, ce qui rend ces outils extrêmement populaires pour les fournisseurs de PaaS. Services comme Heroku et Google App Engine utilisez ces outils pour isoler et exécuter plusieurs applications de serveur Web sur le même matériel réel. Ces outils leur permettent d'exécuter chaque application (qui peut avoir été déployée par l'un des nombreux utilisateurs différents) sans se soucier que l'un d'entre eux utilise trop de ressources système, ou interfère et / ou entre en conflit avec d'autres services déployés sur la même machine. Avec une telle isolation de processus, il est même possible d'avoir des piles de logiciels de dépendance (et versions) entièrement différentes pour chaque environnement isolé!
Si vous avez utilisé des outils comme Docker, vous savez déjà que ces outils sont capables d'isoler les processus dans de petits «conteneurs». L'exécution de processus dans des conteneurs Docker revient à les exécuter dans des machines virtuelles, seuls ces conteneurs sont nettement plus légers que les machines virtuelles. Une machine virtuelle émule généralement une couche matérielle au-dessus de votre système d'exploitation, puis exécute un autre système d'exploitation en plus de cela. Cela vous permet d'exécuter des processus à l'intérieur d'une machine virtuelle, en totale isolation de votre système d'exploitation réel. Mais les machines virtuelles sont lourdes! Les conteneurs Docker, quant à eux, utilisent certaines fonctionnalités clés de votre système d'exploitation réel, y compris les espaces de noms, et garantissent un niveau d'isolation similaire, mais sans émuler le matériel et exécuter encore un autre système d'exploitation sur la même machine. Cela les rend très légers.
Historiquement, le noyau Linux a conservé une seule arborescence de processus. L'arborescence contient une référence à chaque processus en cours d'exécution dans une hiérarchie parent-enfant. Un processus, étant donné qu'il dispose de privilèges suffisants et remplit certaines conditions, peut inspecter un autre processus en y attachant un traceur ou peut même être capable de le tuer.
Avec l'introduction des espaces de noms Linux, il est devenu possible d'avoir plusieurs arborescences de processus «imbriquées». Chaque arborescence de processus peut avoir un ensemble de processus entièrement isolé. Cela peut garantir que les processus appartenant à une arborescence de processus ne peuvent pas inspecter ou tuer - en fait ne peuvent même pas connaître l'existence de - processus dans d'autres arborescences de processus frères ou parents.
Chaque fois qu'un ordinateur avec Linux démarre, il démarre avec un seul processus, avec l'identificateur de processus (PID) 1. Ce processus est la racine de l'arborescence des processus, et il lance le reste du système en effectuant les travaux de maintenance appropriés et en démarrant les démons / services appropriés. Tous les autres processus démarrent en dessous de ce processus dans l'arborescence. L'espace de noms PID permet de créer une nouvelle arborescence, avec son propre processus PID 1. Le processus qui fait cela reste dans l'espace de noms parent, dans l'arborescence d'origine, mais fait de l'enfant la racine de sa propre arborescence de processus.
Avec l’isolement de l’espace de noms PID, les processus de l’espace de noms enfant n’ont aucun moyen de connaître l’existence du processus parent. Cependant, les processus de l'espace de noms parent ont une vue complète des processus de l'espace de noms enfant, comme s'il s'agissait d'un autre processus de l'espace de noms parent.
portefeuille de concepteurs ux / ui
Il est possible de créer un ensemble imbriqué d'espaces de noms enfants: un processus démarre un processus enfant dans un nouvel espace de noms PID, et ce processus enfant engendre un autre processus dans un nouvel espace de noms PID, et ainsi de suite.
Avec l'introduction des espaces de noms PID, un même processus peut désormais être associé à plusieurs PID, un pour chaque espace de noms auquel il appartient. Dans le code source Linux, nous pouvons voir qu'une structure nommée pid
, qui servait à garder une trace d'un seul PID, suit désormais plusieurs PID grâce à l'utilisation d'une structure nommée upid
:
struct upid { int nr; // the PID value struct pid_namespace *ns; // namespace where this PID is relevant // ... }; struct pid { // ... int level; // number of upids struct upid numbers[0]; // array of upids };
Pour créer un nouvel espace de noms PID, il faut appeler le clone()
appel système avec un indicateur spécial CLONE_NEWPID
. (C fournit un wrapper pour exposer cet appel système, ainsi que de nombreux autres langages populaires.) Alors que les autres espaces de noms décrits ci-dessous peuvent également être créés à l'aide de unshare()
appel système, un espace de noms PID ne peut être créé qu'au moment où un nouveau processus est généré à l'aide de clone()
. Une fois clone()
est appelé avec cet indicateur, le nouveau processus démarre immédiatement dans un nouvel espace de noms PID, sous une nouvelle arborescence de processus. Cela peut être démontré avec un simple programme C:
#define _GNU_SOURCE #include #include #include #include #include static char child_stack[1048576]; static int child_fn() { printf('PID: %ld
', (long)getpid()); return 0; } int main() pid_t child_pid = clone(child_fn, child_stack+1048576, CLONE_NEWPID
Compilez et exécutez ce programme avec les privilèges root et vous remarquerez une sortie qui ressemble à ceci:
clone() = 5304 PID: 1
Le PID, tel qu'imprimé à partir de child_fn
, sera 1
.
Même si ce code du didacticiel d'espace de noms ci-dessus n'est pas beaucoup plus long que «Hello, world» dans certaines langues, beaucoup de choses se sont passées dans les coulisses. Le clone()
, comme vous vous en doutez, a créé un nouveau processus en clonant le processus actuel et a commencé l'exécution au début de child_fn()
fonction. Cependant, ce faisant, il a détaché le nouveau processus de l'arborescence de processus d'origine et créé une arborescence de processus distincte pour le nouveau processus.
Essayez de remplacer le static int child_fn()
fonction avec ce qui suit, pour imprimer le PID parent du point de vue du processus isolé:
static int child_fn() { printf('Parent PID: %ld
', (long)getppid()); return 0; }
L'exécution du programme cette fois donne le résultat suivant:
clone() = 11449 Parent PID: 0
Remarquez que le PID parent du point de vue du processus isolé est 0, indiquant l'absence de parent. Essayez à nouveau d'exécuter le même programme, mais cette fois, supprimez le CLONE_NEWPID
drapeau depuis le clone()
appel de fonction:
dans quelle langue est écrit Windows 10
pid_t child_pid = clone(child_fn, child_stack+1048576, SIGCHLD, NULL);
Cette fois, vous remarquerez que le PID parent n'est plus 0:
clone() = 11561 Parent PID: 11560
Cependant, ce n'est que la première étape de notre tutoriel. Ces processus ont toujours un accès illimité à d'autres ressources communes ou partagées. Par exemple, l'interface réseau: si le processus enfant créé ci-dessus devait écouter sur le port 80, cela empêcherait tous les autres processus du système de pouvoir l'écouter.
C'est là qu'un espace de noms réseau devient utile. Un espace de noms réseau permet à chacun de ces processus de voir un ensemble entièrement différent d'interfaces réseau. Même l'interface de bouclage est différente pour chaque espace de noms réseau.
Isoler un processus dans son propre espace de noms réseau implique l'introduction d'un autre indicateur dans le clone()
appel de fonction: CLONE_NEWNET
;
#define _GNU_SOURCE #include #include #include #include #include static char child_stack[1048576]; static int child_fn() { printf('New `net` Namespace:
'); system('ip link'); printf('
'); return 0; } int main() SIGCHLD, NULL); waitpid(child_pid, NULL, 0); return 0;
Production:
Original `net` Namespace: 1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: enp4s0: mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 00:24:8c:a1:ac:e7 brd ff:ff:ff:ff:ff:ff New `net` Namespace: 1: lo: mtu 65536 qdisc noop state DOWN mode DEFAULT group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
Que se passe t-il ici? Le périphérique Ethernet physique enp4s0
appartient à l'espace de noms du réseau global, comme indiqué par l'outil «ip» exécuté à partir de cet espace de noms. Cependant, l'interface physique n'est pas disponible dans le nouvel espace de noms réseau. De plus, le périphérique de bouclage est actif dans l'espace de noms réseau d'origine, mais est «en panne» dans l'espace de noms réseau enfant.
Afin de fournir une interface réseau utilisable dans l'espace de noms enfant, il est nécessaire de configurer des interfaces réseau «virtuelles» supplémentaires qui s'étendent sur plusieurs espaces de noms. Une fois cela fait, il est alors possible de créer des ponts Ethernet, et même d'acheminer des paquets entre les espaces de noms. Enfin, pour que tout fonctionne, un «processus de routage» doit être en cours d'exécution dans l'espace de noms du réseau global pour recevoir le trafic de l'interface physique et l'acheminer via les interfaces virtuelles appropriées vers les espaces de noms de réseau enfants appropriés. Peut-être pouvez-vous comprendre pourquoi des outils comme Docker, qui font tout ce travail pour vous, sont si populaires!
Pour ce faire manuellement, vous pouvez créer une paire de connexions Ethernet virtuelles entre un espace de noms parent et enfant en exécutant une seule commande à partir de l'espace de noms parent:
ip link add name veth0 type veth peer name veth1 netns
Ici, doit être remplacé par l'ID de processus du processus dans l'espace de noms enfant comme observé par le parent. L'exécution de cette commande établit une connexion en forme de tube entre ces deux espaces de noms. L'espace de noms parent conserve le veth0
périphérique, et passe le veth1
périphérique à l'espace de noms enfant. Tout ce qui entre à l'une des extrémités sort par l'autre extrémité, comme on peut s'y attendre d'une vraie connexion Ethernet entre deux vrais nœuds. En conséquence, les deux côtés de cette connexion Ethernet virtuelle doivent se voir attribuer des adresses IP.
Linux maintient également une structure de données pour tous les points de montage du système. Il comprend des informations telles que les partitions de disque montées, où elles sont montées, si elles sont en lecture seule, et cetera. Avec les espaces de noms Linux, on peut avoir cette structure de données clonée, de sorte que les processus sous différents espaces de noms puissent changer les points de montage sans s'influencer les uns les autres.
Meilleures pratiques de gestion des exceptions javascript
La création d'un espace de noms de montage séparé a un effet similaire à un chroot()
. chroot()
est bon, mais il ne fournit pas une isolation complète et ses effets sont limités au point de montage racine uniquement. La création d’un espace de noms de montage distinct permet à chacun de ces processus isolés d’avoir une vue complètement différente de la structure de point de montage du système entier par rapport à l’original. Cela vous permet d'avoir une racine différente pour chaque processus isolé, ainsi que d'autres points de montage spécifiques à ces processus. Utilisé avec soin par ce didacticiel, vous pouvez éviter d'exposer des informations sur le système sous-jacent.
Le clone()
L'indicateur requis pour y parvenir est CLONE_NEWNS
:
clone(child_fn, child_stack+1048576, CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWNS | SIGCHLD, NULL)
Au départ, le processus enfant voit exactement les mêmes points de montage que son processus parent. Cependant, étant sous un nouvel espace de noms de montage, le processus enfant peut monter ou démonter tous les points de terminaison qu'il souhaite, et la modification n'affectera ni l'espace de noms de son parent, ni aucun autre espace de noms de montage dans l'ensemble du système. Par exemple, si le processus parent a une partition de disque particulière montée à la racine, le processus isolé verra exactement la même partition de disque montée à la racine au début. Mais l'avantage d'isoler l'espace de noms de montage est évident lorsque le processus isolé tente de changer la partition racine en autre chose, car la modification n'affectera que l'espace de noms de montage isolé.
Fait intéressant, cela fait en fait une mauvaise idée de générer le processus enfant cible directement avec le CLONE_NEWNS
drapeau. Une meilleure approche consiste à démarrer un processus spécial «init» avec le CLONE_NEWNS
, demandez à ce processus «init» de modifier «/», «/ proc», «/ dev» ou d'autres points de montage comme vous le souhaitez, puis démarrez le processus cible. Ceci est discuté un peu plus en détail vers la fin de ce didacticiel sur l'espace de noms.
Il existe d'autres espaces de noms dans lesquels ces processus peuvent être isolés, à savoir utilisateur, IPC et UTS. L'espace de noms utilisateur permet à un processus d'avoir des privilèges root dans l'espace de noms, sans lui donner cet accès aux processus en dehors de l'espace de noms. L'isolement d'un processus par l'espace de noms IPC lui donne ses propres ressources de communication interprocessus, par exemple, les messages System V IPC et POSIX. L'espace de noms UTS isole deux identificateurs spécifiques du système: nodename
et domainname
.
Un exemple rapide pour montrer comment l'espace de noms UTS est isolé est illustré ci-dessous:
#define _GNU_SOURCE #include #include #include #include #include #include static char child_stack[1048576]; static void print_nodename() { struct utsname utsname; uname(&utsname); printf('%s
', utsname.nodename); } static int child_fn() { printf('New UTS namespace nodename: '); print_nodename(); printf('Changing nodename inside new UTS namespace
'); sethostname('GLaDOS', 6); printf('New UTS namespace nodename: '); print_nodename(); return 0; } int main() SIGCHLD, NULL); sleep(1); printf('Original UTS namespace nodename: '); print_nodename(); waitpid(child_pid, NULL, 0); return 0;
Ce programme produit la sortie suivante:
Original UTS namespace nodename: XT New UTS namespace nodename: XT Changing nodename inside new UTS namespace New UTS namespace nodename: GLaDOS Original UTS namespace nodename: XT
Ici, child_fn()
imprime le nodename
, le change en autre chose et l'imprime à nouveau. Naturellement, le changement se produit uniquement à l'intérieur du nouvel espace de noms UTS.
fonds immobilier de placement privé
Vous trouverez plus d'informations sur ce que tous les espaces de noms fournissent et isolent dans le didacticiel Ici
Il est souvent nécessaire d'établir une sorte de communication entre le parent et l'espace de noms enfant. Cela peut être pour effectuer un travail de configuration dans un environnement isolé ou simplement pour conserver la possibilité de jeter un coup d'œil sur l'état de cet environnement de l'extérieur. Une façon de faire est de maintenir un démon SSH en cours d'exécution dans cet environnement. Vous pouvez avoir un démon SSH distinct dans chaque espace de noms réseau. Cependant, l'exécution de plusieurs démons SSH utilise beaucoup de ressources précieuses comme la mémoire. C'est là que le fait d'avoir un processus spécial «init» s'avère à nouveau être une bonne idée.
Le processus «init» peut établir un canal de communication entre l'espace de noms parent et l'espace de noms enfant. Ce canal peut être basé sur des sockets UNIX ou peut même utiliser TCP. Pour créer un socket UNIX qui s'étend sur deux espaces de noms de montage différents, vous devez d'abord créer le processus enfant, puis créer le socket UNIX, puis isoler l'enfant dans un espace de noms de montage distinct. Mais comment pouvons-nous créer le processus en premier et l'isoler plus tard? Linux fournit unshare()
. Cet appel système spécial permet à un processus de s'isoler de l'espace de noms d'origine, au lieu de laisser le parent isoler l'enfant en premier lieu. Par exemple, le code suivant a exactement le même effet que le code mentionné précédemment dans la section d'espace de noms réseau:
#define _GNU_SOURCE #include #include #include #include #include static char child_stack[1048576]; static int child_fn() { // calling unshare() from inside the init process lets you create a new namespace after a new process has been spawned unshare(CLONE_NEWNET); printf('New `net` Namespace:
'); system('ip link'); printf('
'); return 0; } int main() SIGCHLD, NULL); waitpid(child_pid, NULL, 0); return 0;
Et puisque le processus «init» est quelque chose que vous avez conçu, vous pouvez lui faire faire tout le travail nécessaire en premier, puis s'isoler du reste du système avant d'exécuter l'enfant cible.
Ce didacticiel n'est qu'un aperçu de l'utilisation des espaces de noms sous Linux. Cela devrait vous donner une idée de base de la Développeur Linux pourrait commencer à mettre en œuvre l'isolation du système, partie intégrante de l'architecture d'outils tels que Docker ou conteneurs Linux. Dans la plupart des cas, il serait préférable d'utiliser simplement l'un de ces outils existants, déjà bien connus et testés. Mais dans certains cas, il peut être judicieux d'avoir votre propre mécanisme d'isolation de processus personnalisé, et dans ce cas, ce didacticiel sur l'espace de noms vous aidera énormément.
Il se passe beaucoup plus de choses sous le capot que ce que j'ai abordé dans cet article, et il existe d'autres moyens de limiter vos processus cibles pour plus de sécurité et d'isolement. Mais, espérons-le, cela peut servir de point de départ utile pour quelqu'un qui souhaite en savoir plus sur le fonctionnement réel de l'isolation des espaces de noms avec Linux.