RKT in action

Dans un précédent article, nous vous avions présenté les caractéristiques du container runtime RKT. Il est désormais temps de passer à la pratique.

Installation

Avant de pouvoir utiliser RKT, sur la plupart des systèmes d’exploitation, il est nécessaire de l’installer.
Plusieurs méthodes s’offrent à vous :

  • l’utilisation du gestionnaire de paquets pour la plupart des distributions Linux
  • l’utilisation de Container Linux OS pour lequel RKT est fourni à l’installation (et tout simplement parce que Container Linux OS c’est bien)

La version qui sera alors installée ne sera pas forcément la plus récente (la dernière version est la 1.25). Afin d’installer celle-ci, le plus simple est le téléchargement de l’archive disponible ici.
Les équipes de CoreOS fournissent un script permettant cette installation de manière sécurisée via une unité Systemd. Une version plus récente permettra d’utiliser de nouvelles fonctionnalités disponibles avec un support expérimental.
Une fois l’installation réalisée, partons à la découverte de cet outil.

Premiers pas

Téléchargement d’une image

Un container a besoin d’une image du système à lancer afin de s’exécuter. Comme nous l’avons vu dans notre précédent article, la signature ainsi que l’intégrité d’une image sont vérifiées lors du téléchargement. Nous pouvons prendre en exemple un service Redis :

# rkt fetch quay.io/quay/redis
pubkey: prefix: "quay.io/quay/redis"  
key: "https://quay.io/aci-signing-key"  
gpg key fingerprint is: BFF3 13CD AA56 0B16 A898  7B8F 72AB F5F6 799D 33BC  
    Quay.io ACI Converter (ACI conversion signing key) <support@quay.io>
Are you sure you want to trust this key (yes/no)?  
yes  
Trusting "https://quay.io/aci-signing-key" for prefix "quay.io/quay/redis" after fingerprint review.  
Added key for prefix "quay.io/quay/redis" at "/etc/rkt/trustedkeys/prefix.d/quay.io/quay/redis/bff313cdaa560b16a8987b8f72abf5f6799d33bc"  
Downloading signature: [=======================================] 473 B/473 B  
Downloading ACI: [=============================================] 115 MB/115 MB  
image: signature verified:  
  Quay.io ACI Converter (ACI conversion signing key) <support@quay.io>
sha512-5b31024cd779a03bb85de8fe4b470fec  

Le hash sha512 affiché à la fin du téléchargement correspond à l’ID de l’image.
Il est possible de lancer aussi des images Docker. Pour ce faire, nous allons nous baser sur une image de Luke Bond, qui nous sera utile dans les prochaines étapes. Ces images, qui ne proposent pas ce mécanisme de signatures, il faut dès lors passer une option afin d’ignorer ces vérifications :

# rkt fetch --insecure-options=image docker://lukebond/demo-api-redis
Downloading sha256:11b0f785601 [=============================]     547 B / 547 B  
Downloading sha256:de4b2408330 [=============================] 2.38 MB / 2.38 MB  
Downloading sha256:15559fbe3f4 [=============================]     125 B / 125 B  
Downloading sha256:675734e2e0d [=============================]     486 B / 486 B  
Downloading sha256:14547e35356 [=============================] 77.8 MB / 77.8 MB  
Downloading sha256:427713f7fc5 [=============================] 3.16 MB / 3.16 MB  
sha512-caeacc57d886370ccc98727bb7313f56  

Le téléchargement ainsi que les différentes vérifications peuvent aussi être effectués lors du lancement du container. Ce téléchargement, réalisé séparément, peut être utile si nous voulons inspecter le contenu de l’image avant de l’utiliser, modifier son contenu avant de construire une image qui correspond plus aux besoins par exemple.

Lancement d’un container

Nous avons donc désormais à notre disposition des images de container. C’est pas mal, mais un peu inutile pour le moment. Nous allons donc démarrer notre premier container de la façon suivante :

# rkt run quay.io/quay/redis
stage1: warning: no volume specified for mount point "volume-var-lib-redis", implicitly creating an "empty" volume. This volume will be removed when the pod is garbage-collected.  
stage1: warning: no volume specified for mount point "volume-var-lib-redis", implicitly creating an "empty" volume. This volume will be removed when the pod is garbage-collected.  

Les warnings sont ici pour nous indiquer qu’il est possible de fournir un volume pour stocker de manière persistante les données du serveur Redis ici lancé.
Afin de terminer un container, il faut utiliser la séquence CTRL+] (CTRL+$ sur un clavier azerty OSX) 3 fois de suite, ce qui donne en reprenant le container précédent :

stage1: warning: no volume specified for mount point "volume-var-lib-redis", implicitly creating an "empty" volume. This volume will be removed when the pod is garbage-collected.  
^]^]Container rkt-f655ee2e-7c24-4745-9aac-88b9f668cb2d terminated by signal KILL.

Et les logs ?

La question que doit se poser tout DevOps est l’accessibilité des logs, et ce afin d’être capable de débugger son application ou son image de container.
Avec RKT, une forte utilisation des mécanismes de systemd est réalisée.
Nous pouvons utiliser machinectl afin d’obtenir les UUID des containers lancés.

# machinectl
MACHINE                                                          CLASS     SERVICE  
rkt-f655ee2e-7c24-4745-9aac-88b9f668cb2d container rkt  

Il est aussi possible d’utiliser journalctl afin d’obtenir les logs des applicatifs en cours d’exécution.

journalctl -M rkt-f655ee2e-7c24-4745-9aac-88b9f668cb2d -t redis  
-- No entries --

Gestion des ressources

Nous sommes donc désormais capables d’effectuer un certain nombre d’actions avec RKT. Nous pouvons donc déployer des containers, mais comment le terminer, éliminer les ressources superflues, savoir ce qui tourne sur notre serveur ?
Pour toutes ces opérations, quelques commandes sont utiles.

Lister ses containers

Rien de plus simple pour ceci :

# rkt list
UUID        APP IMAGE NAME          STATE   CREATED     STARTED     NETWORKS  
f655ee2e    redis   quay.io/quay/redis:latest   exited  1 minute ago    1 minute ago  

L’ensemble des informations utiles y sont et il n’y a aucun besoin d’expliciter plus cela. Les informations réseaux ne sont plus disponibles, le container étant terminé.

Statut d’un container

Une commande permet de connaître rapidement le statut d’un container avec quelques informations supplémentaires.

# rkt status f655ee2e
state=exited  
created=2017-02-27 21:46:17 +0000 UTC  
started=2017-02-27 21:46:17 +0000 UTC  
pid=1899  
exited=true  

Faire un peu de ménage

Il est de temps en temps nécessaire de faire un peu de rangement parmi ces containers qui ne tournent plus. Pour cela, un garbage collector est disponible. Il est censé tourner de façon périodique et marche en 2 temps : dans un premier temps, le contenu du container sur le système de fichiers est déplacé et le container marqué comme étant dans le garbage collector. Ensuite, une période de grâce, de 30 minutes par défaut, permettant de récupérer des éléments qui aurait pu être oubliés, est active. Un second appel au garbage collector durant cette période n’aura aucun effet. A la fin de cette période, cet appel supprimera définitivement le container.
Cela peut donner (en changeant la période à 10s) :

# rkt gc --grace-period=10s
gc: moving pod "f655ee2e-7c24-4745-9aac-88b9f668cb2d" to garbage  
gc: pod "f655ee2e-7c24-4745-9aac-88b9f668cb2d" not removed: still within grace period (10s)  
# rkt gc --grace-period=10s
Garbage collecting pod "f655ee2e-7c24-4745-9aac-88b9f668cb2d"  

Bien évidemment, les mêmes commandes s’appliquent aux images, tel que rkt image list.

Utiliser le shell d’un container

Maintenant que notre container est lancé, il est possible que nous ayons besoin de rentrer dans celui-ci, afin de vérifier les processus qui tournent, modifier les fichiers de configuration des services du container. Afin de réaliser cette opération, il nous suffit d’utiliser l’UUID du container (nouvellement créé, le précédent ayant été supprimé) via la commande suivante :

# rkt enter 5d1e2e76
enter: no command specified, assuming "/bin/bash"  
groups: cannot find name for group ID 11  
root@rkt-5d1e2e76-b28e-4aa3-9a09-fe52e9ea4c3a:/# ps auxw  
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND  
root         1  0.0  0.5  49692  6076 ?        Ss   20:57   0:00 /usr/lib/systemd/systemd --default-standard-output=tty --log-target=null --show-status=0  
root         3  0.0  0.5  49572  6092 ?        Ss   20:57   0:00 /usr/lib/systemd/systemd-journald  
root         5  0.0  0.8  37004  8964 ?        Ssl  20:57   0:00 /usr/bin/redis-server *:6379  
root        31  0.0  0.3  18176  3304 ?        S    21:06   0:00 /bin/bash  
root        41  0.0  0.2  15576  2204 ?        R+   21:06   0:00 ps auxw  
root@rkt-7039ad45-a0db-4499-ad48-1eca6373ad2d:/#  

Opérations sur les images

Vous allez me dire : “Oui c’est bien gentil, on peut télécharger, vérifier et utiliser des images, mais c’est un peu léger tout ça”. Et vous n’avez pas tort. Il est en effet possible de réaliser quelques actions supplémentaires.

Obtenir des informations

Nous pouvons obtenir un certain nombre d’informations sur une image téléchargée. Cela se fait de la façon suivante :

# rkt image cat-manifest quay.io/quay/redis
{
    "acKind": "ImageManifest",
    "acVersion": "0.6.1",
    "name": "quay.io/quay/redis",
    "labels": [
        {
            "name": "version",
            "value": "latest"
        },
        {
            "name": "arch",
            "value": "amd64"
        },
        {
            "name": "os",
            "value": "linux"
        }
    ],
    "app": {
        "exec": [
            "/usr/bin/redis-server",
            "conf/redis.conf"
        ],
        "user": "root",
        "group": "root",
        "workingDirectory": "/",
        "environment": [
            {
                "name": "HOME",
                "value": "/root"
            },
            {
                "name": "PATH",
                "value": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            },
            {
                "name": "DEBIAN_FRONTEND",
                "value": "noninteractive"
            }
        ],
        "mountPoints": [
            {
                "name": "volume-var-lib-redis",
                "path": "/var/lib/redis"
            }
        ]
    }
}

Nous pouvons alors savoir quelle est l’application lancée par le container, sur les utilisateurs, ainsi que d’autres informations sur la construction de l’image ou définissant des options qui peuvent être ajoutées lors du lancement du container, tel que des points de montage.

Contenu d'une image

Nous avons téléchargé une image, obtenu quelques informations sur celle-ci mais que contient-elle réellement ? Encore une fois, tout est prévu. Il suffit de lancer la commande suivante et la magie opère (le répertoire de destination est créé à l’exécution) :

# rkt image extract quay.io/quay/redis /opt/redis-image
# ls /opt/redis-image/*
/opt/redis-image/manifest

/opt/redis-image/rootfs:
bin  boot  conf  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  

Nous retrouvons donc le système de fichiers du container ainsi que le manifest de l’image contenant les informations vues précédemment.

Construction d’images

Afin de construire des images, il faut utiliser acbuild. La définition d’une image peut être considérée comme l’équivalent d’un Dockerfile, c’est un fichier qui contient une suite d’appel à acbuild pour définir à la fois le contenu et les métadonnées de l’image. Un exemple est disponible ici

Et c’est comment le stockage et le réseau ?

Nous avons pour le moment découvert les quelques commandes qui nous permettent déjà de faire pas mal de choses avec RKT. On souhaiterait tout de même avoir du stockage persistant pour mettre les données de nos services ou bien encore exposer ceux-ci au monde.

Stockage

Comme nous l’avons vu lors du lancement de l’image Redis ainsi que dans le listing des attributs de l’image, des points de montage peuvent être associés à un container. Il existe 2 types de points de montage :

  • empty, qui est le cas par défaut et qui a été appliqué lors de nos précédents lancements de Redis. Le volume est créé localement dans le container et supprimé lorsque celui-ci passe à la poubelle.
  • host, qui utilise un dossier existant sur le système afin de stocker les données utilisables ou écrites par l’application. Lorsque le container est détruit, ces données sont toujours disponibles

