Jouer avec SĆzu - 1ers pas
- Objectif de ce blog post: mettre en place un environnement pour pouvoir âjouerâ avec SĆzu
- Niveau: débutant
- ce que jâĂ©cris nâengage que moi bien sĂ»r đ
- le rĂ©seau nâest vraiment pas mon domaine đ
- Nous verrons (rapidement)
- comment installer SĆzu
- comment lâutiliser pour rĂ©partir la charge sur plusieurs VMs
- comment lâutiliser pour dĂ©ployer une nouvelle version de site Et tout cela de maniĂšre transparente mais Ă la main âđ€ pour mieux comprendre
1) SĆzu?
SĆzu est un reverse proxy HTTP dĂ©veloppĂ© chez https://www.clever-cloud.com/ qui peut changer sa configuration au runtime, sans re-dĂ©marrer. Le proxy expose une chaĂźne de communication (communication channel in đŹđ§) et du coup on peut envoyer des commandes Ă chaud Ă SĆzu.
Si vous voulez savoir ce quâest un reverse proxy parce que vous nây connaissez rien ou presque sur le sujet, je vous conseille cette vidĂ©o Comprendre le Proxy et le Reverse Proxy en 5 minutes par âCookie connectĂ©â.
Si vous voulez en savoir plus sur SĆzu, je vous conseille la lecture de ce blog post (le comment, le pourquoi de SĆzu): Hot reloading configuration: why and how? par Geoffroy Couprie le papa de SĆzu (Ă qui je nâai rien fait relire đ)
Et le repository GitHub est par ici: https://github.com/sozu-proxy/sozu
âšâšâš Remerciements pour leurs explications
2) Mise en place du terrain de jeux
- Nous aurons besoin de plusieurs VMs (virtual machines), jâai choisi dâutiliser:
- VirtualBox https://www.virtualbox.org/
- Vagrant https://www.vagrantup.com/
- âčïž vous pouvez adapter avec vos outils, lâimportant câest de pouvoir simuler plusieurs machines
- Les installations de VirtualBox et Vagrant sont trĂšs simples Ă faire
- Il faudra âbuilderâ SĆzu
- Nous devront donc installer Rust (car, je le rappelle SĆzu est codĂ© en Rust).
- â ïž SĆzu est encore en đ§ donc certaines choses peuvent changer
Quâallons nous faire?: hĂ©berger un mĂȘme code source de site web en NodeJS dans plusieurs VMs
Tout dâabord crĂ©ez une arborescence pour hĂ©berger nos expĂ©rimentations:
sandbox
âââ hello-earth-v1 # ici le code source de mon site web
âââ vms # le projet Vagrant pour gĂ©nĂ©rer et provisionner nos VM
âââ sozu-demo # ici nous builderons le projet sozu
A) Le code source du site web
Jâai utilisĂ© ExpressJS. vous allez avoir besoin uniquement de 2 fichiers:
index.js
package.js
sandbox
âââ hello-earth-v1
â âââ index.js
â âââ package.json
âââ vms
âââ sozu-demo
index.js
âčïž jâutilise la librairie 'project-name-generator'
pour générer un nom de machine différent pour chacune des VMs.
const express = require("express");
const bodyParser = require("body-parser");
const generate = require('project-name-generator');
let port = process.env.PORT || 8080;
let app = express();
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: false}))
let machineName = generate({ words: 3, number: true }).dashed
app.disable('etag');
app.get('/', (req, res) => {
res.send(`
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>WebApp</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.container
{
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.title
{
font-family: "Source Sans Pro", "Helvetica Neue", Arial, sans-serif;
display: block;
font-weight: 300;
font-size: 40px;
color: #35495e;
letter-spacing: 1px;
}
.subtitle
{
font-family: "Source Sans Pro", "Helvetica Neue", Arial, sans-serif;
font-weight: 300;
font-size: 30px;
color: #526488;
word-spacing: 5px;
padding-bottom: 15px;
}
</style>
</head>
<body>
<section class="container">
<div>
<h1 class="title">
đ I am ${machineName}
</h1>
<h2 class="subtitle">
Hello đ v1
</h2>
</div>
</section>
</body>
</html>
`)
})
app.listen(port)
console.log(`đ ${machineName} is started - listening on `, port)
package.json
{
"name": "hello-earth",
"scripts": {
"start": "node index.js"
},
"main": "index.js",
"dependencies": {
"body-parser": "^1.17.2",
"express": "^4.15.3",
"project-name-generator": "^2.1.3"
}
}
B) Notre projet Vagrant
Dans le répertoire
vms
, allez créer un fichierVagrantfile
sandbox
âââ hello-earth-v1
â âââ index.js
â âââ package.json
âââ vms
â âââ Vagrantfile
âââ sozu-demo
Vagrantfile
Que fait le script?
- je crĂ©e 3 VMs Ă partie dâune image
bento/ubuntu-17.04
- chaque VM aura une ip fixe et se nomme
webappN
:
webapp1
:192.168.1.21
webapp2
:192.168.1.22
webapp3
:192.168.1.23
- jâexpose le port
8080
(vous pourrez donc accéder à la webapp par http://192.168.1.2N:8080/)- je copie le code source de
/hello-earth-v1
dans le répertoire/hello-earth
de la vm- jâinstalle NodeJS
- jâinstalle les packages nĂ©cessaires pour faire fonctionner la webapp (
npm install
)
BOX_IMAGE = "bento/ubuntu-17.04"
NODE_COUNT = 3
Vagrant.configure(2) do |config|
config.vm.box = BOX_IMAGE
(1..NODE_COUNT).each do |i|
config.vm.define "webapp#{i}" do |node|
node.vm.network :forwarded_port, guest: 8080, host: 9090 + i
node.vm.network "public_network", ip: "192.168.1.2#{i}", bridge: "en0: Wi-Fi (AirPort)"
node.vm.provider "virtualbox" do |node|
node.memory = 256
node.cpus = 1
end
node.vm.synced_folder '.', '/vagrant', disabled: true
node.vm.provision "file", source: "../hello-earth-v1", destination: "hello-earth"
node.vm.provision :shell, inline: <<-SHELL
echo "đ Installing NodeJS..."
apt-get install curl python-software-properties -y
curl -sL https://deb.nodesource.com/setup_7.x | sudo bash -
apt-get install nodejs -y
cd hello-earth
npm install
echo "đ bye! đđđ"
SHELL
end
end
end
Nous pouvons dĂšs maintenant gĂ©nĂ©rer les VMs et les dĂ©marrer ainsi que les webapps. âčïž Mais, vous n`ĂȘtes pas obligĂ©s de le faire tout de suite.
Générer (et démarrer les VMs) les VM
Câest tout simple:
cd vms
vagrant up
# âł patientez un peu, il faut tout de mĂȘme rĂ©cupĂ©rer l'image de l'OS
DĂ©marrer les webapps
Il faut donc démarrer les webapps au sein de chaque VM, comme cela:
vagrant ssh webapp1 -c "cd hello-earth; npm start"&
vagrant ssh webapp2 -c "cd hello-earth; npm start"&
vagrant ssh webapp3 -c "cd hello-earth; npm start"&
Vous devriez obtenir cette sortie:
đ delirious-flagrant-expert-3862 is started - listening on 8080
đ stimulating-jazzy-spoon-4201 is started - listening on 8080
đ knotty-responsible-muscle-3315 is started - listening on 8080
âčïž je gĂ©nĂšre un nom alĂ©atoire pour chaque application pour mieux les reconnaĂźtre.
Vous pouvez dĂ©jĂ tester lâaccĂšs aux applications:
Maintenant passons aux choses sĂ©rieuses đ
C) Installation de SĆzu
Suivre les Ă©tapes suivantes (cela peut ĂȘtre un peu long selon a configuration de votre machine):
# Installer Rust et le tooling associé
curl https://sh.rustup.rs -sSf | sh
# wait... đ€
# cloner SĆzu
cd sozu-demo
git clone https://github.com/sozu-proxy/sozu
# compiler SĆzu
cd sozu
cd ctl && cargo build; cd ../bin && cargo build
# wait... đ€
Vous devrier avoir cette arborescence:
sandbox
âââ hello-earth-v1
â âââ index.js
â âââ package.json
âââ vms
â âââ Vagrantfile
âââ sozu-demo
â âââ sozu
Dans le répertoire /sozu/demo
nous allons créer:
- un répertoire
command_folder
- un fichier vide
state.json
- un fichier
404.html
- un fichier
503.html
- un fichier
demo.toml
404.html
HTTP/1.1 404 nope
Cache-Control: no-cache
Content-Type: text/html; charset=UTF-8
Connection: close
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta http-equiv="Pragma" content="no-cache">
<style>
.title
{
font-family: "Source Sans Pro", "Helvetica Neue", Arial, sans-serif;
display: block;
font-weight: 300;
font-size: 60px;
color: #35495e;
letter-spacing: 1px;
}
</style>
</head>
<body>
<h1 class="title">
đĄ Nopeâïž
</h1>
</body>
</html>
503.html
HTTP/1.1 503 your application is in deployment
Cache-Control: no-cache
Content-Type: text/html; charset=UTF-8
Connection: close
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
.title
{
font-family: "Source Sans Pro", "Helvetica Neue", Arial, sans-serif;
display: block;
font-weight: 300;
font-size: 60px;
color: #35495e;
letter-spacing: 1px;
}
</style>
</head>
<body>
<h1 class="title">
đą Ouch...
</h1>
</body>
</html>
demo.toml
Câest le fichier de configuration utilisĂ© par SĆzu
# sozu proxy simple demo config file
command_socket = "./command_folder/sock"
saved_state = "./state.json"
log_level = "info"
log_target = "stdout"
command_buffer_size = 16384
worker_count = 2
handle_process_affinity = false
# you need this, but currently it`s not used
[metrics]
address = "192.168.59.103"
port = 8125
[http]
address = "127.0.0.1"
max_connections = 10
port = 9090
buffer_size = 16384
answer_404 = "./404.html"
answer_503 = "./503.html"
[applications]
[applications.webapp]
hostname = "localhost"
frontends = [ "HTTP" ] # list of proxy tags
backends = [ "192.168.1.21:8080", "192.168.1.22:8080", "192.168.1.22:8080" ] # list of IP/port
Les 2 sections les plus importantes pour notre âPOCâ sont [http]
et [applications.webapp]:
- avec
[http]
, vous pouvez dĂ©duire que vos allez accĂ©der au reverse-proxy via lâip127.0.0.1
et le port http9090
- avec
[applications.webapp]
, le nom de domaine pour accéder au proxy est"localhost"
et vous serez redirigĂ©s vers une des machines comprises dans la liste des ip sur un port particulier - âčïž dans
[applications.webapp]
câest vous qui donnez le nomwebapp
, vous lâappelez comme vous voulez
Maintenant vous devriez avoir cette arborescence:
sandbox
âââ hello-earth-v1
â âââ index.js
â âââ package.json
âââ vms
â âââ Vagrantfile
âââ sozu-demo
â âââ 404.html
â âââ 503.html
â âââ demo.toml
â âââ state.json
â âââ command_folder/
â âââ sozu/
3) On joue ⊠Une 1Úre fois!
Si vous ne lâavez pas dĂ©jĂ fait, gĂ©nĂ©rez vos VM et lancez les webapps
Dans un 1er templ, lancez SĆzu:
cd sozu-demo
./sozu/target/debug/sozu start -c ./demo.toml
A) 1er contact
Maintenant ouvrez 2 navigateurs diffĂ©rents (jâai fait le test avec Chrome et FireFox) avec lâurl http://localhost:9090/ et vous obtiendrez ceci:
Vous pouvez voir que SĆzu vous a redirigĂ© sur des machines diffĂ©rentes (pour une seule et mĂȘme url)
B) Tuons des VMs
ArrĂȘtons 2 VMs:
# obtenir la liste des VMs
cd vms
vagrant status
# Vous allez obtenir ceci:
Current machine states:
webapp1 running (virtualbox)
webapp2 running (virtualbox)
webapp3 running (virtualbox)
# arrĂȘtons webapp2 et webapp3 ... et supprimons les
vagrant halt webapp2; vagrant destroy webapp2 -f
vagrant halt webapp3; vagrant destroy webapp3 -f
vagrant status
# nouveau status
webapp1 running (virtualbox)
webapp2 not created (virtualbox)
webapp3 not created (virtualbox)
- Raffraichissez vos navigateurs
- Il va falloir attendre un peu: SĆzu dispose dâun circuit-breaker qui va tenter pendant un petit moment de joindre les 2 machines âdisparuesâ
- puis SĆzu va âse rabattreâ sur la machine restante
Et vous devriez obtenir ceci (jâai fait un test supplĂ©mentaire avec Safari):
ArrĂȘtons la derniĂšre VM
vagrant halt webapp1; vagrant destroy webapp1 -f
- Raffraichissez vos navigateurs
- Attendez un peu⊠(selon les navigateurs et leur cache, les comportements peuvent ĂȘtre variables)
Et vous devriez obtenir notre favuleuse page 503:
4) On relance les sites
Alors on recrée les VMs une nouvelle fois, on démarre les webapps:
cd vms
vagrant up
Et vous relancez la webapp ExpressJS de la 1Ăšre VM:
vagrant ssh webapp1 -c "cd hello-earth; npm start"
Ensuite nous allons âexpliquerâ Ă Sozu que nous avons une nouvelle machine Ă nouveau disponible en lui passant la commande suivante:
cd sozu-demo
./sozu/target/debug/sozuctl --config ./demo.toml backend add --id webapp --ip 192.168.1.21 --port 8080
- Raffraichissez vos navigateurs
- Attendez un peuâŠ
- Et đ„đ„đ„
Et ceci sans redĂ©marrer SĆzu đđ€
Relancez les autres webapps:
vagrant ssh webapp2 -c "cd hello-earth; npm start"&
vagrant ssh webapp3 -c "cd hello-earth; npm start"&
Expliquons Ă SĆzu quâil y a nouveau des machines supplĂ©mentaires:
./sozu/target/debug/sozuctl --config ./demo.toml backend add --id webapp --ip 192.168.1.22 --port 8080
puis
./sozu/target/debug/sozuctl --config ./demo.toml backend add --id webapp --ip 192.168.1.23 --port 8080
- Raffraichissez vos navigateurs
- Et voilĂ :
5) On fait une mise Ă jour de site
Jâai crĂ©Ă© une nouvelle version du site dans un rĂ©pertoire /hello-earth-v2
avec une Ă©volution majeure, jâai modifiĂ© une partie du code html:
<body>
<section class="container">
<div>
<h1 class="title">
đ I am ${machineName} I â€ïž đŒ
</h1>
<h2 class="subtitle">
Hello đ v2
</h2>
</div>
</section>
</body>
A) Nouveau projet Vagrant
Je vais donc créer de nouvelles VMs dans un répéertoire /vms-new
sandbox
âââ hello-earth-v1
â âââ index.js
â âââ package.json
âââ hello-earth-v2
â âââ index.js
â âââ package.json
âââ vms
â âââ Vagrantfile
âââ vms-new
â âââ Vagrantfile
âââ sozu-demo
â âââ sozu/
⊠Avec un nouveau Vagrantfile
- chaque VM aura une nouvelle ip fixe et se nomme
webapp_newN
:
webapp1
:192.168.1.31
webapp2
:192.168.1.32
webapp3
:192.168.1.33
- je copie le code source de
/hello-earth-v2
dans le répertoire/hello-earth
de la vm
BOX_IMAGE = "bento/ubuntu-17.04"
NODE_COUNT = 3
Vagrant.configure(2) do |config|
config.vm.box = BOX_IMAGE
(1..NODE_COUNT).each do |i|
config.vm.define "webapp_new#{i}" do |node|
node.vm.network :forwarded_port, guest: 8080, host: 9100 + i
node.vm.network "public_network", ip: "192.168.1.3#{i}", bridge: "en0: Wi-Fi (AirPort)"
node.vm.provider "virtualbox" do |node|
node.memory = 256
node.cpus = 1
end
node.vm.synced_folder '.', '/vagrant', disabled: true
node.vm.provision "file", source: "../hello-earth-v2", destination: "hello-earth"
node.vm.provision :shell, inline: <<-SHELL
echo "đ Installing NodeJS..."
apt-get install curl python-software-properties -y
curl -sL https://deb.nodesource.com/setup_7.x | sudo bash -
apt-get install nodejs -y
cd hello-earth
npm install
echo "đ bye! đđđ"
SHELL
end
end
end
B) Création, provisionning et lancement
On provisionne donc les nouvelles machines:
vagrant up
# puis
vagrant ssh webapp_new1 -c "cd hello-earth; npm start"
vagrant ssh webapp_new2 -c "cd hello-earth; npm start"
vagrant ssh webapp_new3 -c "cd hello-earth; npm start"
On âđ notifieâ SĆzu de lâarrivĂ©e de nouvelles machines
./sozu/target/debug/sozuctl --config ./demo.toml backend add --id webapp --ip 192.168.1.31 --port 8080
./sozu/target/debug/sozuctl --config ./demo.toml backend add --id webapp --ip 192.168.1.32 --port 8080
./sozu/target/debug/sozuctl --config ./demo.toml backend add --id webapp --ip 192.168.1.33 --port 8080
Ensuite on âđ notifieâ SĆzu du dĂ©part des anciennes machines (cette fois çi avec le mot-clĂ© remove
)
./sozu/target/debug/sozuctl --config ./demo.toml backend remove --id webapp --ip 192.168.1.21 --port 8080
./sozu/target/debug/sozuctl --config ./demo.toml backend remove --id webapp --ip 192.168.1.22 --port 8080
./sozu/target/debug/sozuctl --config ./demo.toml backend remove --id webapp --ip 192.168.1.23 --port 8080
- Raffraichissez vos navigateurs
- Attendez un peuâŠ
- Et âšđż le nouveau site a Ă©tĂ© dĂ©plotĂ© sans aucun arrĂȘt relance đș
VoilĂ , câest tout pour aujourdâhui. SĆzu Ă©volue et de nouvelles fonctionnalitĂ©s sont Ă venir. Et de mon cĂŽtĂ© je pense dĂ©jĂ au prochain tuto SĆzu avec des microservices Vert.x.
Tweet