Le blog tech de Nicolas Steinmetz (Time Series, IoT, Web, Ops, Data)
Suite à une mission, synthèse sur la possibilité à date de gérer des conteneurs Linux et Windows avec Docker.
Les tests ont été réalisés, début mai 2017, sur les environnements suivants :
En début de mission, il était supposé qu’une application métier en C# pourrait migrer vers ASP.net Core (la version opensource de .Net et sa déclinaison ASP) et donc sur un conteneur Linux. La suite nous prouva que toutes les APIs ne sont pas (et ne seront pas forcément) dans la version opensource de .Net et qu’il nous fallait envisager des conteneurs Windows à court terme et une infrastructure hybride Windows & Linux, tant au niveau des hôtes que des conteneurs.
Avant d’aller plus loin, il faut bien avoir en tête la jeunesse du support de Windows dans le monde des conteneurs. Il faut distinguer deux niveaux de supports de l’OS Windows :
Support de Windows comme machine hôte :
Support de Windows comme OS de container :
Dans le cadre de la DockerCon d’Avril 2017, Docker et Microsoft ont annoncé le support des conteneurs Linux sous Microsoft Server 2016 via Hyper-V. Il devrait alors être possible de pouvoir lancer simultanément des conteneurs Linux ET Windows sous Windows Server 2016. Il n’y a pas de date connue pour la sortie de la version supportant cette nouveauté. Il faudra surveiller les prochaines releases trimestrielles de Docker pour savoir quand cela sera utilisable de façon “stable”.
En somme, en continuant notre test plus loin, nous savons que nous entrons dans un monde immature avec un support incomplet.
La première surprise fut de voir qu’il était possible de créer un cluster Swarm avec un noeud Windows et un noeud Linux sans pré-requis particulier.
Il faut ensuite créer manuellement le réseau overlay pour son application (ce sera supporté dans docker-compose 1.13+, version 3.2 du format). Si vous utiliser docker-compose, il faudra alors spécifier ce réseau comme un réseau externe afin que l’application s’y attache à son lancement.
Afin de piloter le déploiement des conteneurs sur les bons hôtes, il convient d’ajouter des labels (ou de s’appuyer sur des labels existants comme node.platform.OS
). Ainsi, un conteneur Windows se déploira sur un hôte Windows et idem pour du Linux.
Jusque là, tout va bien mais c’est là que les limitations se font sentir :
Donc au final :
Bon à savoir également :
Une série de trois vidéos, publiées il y a quelques jours, montrent bien ce qu’il est possible de faire avec Swarm à ce jour.
Pour conclure, il est possible d’utiliser des conteneurs Windows mais que ce n’est pas encore la panacée. Cela reste néanmoins prometteur et les annonces de Microsoft vont dans le bon sens. Il va falloir attendre quelques mois pour envisager cela plus sereinement.
Update 16/8/2017 : La version 17.06 entreprise edition semble résoudre les limites évoquées précédemment.
Pour pouvoir tester différentes solutions, il peut être utile de pouvoir créer rapidement une infrastructure chez un fournisseur tiers. Pour cela nous allons nous appuyer sur la solution Terraform, dont l’objectif est de pouvoir gérer une insfrastructure via du code qui permet de décrire cette infrastructure et les règles associées (dans la tendance Infrastructure as Code).
Cela se fera chez Scaleway mais cela peut se faire chez d’autres fournisseurs tant qu’un provider Terraform existe.
Nous allons nous appuyer sur l’intégration Terraform/Scaleway pour créer un cluster de 3 machines.
Créer un ficheir cluster-3.tf
dans un dossier vide. Il est important qu’il soit vide car Terraform prend en compte tous les fichiers .tf
qu’il rencontre dans le répertoire courant.
Il faut commencer par déclarer notre provider
; je fournis les infos de key & token, ainsi que le datacenter où je souhaite lancer mon cluster :
provider "scaleway" {
organization = "<access key>"
token = "<token>"
region = "par1"
}
Je déclare ensuite des data
, que l’on peut assimiler à des variables à ce stade :
data "scaleway_bootscript" "latest" {
architecture = "x86_64"
name_filter = "stable"
}
data "scaleway_image" "ubuntu" {
architecture = "x86_64"
name = "Ubuntu Xenial"
}
Ensuite, je définis une politique de sécurité en 2 étapes :
resource "scaleway_security_group" "cluster_default" {
name = "cluster_default"
description = "Allow SSH, HTTP, HTTPS traffic"
}
resource "scaleway_security_group_rule" "ssh_accept" {
security_group = "${scaleway_security_group.cluster_default.id}"
action = "accept"
direction = "inbound"
ip_range = "0.0.0.0/0"
protocol = "TCP"
port = 22
}
resource "scaleway_security_group_rule" "http_accept" {
security_group = "${scaleway_security_group.cluster_default.id}"
action = "accept"
direction = "inbound"
ip_range = "0.0.0.0/0"
protocol = "TCP"
port = 80
}
resource "scaleway_security_group_rule" "https_accept" {
security_group = "${scaleway_security_group.cluster_default.id}"
action = "accept"
direction = "inbound"
ip_range = "0.0.0.0/0"
protocol = "TCP"
port = 443
}
Je pourrais donc me connecter en ssh, http et https sur l’ensemble de mon cluster une fois qu’il sera initialisé.
Je déclare ensuite une IP et je l’associe au serveur qui l’utilisera :
resource "scaleway_ip" "cluster-master_ip" {
server = "${scaleway_server.cluster-master.id}"
}
Enfin, je déclare mon serveur qui va reprendre l’ensemble des informations précédentes, ainsi que quelques informations spécifique comme le type d’instance (type
) ou encore le volume additionnel (volume
) attaché au serveur. Il y a des directives scaleway_volume
ou scaleway_volume_attachment
mais l’API Scaleway ne permet pas de les utiliser pour ce type de serveur.
resource "scaleway_server" "cluster-master" {
name = "cluster-master"
image = "${data.scaleway_image.ubuntu.id}"
type = "VC1M"
bootscript = "${data.scaleway_bootscript.latest.id}"
security_group = "${scaleway_security_group.cluster_default.id}"
volume {
size_in_gb = 50
type = "l_ssd"
}
}
Sur le même modèle, nous allons instancier les 2 autres noeuds de notre cluster :
resource "scaleway_ip" "cluster-node1_ip" {
server = "${scaleway_server.cluster-node1.id}"
}
resource "scaleway_server" "cluster-node1" {
name = "cluster-node1"
image = "${data.scaleway_image.ubuntu.id}"
type = "VC1M"
bootscript = "${data.scaleway_bootscript.latest.id}"
security_group = "${scaleway_security_group.cluster_default.id}"
volume {
size_in_gb = 50
type = "l_ssd"
}
}
resource "scaleway_ip" "cluster-node2_ip" {
server = "${scaleway_server.cluster-node2.id}"
}
resource "scaleway_server" "cluster-node2" {
name = "cluster-node2"
image = "${data.scaleway_image.ubuntu.id}"
type = "VC1M"
bootscript = "${data.scaleway_bootscript.latest.id}"
security_group = "${scaleway_security_group.cluster_default.id}"
volume {
size_in_gb = 50
type = "l_ssd"
}
}
Vous pouvez déjà valider qu’il n’y a pas d’erreur de syntaxe avec
↪ terraform fmt
cluster-3.tf
Si pas d’erreur, alors il ne retourne que le nom du fichier ou rien si commande déjà exécutée.
Ensuite vous pouvez regarder ce qu’il va se passer avec terraform plan
. Cela vous sort un diff
de ce qui va être réalisé (ou changé s’il y a mise à jour du plan)
Dans notre cas :
↪ terraform plan
[...]
+ scaleway_ip.cluster-master_ip
ip: "<computed>"
server: "${scaleway_server.cluster-master.id}"
+ scaleway_ip.cluster-node1_ip
ip: "<computed>"
server: "${scaleway_server.cluster-node1.id}"
+ scaleway_ip.cluster-node2_ip
ip: "<computed>"
server: "${scaleway_server.cluster-node2.id}"
+ scaleway_security_group.cluster_default
description: "Allow SSH, HTTP, HTTPS traffic"
name: "cluster_default"
+ scaleway_security_group_rule.http_accept
action: "accept"
direction: "inbound"
ip_range: "0.0.0.0/0"
port: "80"
protocol: "TCP"
security_group: "${scaleway_security_group.cluster_default.id}"
+ scaleway_security_group_rule.https_accept
action: "accept"
direction: "inbound"
ip_range: "0.0.0.0/0"
port: "443"
protocol: "TCP"
security_group: "${scaleway_security_group.cluster_default.id}"
+ scaleway_security_group_rule.ssh_accept
action: "accept"
direction: "inbound"
ip_range: "0.0.0.0/0"
port: "22"
protocol: "TCP"
security_group: "${scaleway_security_group.cluster_default.id}"
+ scaleway_server.cluster-master
bootscript: "8fd15f37-c176-49a4-9e1d-10eb912942ea"
enable_ipv6: "false"
image: "89457135-d446-41ba-a8df-d53e5bb54710"
name: "cluster"
private_ip: "<computed>"
public_ip: "<computed>"
public_ipv6: "<computed>"
security_group: "${scaleway_security_group.cluster_default.id}"
state: "<computed>"
state_detail: "<computed>"
type: "VC1M"
volume.#: "1"
volume.0.size_in_gb: "50"
volume.0.type: "l_ssd"
volume.0.volume_id: "<computed>"
+ scaleway_server.cluster-node1
bootscript: "8fd15f37-c176-49a4-9e1d-10eb912942ea"
enable_ipv6: "false"
image: "89457135-d446-41ba-a8df-d53e5bb54710"
name: "cluster-node1"
private_ip: "<computed>"
public_ip: "<computed>"
public_ipv6: "<computed>"
security_group: "${scaleway_security_group.cluster_default.id}"
state: "<computed>"
state_detail: "<computed>"
type: "VC1M"
volume.#: "1"
volume.0.size_in_gb: "50"
volume.0.type: "l_ssd"
volume.0.volume_id: "<computed>"
+ scaleway_server.cluster-node2
bootscript: "8fd15f37-c176-49a4-9e1d-10eb912942ea"
enable_ipv6: "false"
image: "89457135-d446-41ba-a8df-d53e5bb54710"
name: "cluster-node2"
private_ip: "<computed>"
public_ip: "<computed>"
public_ipv6: "<computed>"
security_group: "${scaleway_security_group.cluster_default.id}"
state: "<computed>"
state_detail: "<computed>"
type: "VC1M"
volume.#: "1"
volume.0.size_in_gb: "50"
volume.0.type: "l_ssd"
volume.0.volume_id: "<computed>"
Plan: 10 to add, 0 to change, 0 to destroy.
Pour provisionner l’infrastructure, il ne vous reste plus qu’à faire terraform apply
.
↪ terraform apply
data.scaleway_bootscript.latest: Refreshing state...
data.scaleway_image.ubuntu: Refreshing state...
scaleway_security_group.cluster_default: Creating...
description: "" => "Allow SSH, HTTP, HTTPS traffic"
name: "" => "cluster_default"
scaleway_security_group.cluster_default: Creation complete (ID: 06b93dc3-...2beffd62)
scaleway_security_group_rule.ssh_accept: Creating...
action: "" => "accept"
direction: "" => "inbound"
ip_range: "" => "0.0.0.0/0"
port: "" => "22"
protocol: "" => "TCP"
security_group: "" => "06b93dc3-9a8b-4022-80bf-e9172beffd62"
scaleway_server.cluster-master: Creating...
[...]
Apply complete! Resources: 10 added, 0 changed, 0 destroyed.
Vous pouvez consulter l’ensemble des informations de votre infrastructure avec la commande terraform show
.
Il ne vous reste plus qu’à vous connecter sur vos serveurs, faire les actions dont vous avez besoin.
Supposons que nous ayons besoin d’un 4ème noeud, il suffirait de rajouter dans le fichier cluster-3.tf
:
resource "scaleway_ip" "cluster-node3_ip" {
server = "${scaleway_server.cluster-node3.id}"
}
resource "scaleway_server" "cluster-node3" {
name = "cluster-node3"
image = "${data.scaleway_image.ubuntu.id}"
type = "VC1M"
bootscript = "${data.scaleway_bootscript.latest.id}"
security_group = "${scaleway_security_group.cluster_default.id}"
volume {
size_in_gb = 50
type = "l_ssd"
}
}
On peut valider notre changement avec terraform plan
:
↪ terraform plan
[...]
+ scaleway_ip.cluster-node3_ip
ip: "<computed>"
server: "${scaleway_server.cluster-node3.id}"
+ scaleway_server.cluster-node3
bootscript: "8fd15f37-c176-49a4-9e1d-10eb912942ea"
enable_ipv6: "false"
image: "89457135-d446-41ba-a8df-d53e5bb54710"
name: "cluster-node3"
private_ip: "<computed>"
public_ip: "<computed>"
public_ipv6: "<computed>"
security_group: "06b93dc3-9a8b-4022-80bf-e9172beffd62"
state: "<computed>"
state_detail: "<computed>"
type: "VC1M"
volume.#: "1"
volume.0.size_in_gb: "50"
volume.0.type: "l_ssd"
volume.0.volume_id: "<computed>"
Plan: 2 to add, 0 to change, 0 to destroy.
Puis de mettre à jour le cluster avec terraform apply
↪ terraform apply
[...]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Enfin, comme toutes les choses ont une fin, vous pouvez détruire l’ensemble de l’infrastructure créé via terraform destroy
.
↪ terraform destroy
[...]
Destroy complete! Resources: 14 destroyed.
J’espère que cette introduction à Terraform vous donnera des idées ; les éditeurs de code modernes fournissent souvent des plugins pour la syntaxe et les snippets terraform. Scaleway reste assez limité en tant que provider terraform. Si vous regardez le provider AWS, vous pouvez interagir avec énormément de services AWS (pour ne pas dire tous) : VPC, EC2, ELB, RDS, etc.
zsh
via “Oh My ZSH” mais je n’étais pas allé bien loin, revenant au final au bon vieux bash
. L’article m’a donné envie d’essayer fish et pour le moment, je trouve ça plutôt pas mal. Ne pas se fier à la première impression du site :)JSON
et surtout qu’il n’y a pas de rotation des journaux par défaut :’( ; l’article montre ensuite les intérêts du format GELF (avoir un message sous la forme d’un dictionnaire/tableau au format clé/valeur) et les limites (connextion UDP) avec les solutions de contournement actuelles et les solutions à venir prochainement.