Eina per gestionar els backups de rundeck

Continuem amb la ratxa dels posts de rundeck. Vam veure al post anterior com moure el rundeck d’un servidor a un altre, i vam veure que son uns quants fitxerets que s’han de tocar (les claus ssh, la configuracio del rundeck, la definició dels projectes, la definició dels jobs…). Doncs aprofitant aquella informació, i per ajudar en les tasques de backup, he creat un shell-script que s’encarrega de gestionar les còpies de seguretat de rundeck, tant el backup com el restore. El podreu trobar a github: https://github.com/ersiko/rundeck-backup i aqui mateix a la pàgina del projecte rundeck-backup

El funcionament es ben fàcil. Per fer un backup, tan sols s’ha de fer:

[[email protected] ~]# ./rundeck-backup.sh backup rundeck.tar.gz
OK - backup finished successfully using /root/rundeck-backup.tar.gz

Si no posem res, el backup es guardarà amb la data del dia:

[[email protected] ~]# ./rundeck-backup.sh backup
OK - backup finished successfully using /root/rundeck-backup-20130327.tar.gz

I per restaurar, tan fàcil com:

[[email protected] ~]# ./rundeck-backup.sh restore
Rundeck service is not running, so jobs can't be restored. Do you want to start rundeck? (y/N) y
S'està iniciant el rundeckd: [ FET ]
OK - restore finished successfully using /root/rundeck-backup-20130327.tar.gz

També té altres opcions per cobrir totes les circumstàncies que se m’han acudit:

[[email protected] ~]# ./rundeck-backup.sh -h
rundeck_backup - v1.00
Copyleft (c) 2013 Tomàs Núñez Lirola under GPL License
This script deals with rundeck backup/recovery.

Usage: ./rundeck-backup.sh [OPTIONS...] {backup|restore} [backup_file] | -h --help

Options:
-h | --help
Print detailed help
--exclude-config
Don't backup / restore config files
--exclude-projects
Don't backup / restore project definitions
--exclude-keys
Don't backup / restore ssh key files
--exclude-jobs
Don't backup / restore job definitions
--exclude-hosts
Don't backup / restore .ssh/known_hosts file
--include-logs
Include execution logs in the backup / restore procedure (they are excluded by default)
-c | --configdir
Change default rundeck config directory (/etc/rundeck)
-u | --user
Change default rundeck user (rundeck)
-s | --service

Ho he fet el millor que he sabut (i que he tingut ganes :P), o sigui que probablement sigui molt millorable. S'accepten qualsevol tipus de crítiques i suggerències per millorar-ho.

Gràcies!

Migració de rundeck d’un servidor a un altre

La gent de rundeck acaba de treure una nova versió, la 1.5. Actualitzar a aquesta versió no es tan fàcil com les anteriors (normalment yum update o apt-get upgrade) perquè han fet canvis a l’esquema de la base de dades i per això recomanen seguir el proces de backup/recovery per actualitzar.

Fa temps que jo volia moure el rundeck a un altre servidor amb més recursos, i he decidit aprofitar l’actualització per fer-ho. Així que amb aquest article explicarem les passes que he seguit per moure-ho.

Comencem localitzant les parts que volem moure, que son 4:
– Configuració de rundeck
– Definició dels projectes
– Claus ssh dels projectes
– Definició dels jobs
– Logs d’execució dels jobs

La configuració del rundeck està a /etc/rundeck/. Per trobar on està la definició dels projectes haurem de mirar al fitxer /etc/rundeck/project.properties el valor project.dir (per defecte està a /var/rundeck/projects/). El path a les claus ssh dels projectes el trobarem a dintre del etc/project. properties de cada projecte, en el valor project.ssh-keypath. La definició dels jobs està a la base de dades, i podrem veure el path dels logs d’execució al fitxer /etc/rundeck/framework.properties, en el valor framework.logs.dir (normalment /var/lib/rundeck/logs).

Un cop localitzat tot, comencem a fer el “paquet” del rundeck que mourem de servidor a servidor. Comencem amb els fitxers de text, que son la configuració del rundeck, la definició dels projectes i els logs d’execució:


mkdir rundeck-backup
cp -a /etc/rundeck/ rundeck-backup/
cp -a /var/rundeck/projects/ rundeck-backup
cp -a /var/lib/rundeck/logs/ rundeck-backup

I estaria be conserver el fitxer “know_hosts” de l’usuari rundeck:

cp getent passwd rundeck|cut -d":" -f6/.ssh/known_hosts rundeck-backup

for project in rundeck-backup/projects/*;do cp grep project.ssh-keypath $project/etc/project.properties|cut -d"=" -f 2 $project;done

I per extreure de la base de dades la definicio dels jobs, haurem de fer una crida rd-jobs list per cadascun dels projectes, exportant així la definició xml:


for project in rundeck-backup/projects/*;do rd-jobs list -f rundeck-backup/basename $project.xml -p basename $project;done

Amb això tenim un backup complet de la nostra instal·lació. Ara enviem aquest directori rundeck-backup al servidor destí (si, obvi, pero ho poso també :P)

scp -r rundeck-backup [email protected]:.

I ara ens connectem al nou servidor. Donem per suposat que al nou servidor tenim rundeck instal·lat (i si no, en un post anterior vam parlar de com fer-ho), per tant l’únic que haurem de fer es distribuir els fitxers on toca. Primer les claus:


for project in rundeck-backup/projects/*;do filename=grep project.ssh-keypath $project/etc/project.properties|cut -d"=" -f 2;cp $project/basename $filename $filename;done

I després la resta de fitxers

cp -a rundeck-backup/rundeck/ /etc/
cp -a rundeck-backup/projects/ /var/rundeck/
cp -a rundeck-backup/logs/ /var/lib/rundeck/
cp rundeck-backup/known_hosts getent passwd rundeck|cut -d":" -f6/.ssh/known_hosts

Amb això ja tindrem la configuració del rundeck i la definició dels projectes, pero faltaran els jobs. Recordem que al servidor antic també s’estan executant, i no volem que s’executin als dos servidors alhora. Tampoc no volem deshabilitar-los al servidor antic fins que no estem segurs que està tot correcte al servidor nou, perquè no volem que cap d’ells es quedi sense executar. Per aconseguir les dues coses farem que els jobs simulin la seva execució, pero realmente no executin res. Això es fa canviant el valor service.NodeExecutor.default.provider del fitxer /var/rundeck/projects/$PROJECT/etc/project.properties, de jsch-ssh a stub. En una sola línia seria:

sed /var/rundeck/projects/*/etc/project.properties -e 's/jsch-ssh/stub/g' -i

Amb això ja estem segurs que el servidor nou no executarà res fins que nosaltres volguem. Ara ja podem importar els jobs sense risc:

for project in rundeck-backups/projects/*;do rd-jobs load -f rundeck-backup/basename $project.xml -p basename $project;done

Amb els jobs carregats ja ho tenim tot. Ara podem entrar a l’interface web i comprovar que tot és correcte: que els usuaris tenen acces a on toca, que els jobs estan ben configurats, etc, etc. Un cop estem segurs ja podem anar movent projecte a projecte (o tots de cop, com es vulgui) només canviant el valor que parlavem abans (service.NodeExecutor.default.provider). Al servidor vell canviem “jsch-ssh” per “stub” i al nou a l’inrevés, “stub” per “jsch-ssh”. Jugant amb aquests valors estem tranquils que si trobem que hi ha qualsevol problema amb algun projecte, sempre podrem tornar aquest projecte (o tots, per assegurar) al servidor vell mentre el solucionem.

I ja ho tenim! L’únic que podriem fer ara és canviar al DNS el nom per continuar accedint al rundeck amb la mateixa URL, pero això ja és al gust de cadascú.

Instal·lació bàsica de rundeck a RedHat, amb apache com a proxy i mysql com a base de dades

Quan tenim moltes màquines i necessitem executar tasques periòdiques, el cron se’ns queda petit, perquè està repartit per tots els servidors i no hi ha manera senzilla de, per exemple, comprovar quin ha estat el resultat de l’execució d’una tasca a tots els servidors, o quines tasques s’estaven executant entre les 16:33 i les 16:36, o per calcular a quina hora hi ha programades menys coses a l’arquitectura per posar una tasca nova. O milers de coses.

Per centralitzar aquesta informació hi ha algunes alternatives. Fa poc que ha aparegut chronos i té bona pinta, però jo fa un temps que estic fent servir rundeck i estic força content.

Funciona d’una manera molt senzilla: té un servidor programat en java amb una interface grails per l’acces web i un programador quartz per la programació dels esdeveniments. Aquest servidor es connecta via ssh a les màquines per executar-hi les tasques configurades. Això ens permet tenir un cron centralitzat (el que buscàvem originàriament en aquest article), però també podriem fer-lo servir com un sudo centralitzat (podem decidir quin usuari pot executar quina comanda a quins servidors, tot des de la consola web, sense donar-li acces ssh), i també ens permet tenir una consola shell centralitzada per executar una comanda a molts servidors alhora, a l’estil del terminator o més aviat del fabric .

Un cop fetes les presentacions, passem a l’acció i comencem a instal·lar-lo a la nostra RedHat. Per començar hem de tenir en compte que el rundeck s’executa amb l’usuari rundeck, per tant no té privilegis, i per tant no pot funcionar al port 80. Per tal de que funcioni de manera ràpida per aquest exemple, farem un proxypass amb apache. Comencem instal·lant l’apache:


# yum install httpd

Editarem el fitxer /etc/httpd/conf/httpd.conf i afegirem dues línies:


ProxyPass / http://localhost:4440/
ProxyPassReverse / http://localhost:4440/

Així l’apache reenviarà tot el trànsit que rebi al port 80 al port 4440, on el tractarà el rundeck.
Ara les dades. Per defecte el rundeck fa servir un fitxer de text com a base de dades (antigament feia servir hsql, ara fa servir h2). Això està bé, però a partir de cert punt se’ns quedarà petit. Per evitar-ho, voldrem fer servir una base de dades mysql. Primer l’haurem d’instal·lar


yum install mysql mysqld
chkconfig mysqld on

El podem tunejar al gust tocant el my.cnf amb les tipiques default-storage-engine=innodb, innodb_file_per_table, etc, etc. Després hem de crear una base de dades pel rundeck i un usuari amb permisos


[[email protected] rundeck]# mysql -p
Enter password: Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 18536
Server version: 5.5.30 MySQL Community Server (GPL) by Remi

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.

mysql> create database rundeck;
Query OK, 1 row affected (0.00 sec)

mysql> grant all on rundeck.* to 'rundeck'@'localhost' identified by 'password';
Query OK, 0 rows affected (0.00 sec)

mysql> quit
Bye

Ara instal·lem el rundeck, instal·lant primer el repositori oficial del programa, i després el programa en si:


wget http://repo.rundeck.org/latest.rpm
rpm -Uvh latest.rpm
yum install rundeck

I configurem la base de dades al fitxer /etc/rundeck/rundeck-config.properties, comentant la linia existent i afegint-ne unes altres:


#dataSource.url = jdbc:h2:file:/var/lib/rundeck/data/rundeckdb
dataSource.url = jdbc:mysql://localhost/rundeck
dataSource.username = rundeck
dataSource.password = password

I ara l’engegem


/etc/init.d/rundeck start

Podem comprovar que està fent servir la base de dades perque hi haurà creat les seves taules:


[[email protected] rundeck]# mysql -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 31
Server version: 5.5.30 MySQL Community Server (GPL) by Remi

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.

mysql> use rundeck
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+----------------------------+
| Tables_in_rundeck |
+----------------------------+
| auth_token |
| base_report |
| execution |
| node_filter |
| notification |
| rdoption |
| rdoption_values |
| rduser |
| report_filter |
| scheduled_execution |
| scheduled_execution_filter |
| workflow |
| workflow_step |
| workflow_workflow_step |
+----------------------------+
14 rows in set (0.00 sec)

Ja tenim el servidor en marxa. Ara haurem d’exportar la clau publica ssh per poder executar comandes a les maquines desti:


[[email protected] .ssh]# su - rundeck
[[email protected] ~]$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/var/lib/rundeck/.ssh/id_rsa): project1_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in project1_rsa.
Your public key has been saved in project1_rsa.pub.
The key fingerprint is:
f6:be:e5:0r:b2:zd:9b:89:1e:2c:6f:fc:od:e5:a5:00 [email protected]
[[email protected] ~]$ ssh-copy-id -i /var/lib/rundeck/.ssh/project1_rsa [email protected]
[email protected]'s password:
0
The authenticity of host 'server2 (222.333.444.555)' can't be established.
RSA key fingerprint is b6:6z:34:2o:04:2f:j1:71:1e:12:b3:fd:e2:f2:79:cf.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'server2-es,222.333.444.555' (RSA) to the list of known hosts.
Now try logging into the machine, with "ssh [email protected]'", and check in:

.ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.

[[email protected] ~]$ ssh [email protected] whoami
user

Continueu amb mi, que ja gairebé estem. Ara podem entrar a la web amb l’usuari admin i password admin:
rundeck login

I el primer que farà serà demanar-nos que creem un projecte, i aquí posem les dades que hem generat abans

rundeck create project

Quan generem el projecte, apareixerem a la pàgina del mateix, on podrem executar comandes en local:
rundeck home

Ara falta l’últim pas: donar d’alta els servidors remots on executar les comandes. Tal i com hem configurat en la creació del projecte, ho posarem en el fitxer /etc/rundeck/servers/project1 en el següent format:

I un cop ho tinguem ja podrem fer-ho servir sense reiniciar. Nomes cal que apretem el boto “show all nodes”

rundeck home with new server

I amb això ja ho tenim. A partir d’aquí es molt senzill. Des d’aquesta consola podrem executar comandes remotament, i des de la pestanya “jobs” podrem començar a crear jobs.

Hi ha més coses que es poden configurar. Per exemple, per canviar el logo de rundeck pel de la nostra empresa, ho podem posar al fitxer /etc/rundeck/rundeck-config.properties

rundeck.gui.title = Programador de tareas de la nostra empresa
rundeck.gui.logo = logo.jpg
rundeck.gui.logo-width = 68
rundeck.gui.logo-heigh = 31

O si volem crear més usuaris, els haurem d’afegir al fitxer /etc/rundeck/realm.properties

admin: MD5:5a527f8fegf916h8485dj6681ff8d7a6a,user,admin,architect,deploy,build
newuser: MD5:0cddh73e3g6108a7fh5f3716a9jf97and4e56ff,user

I els permisos d’accés es gestionen al fitxer /etc/rundeck/admin.aclpolicy.

I amb això ja tenim la base per poder començar a jugar amb el rundeck.

Crear usuari de graphite

El graphite és una eina molt bona per fer gràfiques. Et permet ràpidament fer-ne de molt completes i aplicant un munt de funcions per treure les dades exactament com les vols. Els paràmetres de configuració de cada gràfica (dades a mostrar, dimensions de la gràfica, llegenda, funcions, etc) estan a la pròpia URL, per tant si volem compartir una gràfica en concret nomes hem de compartir la URL. Però el propi graphite té un sistema per guardar gràfiques y tenir-les a mà a l’apartat “My Graphs” o “User Graphs” que es bastant còmode. Per poder guardar les gràfiques primer ens hem d’autenticar (s’han d’assignar a algun usuari!) i, evidentment, per autenticar-nos hem de tenir un usuari. I a l’anterior post que explicava com instal·lar-lo no ho explicava.

Els usuaris, gràfiques i dashboards estan guardats al fitxer /opt/graphite/storage/graphite.db, que és una base de dades sqlite . Podem mirar el contingut (requereix tenir instal·lat el client sqlite3):

$ cd /opt/graphite/webapp/graphite
$ python manage.py dbshell
Error: You appear not to have the 'sqlite3' program installed or on your path.
$ sudo apt-get install sqlite3
(...)
Processing triggers for man-db ...
Setting up sqlite3 (3.7.3-1) ...
$ python manage.py dbshell
SQLite version 3.7.3
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .databases
seq name file
--- --------------- ----------------------------------------------------------
0 main /opt/graphite/storage/graphite.db
sqlite> .table
account_mygraph auth_user_groups
account_profile auth_user_user_permissions
account_variable dashboard_dashboard
account_view dashboard_dashboard_owners
account_window django_admin_log
auth_group django_content_type
auth_group_permissions django_session
auth_message events_event
auth_permission tagging_tag
auth_user tagging_taggeditem
sqlite> ^D
$

En comptes de tocar aquestes dades nosaltres mateixos (que requeriria que entenguessim exactament el que fan, i ara mateix no tinc l’interes :P), voldrem fer-ho a través del graphite (o millor dit, a través del seu framework, django). En primer lloc necessitem un superusuari, que es crea des de la línia de comandes:


$ cd /opt/graphite/webapp/graphite
$ python manage.py createsuperuser
Username: tomas
E-mail address: [email protected]
Password: xxxxxx
Password (again): xxxxxx
Superuser created successfully.
$

Ara podem entrar amb aquest nom d’usuari i contrassenya al login que apareix a la part superior del graphite.

Fer login al graphite

Un cop autenticats, podrem anar a l’interfície d’administració accedint a “/admin/“, http://your-graphite-server.tld/admin/, i aqui podrem donar d’alta tants usuaris com volguem.

Panel d'administracio django a graphite

Configuració bàsica de Varnish amb http cache i stale-while

En entorns d’alta demanda arriba un moment on les peticions php (o similar, CGI en general) que volem servir a traves del nostre apache httpd son més de les que el nostre servidor pot processar. Per solucionar-ho podem fer el més senzill, que és afegir més servidors a la granja de balanceig i disminuir així la càrrega (es reparteixen les peticions entre més servidors). Però el més senzill no necessariament és el més eficient. En comptes de repartir la càrrega entre més servidors, no podriem fer que cada servidor pogués servir més peticions?

I tant. D’una banda podem fer més ràpid el processament dels PHP (o similar, CGI en general) amb FastCGI. D’altra banda podem fer que el nostre servidor HTTP sigui més ràpid, canviant-lo per un de mes lleuger, com per exemple nginx. Una altra aproximació, de la que parlarem aquí, es tracta de mantenir una cache en memòria dels continguts, en comptes de processar-los cada vegada, evitant així el consum de CPU i accelerant enormement el temps que es triga a servir-los. Ho farem fent servir varnish .

Mantenir una cache és força delicat perquè s’han de tenir en compte moltes coses. No s’hauria de fer cache si hi ha cookies pel mig, per exemple, o si hi la petició http és de tipus POST. Però això es una cosa a avaluar dintre de cada aplicació, els desenvolupadors han de poder indicar què es pot guardar a la cache i què no, i els administradors configurar els servidors en conseqüencia.Aleshores, suposem que comencem de zero, que no tenim res en la cache del varnish, i volem començar posant-hi una URL en concret, de la que sabem que no te risc. Això farem aquí, caché selectiva d’una sola URL.

Per il·lustrar la nostra demostració, farem servir un fitxer PHP senzill que triga 10 segons a tornar el resultat, i que té una capçalera que el fa caducar en 5 segons. L’anomenarem sleep.php:

Si el demanem comprovarem que efectivament triga 10 segons a servir-se:

El primer que hem de fer es instal·lar varnish amb el nostre gestor de paquets (apt-get install varnish, yum install varnish, el que sigui). Després voldrem que sigui el varnish qui escolti pel port 80 en comptes de l’apache. Per això mourem el apache de port (directiva “Listen: “), i el posarem al 8080, per exemple. Després canviarem el port del varnish (directiva VARNISH_LISTEN_PORT= , normalment esta al fitxer /etc/default/varnish o /etc/sysconfig/varnish, depenent de la distro). Necessitem dir-li al varnish quins servidors tindrà darrera, als que ha de reenviar les peticions (els servidors backend). Per això crearem el fitxer /etc/varnish/default.vcl amb el següent contingut:

Amb tot això reiniciem tant el apache com el varnish, i podrem comprobar que estan ambdos en marxa:

Veiem que les capçaleres que retornen un i l’altre són diferents. Quan demanem al varnish apareixen “Via: 1.1 varnish” i “Age: 0”, entre d’altres que amb l’apache no apareixen. Si ho tenim així, ja tenim la base configurada.

El comportament que tindrem ara mateix es de fer cache de tot.

Però com que volem ser selectius i no volem fer cache de tot, sino de algunes URL en concret, evitant que es faci cache de cookies i coses semblants, canviarem el comportament de la rutina sub vcl_recv perque no faci cache, afegint això al fitxer /etc/varnish/default.vcl:

Ho comprovem:

Ara fem que faci cache només del fitxer sleep.php, afegint aixo al default.vcl:

Ho podem comprovar:

També comprovem que la capçalera “Age:” va pujant, i quan arriba a 5 (el max-age que li hem configurat), torna a trigar 10 segons:

Veiem que quan el contingut caduca, el torna a demanar i triga 10 segons. Pero què passa en aquest interval? La resta de peticions que arriben al varnish mentre es fa aquesta petició al backend, s’han d’esperar? Doncs no. Hi ha un periode de gràcia de 10 segons, durant els quals el varnish continuará servint l’objecte antic (o “ranci”, “stale” en anglés). Ho podem comprobar si fem dos curl alhora, en comptes d’un, i veurem com n’hi ha un que s’atura mentre l’altre continua servint les pagines ràpid, amb la capçalera “Age” per sobre dels 5 segons que li hem assignat:

També podem comprovar-ho amb el siege, posant dos usuaris concurrents, i veurem com durant una estona només un d’ells serveix contingut, pero que en cap moment es deixa de rebre continguts:

Si ens sembla que 10 segons de gràcia és massa poc, podem canviar aquest valor amb la directiva beresp.grace dintre de la rutina vcl_fetch al fitxer default.vcl. Per exemple, si volem posar un minut:

I si cau el servidor backend? Continuará servint el contingut antic (“stale“)? Doncs tal i com ho tenim, no. Perquè tal i com ho tenim, al varnish no li hem configurat res per distingir entre un backend saludable i un que no ho és, per tant els considerarà tots saludables. Per tant, si el backend cau, i el contingut caduca, tornarem error 503:

D’aquesta manera es continua servint el contingut antic quan el backend cau, i el servim fins que s’aixequi i el varnish pugui tornar a demanar-li el contingut.

Fent proves amb el siege i curl, podem veure que tant en el cas del contingut que caduca com en el cas del servidor que cau, sempre hi ha un fil que “pringa”. La primera vegada que el varnish es troba amb el contingut caducat, el demana i espera que acabi. Mentrestant, la resta de fils reben el contingut antic, pero aquest fil “pringa”. El mateix passa amb el servidor caigut. Hi ha molta literatura intentant trobar la manera d’evitar que això passi, i pots llegir molt al respecte, pero el resum es que no hi ha manera d’evitar-ho. Que passa i punt. Un d’els fils “pringa”.

Amb això cobrim dos casos en els quals continuarem servint continguts antics (stale):
– No hi ha cap backend disponible, per tant servim contingut antic.
– Hi ha backends disponibles, i un fil ja ha demanat nou contingut. Mentre aquest nou contingut arriba des del backend, el varnish continua servint l’antic a la resta de fils.

I si volem que aquests dos casos tinguin un timeout diferent? Per exemple, pot donar-se el cas que volguem que, si el backend està disponible, els continguts caducats triguin un temps màxim. Passat aquest temps, deixem de servir el contingut antic i forcem a que s’esperin per al contingut nou. Aquest timeout normalment serà d’uns segons. I alhora, volem que si els backends estan caiguts, i per tant no hi ha manera d’aconseguir contingut nou, que el varnish continui servint el contingut antic durant molta estona, que normalment és millor que estar servint una pàgina d’error 503. Això s’ha de configurar a la rutina vcl_recv del default.vcl, i es fa aixi:

Per tant, el nostre fitxer default.vcl complet tindra el seguent contingut: