SlideShare una empresa de Scribd logo
1 de 336
Descargar para leer sin conexión
Jorge&Bas*da
me@jorgebas*da.com
@jorgebas*da
Jaime&Irurzun
jaime@irurzun.com
@jaimeirurzun
Open Source
Modern web development
env environment
Open source modern
web development
!
⚒
#
dev development
ops operations
dev1
ops2
env3
browser
http
optimización
arquitectura
despliegue
seguridad
monitorización
provisionamiento
herramientas
buenas prácticas
dev1
ops2
env3
browser
http
optimización
arquitectura
despliegue
seguridad
monitorización
provisionamiento
herramientas
buenas prácticas
Browser1
renderiza
ejecuta
habla
Browser
Más que un terminal tonto,
pero no tanto más
HTML + CSS
JavaScript
HTTP (+DNS)
HTML + CSS
JavaScript
HTTP (+DNS)
Browser
Más que un terminal tonto,
pero no tanto más
frontend
backend
renderiza HTML + CSS
<html>
<head>
<title>Example</title>
<link rel="stylesheet"
type="text/css"
href="example.css">
</head>
<body>
<h1>Title</h1>
<p>
This is <strong>important</strong>.
</p>
</body>
</html>
body { font-family: 'Arial'; }
strong { color: red; }
+ =
example.html
example.css
ejecuta JavaScript
<html>
...
<body>
<h1>Title</h1>
...
<script type="text/javascript"
src="example.js"></script>
</body>
</html>
document.getElementsByTagName('h1')
[0].onclick = function() {
alert("You've clicked!");
};
+ =
example.html
example.js
¿qué ocurre
por detrás?
habla HTTP (+DNS)
Escribes una URL en el navegador1
Se hace una petición DNS
para traducir el hostname de
la URL a su dirección IP
2
Se hace una petición HTTP a esa IP pidiendo el recurso / y se
recibe el resultado, normalmente un fichero .html
3
www.wikipedia.org
91.198.174.225
91.198.174.225
GET / HTTP/1.1
...
HTTP/1.1 200 OK
...
$#
El navegador comienza a renderizar el HTML y hace más
peticiones [DNS+] HTTP para cada recurso (css, img, js, etc)
que encuentre referenciado en el código (src=..., href=...)
4
<div class="central-featured-logo-inner">
<img src="//upload.wikimedia.org/wikipedia/commons/Wikipedia-logo.png">
</div>
A partir de aquí, y hasta la próxima petición HTTP que fuerce
una recarga completa de la página, todo lo que puede ocurrir
son efectos CSS y código JavaScript.
5
Desde JavaScript podemos hacer peticiones HTTP asíncronas
(AJAX) que fuercen acciones en el servidor y como resultado
realicen cambios en el DOM de la página.Y esto es todo.
El navegador comienza a renderizar el HTML y hace más
peticiones [DNS+] HTTP para cada recurso (css, img, js, etc)
que encuentre referenciado en el código (src=..., href=...)
4
<div class="central-featured-logo-inner">
<img src="//upload.wikimedia.org/wikipedia/commons/Wikipedia-logo.png">
</div>
A partir de aquí, y hasta la próxima petición HTTP que fuerce
una recarga completa de la página, todo lo que puede ocurrir
son efectos CSS y código JavaScript.
5
Desde JavaScript podemos hacer peticiones HTTP asíncronas
(AJAX) que fuercen acciones en el servidor y como resultado
realicen cambios en el DOM de la página.Y esto es todo.
HTTP es el idioma de la web
y hay que conocerlo
dev1
ops2
env3
browser
http
optimización
arquitectura
despliegue
seguridad
monitorización
provisionamiento
herramientas
buenas prácticas
HTTP2
físico
enlace de datos
red
transporte
sesión
presentación
aplicación
Modelo OSI
Hardware
Acceso al medio (MAC)
Enrutamiento entre redes
Transmisión fiable del mensaje
Diálogo
Codificación, cifrado, compresión...
Contenido del mensaje
acceso al medio
red
transporte
aplicación
TCP/IP
físico
enlace de datos
red
transporte
sesión
presentación
aplicación
Modelo OSI
http, ftp,
smtp, pop,
imap, ssh,
irc, ...
TCP, UDP
IP
ethernet,
token ring,
fddi, ...
HTTP
Protocolo de manipulación de recursos, sin estado
<OPERACIÓN> <recurso> HTTP/1.1
<cabeceras>
<cuerpo>
HTTP/1.1 <código> <descripción>
<cabeceras>
<cuerpo>
Petición
Respuesta
$
#
HTTP
Protocolo de manipulación de recursos, sin estado
<OPERACIÓN> <recurso> HTTP/1.1
<cabeceras>
<cuerpo>
HTTP/1.1 <código> <descripción>
<cabeceras>
<cuerpo>
Respuesta
Petición
$
#
HTTP
Protocolo de manipulación de recursos, sin estado
<OPERACIÓN> <recurso> HTTP/1.1
<cabeceras>
<cuerpo>
HTTP/1.1 <código> <descripción>
<cabeceras>
<cuerpo>
Petición
Respuesta
$
#
Un recurso se identifica mediante una URL
<OPERACIÓN> <recurso> HTTP/1.1
protocol://[user:pass@]host[:port][/resource]
en http, por defecto:
user = pass =
port = 80
resource = /
http://www.wikipedia.org:80/
<OPERACIÓN> <recurso> HTTP/1.1
Las URLs son parte fundamental
del diseño de una aplicación web
http://www.wordpress.org/
http://www.wordpress.org/about/
http://www.wordpress.org/support/
http://www.wordpress.org/extend/themes/
http://www.wordpress.org/extend/themes/montezuma
...
HTTP
Protocolo de manipulación de recursos, sin estado
<OPERACIÓN> <recurso> HTTP/1.1
<cabeceras>
<cuerpo>
HTTP/1.1 <código> <descripción>
<cabeceras>
<cuerpo>
Petición
Respuesta
$
#
GET Obtiene un recurso. No debería producir cambios.
POST
PUT
Crea un recurso.
Reemplaza o crea un recurso.
DELETE Elimina un recurso.
<OPERACIÓN> <recurso> HTTP/1.1
HEAD Como GET, pero pide sólo las cabeceras.
TRACE Diagnóstico.
OPTIONS Pregunta por los métodos que soporta el servidor.
CONNECT Diagnóstico.
<OPERACIÓN> <recurso> HTTP/1.1
REST es un enfoque de diseño de APIs que,
entre otras cosas, explota la pureza de estos conceptos
http://example.com/recetas/
http://example.com/recetas/453
PUT
GET
POST
DELETE
PUT
GET
POST
DELETE
Lista las URIs de recetas y quizá otros detalles.
Reemplaza la colección de recetas por una nueva.
Inserta una nueva receta y devuelve su URI.
Borra la colección de recetas.
Devuelve el detalle de una receta.
Reemplaza o crea (si no existe) una receta.
---
Borra una receta.
+
La navaja suiza de las URLs
cURL
La navaja suiza de las URLs
$ curl example.com/recetas
$ curl -XGET example.com/recetas
$ curl -XPOST example.com/recetas
$ curl -XPUT example.com/recetas
$ curl -XDELETE example.com/recetas
cURL
La navaja suiza de las URLs
$ curl example.com/recetas
$ curl -XGET example.com/recetas
$ curl -XPOST example.com/recetas
$ curl -XPUT example.com/recetas
$ curl -XDELETE example.com/recetas
cURL
$ curl -X GET google.com
<HTML><HEAD><meta http-equiv="content-type"
content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>
cURL
La navaja suiza de las URLs
HTTP
Protocolo de manipulación de recursos, sin estado
<OPERACIÓN> <recurso> HTTP/1.1
<cabeceras>
<cuerpo>
HTTP/1.1 <código> <descripción>
<cabeceras>
<cuerpo>
Petición
Respuesta
$
#
<cabeceras>
Son parejas Clave: valor que transmiten al
servidor información acerca de la request
Accept: text/plain
Accept-Charset: utf-8
Accept-Encoding: gzip, deflate
Accept-Language: en-US
Accept-Datetime: Thu, 31 May 2007 20:35:00 GMT
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Cache-Control: no-cache
Connection: keep-alive
Cookie: $Version=1; Skin=new;
Content-Length: 348
<cabeceras>
Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ==
Content-Type: application/x-www-form-urlencoded
Date: Tue, 15 Nov 1994 08:12:31 GMT
Expect: 100-continue
From: user@example.com
Host: en.wikipedia.org:80
If-Match: "737060cd8c284d8af7ad3082f209582d"
If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
If-None-Match: "737060cd8c284d8af7ad3082f209582d"
If-Range: "737060cd8c284d8af7ad3082f209582d"
If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT
<cabeceras>
Max-Forwards: 10
Origin: http://www.example-social-network.com
Pragma: no-cache
Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Range: bytes=500-999
Referer: http://en.wikipedia.org/wiki/Main_Page
TE: trailers, deflate
Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, ...
User-Agent: Mozilla/5.0 (X11; Linux x86_64; ...
Via: 1.0 fred, 1.1 example.com (Apache/1.1)
Warning: 199 Miscellaneous warning
X-<YYY>: ZZZ
cURL:ver cabeceras
$ curl -v -X GET google.com
* About to connect() to google.com port 80 (#0)
* Trying 173.194.41.8...
* connected
* Connected to google.com (173.194.41.8) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5
> Host: google.com
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Location: http://www.google.com/
< Content-Type: text/html; charset=UTF-8
< Date: Mon, 06 May 2013 08:03:50 GMT
< Expires: Wed, 05 Jun 2013 08:03:50 GMT
< Cache-Control: public, max-age=2592000
< Server: gws
< Content-Length: 219
< X-XSS-Protection: 1; mode=block
< X-Frame-Options: SAMEORIGIN
<
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>
* Connection #0 to host google.com left intact
* Closing connection #0
cURL:enviar cabeceras
$ curl -v -X GET google.com -H 'User-Agent: Mozilla/5.0'
* About to connect() to google.com port 80 (#0)
* Trying 173.194.41.232...
* connected
* Connected to google.com (173.194.41.232) port 80 (#0)
> GET / HTTP/1.1
> Host: google.com
> Accept: */*
> User-Agent: Mozilla/5.0
>
< HTTP/1.1 301 Moved Permanently
< Location: http://www.google.com/
< Content-Type: text/html; charset=UTF-8
< Date: Mon, 06 May 2013 08:16:10 GMT
< Expires: Wed, 05 Jun 2013 08:16:10 GMT
< Cache-Control: public, max-age=2592000
< Server: gws
< Content-Length: 219
< X-XSS-Protection: 1; mode=block
< X-Frame-Options: SAMEORIGIN
<
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>
* Connection #0 to host google.com left intact
* Closing connection #0
HTTP
Protocolo de manipulación de recursos, sin estado
<OPERACIÓN> <recurso> HTTP/1.1
<cabeceras>
<cuerpo>
HTTP/1.1 <código> <descripción>
<cabeceras>
<cuerpo>
Petición
Respuesta
$
#
<cuerpo>
Content-Type: application/json
application/pdf
application/x-www-form-urlencoded
multipart/form-data
image/jpeg
text/plain
video/mpeg
...
Tiene sentido en peticiones PUT y POST.
Su formato lo define la cabecera Content-Type:
<cuerpo>
POST /blog/posts HTTP/1.1
Accept: application/json
Content-Type: application/json
Content-Length: 57
Host: www.example.com:80
{"title":"Hello!","body":"This is my first post!"}
POST /blog/posts HTTP/1.1
Accept: */*
Content-Type: application/x-www-form-urlencoded
Content-Length: 47
Host: www.example.com:80
title=Hello%21&body=This+is+my+first+post%21
<cuerpo>
POST /blog/posts HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Content-Type: multipart/form-data; boundary=AaB03x
Content-Length: 240
Host: www.example.com:80
--AaB03x
Content-Disposition: form-data; name="name"
Larry
--AaB03x
Content-Disposition: form-data; name="files"
Content-Type: multipart/mixed; boundary=BbC04y
--BbC04y
Content-Disposition: file; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--BbC04y
Content-Disposition: file; filename="file2.gif"
Content-Type: image/gif
Content-Transfer-Encoding: binary
...contents of file2.gif...
--BbC04y--
--AaB03x--
cURL:cuerpo de una petición
$ curl -v -X POST localhost:8000/jugadores/ -d "username=pablo"
* About to connect() to localhost port 8000 (#0)
* Trying ::1...
* Connection refused
* Trying 127.0.0.1...
* connected
* Connected to localhost (127.0.0.1) port 8000 (#0)
> POST /jugadores/ HTTP/1.1
> User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5
> Host: localhost:8000
> Accept: */*
> Content-Length: 14
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 14 out of 14 bytes
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Date: Mon, 06 May 2013 07:48:08 GMT
< Server: WSGIServer/0.1 Python/2.7.2
< Content-Type: text/html; charset=utf-8
<
...
...
* Closing connection #0
HTTP
Protocolo de manipulación de recursos, sin estado
<OPERACIÓN> <recurso> HTTP/1.1
<cabeceras>
<cuerpo>
HTTP/1.1 <código> <descripción>
<cabeceras>
<cuerpo>
Petición
Respuesta
$
#
HTTP
Protocolo de manipulación de recursos, sin estado
<OPERACIÓN> <recurso> HTTP/1.1
<cabeceras>
<cuerpo>
HTTP/1.1 <código> <descripción>
<cabeceras>
<cuerpo>
Petición
Respuesta
$
#
HTTP/1.1 <código> <descripción>
200 OK
201 Created
202 Accepted
203 Non-Authoritative Information
204 No Content
205 Reset Content
206 Partial Content
✓
ℹ
1XX Informational
2XX Success
100 Continue
101 Switching Protocols
300 Multiple Choices
301 Moved Permanently
302 Found
303 See Other
304 Not Modified
305 Use Proxy
306 (Unused)
307 Temporary Redirect

3XX Redirection
HTTP/1.1 <código> <descripción>
#
4XX Client Error
400 Bad Request
401 Unauthorized
402 Payment Required
403 Forbidden
404 Not Found
405 Method Not Allowed
406 Not Acceptable
407 Proxy Authentication Required
408 Request Timeout
409 Conflict
410 Gone
411 Length Required
412 Precondition Failed
413 Request Entity Too Large
414 Request-URI Too Long
415 Unsupported Media Type
416 Requested Range Not Satisfiable
417 Expectation Failed
500 Internal Server Error
501 Not Implemented
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
505 HTTP Version Not
Supported
5XX Server Error
$
HTTP
Protocolo de manipulación de recursos, sin estado
<OPERACIÓN> <recurso> HTTP/1.1
<cabeceras>
<cuerpo>
HTTP/1.1 <código> <descripción>
<cabeceras>
<cuerpo>
Petición
Respuesta
$
#
<cabeceras>
Access-Control-Allow-Origin: *
Accept-Ranges: bytes
Age: 12
Allow: GET, HEAD
Cache-Control: max-age=3600
Connection: close
Content-Encoding: gzip
Content-Language: en
Content-Length: 348
Content-Location: /index.html
Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ==
Content-Disposition: attachment; filename="f.txt"
<cabeceras>
Content-Range: bytes 21010-47021/47022
Content-Type: text/html; charset=utf-8
Date: Tue, 15 Nov 1994 08:12:31 GMT
ETag: "737060cd8c284d8af7ad3082f209582d"
Expires: Thu, 01 Dec 1994 16:00:00 GMT
Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT
Link: </feed>; rel="alternate"[25]
Location: http://www.w3.org/pub/WWW/People.html
P3P: CP="This is not a P3P policy! See..."
Pragma: no-cache
Proxy-Authenticate: Basic
Refresh: 5; url=http://...
<cabeceras>
Retry-After: 120
Server: Apache/2.4.1 (Unix)
Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1
Status: 200 OK
Strict-Transport-Security: max-age=16070; includeSubDomains
Trailer: Max-Forwards
Transfer-Encoding: chunked
Vary: *
Via: 1.0 fred, 1.1 example.com (Apache/1.1)
Warning: 199 Miscellaneous warning
WWW-Authenticate: Basic
X-<YYY>: ZZZ
HTTP
Protocolo de manipulación de recursos, sin estado
<OPERACIÓN> <recurso> HTTP/1.1
<cabeceras>
<cuerpo>
HTTP/1.1 <código> <descripción>
<cabeceras>
<cuerpo>
Petición
Respuesta
$
#
<cuerpo>
HTTP/1.1 200 OK
Content-Type: text/html
Date: Thu, 31 May 2007 20:35:00 GMT
<html>
<head>
<title>Web page</title>
</head>
<body>
<h1>Hello world</h1>
</body>
</html>
HTTP
Protocolo de manipulación de recursos, sin estado
<OPERACIÓN> <recurso> HTTP/1.1
<cabeceras>
<cuerpo>
HTTP/1.1 <código> <descripción>
<cabeceras>
<cuerpo>
Petición
Respuesta
$
#
HTTP/1.1 200 OK
Content-Type: text/html
Date: Thu, 31 May 2007 20:35:00 GMT
<html>
<body>
<h1>Hello world</h1>
</body>
</html>
HTTP/1.1 304 Not Modified
Date: Thu, 06 Jun 2007 19:40:00 GMT
HTTP Imprescindible
HTTP/1.1 301 Moved Permanently
Location: http://www.example.com/new/url/
HTTP/1.1 302 Found
Location: http://www.example.com/other/url/
HTTP/1.1 303 See Other
Location: http://www.example.com/other/url/
HTTP/1.1 307 Temporary Redirect
Location: http://www.example.com/other/url/
http 1.0
http 1.1
GET
XXX
GET
XXX
HTTP Imprescindible
HTTP/1.1 400 Bad Request
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="..."
HTTP/1.1 403 Forbidden
HTTP/1.1 404 Not Found
HTTP/1.1 405 Method Not Allowed
HTTP/1.1 410 Gone
HTTP Imprescindible
HTTP/1.1 500 Internal Server Error
HTTP/1.1 501 Not Implemented
HTTP/1.1 502 Bad Gateway
HTTP/1.1 503 Service Unavailable
HTTP Imprescindible
Cookies
Solucionan la falta de estado del protocolo HTTP
$#
$#
Son simples strings que se almacenan en el navegador
GET / HTTP/1.1
...
GET / HTTP/1.1
Cookie: sessionid=xxx
HTTP/1.1 200 OK
Set-Cookie: sessionid=xxx
HTTP/1.1 200 OK
...
Cliente Servidor
Cookies
Set-Cookie: sessionid=xxx; Domain=docs.foo.com; Path=/accounts;
Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly
En qué requests debería enviarse como Cookie:Domain + Path
Expires Cuándo el User-Agent debería borrar la cookie
Secure Sólo debe enviarse si el tráfico es https
HttpOnly Sólo accessible desde HTTP, no desde JavaScript
XSS!⚠document.cookie = ...
Cookies
Set-Cookie: sessionid=xxx; Domain=docs.foo.com; Path=/accounts;
Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly
En qué requests debería enviarse como Cookie:Domain + Path
Expires Cuándo el User-Agent debería borrar la cookie
Secure Sólo debe enviarse si el tráfico es https
HttpOnly Sólo accessible desde HTTP, no desde JavaScript
XSS!⚠document.cookie = ...
Método sencillo para proveer de autenticación a peticiones
HTTP, sin necesidad de cookies
$# GET / HTTP/1.1
...
Cliente Servidor
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Login"
Basic HTTP auth
Basic HTTP auth
Método sencillo para proveer de autenticación a peticiones
HTTP, sin necesidad de cookies
$# GET / HTTP/1.1
...
Cliente Servidor
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Login"
$# GET / HTTP/1.1
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
HTTP/1.1 200 OK
...
base64(username:password) HTTPS!⚠
cURL:Basic HTTP auth
$ curl -v -X GET localhost:8000/ --user pablo:x6f8
* About to connect() to localhost port 8000 (#0)
* Trying ::1...
* Connection refused
* Trying 127.0.0.1...
* connected
* Connected to localhost (127.0.0.1) port 8000 (#0)
* Server auth using Basic with user 'pablo'
> GET / HTTP/1.1
> Authorization: Basic cGFibG86eDZmOA==
> User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5
> Host: localhost:8000
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Date: Mon, 06 May 2013 08:36:25 GMT
< Server: WSGIServer/0.1 Python/2.7.2
< Content-Type: text/html; charset=utf-8
<
Bienvenido a la mazmorra, espera instrucciones!
* Closing connection #0
Ejercicio cURL: La guarida del dragón.
$ curl -v -XPOST 10.172.104.175/jugadores/ -d "username=pablo"
)
dev1
ops2
env3
browser
http
optimización
arquitectura
despliegue
seguridad
monitorización
provisionamiento
herramientas
buenas prácticas
HTTPS*
acceso al medio
red
transporte
aplicación
físico
enlace de datos
red
transporte
sesión
presentación
aplicación HTTP
TLS/SSL
HTTPS
HTTPS
$# Certificado
Public key (P)
P(K)
Ok
K = ...
Clave simétrica compartida mediante algoritmo asimétrico
K(mensaje)
K(mensaje)
Cliente Servidor
+
Otras navajas suizas
tcpflow
$ sudo tcpflow -i eth0 port 80 -C
Sniffer de tráfico TCP por excelencia en UNIX
Chrome inspector
dev1
ops2
env3
browser
http
optimización
arquitectura
despliegue
seguridad
monitorización
provisionamiento
herramientas
buenas prácticas
Optimización3
Cliente
Servidor
Canal
Cachear, Delegar, Indexar
varnish, redis, cron, batch...
Reducir request ( número y tamaño )
Minify, sprites, gzip, cdn...
Cachear + Optimizar
Cache, dns lookups, redirects, etags...
Optimización3
Cliente
Servidor
Canal
Cachear, Delegar, Indexar
varnish, redis, cron, batch...
Reducir request ( número y tamaño )
Minify, sprites, gzip, cdn...
Cachear + Optimizar
Cache, dns lookups, redirects, etags...
Optimización3
Servidor3.1
Cachear3.1.1
Contenido
Request Response
Varnish
Request
30m 10m no-cache
Memcached, redis etc...
Contenido externo
• APIs, RSS, Twitter
Contenido “Estático”
• Últimas noticias
• Nuevos usuarios
• Últimos tweets
• ...
Cachear Contenido3.1.1
> GET last_tweets
<h1>n<ul><li>Hello from....
Memcached
•Ventajas
• Velocidad
• Sencillez
•Inconvenientes
• Volátil: sólo reside en memoria.
• Sólo entiende cadenas de texto.
Cachear Contenido3.1.1
> INCR message:143:comments 1
4445
Redis
•Ventajas
• Velocidad
• Tipos de datos complejos
• Operaciones atómicas
•Inconvenientes
• Muy pocas
• Abuso = Problemas (como todo)
Welcome to my site.
4445 Comments
Cachear Contenido3.1.1
Existen múltiples “puntos” donde cachear.
•Servidor web
• Intrusismo
• Complejidad media
•Código del proyecto “backend”
• Sencillo de implementar
• Poco eficiente
•Proxy
• Sencillo
• Muy eficiente
Cachear Requests3.1.1
•Requests Anónimas
• Digg effect
• Landing page
• Google
•Contenido Estático
• Assets
• Thumbnails
•APIs
•“Hot Pages”
Request Response
Varnish
Server
Miss
Hit
Cachear Requests3.1.1
Request
* Versión muy simplificada del funcionamiento de Varnish
Varnish
Varnish3.1.1
Request vcl_recv()
* Versión muy simplificada del funcionamiento de Varnish
Varnish
Varnish3.1.1
Request vcl_recv()
lookup
* Versión muy simplificada del funcionamiento de Varnish
in
cache?
Varnish
Varnish3.1.1
Request vcl_recv()
lookup
* Versión muy simplificada del funcionamiento de Varnish
in
cache?
yes
Varnish
Varnish3.1.1
Request vcl_recv()
lookup
* Versión muy simplificada del funcionamiento de Varnish
in
cache?
Build Response
yes
Varnish
Varnish3.1.1
Request vcl_recv()
lookup
* Versión muy simplificada del funcionamiento de Varnish
in
cache?
Build ResponseResponse
yes
Varnish
Varnish3.1.1
Request vcl_recv()
pass
lookup
* Versión muy simplificada del funcionamiento de Varnish
in
cache?
no
Build ResponseResponse
yes
Varnish
Varnish3.1.1
Request vcl_recv()
Backend
pass
lookup
* Versión muy simplificada del funcionamiento de Varnish
in
cache?
no
Build Response
vcl_fetch()
Response
yes cache?
Varnish
Varnish3.1.1
Request vcl_recv()
Backend
pass
lookup
* Versión muy simplificada del funcionamiento de Varnish
in
cache?
no
Build Response
vcl_fetch()
Response
yes cache?
no
Varnish
Varnish3.1.1
Request vcl_recv()
Backend
pass
lookup
* Versión muy simplificada del funcionamiento de Varnish
in
cache?
no
Build Response
vcl_fetch()
Response
yes
Cache
cache?
yesno
Varnish
Varnish3.1.1
sub vcl_recv {
# Pass anything other than GET and HEAD directly.
if (req.request != "GET" && req.request != "HEAD"){
return(pass);
}
# Always lookup static files from the cache.
# We don't need request cookies neither Authorization.
if (req.request == "GET" && req.url ~ "^/static/") {
unset req.http.cookie;
unset req.http.Authorization;
return(lookup);
}
# Remove any cookie we don't know about except `sessionid`.
if (req.http.Cookie) {
set req.http.Cookie = ";" + req.http.Cookie;
set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
set req.http.Cookie = regsuball(req.http.Cookie, ";(sessionid)=", "; 1=");
set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");
if (req.http.Cookie == "") {
# If there are no cookies, remove the header and lookup the cache.
unset req.http.Cookie;
return(lookup);
}
else {
# If `sessionid` cookie is pressent pass the request to the backend.
return (pass);
}
}
}
vcl_recv
sub vcl_fetch {
# If the response status >= 400 don't cache it.
if (beresp.status >= 400) {
return (hit_for_pass);
}
# Remove cookies if this is a static request and set 1 week of ttl.
if (req.url ~ "^/static/") {
unset beresp.http.set-cookie;
set beresp.ttl = 1w;
return (deliver);
}
else{
# If the response is setting any cookie, don't cache it.
if (beresp.http.Set-Cookie) {
return (hit_for_pass);
}
# Cache this response for 10 minutes.
set beresp.ttl = 10m;
return (deliver);
}
}
vcl_fetch
Demo Varnish3A
Delegar3.2
$#
Cliente Servidor
500ms
bd
!
,smtp200ms
5s
Dejar que alguien haga el trabajo sucio, antes o después
csv
#
Delegar3.2
$#
Cliente Servidor
500ms
bd
!
,smtp200ms
5s
¿Cuánto del trabajo sucio es imprescindible al instante?
csv
#
?
?
?
Delegar3.2
$#
Cliente Servidor
500ms
bd
!
,smtp200ms
5s
¿Cuánto del trabajo sucio es imprescindible al instante?
csv
# ?
¿caché?
?
Delegar3.2
$#
Cliente Servidor
500ms
bd
!
,smtp200ms
5s
¿Cuánto del trabajo sucio es imprescindible al instante?
csv
# ?
¿caché?
¿tarea
periódica?
Delegar3.2
$#
Cliente Servidor
500ms
bd
!
,smtp200ms
5s
¿Cuánto del trabajo sucio es imprescindible al instante?
csv
#
¿caché?
¿tarea
periódica?
¿cola de
mensajes?
Delegar3.2
$#
Cliente Servidor
500ms
bd
!
,smtp200ms
5s
¿Cuánto del trabajo sucio es imprescindible al instante?
csv
#
¿caché?
Delegar
antes
Delegar
después
Scheduler de trabajos de UNIX
cron
* * * * * <cmd>
día de la semana (0 - 7)
mes (1 - 12)
día del mes (1 - 31)
hora (0 - 23)
minuto (0 - 59)
# crontab -e
$ crontab -e
Scheduler de trabajos de UNIX
# crontab -l
0 1 * * * /usr/sbin/ntpdate pool.ntp.org
0 */2 * * * /home/root/bin/server-backup
@reboot /home/root/bin/email-admins.sh
cron
$ crontab -l
*/5 * * * * /home/ops/bin/billing.sh
@hourly /home/ops/bin/caches.py
@daily /home/ops/bin/users-csv.py
@weekly /home/ops/bin/spending-reports.sh
Delegar3.2
$#
Cliente Servidor
500ms
bd
!
,smtp200ms
5s
¿Cuánto del trabajo sucio es imprescindible al instante?
csv
#
¿caché?
Delegar
antes
Delegar
después
Celery3.2
Sistema de Tareas Asíncronas distribuidas.
• Features: Colas, Concurrencia, Distribuido...
• Pro: Muy fácil de implementar y escalable.
• Casos prácticos:
• Enviar un email (Notificationes, ...)
• Calcular el karma de de los usuarios del sistema.
• Tareas programadas (Limpieza, Post-procesado, etc...)
• Regenerar caches etc..
!h#p://celeryproject.org
Celery3.2
El principal componente es el Broker. Se encarga de almacenar y
entregar tareas a todos los workers.
Estable
Experimental
Celery+RabbitMQ3.2
Celery+RabbitMQ3.2
Funcionamiento3.2
Server #1
celery worker
celery beat
Server #3
celery worker
Server #4
web node
Server #5
web node
añadir
procesarprocesar
añadir
añadir
Server #2
celery worker
procesar
Funcionamiento3.2
Server #1
celery worker
celery beat
Server #3
celery worker
Server #4
web node
Server #5
web node
añadir
procesarprocesar
añadir
añadir
Server #2
celery worker
procesar
Funcionamiento3.2
Server #1
celery worker
celery beat
Server #3
celery worker
Server #4
web node
Server #5
web node
añadir
procesarprocesar
añadir
añadir
Server #2
celery worker
procesar
Funcionamiento3.2
Conceptos clave:
• Atómico: Las tareas se entregan solo a un worker.
• Distribuido: Los nodos son independientes unos de otros y el
número puede aumentar y disminuir dinámicamente.
• Fiable: Si no se informa a RabbitMQ sobre la finalización de
una tarea, esta vuelve a formar parte de la cola. En caso de
catástrofe no perdemos tareas.
• Rates: Celery nos permite definir rates para nos sobrecargar el
sistema o APIs externas.
• Tareas Periodicas: Celery beat registrará por nosotros tareas en
la cola de la misma manera que lo haría cron.
Indexar3.3
Preparar la información para acceder más
rápido a ella en el momento de la consulta
! DB Search-
!DB index
SELECT date(timestamp) as day, count(*)
FROM stamp WHERE key=%s AND date(timestamp) > current_date - interval %s
GROUP BY day ORDER BY day;
BEGIN;
DROP TABLE IF EXISTS "stamp";
CREATE TABLE "stamp" (
"key" varchar(255) NOT NULL,
"timestamp" timestamp without time zone NOT NULL
)
;
COMMIT;
con 4.221.883 registros, 11.488 segundos
BEGIN;
DROP TABLE IF EXISTS "stamp";
CREATE TABLE "stamp" (
"key" varchar(255) NOT NULL,
"timestamp" timestamp without time zone NOT NULL
)
;
CREATE INDEX "stamp_key_idx" ON stamp(key);
COMMIT;
SELECT date(timestamp) as day, count(*)
FROM stamp WHERE key=%s AND date(timestamp) > current_date - interval %s
GROUP BY day ORDER BY day;
con 4.221.883 registros,
!DB index
11.488 segundos
BEGIN;
DROP TABLE IF EXISTS "stamp";
CREATE TABLE "stamp" (
"key" varchar(255) NOT NULL,
"timestamp" timestamp without time zone NOT NULL
)
;
CREATE INDEX "stamp_key_idx" ON stamp(key);
COMMIT;
SELECT date(timestamp) as day, count(*)
FROM stamp WHERE key=%s AND date(timestamp) > current_date - interval %s
GROUP BY day ORDER BY day;
con 4.221.883 registros,
!DB index
11.488
0.107
segundos
Search index-
$#
Cliente Servidor
bd
!q='covent garden'
SELECT * FROM messages WHERE subject like '%covent garden%' OR
body like '%covent garden%' OR
author like '%covent garden%';
SELECT * FROM locations WHERE name like '%covent garden%' OR
description like '%covent garden%';
SELECT * FROM pages WHERE name like '%covent garden%' OR
description like '%covent garden%';
SELECT * FROM shareables WHERE name like '%covent garden%' OR
description like '%covent garden%';
Search index-
$#
Cliente Servidor
bd
!q='covent garden'
SELECT * FROM messages WHERE subject like '%covent garden%' OR
body like '%covent garden%' OR
author like '%covent garden%';
SELECT * FROM locations WHERE name like '%covent garden%' OR
description like '%covent garden%';
SELECT * FROM pages WHERE name like '%covent garden%' OR
description like '%covent garden%';
SELECT * FROM shareables WHERE name like '%covent garden%' OR
description like '%covent garden%';
mmm... NO
Search index-
$#
Cliente Servidor
bd
!q='covent garden'
-search
engine
.
Search index-
$#
Cliente Servidor
bd
!q='covent garden'
-search
engine
.
Redis3.3.3
Redis is an open source, BSD licensed,
advanced key-value store. It is often
referred to as a data structure server
since keys can contain strings, hashes, lists,
sets and sorted sets.
“
”
hashes
lists sets sorted setsstrings
pub/sub scripts
Enero 2012
Enero 2012
~67%
~23%
150ms
300ms
Memcached Feb 2012
~86%
~14%
50ms
300ms
Redis Feb 2013
~99%
~1%
3 ms
300ms
Redis como Indice3.1
Problema:
Mostrar avatares de 25 usuarios que compartan algún área
contigo promocionando aquellos que no tengan uno de los
avatares por defecto.
Custom
Default
3.1
Solución: Sorted Sets
1. Para cada area crear un sorted set con el id de todos los miembros.
> ZADD area:1:followers 1 1
area:1:followers 1
Redis como Indice
3.1
Solución: Sorted Sets
1. Para cada area crear un sorted set con el id de todos los miembros.
> ZADD area:1:followers 1 1
> ZADD area:1:followers 0 2
area:1:followers 1 2
Redis como Indice
3.1
Solución: Sorted Sets
1. Para cada area crear un sorted set con el id de todos los miembros.
> ZADD area:1:followers 1 1
> ZADD area:1:followers 0 2
> ZADD area:2:followers 1 1
area:1:followers 1 2
area:2:followers 1
Redis como Indice
3.1
Solución: Sorted Sets
1. Para cada area crear un sorted set con el id de todos los miembros.
> ZADD area:1:followers 1 1
> ZADD area:1:followers 0 2
> ZADD area:2:followers 1 1
> ZADD area:3:followers 0 4
area:1:followers 1 2
area:2:followers 1
area:3:followers 4
Redis como Indice
3.1
Solución: Sorted Sets
1. Para cada area crear un sorted set con el id de todos los miembros.
> ZADD area:1:followers 1 1
> ZADD area:1:followers 0 2
> ZADD area:2:followers 1 1
> ZADD area:3:followers 0 4
> ZADD area:3:followers 1 5
area:1:followers 1 2
area:2:followers 1
area:3:followers 5 4
Redis como Indice
3.1
Problema: ¿Usuarios que siguen el area #1?
> GET area:1:followers
area:1:followers 1 2
area:2:followers 1
area:3:followers 5 4
Redis como Indice
3.1
Problema: ¿Usuarios que siguen el area #1 o el area #2?
> ZINTERSTORE areas:1-2:followers 2 area:1:followers
area:2:followers AGGREGATE MAX
> GET areas:1-2:followers
area:2:followers 1
area:3:followers 5 4
areas:1-2:followers
area:1:followers 1 2
1 2
Redis como Indice
3.1
Problema: 25 usuarios que sigan el area #1 o el area #2 promocionando
aquellos que tengan avatar.
> ZREVRANGE areas:1-2:followers 0 25
area:2:followers 1
area:3:followers 5 4
area:1:followers 1 2
Redis como Indice
3.1
Problema: 25 usuarios que sigan el area #1 o el area #2 promocionando
aquellos que tengan avatar.
> ZREVRANGE areas:1-2:followers 0 25
area:2:followers 1
area:3:followers 5 4
areas:1-2:followers
area:1:followers 1 2
1 2
Redis como Indice
Cliente
Servidor
Canal
Cachear, Delegar, Indexar
varnish, redis, cron, batch...
Reducir request ( número y tamaño )
Minify, sprites, gzip, cdn...
Cachear + Optimizar
Cache, dns lookups, redirects, etags...
Optimización3
Canal3.2
Minimizar JS y CSS
SL.Utils.flash = {
init: function () {
// Handle closing of flash messages
$('#flashes .close, .flashes .close').live('click', function (e) {
$(e.target).closest('li').slideUp(120, function () {
// Cleanup after the last one
var container = $(this).closest('#flashes, .flashes'),
all_messages = container.find('li:visible');
if (all_messages.length < 1) {
container.remove();
}
});
e.preventDefault();
});
}
};
SL.Utils.flash={init:function(){$("#flashes .close, .flashes .close").live("click",function(a){$
(a.target).closest("li").slideUp(120,function(){var a=$(this).closest("#flashes, .flashes");
1>a.find("li:visible").length&&a.remove()});a.preventDefault()})}};
585 bytes
255 bytes (~56%)
Un paso más del proceso de build + deploy
--line-break
--type js|css
--charset character-set
--disable-optimizations
$ java -jar yuicompressor.jar file.js -o file-min.js
https://github.com/yui/yuicompressor/
Yahoo YUI compressor
http://refresh-sf.com/yui/
0
1
Sprites?
N 1
A
.sprite-A{
...
}
A
.sprite-A{
background-image: url(sprite.png);
...
}
x:120px
y:50px
A
.sprite-A{
background-image: url(sprite.png);
background-position: -120px -50px;
...
}
A
.sprite-A{
background-image: url(sprite.png);
background-position: -120px -50px;
width: 10px;
height: 20px;
...
}
20px
10px
A<div class=”sprite-A”></div>
#1
By hand
Rebuild sprites should can must
be part of the assets-rebuild*
for 99% of your sprites
*
“
”
Glue$command-line-sprites$command-line-sprites
gluecss.com
Drop source images somewhere
Drop source images somewhere
$ glue source output
Drop source images somewhere
$ glue source output
Party!
.sprite-icons-rainbow{
background-image:url(sprite.png);
background-repeat:no-repeat;
background-position: 247px 147px;
width: 25px;
height: 25px;
}
...
fam fam fam
.glyphicons-187-more{
background-image:url(glyphicons.png);
background-repeat:no-repeat;
background-position: 212px 42px;
width: 23px;
height: 22px;
}
...
glyphish
gzip3.2.2
GET /index.html
Accept-Encoding: gzip
HTTP 1.1 200 OK
<html><head> ...
gzip
Servidor
Servidor sin gzip configurado
Pese a que el navegador soporte gzip y envíe el header
adecuado en la petición, el servidor lo ignora y envía el
contenido sin comprimir.
100Kb
GET /index.html
Accept-Encoding: gzip
Servidor con gzip configurado
Estando gzip configurado en el servidor, si los clientes
envían los header adecuados, el servidor comprimirá la
respuesta utilizando gzip.
HTTP 1.1 200 OK
Content-Encoding: gzip
kk3s(e?3.sn2isn19fkjnasd...
50Kb
gzip3.2.2
gzip
Servidor
A tener en cuenta
•Navegadores MUY antiguos no soportan gzip. (~12 años)
• Netscape <6
• Internet Explorer <5.5 (Julio 2000)
• Opera <5 (Enero 2000)
• Firefox <0.9.5 (Octubre 2001)
•Solo comprimir texto (html, xml, css, js...)
• Imágenes, audio y video suelen estar comprimidos
utilizando codecs más eficientes y resulta una perdida de
tiempo y cpu intentar recomprimirlos.
•El 90% del tráfico de internet se genera utilizando navegadores que
soportan gzip (Yahoo!)
gzip3.2.2
CDN: Content delivery network
•Objetivos principales
• Distribuir contenido de la manera más eficiente posible a
poder ser desde localizaciones geográficamente cercanas
al cliente para reducir la latencia.
• Reducir tráfico de nuestros servidores web distribuyendo el
trafico a otros servidores.
• Disminuir el coste.
•Amazon S3
• $0.095 por GB Almacenado.
• $0.004 por cada 10.000 requests.
• $0.120 por GB transferido
•Distribuir un video de 50Mb a 100K personas (~5Tb)
• $0 (Hosting) + $0.04 (requests) + $585 (transferencia)
CDN3.2.3
Cliente
Servidor
Canal
Cachear, Delegar, Indexar
varnish, redis, cron, batch...
Reducir request ( número y tamaño )
Minify, sprites, gzip, cdn...
Cachear + Optimizar
Cache, dns lookups, redirects, etags...
Optimización3
Cliente3.3
Speeding up your website
1. CSS y JS en ficheros externos
2. CSS al comienzo
3. JS al final
4. Entre 2 y 4 hostnames
http://developer.yahoo.com/performance/rules.html1
A single-user client SHOULD NOT maintain more
than 2 connections with any server or proxy.
“
dev1
ops2
env3
browser
http
optimización
arquitectura
despliegue
seguridad
monitorización
provisionamiento
herramientas
buenas prácticas
Arquitectura4
$Servidor Web
Aplicación
Base de datos
✓
⚠
SENCILLO
❌
✓ OK PARA EMPEZAR
TERMINA SIENDO POCO
SPOF
SSL*
$Servidor Web
Aplicación
✓
⚠
SENCILLO
❌
✓ PUEDE LLEVARTE LEJOS
TERMINA SIENDO POCO
SPOF
$Base de datos
⚠SPOF
SSL*
$Servidor Web
Aplicación
✓
⚠
SENCILLO
❌
✓ PUEDE LLEVARTE LEJOS
TERMINA SIENDO POCO
SPOF
$Base de datos
⚠SPOF
x2
SSL*
$Servidor Web
Aplicación
⚠SPOF
$Base de datos
⚠SPOF
$Servidor Web
Aplicación
⚠SPOF
DNS ROUND ROBIN
:(
SSL* SSL*
$Servidor Web
Aplicación
⚠SPOF
$Base de datos
⚠SPOF
$Servidor Web
Aplicación
⚠SPOF
DNS ROUND ROBIN
:(
SSL* SSL*
$Servidor Web
HAProxy
⚠SPOF
$Base de datos
⚠SPOF
⚠SPOF
$Servidor Web
Aplicación
⚠SPOF
$Servidor Web
Aplicación
SSL*
$Servidor Web
HAProxy
⚠SPOF
$Base de datos
⚠SPOF
$Servidor Web
Aplicación
$Servidor Web
Aplicación
SSL*
$Servidor Web
HAProxy
⚠SPOF
$Base de datos
⚠SPOF
$Servidor Web
Aplicación
$Servidor Web
Aplicación
SSL*
????
Host $host;
X-Real-IP $remote_addr;
X-Forwarded-Proto $scheme;
HAProxy4.2
Balanceador TCP/HTTP
Es uno de los balanceadores de carga más utilizados. Se caracteriza por ser
muy eficiente tanto en CPU como en RAM y es famoso por su estabilidad.
• Permite balancear tanto tráfico TCP como a un más alto nivel tráfico HTTP.
• Nos permite realizar health-check de los servidores backend.
• Podemos activar y desactivar servidores manualmente.
• Dispone de varios criterios para asignar servidores: Random, Round-robin,
Least connection, source, uri, url-parameter etc...
global
log 127.0.0.1 local0 notice
maxconn 4096
user haproxy
group haproxy
defaults
log global
mode http
option httplog
option dontlognull
option redispatch
retries 3
contimeout 5000
clitimeout 50000
srvtimeout 50000
stats enable
stats auth USER:PASSWORD
backend allservers
mode http
server web1 192.168.0.11:80 check
server web2 192.168.0.12:80 check
server web3 192.168.0.13:80 check
...
balance roundrobin
option httpchk HEAD /test/
option forwardfor
...
haproxy.cfg
Demo HAProxy4A
$Servidor Web
HAProxy
⚠SPOF
$Base de datos
⚠SPOF
$Servidor Web
Aplicación
$Servidor Web
Aplicación
SSL*
High availability4.3
Load Balancer
nginx
haproxy
Web #1
nginx
app
Web #2
nginx
app
Web #3
nginx
app
⏶
Web #1 33%
Web #2 33%
Web #3 33%
✓
✓
✓
4up
example.com
High availability4.3
Web #1
nginx
app
Web #2
nginx
app
Web #3
nginx
app
⏶
Web #1 50%
Web #2 50%
Web #3 0%
✓
⚠
✓4up
example.com
⚠
Load Balancer
nginx
haproxy
High availability4.3
Web #1
nginx
app
Web #2
nginx
app
Web #3
nginx
app
⏶
Web #1 100%
Web #2 0%
Web #3 0%
✓
⚠
⚠4up
example.com
⚠⚠
Load Balancer
nginx
haproxy
Load Balancer
nginx
haproxy
High availability4.3
Web #1
nginx
app
Web #2
nginx
app
Web #3
nginx
app
⏶
Web #1 33%
Web #2 33%
Web #3 33%
✓
✓
✓
5down
example.com
⚠
:(
DNS
$example.com
$$$$$$
Datacenter
66666666
$176.58.97.9
DNS
$example.com
176.58.97.9
$$$$$$
Datacenter
66666666
$176.58.97.9
$
6
DNS
$example.com
176.58.97.9
176.58.97.9
$$$$$$
????
Datacenter
6666666
$
6
DNS
$example.com
176.58.97.9
176.58.97.9
$$$$$$
????
Datacenter
6666666
SPOF: Single Point Of Failure
High availability4.3
Problema
Necesitamos hacer que nuestro balanceador no sea un un
SPOF, Single point of failure.
• En caso de fallo no podemos cambiar la configuración
del DNS ya que conllevaría tiempo propagar el cambio.
• No podemos poner otra capa de balanceadores por
encima del balanceador ya que tendríamos el mismo
problema.
• Hagamos lo que hagamos ha de ser rápido para evitar
downtime en la medida de lo posible.
$
6
$$$$$$
#1
Datacenter
6666666
$176.58.97.9
#2
$
6
$$$$$$
#1
Datacenter
6666666
$176.58.97.9
#2
$
6
$$$$$$
#1
Datacenter
6666666
$176.58.97.9
#2
Heartbeat
♥ Pacemaker
8+
Heartbeat
♥ Capa de comunicación
Básicamente es un “bus” que nos
asegura que todos los mensajes
enviados se envían a todos los
miembros del bus y se asegura de que
todo el mundo esté de acuerdo sobre quien
está o no está conectado.
Pacemaker
8 Agente
Se encarga de arrancar y parar servicios
en función de reglas que nosotros
establezcamos. De igual manera, se
cerciora de que estos servicios solo se
ejecuten en uno de los servidores.
Configuración
$ cat /etc/ha.d/ha.cf
keepalive 2
deadtime 15
warntime 5
initdead 120
udpport 694
ucast eth0 123.123.123.123
auto_failback on
node ha-1.example.com
node ha-2.example.com
use_logd yes
crm respawn
Heartbeat4.3
Instalación
$ apt-get install heartbeat
Comprobar nodos cada dos segundos.
Dar un nodo por muerto a los 15s.
Alertar pasados 5 segundos.
Máximo tiempo de espera en arranque.
Puerto.
IP.
Failback automático al nodo primario.
Nodo #1.
Nodo #2.
Enable log.
Arrancar Pacemaker al arranque del cluster.
Hemos de configurar hearbeat en ambos nodos9
Configuración
$ cat /etc/heartbeat/authkeys
auth 1
1 sha1 SECRET
$ chmod 600 /etc/heartbeat/authkeys
Heartbeat4.3
Hemos de configurar hearbeat en ambos nodos9
Arranque
$ service heartbeat start
Estado
$ service heartbeat status
heartbeat OK [pid 2332 et al] is running on
ha-1.example.com [ha-1.example.com]...
Configuración
$ crm configure edit
node $id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ha-1.example.com
node $id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" ha-2.example.com
primitive ip1 ocf:heartbeat:IPaddr2 
params ip="123.123.123.123" nic="eth2" 
op monitor interval="5s"
primitive ip1arp ocf:heartbeat:SendArp 
params ip="123.123.123.123" nic="eth2"
group HAServices ip1 ip1arp 
meta target-role="Started"
order ip-before-arp inf: ip1:start ip1arp:start
property $id="cib-bootstrap-options" 
dc-version="xxxxxxxxxxxxxxxx" 
cluster-infrastructure="Heartbeat" 
expected-quorum-votes="1" 
stonith-enabled="false" 
no-quorum-policy="ignore"
rsc_defaults $id="rsc-options" 
resource-stickiness="100"
Pacemaker4.3
Instalación
$ apt-get install pacemaker
Configuración
$ crm configure edit
node $id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ha-1.example.com
node $id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" ha-2.example.com
primitive ip1 ocf:heartbeat:IPaddr2 
params ip="123.123.123.123" nic="eth2" 
op monitor interval="5s"
primitive ip1arp ocf:heartbeat:SendArp 
params ip="123.123.123.123" nic="eth2"
group HAServices ip1 ip1arp 
meta target-role="Started"
order ip-before-arp inf: ip1:start ip1arp:start
property $id="cib-bootstrap-options" 
dc-version="xxxxxxxxxxxxxxxx" 
cluster-infrastructure="Heartbeat" 
expected-quorum-votes="1" 
stonith-enabled="false" 
no-quorum-policy="ignore"
rsc_defaults $id="rsc-options" 
resource-stickiness="100"
Pacemaker4.3
Instalación
$ apt-get install pacemaker
Configuración
$ crm configure edit
node $id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ha-1.example.com
node $id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" ha-2.example.com
primitive ip1 ocf:heartbeat:IPaddr2 
params ip="123.123.123.123" nic="eth2" 
op monitor interval="5s"
primitive ip1arp ocf:heartbeat:SendArp 
params ip="123.123.123.123" nic="eth2"
group HAServices ip1 ip1arp 
meta target-role="Started"
order ip-before-arp inf: ip1:start ip1arp:start
property $id="cib-bootstrap-options" 
dc-version="xxxxxxxxxxxxxxxx" 
cluster-infrastructure="Heartbeat" 
expected-quorum-votes="1" 
stonith-enabled="false" 
no-quorum-policy="ignore"
rsc_defaults $id="rsc-options" 
resource-stickiness="100"
Pacemaker4.3
Instalación
$ apt-get install pacemaker
Configuración
$ crm configure edit
node $id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ha-1.example.com
node $id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" ha-2.example.com
primitive ip1 ocf:heartbeat:IPaddr2 
params ip="123.123.123.123" nic="eth2" 
op monitor interval="5s"
primitive ip1arp ocf:heartbeat:SendArp 
params ip="123.123.123.123" nic="eth2"
group HAServices ip1 ip1arp 
meta target-role="Started"
order ip-before-arp inf: ip1:start ip1arp:start
property $id="cib-bootstrap-options" 
dc-version="xxxxxxxxxxxxxxxx" 
cluster-infrastructure="Heartbeat" 
expected-quorum-votes="1" 
stonith-enabled="false" 
no-quorum-policy="ignore"
rsc_defaults $id="rsc-options" 
resource-stickiness="100"
Pacemaker4.3
Instalación
$ apt-get install pacemaker
Configuración
$ crm configure edit
node $id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ha-1.example.com
node $id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" ha-2.example.com
primitive ip1 ocf:heartbeat:IPaddr2 
params ip="123.123.123.123" nic="eth2" 
op monitor interval="5s"
primitive ip1arp ocf:heartbeat:SendArp 
params ip="123.123.123.123" nic="eth2"
group HAServices ip1 ip1arp 
meta target-role="Started"
order ip-before-arp inf: ip1:start ip1arp:start
property $id="cib-bootstrap-options" 
dc-version="xxxxxxxxxxxxxxxx" 
cluster-infrastructure="Heartbeat" 
expected-quorum-votes="1" 
stonith-enabled="false" 
no-quorum-policy="ignore"
rsc_defaults $id="rsc-options" 
resource-stickiness="100"
Pacemaker4.3
Instalación
$ apt-get install pacemaker
Configuración
$ crm configure edit
node $id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ha-1.example.com
node $id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" ha-2.example.com
primitive ip1 ocf:heartbeat:IPaddr2 
params ip="123.123.123.123" nic="eth2" 
op monitor interval="5s"
primitive ip1arp ocf:heartbeat:SendArp 
params ip="123.123.123.123" nic="eth2"
group HAServices ip1 ip1arp 
meta target-role="Started"
order ip-before-arp inf: ip1:start ip1arp:start
property $id="cib-bootstrap-options" 
dc-version="xxxxxxxxxxxxxxxx" 
cluster-infrastructure="Heartbeat" 
expected-quorum-votes="1" 
stonith-enabled="false" 
no-quorum-policy="ignore"
rsc_defaults $id="rsc-options" 
resource-stickiness="100"
Pacemaker4.3
Instalación
$ apt-get install pacemaker
Configuración
$ crm configure edit
node $id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ha-1.example.com
node $id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" ha-2.example.com
primitive ip1 ocf:heartbeat:IPaddr2 
params ip="123.123.123.123" nic="eth2" 
op monitor interval="5s"
primitive ip1arp ocf:heartbeat:SendArp 
params ip="123.123.123.123" nic="eth2"
group HAServices ip1 ip1arp 
meta target-role="Started"
order ip-before-arp inf: ip1:start ip1arp:start
property $id="cib-bootstrap-options" 
dc-version="xxxxxxxxxxxxxxxx" 
cluster-infrastructure="Heartbeat" 
expected-quorum-votes="1" 
stonith-enabled="false" 
no-quorum-policy="ignore"
rsc_defaults $id="rsc-options" 
resource-stickiness="100"
Pacemaker4.3
Instalación
$ apt-get install pacemaker
$Servidor Web
HAProxy
$Base de datos
⚠SPOF
$Servidor Web
Aplicación
$Servidor Web
Aplicación
SSL*
$Servidor Web
HAProxy
SSL*
$Servidor Web
HAProxy
$Base de datos
⚠SPOF
$Servidor Web
Aplicación
$Servidor Web
Aplicación
SSL*
$Servidor Web
HAProxy
SSL*
$Servidor Web
Aplicación
$Servidor Web
Aplicación
$Servidor Web
Aplicación
????
$Servidor Web
HAProxy
$Base de datos
Master
$Servidor Web
Aplicación
$Servidor Web
Aplicación
SSL*
$Servidor Web
HAProxy
SSL*
$Servidor Web
Aplicación
$Servidor Web
Aplicación
$Servidor Web
Aplicación
W
W
W W W
$Base de datos
Read Only
$Servidor Web
HAProxy
$Base de datos
Master
$Servidor Web
Aplicación
$Servidor Web
Aplicación
SSL*
$Servidor Web
HAProxy
SSL*
$Servidor Web
Aplicación
$Servidor Web
Aplicación
$Servidor Web
Aplicación
R
R R R
R
$Base de datos
Read Only
Y aún más lejos?
Llegados a este punto deberíamos de tener
a varias personas trabajando en esto a
tiempo completo... pero el resultado podría
parecerse algo como....
:
$Servidor Web
HAProxy
SSL*
$Servidor Web
HAProxy
SSL*
DNS ROUND ROBIN
$Servidor Web
HAProxy
SSL*
$Servidor Web
HAProxy
SSL*
$Servidor Web
HAProxy
SSL*
$Servidor Web
HAProxy
SSL*
$Servidor Web
Aplicación
$Servidor Web
Aplicación
$Servidor Web
Aplicación
$Servidor Web
Aplicación
$Servidor Web
Aplicación
$Servidor Web
Aplicación
$Servidor Web
Aplicación
$Servidor Web
Aplicación
$Servidor Web
Aplicación
Multi Master DB
$Slave
n n n
n
$Master
$Master
$Slave
$Slave
$Slave
$Slave
$Slave
$Slave
$Slave
++
Servidores Web4.4
¿Cuál elijo?
Existen docenas de servidores web, cada empresa suele elegir uno en
función de las necesidades y features de cada uno.
Nosotros utilizamos nginx dada la sencillez de configuración, la estabilidad, los
grandísimos resultados que siempre alcanza en los tests de carga y en
particular porque ya hemos trabajado con él y lo conocemos.
En realidad nginx lo utilizamos como reverse proxy tanto en los balanceadores
de carga como en los servidores web, así como para hacer “spoon-feeding”.
Spoon feeding?
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
???????
9
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
???????
9
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
???????
9
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
3G
???????
9
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
3G
???????
9
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
3G
???????
9
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
3G
???????
9
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
3G
6Usuario
3G
???????
9
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
3G
6Usuario
3G
6Usuario
EDGE
???????
9
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
3G
6Usuario
3G
6Usuario
EDGE
6Usuario
GPRS
???????
9
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
3G
6Usuario
3G
6Usuario
EDGE
6Usuario
GPRS
???????
9
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
3G
6Usuario
3G
6Usuario
EDGE
6Usuario
GPRS
???????
9
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
3G
6Usuario
3G
6Usuario
EDGE
6Usuario
GPRS
???????
9
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
3G
6Usuario
3G
6Usuario
EDGE
6Usuario
GPRS
???????
9
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
3G
6Usuario
3G
6Usuario
EDGE
6Usuario
GPRS
???????
9
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
3G
6Usuario
3G
6Usuario
EDGE
6Usuario
GPRS
???????
9
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
ADSL
6Usuario
3G
6Usuario
EDGE
6Usuario
GPRS
nginx
LAN;
INTERNET;
1Gb/s
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
ADSL
6Usuario
3G
6Usuario
EDGE
6Usuario
GPRS
nginx
LAN;
INTERNET;
1Gb/s
2.5Mb/s
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
ADSL
6Usuario
3G
6Usuario
EDGE
6Usuario
GPRS
nginx
LAN;
INTERNET;
1Gb/s
236Kb/s
$Proceso #1
$Proceso #2
$Proceso #3
$Proceso #4
6Usuario
ADSL
6Usuario
ADSL
6Usuario
3G
6Usuario
EDGE
6Usuario
GPRS
nginx
LAN;
INTERNET;
1Gb/s
60Kb/s
✉Emails
La mayoría de los servicios online
necesitan enviar emails a sus usuarios.
El número de emails que has de enviar
crece mucho más rápido de lo que
esperas...
Amazon SES4.4
¿Qué es Amazon SES?
Servicio cloud de Amazon que nos permite enviar grandes cantidades de emails
sin tener que disponer de una infraestructura para tales efectos.
¿Y porqué no un smtp inhouse?
El tiempo es oro y el día sólo tiene 24 horas.
• Pequeñas empresas que no disponen de personal de sistemas pueden
ahorrarse muchos dolores de cabeza (y ganar otros) externalizando servicios
como este .
• Grandes empresas que necesitan enviar millones de emails en épocas
concretas y no desean sobre escalar sus sistemas para estas situaciones
puntuales.
• El coste es muy competitivo: 0.10 $ por cada 1000 emails.
Actualmente enviamos alrededor de 1M de emails al mes, lo cual nos cuesta ~£64.
dev1
ops2
env3
browser
http
optimización
arquitectura
despliegue
seguridad
monitorización
provisionamiento
herramientas
buenas prácticas
Deploy5
https://github.com/blog/1241-deploying-at-github
Deploying is a big part of the lives of most GitHub employees. We
don't have a release manager and there are no set weekly
deploys. Developers and designers are responsible for shipping new
stuff themselves as soon as it's ready. This means that deploying
needs to be as smooth and safe a process as possible.
“
$
$
$ $
$
$ $ $
$ $ $ $
server #1
server #3
server #11 server #12
server #2
server #4 server #5 server #6
server #7 server #8 server #9 server #10
$ $server #11 server #12
$
$
$ $
$
$ $ $
$ $ $ $
server #1B
server #3B
server #11B server #12B
server #2B
server #4B server #5B server #6B
server #7B server #8B server #9B server #10B
$ $server #11B server #12B
staging live
$
$
$ $
$
$ $ $
$ $ $ $
server #1B
server #3B
server #11B server #12B
server #2B
server #4B server #5B server #6B
server #7B server #8B server #9B server #10B
$ $server #11B server #12B
live
$
$
$ $
$
$ $ $
$ $ $ $
server #1B
server #3B
server #11B server #12B
server #2B
server #4B server #5B server #6B
server #7B server #8B server #9B server #10B
$ $server #11B server #12B
liveactivar modo mantenimiento (503)
desplegar nuevo código
purgar cachés
reiniciar servicios
minimizar javascript
minimizar css
generar sprites
...
desactivar modo mantenimiento
Streamlining SSH scripts
fabric
from fabric.api import run
def host_type():
run('uname -s')
fabfile.py
$ fab -H localhost,linuxbox host_type
[localhost] run: uname -s
[localhost] out: Darwin
[linuxbox] run: uname -s
[linuxbox] out: Linux
Done.
Disconnecting from localhost... done.
Disconnecting from linuxbox... done.
Streamlining SSH scripts
fabric
get(remote_path, local_path=None)
put(local_path=None, remote_path=None, ...)
run(command, ...)
sudo(command, ...)
reboot(wait=120)
local(command, ...)
Hosts
fabric
@hosts('varnish.example.com')
def purge_varnish():
"""Purge varnish cache"""
sudo('varnishadm -T 127.0.0.1:6082 ban.url . -S /etc/varnish/secret')
$ fab purge_varnish
Agrupación de hosts en roles
fabric
env.roledefs = {
'test': ['test-web-1.example.com', 'test-web-2.example.com'],
'test-db': ['test-db-1.example.com', 'test-db-2.example.com'],
'test-ha': ['test-ha-1.example.com', 'test-ha-2.example.com'],
'www': ['www-web-1.example.com', 'www-web-2.example.com'],
'www-db': ['www-db-1.example.com', 'www-db-2.example.com'],
'www-ha': ['www-ha-1.example.com', 'www-ha-2.example.com'],
}
$ fab deploy -R test
$ fab deploy -R www
Helpers de interacción
fabric
confirm(question, default=True)
abort(msg)
error(message, func=None, exception=None, stdout=None, stderr=None)
green(text, bold=False)
red(text, bold=False)
indent(text, spaces=4, strip=False)
dev1
ops2
env3
browser
http
optimización
arquitectura
despliegue
seguridad
monitorización
provisionamiento
herramientas
buenas prácticas
Seguridad6
La seguridad es un tema extenso y delicado.
Os invitamos a profundizar en cada uno de los
aspectos antes de ponerlos en práctica.
Los siguientes son sólo ejemplos y pueden
contener errores.
⚠
*iptables
No lo son todo, pero sin lugar a dudas
son un buen comienzo para evitarnos
problemas.
Funcionamiento iptables
INPUT TRAFFIC
FILTER
NAT
MANGLE
PREROUTING
PREROUTING
FORWARD
FORWARD
POSTROUTINGPOSTROUTING
INPUT
INPUT
LOCAL
OUTPUT
OUTPUT
OUTPUT
Forwarding processLocal process
ROUTING
OUTPUT TRAFFIC
Funcionamiento iptables
INPUT TRAFFIC
FILTER
NAT
MANGLE
PREROUTING
PREROUTING
FORWARD
FORWARD
POSTROUTINGPOSTROUTING
INPUT
INPUT
LOCAL
OUTPUT
OUTPUT
OUTPUT
Forwarding processLocal process
ROUTING
OUTPUT TRAFFIC
Tablas
Cadenas
Funcionamiento iptables
INPUT TRAFFIC
FILTER
NAT
MANGLE
PREROUTING
PREROUTING
FORWARD
FORWARD
POSTROUTINGPOSTROUTING
INPUT
INPUT
LOCAL
OUTPUT
OUTPUT
OUTPUT
Forwarding processLocal process
ROUTING
OUTPUT TRAFFIC
Tablas predefinidas

>
;
FILTER.
NAT.
MANGLE.
Tabla responsable del filtrado de paquetes.
Todos los paquetes pasan por esta tabla.
Tabla responsable de la reescritura de direcciones y/o puertos.
El primer paquete de cada conexión pasa por esta tabla.
Tabla responsable de ajustar opciones de paquetes (e.j) QOS.
Todos los paquetes pasan por esta tabla.
Tablas predefinidas

>
;
FILTER.
NAT.
MANGLE.
Tabla responsable del filtrado de paquetes.
Todos los paquetes pasan por esta tabla.
Tabla responsable de la reescritura de direcciones y/o puertos.
El primer paquete de cada conexión pasa por esta tabla.
Tabla responsable de ajustar opciones de paquetes (e.j) QOS.
Todos los paquetes pasan por esta tabla.
>FILTER.Tabla responsable del filtrado de paquetes.
☰INPUT
☰OUTPUT
☰FORWARD
Todos los paquetes destinados a este sistema atraviesan esta cadena.
Todos los paquetes creados por este sistema atraviesan esta cadena.
Todos los paquetes que pasan por este sistema atraviesan esta cadena.
El destino de cada una de las reglas dentro de las cadenas puede ser:
ACCEPT, DROP, QUEUE, o RETURN (entre otros)
>FILTER.Tabla responsable del filtrado de paquetes.
☰INPUT
☰OUTPUT
☰FORWARD
Todos los paquetes destinados a este sistema atraviesan esta cadena.
Todos los paquetes creados por este sistema atraviesan esta cadena.
Todos los paquetes que pasan por este sistema atraviesan esta cadena.
El destino de cada una de las reglas dentro de las cadenas puede ser:
ACCEPT, DROP, QUEUE, o RETURN (entre otros)
>FILTER:INPUTCadena responsable del filtrado de paquetes de entrada.
*filter
:INPUT DROP [0:0]
:OUTPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -m state --state INVALID -j DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -s $IP/32 -d $IP/32 -p tcp --dport 80 -j ACCEPT
fail2ban6.2
Fail2ban nos permite bloquear ataques de fuerza bruta contra servicios
como ssh, mail, http etc...
• Muy sencillo de instalar y configurar.
• Una buena contramedida activa.
• Su funcionamiento se basa en leer los logs generados por estos
servicios utilizando expresiones regulares.
• Además de bloquear el trafico entrante desde estas fuentes se
pueden desplegar otras medidas o enviar notificaciones.
!h#p://fail2ban.org
SSH root@...6.3
Desactivar la cuenta de root es una de las primeras medidas a tomar al
configurar un servidor.
• Si disponemos de un servicio como fail2ban estaremos impidiendo
en cierta medida que nadie tenga éxito al realizar un ataque de
fuerza bruta.
• Si por alguna razón el servicio está caído tendríamos nuestra cuenta
de root expuesta.
• Es muy recomendable no permitir conexiones ssh utilizando root.
• Una vez en el sistema podemos identificarnos como root o utilizar
sudo.
PermitRootLogin no
/etc/ssh/sshd_config
dev1
ops2
env3
browser
http
optimización
arquitectura
despliegue
seguridad
monitorización
provisionamiento
herramientas
buenas prácticas
Monitoring7
You can’t improve
what you don’t measure
“
”
top7.1
htop7.2
munin7.3
Ventajas
• Muy sencillo de instalar y configurar.
• Fácil de crear nuevas gráficas usando
cualquier lenguaje de scripting.
• Uso mínimo de recursos.
• Un muy buen punto de partida.
Desventajas
• Sólo tres vistas por cada gráfica
(diaria, semanal, anual)
• Gráficas generadas cada ~5m.
!h#p://munin9monitoring.org
but... What’s next?
Llegado el momento las métricas se
convierten en críticas para analizar no
solo la salud del sistema, si no la del
negocio.
;
graphite7.4
!h#p://graphite.wikidot.com
graphite server
graphite
tcp 80
☁
graphite server
!carbon
graphite
tcp 80
☁
graphite server
db server
!carbon
graphite
tcp 80
☁
graphite server
db server
!carbon
graphite
diamond
tcp 80
☁
graphite server
db server
!carbon
graphite
diamondstatsd
udp 8125
tcp 80
☁
graphite server
db server
!carbon
graphite
tcp 2003
diamondstatsd
udp 8125
tcp 80
☁
graphite server
web server db server
!carbon
graphite
tcp 2003
diamondstatsd
udp 8125
diamond statsd
udp 8125
diamond
statsd
udp 8125
tcp 80
☁
graphite server
web server db server
!carbon
graphite
tcp 2003
diamondstatsd
udp 8125
diamond statsd
udp 8125
diamond
statsd
udp 8125
tcp 80
logs
logs
☁
graphite server
web server db server
!carbon
graphite
tcp 2003
diamondstatsd
udp 8125
diamond statsd
udp 8125
diamond
statsd
udp 8125
tcp 80
app
logs
logs
☁
graphite7.4
No sólo datos... conocimiento!
Descubrir que la carga de un servidor es 9.3 lo fines de semana a las 3am es útil
pero... ¿cual es la causa? ¿Que otros síntomas hay? ¿Algún otro servidor se ve
afectado? ¿Qué estaba haciendo el servidor? ¿Cuantos procesos teníamos en
marcha? ¿Qué tamaño tenía la cola de emails? ¿Hace cuando que hicimos el
último deploy?...
graphite7.4
from pystatsd import Client
sc = Client('127.0.0.1', 8125)
sc.increment('streetlife.emails.immediate.sent')
Python
echo "streetlife.emails.immediate.sent:1|c" | nc -w 1 -u 127.0.0.1 8125
Bash
Son sólo paquetes UDP.
Dado que añadir estadísticas consiste en enviar un simple paquete UDP a
nuestro servidor de statsd, podemos hacerlo desde cualquier sitio!
Nuestra aplicación, un script en bash ... Fire-and-forget!
sentry7.5
!h#p://getsentry.comh#ps://github.com/getsentry/sentry
Open Source SAAS
pingdom7.6
Yo mi me conmigo...
Es muy embarazoso darse cuenta que tu web se ha caído porque te lo diga un
cliente. Hay docenas de servicios como pingdom que se dedican a testear tu
web desde múltiples localizaciones.
Features interesantes:
• Monitorizar estado y tiempo de respuesta de páginas clave.
• Comprobar tiempos de respuesta desde la otra parte del mundo.
• Notificaciones SMS.
• Uptime reports.
dev1
ops2
env3
browser
http
optimización
arquitectura
despliegue
seguridad
monitorización
provisionamiento
herramientas
buenas prácticas
Provisioning8
$server #1
$ ssh user1@server1
$ apt-get install paquete_x
$server #1
$ ssh user1@server1
$ apt-get install paquete_x
$server #2
$ ssh user2@server2
$ apt-get install paquete_x
$server #1
$ ssh user1@server1
$ apt-get install paquete_x
$server #2
$ ssh user2@server2
$ apt-get install paquete_x
$server #3
$ ssh user3@server3
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$server #1
$server #2
$server #3
$server #4
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user3@server3
$ apt-get install paquete_z
$ ssh user4@server4
$ apt-get install paquete_z
$ ssh user1@server1
$ apt-get install paquete_x
$server #1
$server #2
$server #3
$server #4
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user3@server3
$ apt-get install paquete_z
$ ssh user4@server4
$ apt-get install paquete_z
$ ssh user1@server1
$ apt-get install paquete_x
$server #1
$server #2
$server #3
$server #4
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user3@server3
$ apt-get install paquete_z
$ ssh user4@server4
$ apt-get install paquete_z
$
$
$ $
$
$$$
$$$$
$ $
server #1
server #3
server #11 server #12
server #2
server #4 server #5 server #6
server #7 server #8 server #9 server #10
server #13 server #14
$
$
$ $
$
$ $ $
$ $ $ $
server #1
server #3
server #11 server #12
server #2
server #4 server #5 server #6
server #7 server #8 server #9 server #10
$ $server #11 server #12
$
$
$ $
$
$ $ $
$ $ $ $
server #1B
server #3B
server #11B server #12B
server #2B
server #4B server #5B server #6B
server #7B server #8B server #9B server #10B
$ $server #11B server #12B
live staging
$
$
$ $
$
$ $ $
$ $ $ $
server #1
server #3
server #11 server #12
server #2
server #4 server #5 server #6
server #7 server #8 server #9 server #10
$ $server #11 server #12
$
$
$ $
$
$ $ $
$ $ $ $
server #1B
server #3B
server #11B server #12B
server #2B
server #4B server #5B server #6B
server #7B server #8B server #9B server #10B
$ $server #11B server #12B
live staging
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
$ ssh user1@server1
$ apt-get install paquete_x
Shit hapens happens... a lot.
⚠Repetition leads to boredom,
boredom to horrifying mistakes,
horrifying mistakes to God-I-wish-I-was-still-bored.
Provisioning8.1
Automatizar la configuración y mantenimiento de tantos servidores cómo necesitemos.
• Generar plantillas que nos permitan generar nuevas máquinas sin mucho
esfuerzo y de manera automatizada.
• Solucionar casos de catástrofe total ya que podemos regenerar nuestra
arquitectura en otro datacenter sin problemas.
• Todo del código que automatice este proceso se convierte en último
termino en una excelente documentación.
• “Code as Infrastructure”
Puppet8.2
Puppet es junto a Chef uno de los más utilizados.
• Nos permite automatizar la configuración de
servidores UNIX y Windows.
• El lenguaje que se utiliza puede ser tanto Ruby
como un lenguaje declarativo propio de Puppet en
el que se definen tanto recursos del sistema como el
estado de los mismos.
• Servicios, usuarios, paquetes, ficheros...
• Puppet extrae del sistema información como CPUs,
memoria, discos direcciones IP etc... y compila
nuestras plantillas junto a esta información.
• Puede ejecutarse en modo arquitectura con un
servicio central encargado de compilar las plantillas
o en modo “solo-mode” en el cual se compilan las
plantillas en cada servidor.
Puppet8.2
Una de las principales características de Puppet
frente a otros sistemas de configuración es que
es idempotente. Por ejemplo, podemos ejecutarlo
cada 30 minutos y cerciorarnos de que todo está
tal y como lo hemos definido.
Esta es una gran ventaja dado que además de
servirnos como bootstrap para nuevas máquinas,
puppet nos permite administrar nuestras
máquinas a lo largo de todo su ciclo de vida desde
la creación mantenimiento y migración.
package
package { 'nginx':
ensure => installed,
}
present
latest
1.5.3
absent
package
package { 'nginx':
ensure => installed,
}
present
latest
1.5.3
absent
file
file { '/etc/nginx/nginx.conf':
source => 'modules/nginx/nginx.conf',
owner => 'root',
group => 'root',
mode => '640',
require => Package['nginx'],
notify => Service['nginx']
}
????
file
file { '/etc/nginx/nginx.conf':
source => 'modules/nginx/nginx.conf',
owner => 'root',
group => 'root',
mode => '640',
require => Package['nginx'],
notify => Service['nginx']
}
????
service
service { 'nginx':
ensure => running,
enable => true,
hasstatus => true,
hasrestart => true,
}
require, notify
Package['nginx']
File['/etc/nginx/nginx.conf']
Service['nginx']
Installed
Created Updated
user, group
user { 'tom':
ensure => present,
shell => '/bin/bash',
home => '/home/tom',
managehome => true,
}
group { 'friends':
ensure => present
}
nodes
node 'web.example.com' inherits web_node {
include munin
include python
user { 'tom':
ensure => present,
shell => '/bin/bash',
home => '/home/tom',
managehome => true,
}
...
}
apply
$ puppet apply puppet/manifests/site.pp
dev1
ops2
env3
browser
http
optimización
arquitectura
despliegue
seguridad
monitorización
provisionamiento
herramientas
buenas prácticas
Herramientas9
Características
• Wrapper de virtualbox para crear y destruir máquinas desde la
linea de comandos.
• Permite crear “instancias” base para crear máquinas desde un
estado concreto en cuestión de segundos.
• Integración con Puppet y Chef entre otros.
• Gracias a vagrant y puppet podemos lograr que todos los
miembros del equipo dispongan del mismo setup en local sin
mucho quebradero de cabeza.
• La puesta en marcha de nuevos empleados se reduce a minutos
en vez de días.
• Gracias a la sencillez de uso podemos crear distintos setup en
cuestión de minutos y comprobar su funcionamiento.
• Funciona en todas las plataformas: Linux, OSX y Windows.
Vagrant9.1
Añadir un box
Vagrant9.1
$ vagrant box add ubuntu-precise http://bit.ly/ubuntu-precise
Crear una nueva instancia
$ vagrant init ubuntu-precise
Arrancar nuestra nueva máquina virtual
$ vagrant up
!h#p://vagrantbox.es
$ vagrant ssh
Vagrant::Config.run do |config|
config.vm.define :web do |web|
web.vm.box = "ubuntu-precise-64"
web.vm.box_url = "http://bit.ly/ubuntu-precise"
web.vm.host_name = "dev.example.com"
web.vm.network :hostonly, "33.33.33.20"
web.vm.forward_port(22, 2023)
web.vm.forward_port(80, 8081)
web.vm.share_folder("code", "/home/vagrant/code", "./code", :nfs => true)
end
config.vm.define :db do |db|
db.vm.box = "ubuntu-precise-64"
db.vm.box_url = "http://bit.ly/ubuntu-precise"
db.vm.host_name = "dev-db.example.com"
db.vm.network :hostonly, "33.33.33.21"
db.vm.forward_port(22, 2024)
db.vm.forward_port(5432, 5432)
end
end
Múltiples boxes
$ vagrant up web
[web] VM already created. Booting if it's not already running...
[web] Clearing any previously set forwarded ports...
[web] Fixed port collision for 22 => 2222. Now on port 2202.
[web] Forwarding ports...
[web] -- 22 => 2023 (adapter 1)
[web] -- 80 => 8081 (adapter 1)
[web] Exporting NFS shared folders...
[vagrant] Preparing to edit /etc/exports. Administrator privileges will be required...
[web] Creating shared folders metadata...
[web] Clearing any previously set network interfaces...
[web] Preparing network interfaces based on configuration...
[web] Booting VM...
[web] Waiting for VM to boot. This can take a few minutes.
[web] VM booted and ready for use!
[web] Configuring and enabling network interfaces...
[web] Setting host name...
[web] Mounting shared folders...
[web] -- v-root: /vagrant
[web] -- manifests: /tmp/vagrant-puppet/manifests
[web] -- v-pp-m0: /tmp/vagrant-puppet/modules-0
[web] Mounting NFS shared folders...
[web] Running provisioner: Vagrant::Provisioners::Puppet...
[web] Running Puppet with /tmp/vagrant-puppet/manifests/site.pp...
stdin: is not a tty
notice: Finished catalog run in 1.70 seconds
vagrant up
Git branch model9.2
http://nvie.com/posts/a-successful-git-branching-model/1
CSS Preprocessors9.3
Chrome Plugins9.4
Hay docenas de plugins que pueden hacer nuestro día a día mucho
más sencillo. Estos son algunos de los que encontramos más
interesantes, además del inspector que Chrome tiene integrado.
User-Agent switcher9.4
Cambiar de User-Agent con dos clicks
Podemos configurar nuestros
propios User-Agent.
Resolution test9.4
Cambiar el tamaño de la ventana con dos clicks
Cache Killer9.4
Mientras esté activo no se utilizará la cache del navegador.
Speed tracer9.4
dev1
ops2
env3
browser
http
optimización
arquitectura
despliegue
seguridad
monitorización
provisionamiento
herramientas
buenas prácticas
Buenas prácticas10
CI: Jenkins10.2
Características
Servicio que nos permite automatizar (entre
otras cosas) la ejecución de tests,
compilación de documentación, generar
reports de test coverage...
Ejecuciones
• Periódicamente
• Por cada commit al repositorio.
Configuración
• Requiere de un poco de práctica pero
una vez configurado no necesita mucho
mantenimiento.
Hipchat/IRC10.3
La comunicación entre los empleados es muy
importante (sobre todo cuando no siempre todo el
mundo está trabajando desde la misma oficina).
Ventajas
• Histórico de todas las conversaciones.
• Facilidad para compartir rápidamente ficheros,
capturas de pantalla etc...
• 0 Configuración y entrada amable para no techies.
• Salas por departamentos, equipos etc...
• Gaticos.
• Notificaciones de deploy, mantenimiento etc...
Questions?
Recursos
http://www.flickr.com/photos/marceldouwedekker/
http://pygments.org/
http://entypo.com/
Fuentes
http://net.tutsplus.com/tutorials/other/http-headers-for-dummies/
http://igoro.com/archive/what-really-happens-when-you-navigate-to-a-url/
http://pyvideo.org/video/1677/how-the-internet-works
http://es.wikipedia.org/wiki/Hypertext_Transfer_Protocol
http://en.wikipedia.org/wiki/List_of_HTTP_header_fields
http://en.wikipedia.org/wiki/MIME_type
http://silex.sensiolabs.org/doc/cookbook/json_request_body.html
http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-1
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4
http://en.wikipedia.org/wiki/HTTP_cookie
http://developer.yahoo.com/performance/rules.html
http://www.tldp.org/HOWTO/SSL-Certificates-HOWTO/x64.html
http://www.varnish-cache.org/docs/3.0/
http://haproxy.1wt.eu/download/1.5/doc/configuration.txt
http://ontwik.com/python/django-deployment-workshop-by-jacob-kaplan-moss/
http://glue.readthedocs.org/en/latest/
http://library.linode.com/
http://code.flickr.net/2008/10/27/counting-timing/
http://codeascraft.etsy.com/2011/02/15/measure-anything-measure-everything/
http://codeascraft.etsy.com/2010/12/08/track-every-release/
http://plusbryan.com/my-first-5-minutes-on-a-server-or-essential-security-for-linux-servers
http://docs.vagrantup.com/v2/

Más contenido relacionado

La actualidad más candente

High performance Web Sites
High performance Web SitesHigh performance Web Sites
High performance Web SitesopenfinanceDev
 
5 servidor web
5 servidor web5 servidor web
5 servidor webangeles104
 
Servlet Hola Mundo con Eclipse y Tomcat
Servlet Hola Mundo con Eclipse y TomcatServlet Hola Mundo con Eclipse y Tomcat
Servlet Hola Mundo con Eclipse y Tomcatjubacalo
 
Varnish para meros mortales
Varnish para meros mortalesVarnish para meros mortales
Varnish para meros mortalesMartín .
 
Introducción al framework Symfony
Introducción al framework SymfonyIntroducción al framework Symfony
Introducción al framework SymfonyAlejandro Hernández
 
Seguridad WordPress Meetup Majadahonda
Seguridad WordPress Meetup MajadahondaSeguridad WordPress Meetup Majadahonda
Seguridad WordPress Meetup MajadahondaPedro Santos
 
Seguridad en WordPress
Seguridad en WordPressSeguridad en WordPress
Seguridad en WordPressPedro Santos
 
Red t3 practica1_apachecms
Red t3 practica1_apachecmsRed t3 practica1_apachecms
Red t3 practica1_apachecmsgarciadebora
 
Rendimiento en aplicaciones web con Symfony2
Rendimiento en aplicaciones web con Symfony2Rendimiento en aplicaciones web con Symfony2
Rendimiento en aplicaciones web con Symfony2Asier Marqués
 
WordPress, Nginx, Ghost y Telegram con Docker - I Meetup Docker Córdoba - Quaip
WordPress, Nginx, Ghost y Telegram con Docker - I Meetup Docker Córdoba - QuaipWordPress, Nginx, Ghost y Telegram con Docker - I Meetup Docker Córdoba - Quaip
WordPress, Nginx, Ghost y Telegram con Docker - I Meetup Docker Córdoba - Quaipquaip
 
Curso desarrollo web_con_php_y_my_sql
Curso desarrollo web_con_php_y_my_sqlCurso desarrollo web_con_php_y_my_sql
Curso desarrollo web_con_php_y_my_sqlwilliam kozisck
 
Hackin9 - Ataques de tipo HTML injection
Hackin9 - Ataques de tipo HTML injectionHackin9 - Ataques de tipo HTML injection
Hackin9 - Ataques de tipo HTML injectiondegarden
 

La actualidad más candente (20)

Deploying Wordpress
Deploying WordpressDeploying Wordpress
Deploying Wordpress
 
High performance Web Sites
High performance Web SitesHigh performance Web Sites
High performance Web Sites
 
5 servidor web
5 servidor web5 servidor web
5 servidor web
 
Servlet Hola Mundo con Eclipse y Tomcat
Servlet Hola Mundo con Eclipse y TomcatServlet Hola Mundo con Eclipse y Tomcat
Servlet Hola Mundo con Eclipse y Tomcat
 
Varnish http cache
Varnish http cacheVarnish http cache
Varnish http cache
 
Semana 4 7 - Spring 4 y 5 Despliegue a producción
Semana 4   7 - Spring 4 y 5 Despliegue a producciónSemana 4   7 - Spring 4 y 5 Despliegue a producción
Semana 4 7 - Spring 4 y 5 Despliegue a producción
 
Varnish para meros mortales
Varnish para meros mortalesVarnish para meros mortales
Varnish para meros mortales
 
Seguridad en web
Seguridad en webSeguridad en web
Seguridad en web
 
Introducción al framework Symfony
Introducción al framework SymfonyIntroducción al framework Symfony
Introducción al framework Symfony
 
Composer: Gestionando dependencias en PHP
Composer: Gestionando dependencias en PHP Composer: Gestionando dependencias en PHP
Composer: Gestionando dependencias en PHP
 
Seguridad WordPress Meetup Majadahonda
Seguridad WordPress Meetup MajadahondaSeguridad WordPress Meetup Majadahonda
Seguridad WordPress Meetup Majadahonda
 
Seguridad en WordPress
Seguridad en WordPressSeguridad en WordPress
Seguridad en WordPress
 
Protocol HTTP
Protocol HTTPProtocol HTTP
Protocol HTTP
 
Red t3 practica1_apachecms
Red t3 practica1_apachecmsRed t3 practica1_apachecms
Red t3 practica1_apachecms
 
Apache
Apache Apache
Apache
 
Semana 2 Arquitectura web y HTML 5
Semana 2   Arquitectura web y HTML 5Semana 2   Arquitectura web y HTML 5
Semana 2 Arquitectura web y HTML 5
 
Rendimiento en aplicaciones web con Symfony2
Rendimiento en aplicaciones web con Symfony2Rendimiento en aplicaciones web con Symfony2
Rendimiento en aplicaciones web con Symfony2
 
WordPress, Nginx, Ghost y Telegram con Docker - I Meetup Docker Córdoba - Quaip
WordPress, Nginx, Ghost y Telegram con Docker - I Meetup Docker Córdoba - QuaipWordPress, Nginx, Ghost y Telegram con Docker - I Meetup Docker Córdoba - Quaip
WordPress, Nginx, Ghost y Telegram con Docker - I Meetup Docker Córdoba - Quaip
 
Curso desarrollo web_con_php_y_my_sql
Curso desarrollo web_con_php_y_my_sqlCurso desarrollo web_con_php_y_my_sql
Curso desarrollo web_con_php_y_my_sql
 
Hackin9 - Ataques de tipo HTML injection
Hackin9 - Ataques de tipo HTML injectionHackin9 - Ataques de tipo HTML injection
Hackin9 - Ataques de tipo HTML injection
 

Similar a Open Source Modern Web Development

PHP.pdf PHP.pdf PHP.pdf PHP.pdf PHP.pdf PHP.pdf
PHP.pdf PHP.pdf PHP.pdf PHP.pdf PHP.pdf PHP.pdfPHP.pdf PHP.pdf PHP.pdf PHP.pdf PHP.pdf PHP.pdf
PHP.pdf PHP.pdf PHP.pdf PHP.pdf PHP.pdf PHP.pdfRaaulroodriguez
 
ROA - Resource Oriented Architecture
ROA - Resource Oriented ArchitectureROA - Resource Oriented Architecture
ROA - Resource Oriented ArchitectureJavier Lafora Rey
 
PHP Tema 7 - Seguridad
PHP Tema 7 - SeguridadPHP Tema 7 - Seguridad
PHP Tema 7 - SeguridadSpacetoshare
 
Generación de web sites dinámicos usando php
Generación de web sites dinámicos usando phpGeneración de web sites dinámicos usando php
Generación de web sites dinámicos usando phpCarlos Cruz Rincon
 
Tu api ha muerto larga vida a tu dsl
Tu api ha muerto  larga vida a tu dslTu api ha muerto  larga vida a tu dsl
Tu api ha muerto larga vida a tu dslJorge Aguilera
 
Curso de Desarrollo Web de Platzi
Curso de Desarrollo Web de PlatziCurso de Desarrollo Web de Platzi
Curso de Desarrollo Web de PlatziCarlos Azaustre
 
Screen scraping
Screen scrapingScreen scraping
Screen scrapingThirdWay
 
Prueba De Aplicaciones Web con Selenium 2 y WebDriver
Prueba De Aplicaciones Web con Selenium 2 y WebDriverPrueba De Aplicaciones Web con Selenium 2 y WebDriver
Prueba De Aplicaciones Web con Selenium 2 y WebDriverDavid Gómez García
 
Desarrollo web Front End
Desarrollo web Front EndDesarrollo web Front End
Desarrollo web Front Endfcarril
 
Desarrollo de sistios web
Desarrollo de sistios webDesarrollo de sistios web
Desarrollo de sistios webesmartcrimt
 
Esencia de web components
Esencia de web componentsEsencia de web components
Esencia de web componentsPedro J. Molina
 
Mootools Y Otros Frameworks JS
Mootools Y Otros Frameworks JSMootools Y Otros Frameworks JS
Mootools Y Otros Frameworks JSIan Monge Pérez
 
Esencia de Web Components
Esencia de Web ComponentsEsencia de Web Components
Esencia de Web ComponentsPedro J. Molina
 

Similar a Open Source Modern Web Development (20)

ASP.NET MVC Workshop Día 3
ASP.NET MVC Workshop Día 3ASP.NET MVC Workshop Día 3
ASP.NET MVC Workshop Día 3
 
myprofly
myproflymyprofly
myprofly
 
PHP.pdf PHP.pdf PHP.pdf PHP.pdf PHP.pdf PHP.pdf
PHP.pdf PHP.pdf PHP.pdf PHP.pdf PHP.pdf PHP.pdfPHP.pdf PHP.pdf PHP.pdf PHP.pdf PHP.pdf PHP.pdf
PHP.pdf PHP.pdf PHP.pdf PHP.pdf PHP.pdf PHP.pdf
 
Navegación Segura con SSL
Navegación Segura con SSLNavegación Segura con SSL
Navegación Segura con SSL
 
ROA - Resource Oriented Architecture
ROA - Resource Oriented ArchitectureROA - Resource Oriented Architecture
ROA - Resource Oriented Architecture
 
PHP Tema 7 - Seguridad
PHP Tema 7 - SeguridadPHP Tema 7 - Seguridad
PHP Tema 7 - Seguridad
 
Servicios web java, php, perl, google
Servicios web java, php, perl, googleServicios web java, php, perl, google
Servicios web java, php, perl, google
 
Generación de web sites dinámicos usando php
Generación de web sites dinámicos usando phpGeneración de web sites dinámicos usando php
Generación de web sites dinámicos usando php
 
Generación de web sites dinámicos usando php
Generación de web sites dinámicos usando phpGeneración de web sites dinámicos usando php
Generación de web sites dinámicos usando php
 
Tu api ha muerto larga vida a tu dsl
Tu api ha muerto  larga vida a tu dslTu api ha muerto  larga vida a tu dsl
Tu api ha muerto larga vida a tu dsl
 
Curso de Desarrollo Web de Platzi
Curso de Desarrollo Web de PlatziCurso de Desarrollo Web de Platzi
Curso de Desarrollo Web de Platzi
 
ASP.NET MVC
ASP.NET MVCASP.NET MVC
ASP.NET MVC
 
HTML5
HTML5HTML5
HTML5
 
Screen scraping
Screen scrapingScreen scraping
Screen scraping
 
Prueba De Aplicaciones Web con Selenium 2 y WebDriver
Prueba De Aplicaciones Web con Selenium 2 y WebDriverPrueba De Aplicaciones Web con Selenium 2 y WebDriver
Prueba De Aplicaciones Web con Selenium 2 y WebDriver
 
Desarrollo web Front End
Desarrollo web Front EndDesarrollo web Front End
Desarrollo web Front End
 
Desarrollo de sistios web
Desarrollo de sistios webDesarrollo de sistios web
Desarrollo de sistios web
 
Esencia de web components
Esencia de web componentsEsencia de web components
Esencia de web components
 
Mootools Y Otros Frameworks JS
Mootools Y Otros Frameworks JSMootools Y Otros Frameworks JS
Mootools Y Otros Frameworks JS
 
Esencia de Web Components
Esencia de Web ComponentsEsencia de Web Components
Esencia de Web Components
 

Open Source Modern Web Development

  • 2.
  • 3. env environment Open source modern web development ! ⚒ # dev development ops operations
  • 7. renderiza ejecuta habla Browser Más que un terminal tonto, pero no tanto más HTML + CSS JavaScript HTTP (+DNS)
  • 8. HTML + CSS JavaScript HTTP (+DNS) Browser Más que un terminal tonto, pero no tanto más frontend backend
  • 9. renderiza HTML + CSS <html> <head> <title>Example</title> <link rel="stylesheet" type="text/css" href="example.css"> </head> <body> <h1>Title</h1> <p> This is <strong>important</strong>. </p> </body> </html> body { font-family: 'Arial'; } strong { color: red; } + = example.html example.css
  • 12. Escribes una URL en el navegador1 Se hace una petición DNS para traducir el hostname de la URL a su dirección IP 2 Se hace una petición HTTP a esa IP pidiendo el recurso / y se recibe el resultado, normalmente un fichero .html 3 www.wikipedia.org 91.198.174.225 91.198.174.225 GET / HTTP/1.1 ... HTTP/1.1 200 OK ... $#
  • 13. El navegador comienza a renderizar el HTML y hace más peticiones [DNS+] HTTP para cada recurso (css, img, js, etc) que encuentre referenciado en el código (src=..., href=...) 4 <div class="central-featured-logo-inner"> <img src="//upload.wikimedia.org/wikipedia/commons/Wikipedia-logo.png"> </div> A partir de aquí, y hasta la próxima petición HTTP que fuerce una recarga completa de la página, todo lo que puede ocurrir son efectos CSS y código JavaScript. 5 Desde JavaScript podemos hacer peticiones HTTP asíncronas (AJAX) que fuercen acciones en el servidor y como resultado realicen cambios en el DOM de la página.Y esto es todo.
  • 14. El navegador comienza a renderizar el HTML y hace más peticiones [DNS+] HTTP para cada recurso (css, img, js, etc) que encuentre referenciado en el código (src=..., href=...) 4 <div class="central-featured-logo-inner"> <img src="//upload.wikimedia.org/wikipedia/commons/Wikipedia-logo.png"> </div> A partir de aquí, y hasta la próxima petición HTTP que fuerce una recarga completa de la página, todo lo que puede ocurrir son efectos CSS y código JavaScript. 5 Desde JavaScript podemos hacer peticiones HTTP asíncronas (AJAX) que fuercen acciones en el servidor y como resultado realicen cambios en el DOM de la página.Y esto es todo.
  • 15. HTTP es el idioma de la web y hay que conocerlo
  • 17. HTTP2
  • 18. físico enlace de datos red transporte sesión presentación aplicación Modelo OSI Hardware Acceso al medio (MAC) Enrutamiento entre redes Transmisión fiable del mensaje Diálogo Codificación, cifrado, compresión... Contenido del mensaje
  • 19. acceso al medio red transporte aplicación TCP/IP físico enlace de datos red transporte sesión presentación aplicación Modelo OSI http, ftp, smtp, pop, imap, ssh, irc, ... TCP, UDP IP ethernet, token ring, fddi, ...
  • 20. HTTP Protocolo de manipulación de recursos, sin estado <OPERACIÓN> <recurso> HTTP/1.1 <cabeceras> <cuerpo> HTTP/1.1 <código> <descripción> <cabeceras> <cuerpo> Petición Respuesta $ #
  • 21. HTTP Protocolo de manipulación de recursos, sin estado <OPERACIÓN> <recurso> HTTP/1.1 <cabeceras> <cuerpo> HTTP/1.1 <código> <descripción> <cabeceras> <cuerpo> Respuesta Petición $ #
  • 22. HTTP Protocolo de manipulación de recursos, sin estado <OPERACIÓN> <recurso> HTTP/1.1 <cabeceras> <cuerpo> HTTP/1.1 <código> <descripción> <cabeceras> <cuerpo> Petición Respuesta $ #
  • 23. Un recurso se identifica mediante una URL <OPERACIÓN> <recurso> HTTP/1.1 protocol://[user:pass@]host[:port][/resource] en http, por defecto: user = pass = port = 80 resource = / http://www.wikipedia.org:80/
  • 24. <OPERACIÓN> <recurso> HTTP/1.1 Las URLs son parte fundamental del diseño de una aplicación web http://www.wordpress.org/ http://www.wordpress.org/about/ http://www.wordpress.org/support/ http://www.wordpress.org/extend/themes/ http://www.wordpress.org/extend/themes/montezuma ...
  • 25. HTTP Protocolo de manipulación de recursos, sin estado <OPERACIÓN> <recurso> HTTP/1.1 <cabeceras> <cuerpo> HTTP/1.1 <código> <descripción> <cabeceras> <cuerpo> Petición Respuesta $ #
  • 26. GET Obtiene un recurso. No debería producir cambios. POST PUT Crea un recurso. Reemplaza o crea un recurso. DELETE Elimina un recurso. <OPERACIÓN> <recurso> HTTP/1.1 HEAD Como GET, pero pide sólo las cabeceras. TRACE Diagnóstico. OPTIONS Pregunta por los métodos que soporta el servidor. CONNECT Diagnóstico.
  • 27. <OPERACIÓN> <recurso> HTTP/1.1 REST es un enfoque de diseño de APIs que, entre otras cosas, explota la pureza de estos conceptos http://example.com/recetas/ http://example.com/recetas/453 PUT GET POST DELETE PUT GET POST DELETE Lista las URIs de recetas y quizá otros detalles. Reemplaza la colección de recetas por una nueva. Inserta una nueva receta y devuelve su URI. Borra la colección de recetas. Devuelve el detalle de una receta. Reemplaza o crea (si no existe) una receta. --- Borra una receta.
  • 28. + La navaja suiza de las URLs cURL
  • 29. La navaja suiza de las URLs $ curl example.com/recetas $ curl -XGET example.com/recetas $ curl -XPOST example.com/recetas $ curl -XPUT example.com/recetas $ curl -XDELETE example.com/recetas cURL
  • 30. La navaja suiza de las URLs $ curl example.com/recetas $ curl -XGET example.com/recetas $ curl -XPOST example.com/recetas $ curl -XPUT example.com/recetas $ curl -XDELETE example.com/recetas cURL
  • 31. $ curl -X GET google.com <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8"> <TITLE>301 Moved</TITLE></HEAD><BODY> <H1>301 Moved</H1> The document has moved <A HREF="http://www.google.com/">here</A>. </BODY></HTML> cURL La navaja suiza de las URLs
  • 32. HTTP Protocolo de manipulación de recursos, sin estado <OPERACIÓN> <recurso> HTTP/1.1 <cabeceras> <cuerpo> HTTP/1.1 <código> <descripción> <cabeceras> <cuerpo> Petición Respuesta $ #
  • 33. <cabeceras> Son parejas Clave: valor que transmiten al servidor información acerca de la request Accept: text/plain Accept-Charset: utf-8 Accept-Encoding: gzip, deflate Accept-Language: en-US Accept-Datetime: Thu, 31 May 2007 20:35:00 GMT Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== Cache-Control: no-cache Connection: keep-alive Cookie: $Version=1; Skin=new; Content-Length: 348
  • 34. <cabeceras> Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ== Content-Type: application/x-www-form-urlencoded Date: Tue, 15 Nov 1994 08:12:31 GMT Expect: 100-continue From: user@example.com Host: en.wikipedia.org:80 If-Match: "737060cd8c284d8af7ad3082f209582d" If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT If-None-Match: "737060cd8c284d8af7ad3082f209582d" If-Range: "737060cd8c284d8af7ad3082f209582d" If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT
  • 35. <cabeceras> Max-Forwards: 10 Origin: http://www.example-social-network.com Pragma: no-cache Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== Range: bytes=500-999 Referer: http://en.wikipedia.org/wiki/Main_Page TE: trailers, deflate Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, ... User-Agent: Mozilla/5.0 (X11; Linux x86_64; ... Via: 1.0 fred, 1.1 example.com (Apache/1.1) Warning: 199 Miscellaneous warning X-<YYY>: ZZZ
  • 36. cURL:ver cabeceras $ curl -v -X GET google.com * About to connect() to google.com port 80 (#0) * Trying 173.194.41.8... * connected * Connected to google.com (173.194.41.8) port 80 (#0) > GET / HTTP/1.1 > User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5 > Host: google.com > Accept: */* > < HTTP/1.1 301 Moved Permanently < Location: http://www.google.com/ < Content-Type: text/html; charset=UTF-8 < Date: Mon, 06 May 2013 08:03:50 GMT < Expires: Wed, 05 Jun 2013 08:03:50 GMT < Cache-Control: public, max-age=2592000 < Server: gws < Content-Length: 219 < X-XSS-Protection: 1; mode=block < X-Frame-Options: SAMEORIGIN < <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8"> <TITLE>301 Moved</TITLE></HEAD><BODY> <H1>301 Moved</H1> The document has moved <A HREF="http://www.google.com/">here</A>. </BODY></HTML> * Connection #0 to host google.com left intact * Closing connection #0
  • 37. cURL:enviar cabeceras $ curl -v -X GET google.com -H 'User-Agent: Mozilla/5.0' * About to connect() to google.com port 80 (#0) * Trying 173.194.41.232... * connected * Connected to google.com (173.194.41.232) port 80 (#0) > GET / HTTP/1.1 > Host: google.com > Accept: */* > User-Agent: Mozilla/5.0 > < HTTP/1.1 301 Moved Permanently < Location: http://www.google.com/ < Content-Type: text/html; charset=UTF-8 < Date: Mon, 06 May 2013 08:16:10 GMT < Expires: Wed, 05 Jun 2013 08:16:10 GMT < Cache-Control: public, max-age=2592000 < Server: gws < Content-Length: 219 < X-XSS-Protection: 1; mode=block < X-Frame-Options: SAMEORIGIN < <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8"> <TITLE>301 Moved</TITLE></HEAD><BODY> <H1>301 Moved</H1> The document has moved <A HREF="http://www.google.com/">here</A>. </BODY></HTML> * Connection #0 to host google.com left intact * Closing connection #0
  • 38. HTTP Protocolo de manipulación de recursos, sin estado <OPERACIÓN> <recurso> HTTP/1.1 <cabeceras> <cuerpo> HTTP/1.1 <código> <descripción> <cabeceras> <cuerpo> Petición Respuesta $ #
  • 40. <cuerpo> POST /blog/posts HTTP/1.1 Accept: application/json Content-Type: application/json Content-Length: 57 Host: www.example.com:80 {"title":"Hello!","body":"This is my first post!"} POST /blog/posts HTTP/1.1 Accept: */* Content-Type: application/x-www-form-urlencoded Content-Length: 47 Host: www.example.com:80 title=Hello%21&body=This+is+my+first+post%21
  • 41. <cuerpo> POST /blog/posts HTTP/1.1 Accept: text/html, application/xhtml+xml, */* Content-Type: multipart/form-data; boundary=AaB03x Content-Length: 240 Host: www.example.com:80 --AaB03x Content-Disposition: form-data; name="name" Larry --AaB03x Content-Disposition: form-data; name="files" Content-Type: multipart/mixed; boundary=BbC04y --BbC04y Content-Disposition: file; filename="file1.txt" Content-Type: text/plain ... contents of file1.txt ... --BbC04y Content-Disposition: file; filename="file2.gif" Content-Type: image/gif Content-Transfer-Encoding: binary ...contents of file2.gif... --BbC04y-- --AaB03x--
  • 42. cURL:cuerpo de una petición $ curl -v -X POST localhost:8000/jugadores/ -d "username=pablo" * About to connect() to localhost port 8000 (#0) * Trying ::1... * Connection refused * Trying 127.0.0.1... * connected * Connected to localhost (127.0.0.1) port 8000 (#0) > POST /jugadores/ HTTP/1.1 > User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5 > Host: localhost:8000 > Accept: */* > Content-Length: 14 > Content-Type: application/x-www-form-urlencoded > * upload completely sent off: 14 out of 14 bytes * HTTP 1.0, assume close after body < HTTP/1.0 200 OK < Date: Mon, 06 May 2013 07:48:08 GMT < Server: WSGIServer/0.1 Python/2.7.2 < Content-Type: text/html; charset=utf-8 < ... ... * Closing connection #0
  • 43. HTTP Protocolo de manipulación de recursos, sin estado <OPERACIÓN> <recurso> HTTP/1.1 <cabeceras> <cuerpo> HTTP/1.1 <código> <descripción> <cabeceras> <cuerpo> Petición Respuesta $ #
  • 44. HTTP Protocolo de manipulación de recursos, sin estado <OPERACIÓN> <recurso> HTTP/1.1 <cabeceras> <cuerpo> HTTP/1.1 <código> <descripción> <cabeceras> <cuerpo> Petición Respuesta $ #
  • 45. HTTP/1.1 <código> <descripción> 200 OK 201 Created 202 Accepted 203 Non-Authoritative Information 204 No Content 205 Reset Content 206 Partial Content ✓ ℹ 1XX Informational 2XX Success 100 Continue 101 Switching Protocols 300 Multiple Choices 301 Moved Permanently 302 Found 303 See Other 304 Not Modified 305 Use Proxy 306 (Unused) 307 Temporary Redirect  3XX Redirection
  • 46. HTTP/1.1 <código> <descripción> # 4XX Client Error 400 Bad Request 401 Unauthorized 402 Payment Required 403 Forbidden 404 Not Found 405 Method Not Allowed 406 Not Acceptable 407 Proxy Authentication Required 408 Request Timeout 409 Conflict 410 Gone 411 Length Required 412 Precondition Failed 413 Request Entity Too Large 414 Request-URI Too Long 415 Unsupported Media Type 416 Requested Range Not Satisfiable 417 Expectation Failed 500 Internal Server Error 501 Not Implemented 502 Bad Gateway 503 Service Unavailable 504 Gateway Timeout 505 HTTP Version Not Supported 5XX Server Error $
  • 47. HTTP Protocolo de manipulación de recursos, sin estado <OPERACIÓN> <recurso> HTTP/1.1 <cabeceras> <cuerpo> HTTP/1.1 <código> <descripción> <cabeceras> <cuerpo> Petición Respuesta $ #
  • 48. <cabeceras> Access-Control-Allow-Origin: * Accept-Ranges: bytes Age: 12 Allow: GET, HEAD Cache-Control: max-age=3600 Connection: close Content-Encoding: gzip Content-Language: en Content-Length: 348 Content-Location: /index.html Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ== Content-Disposition: attachment; filename="f.txt"
  • 49. <cabeceras> Content-Range: bytes 21010-47021/47022 Content-Type: text/html; charset=utf-8 Date: Tue, 15 Nov 1994 08:12:31 GMT ETag: "737060cd8c284d8af7ad3082f209582d" Expires: Thu, 01 Dec 1994 16:00:00 GMT Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT Link: </feed>; rel="alternate"[25] Location: http://www.w3.org/pub/WWW/People.html P3P: CP="This is not a P3P policy! See..." Pragma: no-cache Proxy-Authenticate: Basic Refresh: 5; url=http://...
  • 50. <cabeceras> Retry-After: 120 Server: Apache/2.4.1 (Unix) Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1 Status: 200 OK Strict-Transport-Security: max-age=16070; includeSubDomains Trailer: Max-Forwards Transfer-Encoding: chunked Vary: * Via: 1.0 fred, 1.1 example.com (Apache/1.1) Warning: 199 Miscellaneous warning WWW-Authenticate: Basic X-<YYY>: ZZZ
  • 51. HTTP Protocolo de manipulación de recursos, sin estado <OPERACIÓN> <recurso> HTTP/1.1 <cabeceras> <cuerpo> HTTP/1.1 <código> <descripción> <cabeceras> <cuerpo> Petición Respuesta $ #
  • 52. <cuerpo> HTTP/1.1 200 OK Content-Type: text/html Date: Thu, 31 May 2007 20:35:00 GMT <html> <head> <title>Web page</title> </head> <body> <h1>Hello world</h1> </body> </html>
  • 53. HTTP Protocolo de manipulación de recursos, sin estado <OPERACIÓN> <recurso> HTTP/1.1 <cabeceras> <cuerpo> HTTP/1.1 <código> <descripción> <cabeceras> <cuerpo> Petición Respuesta $ #
  • 54. HTTP/1.1 200 OK Content-Type: text/html Date: Thu, 31 May 2007 20:35:00 GMT <html> <body> <h1>Hello world</h1> </body> </html> HTTP/1.1 304 Not Modified Date: Thu, 06 Jun 2007 19:40:00 GMT HTTP Imprescindible
  • 55. HTTP/1.1 301 Moved Permanently Location: http://www.example.com/new/url/ HTTP/1.1 302 Found Location: http://www.example.com/other/url/ HTTP/1.1 303 See Other Location: http://www.example.com/other/url/ HTTP/1.1 307 Temporary Redirect Location: http://www.example.com/other/url/ http 1.0 http 1.1 GET XXX GET XXX HTTP Imprescindible
  • 56. HTTP/1.1 400 Bad Request HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic realm="..." HTTP/1.1 403 Forbidden HTTP/1.1 404 Not Found HTTP/1.1 405 Method Not Allowed HTTP/1.1 410 Gone HTTP Imprescindible
  • 57. HTTP/1.1 500 Internal Server Error HTTP/1.1 501 Not Implemented HTTP/1.1 502 Bad Gateway HTTP/1.1 503 Service Unavailable HTTP Imprescindible
  • 58. Cookies Solucionan la falta de estado del protocolo HTTP $# $# Son simples strings que se almacenan en el navegador GET / HTTP/1.1 ... GET / HTTP/1.1 Cookie: sessionid=xxx HTTP/1.1 200 OK Set-Cookie: sessionid=xxx HTTP/1.1 200 OK ... Cliente Servidor
  • 59. Cookies Set-Cookie: sessionid=xxx; Domain=docs.foo.com; Path=/accounts; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly En qué requests debería enviarse como Cookie:Domain + Path Expires Cuándo el User-Agent debería borrar la cookie Secure Sólo debe enviarse si el tráfico es https HttpOnly Sólo accessible desde HTTP, no desde JavaScript XSS!⚠document.cookie = ...
  • 60. Cookies Set-Cookie: sessionid=xxx; Domain=docs.foo.com; Path=/accounts; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly En qué requests debería enviarse como Cookie:Domain + Path Expires Cuándo el User-Agent debería borrar la cookie Secure Sólo debe enviarse si el tráfico es https HttpOnly Sólo accessible desde HTTP, no desde JavaScript XSS!⚠document.cookie = ...
  • 61. Método sencillo para proveer de autenticación a peticiones HTTP, sin necesidad de cookies $# GET / HTTP/1.1 ... Cliente Servidor HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic realm="Login" Basic HTTP auth
  • 62. Basic HTTP auth Método sencillo para proveer de autenticación a peticiones HTTP, sin necesidad de cookies $# GET / HTTP/1.1 ... Cliente Servidor HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic realm="Login" $# GET / HTTP/1.1 Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== HTTP/1.1 200 OK ... base64(username:password) HTTPS!⚠
  • 63. cURL:Basic HTTP auth $ curl -v -X GET localhost:8000/ --user pablo:x6f8 * About to connect() to localhost port 8000 (#0) * Trying ::1... * Connection refused * Trying 127.0.0.1... * connected * Connected to localhost (127.0.0.1) port 8000 (#0) * Server auth using Basic with user 'pablo' > GET / HTTP/1.1 > Authorization: Basic cGFibG86eDZmOA== > User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5 > Host: localhost:8000 > Accept: */* > * HTTP 1.0, assume close after body < HTTP/1.0 200 OK < Date: Mon, 06 May 2013 08:36:25 GMT < Server: WSGIServer/0.1 Python/2.7.2 < Content-Type: text/html; charset=utf-8 < Bienvenido a la mazmorra, espera instrucciones! * Closing connection #0
  • 64. Ejercicio cURL: La guarida del dragón. $ curl -v -XPOST 10.172.104.175/jugadores/ -d "username=pablo" )
  • 67. acceso al medio red transporte aplicación físico enlace de datos red transporte sesión presentación aplicación HTTP TLS/SSL HTTPS
  • 68. HTTPS $# Certificado Public key (P) P(K) Ok K = ... Clave simétrica compartida mediante algoritmo asimétrico K(mensaje) K(mensaje) Cliente Servidor +
  • 69. Otras navajas suizas tcpflow $ sudo tcpflow -i eth0 port 80 -C Sniffer de tráfico TCP por excelencia en UNIX Chrome inspector
  • 72. Cliente Servidor Canal Cachear, Delegar, Indexar varnish, redis, cron, batch... Reducir request ( número y tamaño ) Minify, sprites, gzip, cdn... Cachear + Optimizar Cache, dns lookups, redirects, etags... Optimización3
  • 73. Cliente Servidor Canal Cachear, Delegar, Indexar varnish, redis, cron, batch... Reducir request ( número y tamaño ) Minify, sprites, gzip, cdn... Cachear + Optimizar Cache, dns lookups, redirects, etags... Optimización3
  • 76. 30m 10m no-cache Memcached, redis etc... Contenido externo • APIs, RSS, Twitter Contenido “Estático” • Últimas noticias • Nuevos usuarios • Últimos tweets • ... Cachear Contenido3.1.1
  • 77. > GET last_tweets <h1>n<ul><li>Hello from.... Memcached •Ventajas • Velocidad • Sencillez •Inconvenientes • Volátil: sólo reside en memoria. • Sólo entiende cadenas de texto. Cachear Contenido3.1.1
  • 78. > INCR message:143:comments 1 4445 Redis •Ventajas • Velocidad • Tipos de datos complejos • Operaciones atómicas •Inconvenientes • Muy pocas • Abuso = Problemas (como todo) Welcome to my site. 4445 Comments Cachear Contenido3.1.1
  • 79. Existen múltiples “puntos” donde cachear. •Servidor web • Intrusismo • Complejidad media •Código del proyecto “backend” • Sencillo de implementar • Poco eficiente •Proxy • Sencillo • Muy eficiente Cachear Requests3.1.1
  • 80. •Requests Anónimas • Digg effect • Landing page • Google •Contenido Estático • Assets • Thumbnails •APIs •“Hot Pages” Request Response Varnish Server Miss Hit Cachear Requests3.1.1
  • 81. Request * Versión muy simplificada del funcionamiento de Varnish Varnish Varnish3.1.1
  • 82. Request vcl_recv() * Versión muy simplificada del funcionamiento de Varnish Varnish Varnish3.1.1
  • 83. Request vcl_recv() lookup * Versión muy simplificada del funcionamiento de Varnish in cache? Varnish Varnish3.1.1
  • 84. Request vcl_recv() lookup * Versión muy simplificada del funcionamiento de Varnish in cache? yes Varnish Varnish3.1.1
  • 85. Request vcl_recv() lookup * Versión muy simplificada del funcionamiento de Varnish in cache? Build Response yes Varnish Varnish3.1.1
  • 86. Request vcl_recv() lookup * Versión muy simplificada del funcionamiento de Varnish in cache? Build ResponseResponse yes Varnish Varnish3.1.1
  • 87. Request vcl_recv() pass lookup * Versión muy simplificada del funcionamiento de Varnish in cache? no Build ResponseResponse yes Varnish Varnish3.1.1
  • 88. Request vcl_recv() Backend pass lookup * Versión muy simplificada del funcionamiento de Varnish in cache? no Build Response vcl_fetch() Response yes cache? Varnish Varnish3.1.1
  • 89. Request vcl_recv() Backend pass lookup * Versión muy simplificada del funcionamiento de Varnish in cache? no Build Response vcl_fetch() Response yes cache? no Varnish Varnish3.1.1
  • 90. Request vcl_recv() Backend pass lookup * Versión muy simplificada del funcionamiento de Varnish in cache? no Build Response vcl_fetch() Response yes Cache cache? yesno Varnish Varnish3.1.1
  • 91. sub vcl_recv { # Pass anything other than GET and HEAD directly. if (req.request != "GET" && req.request != "HEAD"){ return(pass); } # Always lookup static files from the cache. # We don't need request cookies neither Authorization. if (req.request == "GET" && req.url ~ "^/static/") { unset req.http.cookie; unset req.http.Authorization; return(lookup); } # Remove any cookie we don't know about except `sessionid`. if (req.http.Cookie) { set req.http.Cookie = ";" + req.http.Cookie; set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";"); set req.http.Cookie = regsuball(req.http.Cookie, ";(sessionid)=", "; 1="); set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", ""); set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", ""); if (req.http.Cookie == "") { # If there are no cookies, remove the header and lookup the cache. unset req.http.Cookie; return(lookup); } else { # If `sessionid` cookie is pressent pass the request to the backend. return (pass); } } } vcl_recv
  • 92. sub vcl_fetch { # If the response status >= 400 don't cache it. if (beresp.status >= 400) { return (hit_for_pass); } # Remove cookies if this is a static request and set 1 week of ttl. if (req.url ~ "^/static/") { unset beresp.http.set-cookie; set beresp.ttl = 1w; return (deliver); } else{ # If the response is setting any cookie, don't cache it. if (beresp.http.Set-Cookie) { return (hit_for_pass); } # Cache this response for 10 minutes. set beresp.ttl = 10m; return (deliver); } } vcl_fetch
  • 94. Delegar3.2 $# Cliente Servidor 500ms bd ! ,smtp200ms 5s Dejar que alguien haga el trabajo sucio, antes o después csv #
  • 95. Delegar3.2 $# Cliente Servidor 500ms bd ! ,smtp200ms 5s ¿Cuánto del trabajo sucio es imprescindible al instante? csv # ? ? ?
  • 96. Delegar3.2 $# Cliente Servidor 500ms bd ! ,smtp200ms 5s ¿Cuánto del trabajo sucio es imprescindible al instante? csv # ? ¿caché? ?
  • 97. Delegar3.2 $# Cliente Servidor 500ms bd ! ,smtp200ms 5s ¿Cuánto del trabajo sucio es imprescindible al instante? csv # ? ¿caché? ¿tarea periódica?
  • 98. Delegar3.2 $# Cliente Servidor 500ms bd ! ,smtp200ms 5s ¿Cuánto del trabajo sucio es imprescindible al instante? csv # ¿caché? ¿tarea periódica? ¿cola de mensajes?
  • 99. Delegar3.2 $# Cliente Servidor 500ms bd ! ,smtp200ms 5s ¿Cuánto del trabajo sucio es imprescindible al instante? csv # ¿caché? Delegar antes Delegar después
  • 100. Scheduler de trabajos de UNIX cron * * * * * <cmd> día de la semana (0 - 7) mes (1 - 12) día del mes (1 - 31) hora (0 - 23) minuto (0 - 59) # crontab -e $ crontab -e
  • 101. Scheduler de trabajos de UNIX # crontab -l 0 1 * * * /usr/sbin/ntpdate pool.ntp.org 0 */2 * * * /home/root/bin/server-backup @reboot /home/root/bin/email-admins.sh cron $ crontab -l */5 * * * * /home/ops/bin/billing.sh @hourly /home/ops/bin/caches.py @daily /home/ops/bin/users-csv.py @weekly /home/ops/bin/spending-reports.sh
  • 102. Delegar3.2 $# Cliente Servidor 500ms bd ! ,smtp200ms 5s ¿Cuánto del trabajo sucio es imprescindible al instante? csv # ¿caché? Delegar antes Delegar después
  • 103. Celery3.2 Sistema de Tareas Asíncronas distribuidas. • Features: Colas, Concurrencia, Distribuido... • Pro: Muy fácil de implementar y escalable. • Casos prácticos: • Enviar un email (Notificationes, ...) • Calcular el karma de de los usuarios del sistema. • Tareas programadas (Limpieza, Post-procesado, etc...) • Regenerar caches etc.. !h#p://celeryproject.org
  • 104. Celery3.2 El principal componente es el Broker. Se encarga de almacenar y entregar tareas a todos los workers. Estable Experimental
  • 107. Funcionamiento3.2 Server #1 celery worker celery beat Server #3 celery worker Server #4 web node Server #5 web node añadir procesarprocesar añadir añadir Server #2 celery worker procesar
  • 108. Funcionamiento3.2 Server #1 celery worker celery beat Server #3 celery worker Server #4 web node Server #5 web node añadir procesarprocesar añadir añadir Server #2 celery worker procesar
  • 109. Funcionamiento3.2 Server #1 celery worker celery beat Server #3 celery worker Server #4 web node Server #5 web node añadir procesarprocesar añadir añadir Server #2 celery worker procesar
  • 110. Funcionamiento3.2 Conceptos clave: • Atómico: Las tareas se entregan solo a un worker. • Distribuido: Los nodos son independientes unos de otros y el número puede aumentar y disminuir dinámicamente. • Fiable: Si no se informa a RabbitMQ sobre la finalización de una tarea, esta vuelve a formar parte de la cola. En caso de catástrofe no perdemos tareas. • Rates: Celery nos permite definir rates para nos sobrecargar el sistema o APIs externas. • Tareas Periodicas: Celery beat registrará por nosotros tareas en la cola de la misma manera que lo haría cron.
  • 111. Indexar3.3 Preparar la información para acceder más rápido a ella en el momento de la consulta ! DB Search-
  • 112. !DB index SELECT date(timestamp) as day, count(*) FROM stamp WHERE key=%s AND date(timestamp) > current_date - interval %s GROUP BY day ORDER BY day; BEGIN; DROP TABLE IF EXISTS "stamp"; CREATE TABLE "stamp" ( "key" varchar(255) NOT NULL, "timestamp" timestamp without time zone NOT NULL ) ; COMMIT; con 4.221.883 registros, 11.488 segundos
  • 113. BEGIN; DROP TABLE IF EXISTS "stamp"; CREATE TABLE "stamp" ( "key" varchar(255) NOT NULL, "timestamp" timestamp without time zone NOT NULL ) ; CREATE INDEX "stamp_key_idx" ON stamp(key); COMMIT; SELECT date(timestamp) as day, count(*) FROM stamp WHERE key=%s AND date(timestamp) > current_date - interval %s GROUP BY day ORDER BY day; con 4.221.883 registros, !DB index 11.488 segundos
  • 114. BEGIN; DROP TABLE IF EXISTS "stamp"; CREATE TABLE "stamp" ( "key" varchar(255) NOT NULL, "timestamp" timestamp without time zone NOT NULL ) ; CREATE INDEX "stamp_key_idx" ON stamp(key); COMMIT; SELECT date(timestamp) as day, count(*) FROM stamp WHERE key=%s AND date(timestamp) > current_date - interval %s GROUP BY day ORDER BY day; con 4.221.883 registros, !DB index 11.488 0.107 segundos
  • 115. Search index- $# Cliente Servidor bd !q='covent garden' SELECT * FROM messages WHERE subject like '%covent garden%' OR body like '%covent garden%' OR author like '%covent garden%'; SELECT * FROM locations WHERE name like '%covent garden%' OR description like '%covent garden%'; SELECT * FROM pages WHERE name like '%covent garden%' OR description like '%covent garden%'; SELECT * FROM shareables WHERE name like '%covent garden%' OR description like '%covent garden%';
  • 116. Search index- $# Cliente Servidor bd !q='covent garden' SELECT * FROM messages WHERE subject like '%covent garden%' OR body like '%covent garden%' OR author like '%covent garden%'; SELECT * FROM locations WHERE name like '%covent garden%' OR description like '%covent garden%'; SELECT * FROM pages WHERE name like '%covent garden%' OR description like '%covent garden%'; SELECT * FROM shareables WHERE name like '%covent garden%' OR description like '%covent garden%'; mmm... NO
  • 119.
  • 120. Redis3.3.3 Redis is an open source, BSD licensed, advanced key-value store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets and sorted sets. “ ” hashes lists sets sorted setsstrings pub/sub scripts
  • 121.
  • 122.
  • 127. Redis como Indice3.1 Problema: Mostrar avatares de 25 usuarios que compartan algún área contigo promocionando aquellos que no tengan uno de los avatares por defecto. Custom Default
  • 128. 3.1 Solución: Sorted Sets 1. Para cada area crear un sorted set con el id de todos los miembros. > ZADD area:1:followers 1 1 area:1:followers 1 Redis como Indice
  • 129. 3.1 Solución: Sorted Sets 1. Para cada area crear un sorted set con el id de todos los miembros. > ZADD area:1:followers 1 1 > ZADD area:1:followers 0 2 area:1:followers 1 2 Redis como Indice
  • 130. 3.1 Solución: Sorted Sets 1. Para cada area crear un sorted set con el id de todos los miembros. > ZADD area:1:followers 1 1 > ZADD area:1:followers 0 2 > ZADD area:2:followers 1 1 area:1:followers 1 2 area:2:followers 1 Redis como Indice
  • 131. 3.1 Solución: Sorted Sets 1. Para cada area crear un sorted set con el id de todos los miembros. > ZADD area:1:followers 1 1 > ZADD area:1:followers 0 2 > ZADD area:2:followers 1 1 > ZADD area:3:followers 0 4 area:1:followers 1 2 area:2:followers 1 area:3:followers 4 Redis como Indice
  • 132. 3.1 Solución: Sorted Sets 1. Para cada area crear un sorted set con el id de todos los miembros. > ZADD area:1:followers 1 1 > ZADD area:1:followers 0 2 > ZADD area:2:followers 1 1 > ZADD area:3:followers 0 4 > ZADD area:3:followers 1 5 area:1:followers 1 2 area:2:followers 1 area:3:followers 5 4 Redis como Indice
  • 133. 3.1 Problema: ¿Usuarios que siguen el area #1? > GET area:1:followers area:1:followers 1 2 area:2:followers 1 area:3:followers 5 4 Redis como Indice
  • 134. 3.1 Problema: ¿Usuarios que siguen el area #1 o el area #2? > ZINTERSTORE areas:1-2:followers 2 area:1:followers area:2:followers AGGREGATE MAX > GET areas:1-2:followers area:2:followers 1 area:3:followers 5 4 areas:1-2:followers area:1:followers 1 2 1 2 Redis como Indice
  • 135. 3.1 Problema: 25 usuarios que sigan el area #1 o el area #2 promocionando aquellos que tengan avatar. > ZREVRANGE areas:1-2:followers 0 25 area:2:followers 1 area:3:followers 5 4 area:1:followers 1 2 Redis como Indice
  • 136. 3.1 Problema: 25 usuarios que sigan el area #1 o el area #2 promocionando aquellos que tengan avatar. > ZREVRANGE areas:1-2:followers 0 25 area:2:followers 1 area:3:followers 5 4 areas:1-2:followers area:1:followers 1 2 1 2 Redis como Indice
  • 137. Cliente Servidor Canal Cachear, Delegar, Indexar varnish, redis, cron, batch... Reducir request ( número y tamaño ) Minify, sprites, gzip, cdn... Cachear + Optimizar Cache, dns lookups, redirects, etags... Optimización3
  • 139. Minimizar JS y CSS SL.Utils.flash = { init: function () { // Handle closing of flash messages $('#flashes .close, .flashes .close').live('click', function (e) { $(e.target).closest('li').slideUp(120, function () { // Cleanup after the last one var container = $(this).closest('#flashes, .flashes'), all_messages = container.find('li:visible'); if (all_messages.length < 1) { container.remove(); } }); e.preventDefault(); }); } }; SL.Utils.flash={init:function(){$("#flashes .close, .flashes .close").live("click",function(a){$ (a.target).closest("li").slideUp(120,function(){var a=$(this).closest("#flashes, .flashes"); 1>a.find("li:visible").length&&a.remove()});a.preventDefault()})}}; 585 bytes 255 bytes (~56%) Un paso más del proceso de build + deploy
  • 140. --line-break --type js|css --charset character-set --disable-optimizations $ java -jar yuicompressor.jar file.js -o file-min.js https://github.com/yui/yuicompressor/ Yahoo YUI compressor http://refresh-sf.com/yui/ 0 1
  • 142. N 1
  • 146. A .sprite-A{ background-image: url(sprite.png); background-position: -120px -50px; width: 10px; height: 20px; ... } 20px 10px
  • 149. Rebuild sprites should can must be part of the assets-rebuild* for 99% of your sprites * “ ”
  • 151. Drop source images somewhere
  • 152. Drop source images somewhere $ glue source output
  • 153. Drop source images somewhere $ glue source output Party!
  • 156. gzip3.2.2 GET /index.html Accept-Encoding: gzip HTTP 1.1 200 OK <html><head> ... gzip Servidor Servidor sin gzip configurado Pese a que el navegador soporte gzip y envíe el header adecuado en la petición, el servidor lo ignora y envía el contenido sin comprimir. 100Kb
  • 157. GET /index.html Accept-Encoding: gzip Servidor con gzip configurado Estando gzip configurado en el servidor, si los clientes envían los header adecuados, el servidor comprimirá la respuesta utilizando gzip. HTTP 1.1 200 OK Content-Encoding: gzip kk3s(e?3.sn2isn19fkjnasd... 50Kb gzip3.2.2 gzip Servidor
  • 158. A tener en cuenta •Navegadores MUY antiguos no soportan gzip. (~12 años) • Netscape <6 • Internet Explorer <5.5 (Julio 2000) • Opera <5 (Enero 2000) • Firefox <0.9.5 (Octubre 2001) •Solo comprimir texto (html, xml, css, js...) • Imágenes, audio y video suelen estar comprimidos utilizando codecs más eficientes y resulta una perdida de tiempo y cpu intentar recomprimirlos. •El 90% del tráfico de internet se genera utilizando navegadores que soportan gzip (Yahoo!) gzip3.2.2
  • 159. CDN: Content delivery network •Objetivos principales • Distribuir contenido de la manera más eficiente posible a poder ser desde localizaciones geográficamente cercanas al cliente para reducir la latencia. • Reducir tráfico de nuestros servidores web distribuyendo el trafico a otros servidores. • Disminuir el coste. •Amazon S3 • $0.095 por GB Almacenado. • $0.004 por cada 10.000 requests. • $0.120 por GB transferido •Distribuir un video de 50Mb a 100K personas (~5Tb) • $0 (Hosting) + $0.04 (requests) + $585 (transferencia) CDN3.2.3
  • 160. Cliente Servidor Canal Cachear, Delegar, Indexar varnish, redis, cron, batch... Reducir request ( número y tamaño ) Minify, sprites, gzip, cdn... Cachear + Optimizar Cache, dns lookups, redirects, etags... Optimización3
  • 162. Speeding up your website 1. CSS y JS en ficheros externos 2. CSS al comienzo 3. JS al final 4. Entre 2 y 4 hostnames http://developer.yahoo.com/performance/rules.html1 A single-user client SHOULD NOT maintain more than 2 connections with any server or proxy. “
  • 165. $Servidor Web Aplicación Base de datos ✓ ⚠ SENCILLO ❌ ✓ OK PARA EMPEZAR TERMINA SIENDO POCO SPOF SSL*
  • 166. $Servidor Web Aplicación ✓ ⚠ SENCILLO ❌ ✓ PUEDE LLEVARTE LEJOS TERMINA SIENDO POCO SPOF $Base de datos ⚠SPOF SSL*
  • 167. $Servidor Web Aplicación ✓ ⚠ SENCILLO ❌ ✓ PUEDE LLEVARTE LEJOS TERMINA SIENDO POCO SPOF $Base de datos ⚠SPOF x2 SSL*
  • 168. $Servidor Web Aplicación ⚠SPOF $Base de datos ⚠SPOF $Servidor Web Aplicación ⚠SPOF DNS ROUND ROBIN :( SSL* SSL*
  • 169. $Servidor Web Aplicación ⚠SPOF $Base de datos ⚠SPOF $Servidor Web Aplicación ⚠SPOF DNS ROUND ROBIN :( SSL* SSL*
  • 170. $Servidor Web HAProxy ⚠SPOF $Base de datos ⚠SPOF ⚠SPOF $Servidor Web Aplicación ⚠SPOF $Servidor Web Aplicación SSL*
  • 171. $Servidor Web HAProxy ⚠SPOF $Base de datos ⚠SPOF $Servidor Web Aplicación $Servidor Web Aplicación SSL*
  • 172. $Servidor Web HAProxy ⚠SPOF $Base de datos ⚠SPOF $Servidor Web Aplicación $Servidor Web Aplicación SSL* ???? Host $host; X-Real-IP $remote_addr; X-Forwarded-Proto $scheme;
  • 173. HAProxy4.2 Balanceador TCP/HTTP Es uno de los balanceadores de carga más utilizados. Se caracteriza por ser muy eficiente tanto en CPU como en RAM y es famoso por su estabilidad. • Permite balancear tanto tráfico TCP como a un más alto nivel tráfico HTTP. • Nos permite realizar health-check de los servidores backend. • Podemos activar y desactivar servidores manualmente. • Dispone de varios criterios para asignar servidores: Random, Round-robin, Least connection, source, uri, url-parameter etc...
  • 174. global log 127.0.0.1 local0 notice maxconn 4096 user haproxy group haproxy defaults log global mode http option httplog option dontlognull option redispatch retries 3 contimeout 5000 clitimeout 50000 srvtimeout 50000 stats enable stats auth USER:PASSWORD backend allservers mode http server web1 192.168.0.11:80 check server web2 192.168.0.12:80 check server web3 192.168.0.13:80 check ... balance roundrobin option httpchk HEAD /test/ option forwardfor ... haproxy.cfg
  • 176. $Servidor Web HAProxy ⚠SPOF $Base de datos ⚠SPOF $Servidor Web Aplicación $Servidor Web Aplicación SSL*
  • 177. High availability4.3 Load Balancer nginx haproxy Web #1 nginx app Web #2 nginx app Web #3 nginx app ⏶ Web #1 33% Web #2 33% Web #3 33% ✓ ✓ ✓ 4up example.com
  • 178. High availability4.3 Web #1 nginx app Web #2 nginx app Web #3 nginx app ⏶ Web #1 50% Web #2 50% Web #3 0% ✓ ⚠ ✓4up example.com ⚠ Load Balancer nginx haproxy
  • 179. High availability4.3 Web #1 nginx app Web #2 nginx app Web #3 nginx app ⏶ Web #1 100% Web #2 0% Web #3 0% ✓ ⚠ ⚠4up example.com ⚠⚠ Load Balancer nginx haproxy
  • 180. Load Balancer nginx haproxy High availability4.3 Web #1 nginx app Web #2 nginx app Web #3 nginx app ⏶ Web #1 33% Web #2 33% Web #3 33% ✓ ✓ ✓ 5down example.com ⚠
  • 181. :(
  • 186. High availability4.3 Problema Necesitamos hacer que nuestro balanceador no sea un un SPOF, Single point of failure. • En caso de fallo no podemos cambiar la configuración del DNS ya que conllevaría tiempo propagar el cambio. • No podemos poner otra capa de balanceadores por encima del balanceador ya que tendríamos el mismo problema. • Hagamos lo que hagamos ha de ser rápido para evitar downtime en la medida de lo posible.
  • 191. Heartbeat ♥ Capa de comunicación Básicamente es un “bus” que nos asegura que todos los mensajes enviados se envían a todos los miembros del bus y se asegura de que todo el mundo esté de acuerdo sobre quien está o no está conectado.
  • 192. Pacemaker 8 Agente Se encarga de arrancar y parar servicios en función de reglas que nosotros establezcamos. De igual manera, se cerciora de que estos servicios solo se ejecuten en uno de los servidores.
  • 193. Configuración $ cat /etc/ha.d/ha.cf keepalive 2 deadtime 15 warntime 5 initdead 120 udpport 694 ucast eth0 123.123.123.123 auto_failback on node ha-1.example.com node ha-2.example.com use_logd yes crm respawn Heartbeat4.3 Instalación $ apt-get install heartbeat Comprobar nodos cada dos segundos. Dar un nodo por muerto a los 15s. Alertar pasados 5 segundos. Máximo tiempo de espera en arranque. Puerto. IP. Failback automático al nodo primario. Nodo #1. Nodo #2. Enable log. Arrancar Pacemaker al arranque del cluster. Hemos de configurar hearbeat en ambos nodos9
  • 194. Configuración $ cat /etc/heartbeat/authkeys auth 1 1 sha1 SECRET $ chmod 600 /etc/heartbeat/authkeys Heartbeat4.3 Hemos de configurar hearbeat en ambos nodos9 Arranque $ service heartbeat start Estado $ service heartbeat status heartbeat OK [pid 2332 et al] is running on ha-1.example.com [ha-1.example.com]...
  • 195. Configuración $ crm configure edit node $id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ha-1.example.com node $id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" ha-2.example.com primitive ip1 ocf:heartbeat:IPaddr2 params ip="123.123.123.123" nic="eth2" op monitor interval="5s" primitive ip1arp ocf:heartbeat:SendArp params ip="123.123.123.123" nic="eth2" group HAServices ip1 ip1arp meta target-role="Started" order ip-before-arp inf: ip1:start ip1arp:start property $id="cib-bootstrap-options" dc-version="xxxxxxxxxxxxxxxx" cluster-infrastructure="Heartbeat" expected-quorum-votes="1" stonith-enabled="false" no-quorum-policy="ignore" rsc_defaults $id="rsc-options" resource-stickiness="100" Pacemaker4.3 Instalación $ apt-get install pacemaker
  • 196. Configuración $ crm configure edit node $id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ha-1.example.com node $id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" ha-2.example.com primitive ip1 ocf:heartbeat:IPaddr2 params ip="123.123.123.123" nic="eth2" op monitor interval="5s" primitive ip1arp ocf:heartbeat:SendArp params ip="123.123.123.123" nic="eth2" group HAServices ip1 ip1arp meta target-role="Started" order ip-before-arp inf: ip1:start ip1arp:start property $id="cib-bootstrap-options" dc-version="xxxxxxxxxxxxxxxx" cluster-infrastructure="Heartbeat" expected-quorum-votes="1" stonith-enabled="false" no-quorum-policy="ignore" rsc_defaults $id="rsc-options" resource-stickiness="100" Pacemaker4.3 Instalación $ apt-get install pacemaker
  • 197. Configuración $ crm configure edit node $id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ha-1.example.com node $id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" ha-2.example.com primitive ip1 ocf:heartbeat:IPaddr2 params ip="123.123.123.123" nic="eth2" op monitor interval="5s" primitive ip1arp ocf:heartbeat:SendArp params ip="123.123.123.123" nic="eth2" group HAServices ip1 ip1arp meta target-role="Started" order ip-before-arp inf: ip1:start ip1arp:start property $id="cib-bootstrap-options" dc-version="xxxxxxxxxxxxxxxx" cluster-infrastructure="Heartbeat" expected-quorum-votes="1" stonith-enabled="false" no-quorum-policy="ignore" rsc_defaults $id="rsc-options" resource-stickiness="100" Pacemaker4.3 Instalación $ apt-get install pacemaker
  • 198. Configuración $ crm configure edit node $id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ha-1.example.com node $id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" ha-2.example.com primitive ip1 ocf:heartbeat:IPaddr2 params ip="123.123.123.123" nic="eth2" op monitor interval="5s" primitive ip1arp ocf:heartbeat:SendArp params ip="123.123.123.123" nic="eth2" group HAServices ip1 ip1arp meta target-role="Started" order ip-before-arp inf: ip1:start ip1arp:start property $id="cib-bootstrap-options" dc-version="xxxxxxxxxxxxxxxx" cluster-infrastructure="Heartbeat" expected-quorum-votes="1" stonith-enabled="false" no-quorum-policy="ignore" rsc_defaults $id="rsc-options" resource-stickiness="100" Pacemaker4.3 Instalación $ apt-get install pacemaker
  • 199. Configuración $ crm configure edit node $id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ha-1.example.com node $id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" ha-2.example.com primitive ip1 ocf:heartbeat:IPaddr2 params ip="123.123.123.123" nic="eth2" op monitor interval="5s" primitive ip1arp ocf:heartbeat:SendArp params ip="123.123.123.123" nic="eth2" group HAServices ip1 ip1arp meta target-role="Started" order ip-before-arp inf: ip1:start ip1arp:start property $id="cib-bootstrap-options" dc-version="xxxxxxxxxxxxxxxx" cluster-infrastructure="Heartbeat" expected-quorum-votes="1" stonith-enabled="false" no-quorum-policy="ignore" rsc_defaults $id="rsc-options" resource-stickiness="100" Pacemaker4.3 Instalación $ apt-get install pacemaker
  • 200. Configuración $ crm configure edit node $id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ha-1.example.com node $id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" ha-2.example.com primitive ip1 ocf:heartbeat:IPaddr2 params ip="123.123.123.123" nic="eth2" op monitor interval="5s" primitive ip1arp ocf:heartbeat:SendArp params ip="123.123.123.123" nic="eth2" group HAServices ip1 ip1arp meta target-role="Started" order ip-before-arp inf: ip1:start ip1arp:start property $id="cib-bootstrap-options" dc-version="xxxxxxxxxxxxxxxx" cluster-infrastructure="Heartbeat" expected-quorum-votes="1" stonith-enabled="false" no-quorum-policy="ignore" rsc_defaults $id="rsc-options" resource-stickiness="100" Pacemaker4.3 Instalación $ apt-get install pacemaker
  • 201. Configuración $ crm configure edit node $id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ha-1.example.com node $id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" ha-2.example.com primitive ip1 ocf:heartbeat:IPaddr2 params ip="123.123.123.123" nic="eth2" op monitor interval="5s" primitive ip1arp ocf:heartbeat:SendArp params ip="123.123.123.123" nic="eth2" group HAServices ip1 ip1arp meta target-role="Started" order ip-before-arp inf: ip1:start ip1arp:start property $id="cib-bootstrap-options" dc-version="xxxxxxxxxxxxxxxx" cluster-infrastructure="Heartbeat" expected-quorum-votes="1" stonith-enabled="false" no-quorum-policy="ignore" rsc_defaults $id="rsc-options" resource-stickiness="100" Pacemaker4.3 Instalación $ apt-get install pacemaker
  • 202. $Servidor Web HAProxy $Base de datos ⚠SPOF $Servidor Web Aplicación $Servidor Web Aplicación SSL* $Servidor Web HAProxy SSL*
  • 203. $Servidor Web HAProxy $Base de datos ⚠SPOF $Servidor Web Aplicación $Servidor Web Aplicación SSL* $Servidor Web HAProxy SSL* $Servidor Web Aplicación $Servidor Web Aplicación $Servidor Web Aplicación ????
  • 204. $Servidor Web HAProxy $Base de datos Master $Servidor Web Aplicación $Servidor Web Aplicación SSL* $Servidor Web HAProxy SSL* $Servidor Web Aplicación $Servidor Web Aplicación $Servidor Web Aplicación W W W W W $Base de datos Read Only
  • 205. $Servidor Web HAProxy $Base de datos Master $Servidor Web Aplicación $Servidor Web Aplicación SSL* $Servidor Web HAProxy SSL* $Servidor Web Aplicación $Servidor Web Aplicación $Servidor Web Aplicación R R R R R $Base de datos Read Only
  • 206. Y aún más lejos? Llegados a este punto deberíamos de tener a varias personas trabajando en esto a tiempo completo... pero el resultado podría parecerse algo como.... :
  • 207. $Servidor Web HAProxy SSL* $Servidor Web HAProxy SSL* DNS ROUND ROBIN $Servidor Web HAProxy SSL* $Servidor Web HAProxy SSL* $Servidor Web HAProxy SSL* $Servidor Web HAProxy SSL* $Servidor Web Aplicación $Servidor Web Aplicación $Servidor Web Aplicación $Servidor Web Aplicación $Servidor Web Aplicación $Servidor Web Aplicación $Servidor Web Aplicación $Servidor Web Aplicación $Servidor Web Aplicación Multi Master DB $Slave n n n n $Master $Master $Slave $Slave $Slave $Slave $Slave $Slave $Slave ++
  • 208. Servidores Web4.4 ¿Cuál elijo? Existen docenas de servidores web, cada empresa suele elegir uno en función de las necesidades y features de cada uno. Nosotros utilizamos nginx dada la sencillez de configuración, la estabilidad, los grandísimos resultados que siempre alcanza en los tests de carga y en particular porque ya hemos trabajado con él y lo conocemos. En realidad nginx lo utilizamos como reverse proxy tanto en los balanceadores de carga como en los servidores web, así como para hacer “spoon-feeding”.
  • 210. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL ??????? 9
  • 211. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL ??????? 9
  • 212. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL ??????? 9
  • 213. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario 3G ??????? 9
  • 214. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario 3G ??????? 9
  • 215. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario 3G ??????? 9
  • 216. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario 3G ??????? 9
  • 217. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario 3G 6Usuario 3G ??????? 9
  • 218. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario 3G 6Usuario 3G 6Usuario EDGE ??????? 9
  • 219. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario 3G 6Usuario 3G 6Usuario EDGE 6Usuario GPRS ??????? 9
  • 220. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario 3G 6Usuario 3G 6Usuario EDGE 6Usuario GPRS ??????? 9
  • 221. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario 3G 6Usuario 3G 6Usuario EDGE 6Usuario GPRS ??????? 9
  • 222. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario 3G 6Usuario 3G 6Usuario EDGE 6Usuario GPRS ??????? 9
  • 223. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario 3G 6Usuario 3G 6Usuario EDGE 6Usuario GPRS ??????? 9
  • 224. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario 3G 6Usuario 3G 6Usuario EDGE 6Usuario GPRS ??????? 9
  • 225. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario 3G 6Usuario 3G 6Usuario EDGE 6Usuario GPRS ??????? 9
  • 226. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario ADSL 6Usuario 3G 6Usuario EDGE 6Usuario GPRS nginx LAN; INTERNET; 1Gb/s
  • 227. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario ADSL 6Usuario 3G 6Usuario EDGE 6Usuario GPRS nginx LAN; INTERNET; 1Gb/s 2.5Mb/s
  • 228. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario ADSL 6Usuario 3G 6Usuario EDGE 6Usuario GPRS nginx LAN; INTERNET; 1Gb/s 236Kb/s
  • 229. $Proceso #1 $Proceso #2 $Proceso #3 $Proceso #4 6Usuario ADSL 6Usuario ADSL 6Usuario 3G 6Usuario EDGE 6Usuario GPRS nginx LAN; INTERNET; 1Gb/s 60Kb/s
  • 230. ✉Emails La mayoría de los servicios online necesitan enviar emails a sus usuarios. El número de emails que has de enviar crece mucho más rápido de lo que esperas...
  • 231. Amazon SES4.4 ¿Qué es Amazon SES? Servicio cloud de Amazon que nos permite enviar grandes cantidades de emails sin tener que disponer de una infraestructura para tales efectos. ¿Y porqué no un smtp inhouse? El tiempo es oro y el día sólo tiene 24 horas. • Pequeñas empresas que no disponen de personal de sistemas pueden ahorrarse muchos dolores de cabeza (y ganar otros) externalizando servicios como este . • Grandes empresas que necesitan enviar millones de emails en épocas concretas y no desean sobre escalar sus sistemas para estas situaciones puntuales. • El coste es muy competitivo: 0.10 $ por cada 1000 emails. Actualmente enviamos alrededor de 1M de emails al mes, lo cual nos cuesta ~£64.
  • 234. https://github.com/blog/1241-deploying-at-github Deploying is a big part of the lives of most GitHub employees. We don't have a release manager and there are no set weekly deploys. Developers and designers are responsible for shipping new stuff themselves as soon as it's ready. This means that deploying needs to be as smooth and safe a process as possible. “
  • 235. $ $ $ $ $ $ $ $ $ $ $ $ server #1 server #3 server #11 server #12 server #2 server #4 server #5 server #6 server #7 server #8 server #9 server #10 $ $server #11 server #12 $ $ $ $ $ $ $ $ $ $ $ $ server #1B server #3B server #11B server #12B server #2B server #4B server #5B server #6B server #7B server #8B server #9B server #10B $ $server #11B server #12B staging live
  • 236. $ $ $ $ $ $ $ $ $ $ $ $ server #1B server #3B server #11B server #12B server #2B server #4B server #5B server #6B server #7B server #8B server #9B server #10B $ $server #11B server #12B live
  • 237. $ $ $ $ $ $ $ $ $ $ $ $ server #1B server #3B server #11B server #12B server #2B server #4B server #5B server #6B server #7B server #8B server #9B server #10B $ $server #11B server #12B liveactivar modo mantenimiento (503) desplegar nuevo código purgar cachés reiniciar servicios minimizar javascript minimizar css generar sprites ... desactivar modo mantenimiento
  • 238. Streamlining SSH scripts fabric from fabric.api import run def host_type(): run('uname -s') fabfile.py $ fab -H localhost,linuxbox host_type [localhost] run: uname -s [localhost] out: Darwin [linuxbox] run: uname -s [linuxbox] out: Linux Done. Disconnecting from localhost... done. Disconnecting from linuxbox... done.
  • 239. Streamlining SSH scripts fabric get(remote_path, local_path=None) put(local_path=None, remote_path=None, ...) run(command, ...) sudo(command, ...) reboot(wait=120) local(command, ...)
  • 240. Hosts fabric @hosts('varnish.example.com') def purge_varnish(): """Purge varnish cache""" sudo('varnishadm -T 127.0.0.1:6082 ban.url . -S /etc/varnish/secret') $ fab purge_varnish
  • 241. Agrupación de hosts en roles fabric env.roledefs = { 'test': ['test-web-1.example.com', 'test-web-2.example.com'], 'test-db': ['test-db-1.example.com', 'test-db-2.example.com'], 'test-ha': ['test-ha-1.example.com', 'test-ha-2.example.com'], 'www': ['www-web-1.example.com', 'www-web-2.example.com'], 'www-db': ['www-db-1.example.com', 'www-db-2.example.com'], 'www-ha': ['www-ha-1.example.com', 'www-ha-2.example.com'], } $ fab deploy -R test $ fab deploy -R www
  • 242. Helpers de interacción fabric confirm(question, default=True) abort(msg) error(message, func=None, exception=None, stdout=None, stderr=None) green(text, bold=False) red(text, bold=False) indent(text, spaces=4, strip=False)
  • 245. La seguridad es un tema extenso y delicado. Os invitamos a profundizar en cada uno de los aspectos antes de ponerlos en práctica. Los siguientes son sólo ejemplos y pueden contener errores. ⚠
  • 246. *iptables No lo son todo, pero sin lugar a dudas son un buen comienzo para evitarnos problemas.
  • 250. Tablas predefinidas  > ; FILTER. NAT. MANGLE. Tabla responsable del filtrado de paquetes. Todos los paquetes pasan por esta tabla. Tabla responsable de la reescritura de direcciones y/o puertos. El primer paquete de cada conexión pasa por esta tabla. Tabla responsable de ajustar opciones de paquetes (e.j) QOS. Todos los paquetes pasan por esta tabla.
  • 251. Tablas predefinidas  > ; FILTER. NAT. MANGLE. Tabla responsable del filtrado de paquetes. Todos los paquetes pasan por esta tabla. Tabla responsable de la reescritura de direcciones y/o puertos. El primer paquete de cada conexión pasa por esta tabla. Tabla responsable de ajustar opciones de paquetes (e.j) QOS. Todos los paquetes pasan por esta tabla.
  • 252. >FILTER.Tabla responsable del filtrado de paquetes. ☰INPUT ☰OUTPUT ☰FORWARD Todos los paquetes destinados a este sistema atraviesan esta cadena. Todos los paquetes creados por este sistema atraviesan esta cadena. Todos los paquetes que pasan por este sistema atraviesan esta cadena. El destino de cada una de las reglas dentro de las cadenas puede ser: ACCEPT, DROP, QUEUE, o RETURN (entre otros)
  • 253. >FILTER.Tabla responsable del filtrado de paquetes. ☰INPUT ☰OUTPUT ☰FORWARD Todos los paquetes destinados a este sistema atraviesan esta cadena. Todos los paquetes creados por este sistema atraviesan esta cadena. Todos los paquetes que pasan por este sistema atraviesan esta cadena. El destino de cada una de las reglas dentro de las cadenas puede ser: ACCEPT, DROP, QUEUE, o RETURN (entre otros)
  • 254. >FILTER:INPUTCadena responsable del filtrado de paquetes de entrada. *filter :INPUT DROP [0:0] :OUTPUT ACCEPT [0:0] :FORWARD DROP [0:0] -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -m state --state INVALID -j DROP -A INPUT -i lo -j ACCEPT -A INPUT -p icmp -j ACCEPT -A INPUT -s $IP/32 -d $IP/32 -p tcp --dport 80 -j ACCEPT
  • 255. fail2ban6.2 Fail2ban nos permite bloquear ataques de fuerza bruta contra servicios como ssh, mail, http etc... • Muy sencillo de instalar y configurar. • Una buena contramedida activa. • Su funcionamiento se basa en leer los logs generados por estos servicios utilizando expresiones regulares. • Además de bloquear el trafico entrante desde estas fuentes se pueden desplegar otras medidas o enviar notificaciones. !h#p://fail2ban.org
  • 256. SSH root@...6.3 Desactivar la cuenta de root es una de las primeras medidas a tomar al configurar un servidor. • Si disponemos de un servicio como fail2ban estaremos impidiendo en cierta medida que nadie tenga éxito al realizar un ataque de fuerza bruta. • Si por alguna razón el servicio está caído tendríamos nuestra cuenta de root expuesta. • Es muy recomendable no permitir conexiones ssh utilizando root. • Una vez en el sistema podemos identificarnos como root o utilizar sudo. PermitRootLogin no /etc/ssh/sshd_config
  • 259. You can’t improve what you don’t measure “ ”
  • 260. top7.1
  • 262. munin7.3 Ventajas • Muy sencillo de instalar y configurar. • Fácil de crear nuevas gráficas usando cualquier lenguaje de scripting. • Uso mínimo de recursos. • Un muy buen punto de partida. Desventajas • Sólo tres vistas por cada gráfica (diaria, semanal, anual) • Gráficas generadas cada ~5m. !h#p://munin9monitoring.org
  • 263. but... What’s next? Llegado el momento las métricas se convierten en críticas para analizar no solo la salud del sistema, si no la del negocio. ;
  • 270. graphite server db server !carbon graphite tcp 2003 diamondstatsd udp 8125 tcp 80 ☁
  • 271. graphite server web server db server !carbon graphite tcp 2003 diamondstatsd udp 8125 diamond statsd udp 8125 diamond statsd udp 8125 tcp 80 ☁
  • 272. graphite server web server db server !carbon graphite tcp 2003 diamondstatsd udp 8125 diamond statsd udp 8125 diamond statsd udp 8125 tcp 80 logs logs ☁
  • 273. graphite server web server db server !carbon graphite tcp 2003 diamondstatsd udp 8125 diamond statsd udp 8125 diamond statsd udp 8125 tcp 80 app logs logs ☁
  • 274. graphite7.4 No sólo datos... conocimiento! Descubrir que la carga de un servidor es 9.3 lo fines de semana a las 3am es útil pero... ¿cual es la causa? ¿Que otros síntomas hay? ¿Algún otro servidor se ve afectado? ¿Qué estaba haciendo el servidor? ¿Cuantos procesos teníamos en marcha? ¿Qué tamaño tenía la cola de emails? ¿Hace cuando que hicimos el último deploy?...
  • 275. graphite7.4 from pystatsd import Client sc = Client('127.0.0.1', 8125) sc.increment('streetlife.emails.immediate.sent') Python echo "streetlife.emails.immediate.sent:1|c" | nc -w 1 -u 127.0.0.1 8125 Bash Son sólo paquetes UDP. Dado que añadir estadísticas consiste en enviar un simple paquete UDP a nuestro servidor de statsd, podemos hacerlo desde cualquier sitio! Nuestra aplicación, un script en bash ... Fire-and-forget!
  • 276.
  • 277.
  • 278.
  • 279.
  • 281. pingdom7.6 Yo mi me conmigo... Es muy embarazoso darse cuenta que tu web se ha caído porque te lo diga un cliente. Hay docenas de servicios como pingdom que se dedican a testear tu web desde múltiples localizaciones. Features interesantes: • Monitorizar estado y tiempo de respuesta de páginas clave. • Comprobar tiempos de respuesta desde la otra parte del mundo. • Notificaciones SMS. • Uptime reports.
  • 284. $server #1 $ ssh user1@server1 $ apt-get install paquete_x
  • 285. $server #1 $ ssh user1@server1 $ apt-get install paquete_x $server #2 $ ssh user2@server2 $ apt-get install paquete_x
  • 286. $server #1 $ ssh user1@server1 $ apt-get install paquete_x $server #2 $ ssh user2@server2 $ apt-get install paquete_x $server #3 $ ssh user3@server3 $ apt-get install paquete_x
  • 287. $ ssh user1@server1 $ apt-get install paquete_x $server #1 $server #2 $server #3 $server #4 $ ssh user1@server1 $ apt-get install paquete_x $ ssh user3@server3 $ apt-get install paquete_z $ ssh user4@server4 $ apt-get install paquete_z
  • 288. $ ssh user1@server1 $ apt-get install paquete_x $server #1 $server #2 $server #3 $server #4 $ ssh user1@server1 $ apt-get install paquete_x $ ssh user3@server3 $ apt-get install paquete_z $ ssh user4@server4 $ apt-get install paquete_z
  • 289. $ ssh user1@server1 $ apt-get install paquete_x $server #1 $server #2 $server #3 $server #4 $ ssh user1@server1 $ apt-get install paquete_x $ ssh user3@server3 $ apt-get install paquete_z $ ssh user4@server4 $ apt-get install paquete_z
  • 290. $ $ $ $ $ $$$ $$$$ $ $ server #1 server #3 server #11 server #12 server #2 server #4 server #5 server #6 server #7 server #8 server #9 server #10 server #13 server #14
  • 291. $ $ $ $ $ $ $ $ $ $ $ $ server #1 server #3 server #11 server #12 server #2 server #4 server #5 server #6 server #7 server #8 server #9 server #10 $ $server #11 server #12 $ $ $ $ $ $ $ $ $ $ $ $ server #1B server #3B server #11B server #12B server #2B server #4B server #5B server #6B server #7B server #8B server #9B server #10B $ $server #11B server #12B live staging
  • 292. $ $ $ $ $ $ $ $ $ $ $ $ server #1 server #3 server #11 server #12 server #2 server #4 server #5 server #6 server #7 server #8 server #9 server #10 $ $server #11 server #12 $ $ $ $ $ $ $ $ $ $ $ $ server #1B server #3B server #11B server #12B server #2B server #4B server #5B server #6B server #7B server #8B server #9B server #10B $ $server #11B server #12B live staging $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_ $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x $ ssh user1@server1 $ apt-get install paquete_x
  • 293. Shit hapens happens... a lot. ⚠Repetition leads to boredom, boredom to horrifying mistakes, horrifying mistakes to God-I-wish-I-was-still-bored.
  • 294. Provisioning8.1 Automatizar la configuración y mantenimiento de tantos servidores cómo necesitemos. • Generar plantillas que nos permitan generar nuevas máquinas sin mucho esfuerzo y de manera automatizada. • Solucionar casos de catástrofe total ya que podemos regenerar nuestra arquitectura en otro datacenter sin problemas. • Todo del código que automatice este proceso se convierte en último termino en una excelente documentación. • “Code as Infrastructure”
  • 295. Puppet8.2 Puppet es junto a Chef uno de los más utilizados. • Nos permite automatizar la configuración de servidores UNIX y Windows. • El lenguaje que se utiliza puede ser tanto Ruby como un lenguaje declarativo propio de Puppet en el que se definen tanto recursos del sistema como el estado de los mismos. • Servicios, usuarios, paquetes, ficheros... • Puppet extrae del sistema información como CPUs, memoria, discos direcciones IP etc... y compila nuestras plantillas junto a esta información. • Puede ejecutarse en modo arquitectura con un servicio central encargado de compilar las plantillas o en modo “solo-mode” en el cual se compilan las plantillas en cada servidor.
  • 296. Puppet8.2 Una de las principales características de Puppet frente a otros sistemas de configuración es que es idempotente. Por ejemplo, podemos ejecutarlo cada 30 minutos y cerciorarnos de que todo está tal y como lo hemos definido. Esta es una gran ventaja dado que además de servirnos como bootstrap para nuevas máquinas, puppet nos permite administrar nuestras máquinas a lo largo de todo su ciclo de vida desde la creación mantenimiento y migración.
  • 297. package package { 'nginx': ensure => installed, } present latest 1.5.3 absent
  • 298. package package { 'nginx': ensure => installed, } present latest 1.5.3 absent
  • 299. file file { '/etc/nginx/nginx.conf': source => 'modules/nginx/nginx.conf', owner => 'root', group => 'root', mode => '640', require => Package['nginx'], notify => Service['nginx'] } ????
  • 300. file file { '/etc/nginx/nginx.conf': source => 'modules/nginx/nginx.conf', owner => 'root', group => 'root', mode => '640', require => Package['nginx'], notify => Service['nginx'] } ????
  • 301. service service { 'nginx': ensure => running, enable => true, hasstatus => true, hasrestart => true, }
  • 303. user, group user { 'tom': ensure => present, shell => '/bin/bash', home => '/home/tom', managehome => true, } group { 'friends': ensure => present }
  • 304. nodes node 'web.example.com' inherits web_node { include munin include python user { 'tom': ensure => present, shell => '/bin/bash', home => '/home/tom', managehome => true, } ... }
  • 305. apply $ puppet apply puppet/manifests/site.pp
  • 308.
  • 309. Características • Wrapper de virtualbox para crear y destruir máquinas desde la linea de comandos. • Permite crear “instancias” base para crear máquinas desde un estado concreto en cuestión de segundos. • Integración con Puppet y Chef entre otros. • Gracias a vagrant y puppet podemos lograr que todos los miembros del equipo dispongan del mismo setup en local sin mucho quebradero de cabeza. • La puesta en marcha de nuevos empleados se reduce a minutos en vez de días. • Gracias a la sencillez de uso podemos crear distintos setup en cuestión de minutos y comprobar su funcionamiento. • Funciona en todas las plataformas: Linux, OSX y Windows. Vagrant9.1
  • 310. Añadir un box Vagrant9.1 $ vagrant box add ubuntu-precise http://bit.ly/ubuntu-precise Crear una nueva instancia $ vagrant init ubuntu-precise Arrancar nuestra nueva máquina virtual $ vagrant up !h#p://vagrantbox.es $ vagrant ssh
  • 311. Vagrant::Config.run do |config| config.vm.define :web do |web| web.vm.box = "ubuntu-precise-64" web.vm.box_url = "http://bit.ly/ubuntu-precise" web.vm.host_name = "dev.example.com" web.vm.network :hostonly, "33.33.33.20" web.vm.forward_port(22, 2023) web.vm.forward_port(80, 8081) web.vm.share_folder("code", "/home/vagrant/code", "./code", :nfs => true) end config.vm.define :db do |db| db.vm.box = "ubuntu-precise-64" db.vm.box_url = "http://bit.ly/ubuntu-precise" db.vm.host_name = "dev-db.example.com" db.vm.network :hostonly, "33.33.33.21" db.vm.forward_port(22, 2024) db.vm.forward_port(5432, 5432) end end Múltiples boxes
  • 312. $ vagrant up web [web] VM already created. Booting if it's not already running... [web] Clearing any previously set forwarded ports... [web] Fixed port collision for 22 => 2222. Now on port 2202. [web] Forwarding ports... [web] -- 22 => 2023 (adapter 1) [web] -- 80 => 8081 (adapter 1) [web] Exporting NFS shared folders... [vagrant] Preparing to edit /etc/exports. Administrator privileges will be required... [web] Creating shared folders metadata... [web] Clearing any previously set network interfaces... [web] Preparing network interfaces based on configuration... [web] Booting VM... [web] Waiting for VM to boot. This can take a few minutes. [web] VM booted and ready for use! [web] Configuring and enabling network interfaces... [web] Setting host name... [web] Mounting shared folders... [web] -- v-root: /vagrant [web] -- manifests: /tmp/vagrant-puppet/manifests [web] -- v-pp-m0: /tmp/vagrant-puppet/modules-0 [web] Mounting NFS shared folders... [web] Running provisioner: Vagrant::Provisioners::Puppet... [web] Running Puppet with /tmp/vagrant-puppet/manifests/site.pp... stdin: is not a tty notice: Finished catalog run in 1.70 seconds vagrant up
  • 314.
  • 316.
  • 317.
  • 318.
  • 319.
  • 320.
  • 321. Chrome Plugins9.4 Hay docenas de plugins que pueden hacer nuestro día a día mucho más sencillo. Estos son algunos de los que encontramos más interesantes, además del inspector que Chrome tiene integrado.
  • 322. User-Agent switcher9.4 Cambiar de User-Agent con dos clicks Podemos configurar nuestros propios User-Agent.
  • 323. Resolution test9.4 Cambiar el tamaño de la ventana con dos clicks
  • 324. Cache Killer9.4 Mientras esté activo no se utilizará la cache del navegador.
  • 326.
  • 327.
  • 328.
  • 331.
  • 332. CI: Jenkins10.2 Características Servicio que nos permite automatizar (entre otras cosas) la ejecución de tests, compilación de documentación, generar reports de test coverage... Ejecuciones • Periódicamente • Por cada commit al repositorio. Configuración • Requiere de un poco de práctica pero una vez configurado no necesita mucho mantenimiento.
  • 333.
  • 334. Hipchat/IRC10.3 La comunicación entre los empleados es muy importante (sobre todo cuando no siempre todo el mundo está trabajando desde la misma oficina). Ventajas • Histórico de todas las conversaciones. • Facilidad para compartir rápidamente ficheros, capturas de pantalla etc... • 0 Configuración y entrada amable para no techies. • Salas por departamentos, equipos etc... • Gaticos. • Notificaciones de deploy, mantenimiento etc...
  • 336. Recursos http://www.flickr.com/photos/marceldouwedekker/ http://pygments.org/ http://entypo.com/ Fuentes http://net.tutsplus.com/tutorials/other/http-headers-for-dummies/ http://igoro.com/archive/what-really-happens-when-you-navigate-to-a-url/ http://pyvideo.org/video/1677/how-the-internet-works http://es.wikipedia.org/wiki/Hypertext_Transfer_Protocol http://en.wikipedia.org/wiki/List_of_HTTP_header_fields http://en.wikipedia.org/wiki/MIME_type http://silex.sensiolabs.org/doc/cookbook/json_request_body.html http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-1 http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4 http://en.wikipedia.org/wiki/HTTP_cookie http://developer.yahoo.com/performance/rules.html http://www.tldp.org/HOWTO/SSL-Certificates-HOWTO/x64.html http://www.varnish-cache.org/docs/3.0/ http://haproxy.1wt.eu/download/1.5/doc/configuration.txt http://ontwik.com/python/django-deployment-workshop-by-jacob-kaplan-moss/ http://glue.readthedocs.org/en/latest/ http://library.linode.com/ http://code.flickr.net/2008/10/27/counting-timing/ http://codeascraft.etsy.com/2011/02/15/measure-anything-measure-everything/ http://codeascraft.etsy.com/2010/12/08/track-every-release/ http://plusbryan.com/my-first-5-minutes-on-a-server-or-essential-security-for-linux-servers http://docs.vagrantup.com/v2/