Les tablettes c'est de la merde, ce sont des gadgets complètement fermés impossibles à bidouiller, le fabriquant n'assure jamais les mises à jour, c'est jetable, et d'ailleurs les gens l'ont compris puisque le marché se casse la figure. Il suffit d'aller sur des sites d'actualité Android pour voir qu'on y parle surtout de smartphones et que les comparatifs de tablette remontent à 2016. Néanmoins c'est bien pratique pour voyager, c'est ultra fin et surtout très léger. Si cela me permet d'économiser 3kg sur le dos alors je veux bien essayer.
J'ai sauté sur la Fire HD 8, 125€ en version 16GB avec l'espoir qu'elle soit maintenue à jour vu que c'est quand même Amazon derrière. Alors oui de base on a un Android modifié sans les logiciels Google (donc pas de Play store) mais il est possible de les installer. Notez que sur la fiche Amazon on a le choix entre "Avec offres spéciales" et "Sans offres spéciales" (+25€). Dans le genre bulshit marketing on est à niveau élevé puisqu'il s'agit ni plus ni moins de publicités sur l'écran de veille. Je ne suis pas à 25€ près, donc j'ai pris sans.
Après l'avoir pris en main, que penser de cette tablette ? Pour donner un avis général : elle fait ce à quoi on peut s'attendre dans cette gamme de prix très faible. L'écran n'est pas top car les noirs ne sont pas tout à fait noir, le son n'est pas très bon non et se révèle soit trop fort soit trop faible, pas de puce GPS, pas de port USB-C, appareil photo de 2Mpixel seulement. On est très loin du haut de gamme mais au final est-ce gênant ? L'autonomie est correcte et Google Play accepte plutôt bien la tablette, aucune application n'est réticente à s'installer, aucun plantage.
Au final c'est une tablette d'appoint qui fait son boulot de manière correcte pour un prix plus que raisonnable, et rien ne m'empêche de la recommander sauf si vous cherchez un bijou haut de gamme, auquel cas la Google Pixel C me semble plus intéressante.
Juste un petit billet pour indiquer que le blog tourne à nouveau sous Docker. Cette fois-ci je n'utilise plus un unique container apache, mais 3 containers orchestrés par docker-compose :
Et il y a toujours un nginx "en dur" en frontal qui fait reverse proxy et centralise les logs.
Le serveur est désormais un Scaleway VC1S aux pays-bas sur lequel tourne une distribution Debian Stretch. Pour les containers j'ai choisi d'utiliser au maximum des images alpine en raison de leur légèreté et de la simplicité du système. Et pour le moment, ça marche plutôt bien.
J'ai essayé d'utiliser un serveur ARM Scaleway, mais outre le fait qu'il est compliqué d'installer Docker (il faut utiliser Ubuntu-server ou alors compiler) les images du Dockerhub ne semblent pas disponibles pour cette architecture. Je me suis donc rabattu sur un VC1S qui n'est rien d'autre qu'une machine virtuelle x86_64.
Si vous êtes familier avec l'écosystème des distributions Linux, vous avez probablement levé un sourcil (comme Teal'c) en lisant ce titre car vous les connaissez toutes, vous avez touché à tous les gestionnaires de paquet, vous avez utilisé debian et gentoo, en bref vous avez fait le tour et plus rien ne nous surprend.
Et pourtant, bien que NixOS soit une distribution assez ancienne (2003) elle dispose de nombreux atouts inédits passés plutôt inaperçus jusqu'à présent.
La configuration déclarative centralisée
Ce que je trouve le plus intéressant dans NixOS, c'est la configuration centralisée dans un unique fichier. En effet si vous avez déjà travaillé sur des routeurs ou diverses appliances, vous avez remarqué que l'on peut souvent importer et exporter la configuration sous forme de texte assez facilement, cela rend la maintenance très facile. Sous NixOS c'est le même principe, mais en plus puissant puisqu'on peut rollback voire booter sur une ancienne configuration depuis grub. Exemple de configuration d'un serveur MariaDB :
/etc/nixos/configuration.nix
{ config, pkgs, ... }:
{
imports =
[ # Include the results of the hardware scan.
./hardware-configuration.nix
];
# Use the systemd-boot EFI boot loader.
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
networking = {
hostName = "mariadb";
nameservers = [ "192.168.0.31" ];
defaultGateway = "192.168.0.254";
interfaces.enp0s3.ip4 = [
{
address = "192.168.0.41";
prefixLength = 24;
}
];
};
# Select internationalisation properties.
i18n = {
consoleFont = "Lat2-Terminus16";
consoleKeyMap = "fr";
defaultLocale = "fr_FR.UTF-8";
};
# Set your time zone.
time.timeZone = "Europe/Paris";
# List packages installed in system profile. To search by name, run:
# $ nix-env -qaP | grep wget
environment.systemPackages = with pkgs; [
git
htop
sudo
tree
vim
];
# Services
services = {
openssh = {
enable = true;
permitRootLogin = "yes";
};
mysql = {
enable = true;
package = pkgs.mysql;
extraOptions = ''bind-address=0.0.0.0'';
};
};
# Open ports in the firewall.
networking.firewall.allowedTCPPorts = [ 22 3306 ];
# networking.firewall.allowedUDPPorts = [ ... ];
# Define a user account. Don't forget to set a password with ‘passwd’.
users.extraUsers = {
utux = {
isNormalUser = true;
extraGroups = [ "wheel" ];
};
};
# The NixOS release to be compatible with for stateful data such as databases.
system.stateVersion = "17.03";
}
/etc/nixos/hardware-configuration.nix
# Do not modify this file! It was generated by ‘nixos-generate-config’
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, ... }:
{
imports = [ ];
boot.initrd.availableKernelModules = [ "virtio_pci" "ahci" "xhci_pci" "sr_mod" "virtio_blk" ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/78634ba0-11d1-4f91-85ae-ac2ee247c387";
fsType = "xfs";
};
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/019A-1A05";
fsType = "vfat";
};
swapDevices =
[ { device = "/dev/disk/by-uuid/075a27eb-5656-4b57-b186-73a6d86e5e5c"; }
];
nix.maxJobs = lib.mkDefault 1;
}
Comme vous le voyez, le fichier configuration.nix contient toute la configuration, incluant les services tiers tels que mariadb dans notre cas. Cela va donc encore plus loin que le /etc/rc.conf sur FreeBSD/NetBSD/OpenBSD qui centralise déjà pas mal de choses. Le fichier hardware-configuration.nix lui est généré automatiquement il n'y a pas besoin d'y toucher et il est plus ou moins unique par serveur.
Pour générer et appliquer la configuration :
nixos-rebuild switch
Pour mettre à jour le système :
nixos-rebuild switch --upgrade
Puis un petit mysql_secure_installation la première fois pour préparer notre SGBD.
Ce qu'il reste à faire en dehors du configuration.nix, c'est la définition des mots de passe, avec passwd et bien sûr la gestion des données persistantes (les bases de données pour mariadb par exemple).
Nix, gestionnaire de paquets fonctionnel
Je vais être un peu plus prudent sur ce point, car étant encore en phase de découverte de NixOS, je ne connais pas encore très bien le gestionnaire de paquets Nix. Cependant, à la différence des gestionnaires classiques tels que apt, yum ou pacman, il ne se contente pas d'aller chercher des paquets pour les décompresser. Chaque version de chaque paquet est installé dans une arborescence /nix/store/{identifiant unique}, du coup plusieurs versions peuvent cohabiter ensemble et les mises à jour n'écrasent rien. Il est possible également pour les utilisateurs d'installer des paquets pour leur environnement (non-root) uniquement.
Mon avis
J'ai mis un serveur NixOS en test et il est trop tôt pour en tirer des conclusions. Mais j'aime l'idée de configuration centralisée déclarative, car la configuration classique des systèmes Linux n'est pas toujours simple à maintenir : Docker, Ansible, NixOS : le savoir (re)faire.
Si je dois citer deux inconvénients à NixOS : elle prend de la place (1,6GB à l'installation avec MariaDB) et elle nécessite au moins 1GB de RAM pour s'installer sous peine de voir oomkiller tuer nixos-install... elle peut cependant tourner avec 256MB par la suite.
NixOS nous montre qu'une distribution Linux ce n'est pas seulement un éinième fork de Ubuntu avec un wallpaper personalisé, ou encore une guerre de gestionnaire de paquets (dnf/apt), il existe encore de l'innovation et rien que pour cela elle mérite le coup d’œil.
Docker-compose est un outil permettant d'utiliser docker à l'aide d'un simple fichier .yml, facilitant ainsi grandement la vie et les interactions entre les containers d'un même service. Mais il n'est pas exempt de bugs ou de défauts de conception.
Le défaut dont je vais parler concerne le nommage des containers. Prenons par exemple deux projets docker : projet1 et projet2 avec l'arborescence suivante :
.
├── projet1
│ └── src
│ └── docker-compose.yml
└── projet2
└── src
└── docker-compose.yml
Nos docker-compose.yml sont identiques et commandent le lancement d'un simple container nginx :
# projet1/src/docker-compose.yml
version: '3'
services:
nginx:
image:
nginx:latest
Et :
# projet2/src/docker-compose.yml
version: '3'
services:
nginx:
image:
nginx:latest
Voyons ce qui arrive lorsque je démarre mon projet1 :
utux@docker:~/projet1/src$ docker-compose up -d
Creating src_nginx_1 ...
Creating src_nginx_1 ... done
On voit que notre container a été nommé src_nginx_1 suivant la logique suivante : $dossier_$service_$numero. Très bien. Démarrons maintenant le projet2 :
utux@docker:~/projet2/src$ docker-compose up -d
src_nginx_1 is up-to-date
docker-compose dit que le container existe déjà alors que non ! En fait il applique le même raisonnement et veut nommer le container src_nginx_1 aussi alors qu'il existe déjà ! C'est un défaut de conception et c'est problématique car en cas de modification sur l'un des projets, docker-compose va recréer les containers, et donc écraser ceux de l'autre...
Pour palier à ce problème, plusieurs solutions sont possibles :
- Nommer différemment votre dossier de travail. Ce n'est pas toujours possible car on peut avoir un environnement de dev et un environnement de prod avec les mêmes chemins.
- Utiliser l'attribut container_name mais c'est un peu fastidieux car il faut le faire sur tous les services du docker-compose.yml
- Utiliser la variable d'environnement COMPOSE_PROJECT_NAME. Malheureusement on ne peut pas la définir dans le docker-compose.yml malgré les demandes répétées des utilisateurs (ici et là) il faut la mettre dans un fichier .env dans votre projet.
Exemple d'utilisation du COMPOSE_PROJECT_NAME :
.
├── projet1
│ └── src
│ ├── docker-compose.yml
│ └── .env
└── projet2
└── src
├── docker-compose.yml
└── .env
Avec nos fichiers .env :
# projet1/src/.env
COMPOSE_PROJECT_NAME=projet1
Et :
# projet2/src/.env
COMPOSE_PROJECT_NAME=projet2
Démarrons maintenant notre projet1 puis notre projet2 :
utux@docker:~$ cd projet1/src/
utux@docker:~/projet1/src$ docker-compose up -d
Creating network "projet1_default" with the default driver
Creating projet1_nginx_1 ...
Creating projet1_nginx_1 ... done
utux@docker:~/projet1/src$ cd ../../projet2/src/
utux@docker:~/projet2/src$ docker-compose up -d
Creating network "projet2_default" with the default driver
Creating projet2_nginx_1 ...
Creating projet2_nginx_1 ... done
Cette fois les deux projets cohabitent bien et ne se marchent plus sur les pieds. La preuve :
utux@docker:~/projet2/src$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
eacabeb7e961 nginx:latest "nginx -g 'daemon ..." 4 seconds ago Up 2 seconds 80/tcp projet2_nginx_1
9477b31d2035 nginx:latest "nginx -g 'daemon ..." 16 seconds ago Up 14 seconds 80/tcp projet1_nginx_1
En conclusion il ne faut pas avoir une confiance aveugle en docker-compose, qui est un outil bien pratique mais manifestement sujet à des défauts de conception. Imaginez ce genre de confusion de nommage, voire d'écrasement de containers en production. Utilisez COMPOSE_PROJECT_NAME et testez vos projets en pré-production avant de déployer sur la prod.
L'informatique, comme tous les métiers, demande un savoir-faire, celui-ci vient avec l'expérience et la pratique. Mais s'il y a un autre point qui est important et souvent négligé, c'est de savoir refaire. Je vais expliquer.
Imaginez-vous administrateur système dans une entreprise, on vous charge d'installer un serveur web pour afficher une simple page html. Vous allez alors installer Debian + Apache puis placer le fichier html à la racine, rien de difficile jusque là.
Imaginez ensuite qu'au bout de 2 mois ce fichier html soit remplacé par un fichier php un peu plus avancé, vous allez alors installer libapache2-mod-php5 là encore c'est facile. Par la suite le fichier évolue encore et vous oblige à installer des modules, par exemple php5-gd et php5-curl.
Puis le serveur vit sa vie et au bout de 2 ans on vous demande d'en mettre en place un deuxième avec exactement le même rôle. Et là ça se complique car 2 ans c'est long et vous avez probablement oublié tout ce que vous et vos collègues avez fait pour configurer ce serveur au fur et à mesure. S'il est facile d'identifier que apache2 et php5 sont présents, en revanche les modules sont beaucoup moins évidents, surtout si vous avez utilisé des gestionnaires tiers tels que pecl, cpan, pip.
L'une des grandes problématiques est donc de trouver un moyen pour garder une trace et refaire rapidement toutes les étapes qui ont accompagné la vie du serveur. Alors bien sûr le grand classique est d'utiliser un wiki, mais qui vous garanti que ce qu'y s'y trouve représente bien ce qui est en production ? Personne n'est à l'abri d'une modification "urgente" en prod non rapportée sur le wiki.
Une solution que l'on retrouve souvent et qui est appliquée dans Ansible, Docker et NixOS, c'est d'éliminer toutes les manipulations sur la prod. On y touche plus, à la place on travaille sur un fichier de recette, que l'on va ensuite deployer et jouer. Sur Ansible ce sont les playbook, sur docker les Dockerfile, et sur NixOS le fichier configuration.nix.
Cela parait beaucoup plus propre et ça l'est, c'est une rigueur pas forcément naturelle qui paye sur le long terme. Néanmoins ce n'est pas toujours évident, une manipulation rapide à faire sur un serveur peut se transformer en plusieurs minutes voire heures de devops dans Ansible. Let's Encrypt est un exemple, son automatisation n'est pas simple car vous allez devoir gérer deux cas différents selon la présence ou non d'un certificat. En effet certbot peut soit utiliser le mode standalone et donc couper Nginx (car nécessité du port 80) ou alors utiliser le mode webroot et justement passer par Nginx + vhost de votre site, or ce dernier a justement besoin du certificat pour démarrer. Et quid du cas de Docker où vous devez créer un nouveau container et le relier à l'existant juste pour renouveler vos certificats.
En conclusion le boulot de sysadmin, développeur ou devops n'est pas seulement de faire ou réparer les choses mais également de prévoir l'avenir, s'imposer une rigueur même si elle parait contre-productive sur le moment. J'aurai probablement l'occasion de parler de plus en détail de Docker et de NixOS dans de prochains articles, restez branchés.
Fil RSS des articles