Réseau

Par défaut, chaque container à une ip dans le range x.x.X.x/X. Les applicatifs qui tournent dans nos containers sont accessibles depuis l’hôte avec l’adresse ip privée du container. C’est assez sympa mais pouvoir rendre le service accessible à l’extérieur de notre hôte, c’est quand même mieux. Toujours dans les attributs de l’image, nous pouvons trouver ce genre d’informations :

"ports": [
    {
        "name": "http",
        "port": 80,
        "protocol": "tcp"
    }
]

Dès lors, en ajoutant --port=http: au lancement du container avec un port disponible sur l’hôte, que ce soit le 80 ou un autre, les connexions sur le port défini côté hôte seront transférées au port 80 du container.

Nous allons illustrer ces 2 points en utilisant l’image pour le système de blog Ghost. En effet, dans le manifest de l’image, nous pouvons constater l’utilisation d’un point de montage ainsi que l’exposition d’un port :

        "mountPoints": [
            {
                "name": "volume-var-lib-ghost",
                "path": "/var/lib/ghost"
            }
        ],
        "ports": [
            {
                "name": "2368-tcp",
                "protocol": "tcp",
                "port": 2368,
                "count": 1,
                "socketActivated": false
            }
        ]

De ce fait, une fois le dossier créé, le container peut être lancé de la façon suivante :

# mkdir /opt/ghost
# rkt --insecure-options=image --port=2368-tcp:2368 --volume volume-var-lib-ghost,kind=host,source=/opt/ghost run docker://ghost

Et nous obtenons alors un blog prêt à être configuré et accessible via l’ip publique de l’hôte sur le port 2368. Il aurait aussi été possible que le blog réponde sur le port 80 (via --port=2368-tcp:80) :

ghost alive

Lorsque nous quittons le container, les données du blog sont toujours présentes dans le dossier adéquat :

[ 7179.637791] ghost[5]: GET /favicon.ico 200 0.828 ms - -
[ 7225.932754] ghost[5]: GET / 200 115.729 ms - 4546
^]^]Container rkt-08cb2a23-6093-4b2c-99ff-dee301738e6c terminated by signal KILL.
# ls /opt/ghost/
apps  config.js  data  images  themes  

Aller plus loin

Nous avons ici découvert une utilisation basique de RKT. Il est bien évidemment possible de faire plus de choses avec.

API

Une api gRPC est disponible en version expérimentale afin de communiquer avec RKT. Elle se lance de la façon suivante :

# rkt api-service
api-service: API service starting...  
api-service: Listening on localhost:15441  
api-service: API service running  

Pour l’utiliser, un exemple en Go est fourni.

Activation de fonctionnalités expérimentales

Certaines fonctionnalités de RKT ne sont disponibles qu’en version expérimentale, le temps que celles-ci soient testées en conditions réelles et leur code corrigé des quelques bugs pouvant exister.
Pour utiliser, il suffit d’exporter la variable d’environnement RKTEXPERIMENTAPP, soit globalement, soit à l’utilisation du binaire RKT :

# export RKT_EXPERIMENT_APP=1
# RKT_EXPERIMENT_APP=1 rkt ...

Parmi les fonctionnalités expérimentales au moment de la rédaction de ce billet, on trouve :
la commande app qui permet d’attacher, supprimer, démarrer ou encore arrêter une application dans un container, ainsi que de démarrer un container en mode sandbox, de façon à construire/tester le container applicatif.
les commandes attach/detach avec lesquelles vous pouvez récupérer stdin/stdout/stderr de votre container. Cela n’est fonctionnel que sous certaines conditions

Ressources additionnelles

Je ne peux que vous conseiller de suivre le blog ainsi que le twitter de CoreOS, où de nombreuses informations sont disponibles. Bien évidemment, la documentation est hautement fournie. De nombreux webinaires sont donnés par les équipes de CoreOS sur BrightTalk.

Conclusion

J’espère que cette introduction vous a donné envie d’utiliser RKT. Maintenant lancez-vous, fouillez la documentation (de nombreuses options sont disponibles), mixez cela dans du Kubernetes et faites vous votre avis sur RKT.