...

пятница, 25 октября 2013 г.

«Идеальный» www кластер. Часть 1. Frontend: NGINX + Keepalived (vrrp) на CentOS


Этом цикле статей «Идеальный www кластер», я хочу передать базовые основы построения высокодоступного и высокопроизводительного www решения для нагруженных web проектов для неподготовленного администратора.

Статья будет содержать пошаговую инструкцию и подойдет любому человеку кто освоил силу copy-past

Ошибки найденые вами, помогут в работе и мне и тем кто будет читать эту статью позже! Так что любые улучшение и правки приветствуются!


На frontend мы будем использоваться связку из двух службы:



keepalived — реализации протокола VRRP (Virtual Router Redundancy Protocol) для Linux. Демон keepalived следит за работоспособностью машин и в случае обнаружения сбоя — исключает сбойный сервер из списка активных серверов, делегируя его адреса другому серверу.




nginx [engine x] — это HTTP-сервер и обратный прокси-сервер, а также почтовый прокси-сервер, написанный Игорем Сысоевым. Уже длительное время он обслуживает серверы многих высоконагруженных российских сайтов, таких как Яндекс, Mail.Ru, ВКонтакте и Рамблер. Согласно статистике Netcraft nginx обслуживал или проксировал 15.08% самых нагруженных сайтов в октябре 2013 года.


Основная функциональность HTTP-сервера



  • Обслуживание статических запросов, индексных файлов, автоматическое создание списка файлов, кэш дескрипторов открытых файлов;

  • Акселерированное обратное проксирование с кэшированием, простое распределение нагрузки и отказоустойчивость;

  • Акселерированная поддержка FastCGI, uwsgi, SCGI и memcached серверов с кэшированием, простое распределение нагрузки и отказоустойчивость;

  • Модульность, фильтры, в том числе сжатие (gzip), byte-ranges (докачка), chunked ответы, XSLT-фильтр, SSI-фильтр, преобразование изображений; несколько подзапросов на одной странице, обрабатываемые в SSI-фильтре через прокси или FastCGI, выполняются параллельно;

  • Поддержка SSL и расширения TLS SNI.


Другие возможности HTTP-сервера



  • Виртуальные серверы, определяемые по IP-адресу и имени;

  • Поддержка keep-alive и pipelined соединений;

  • Гибкость конфигурации;

  • Изменение настроек и обновление исполняемого файла без перерыва в обслуживании клиентов;

  • Настройка форматов логов, буферизованная запись в лог, быстрая ротация логов;

  • Специальные страницы для ошибок 3xx-5xx;

  • rewrite-модуль: изменение URI с помощью регулярных выражений;

  • Выполнение разных функций в зависимости от адреса клиента;

  • Ограничение доступа в зависимости от адреса клиента, по паролю (HTTP Basic аутентификация) и по результату подзапроса;

  • Проверка HTTP referer;

  • Методы PUT, DELETE, MKCOL, COPY и MOVE;

  • FLV и MP4 стриминг;

  • Ограничение скорости отдачи ответов;

  • Ограничение числа одновременных соединений и запросов с одного адреса;

  • Встроенный Perl.








Важно! Для приведенного ниже решения, у нас должно быть 2 сетевых интерфейса на каждой из нод keepalived

мы должны точно указать нашу маску и понимать где в нашей сети находится broadcast, если этого не сделать, то будем очень долго пытаться понять почему у нас все работает не так как мы хотим!


# Моя приватная сеть

[root@nginx-frontend-01 ~]#



nano /etc/sysconfig/network-scripts/ifcfg-eth2


DEVICE=eth2
BOOTPROTO=static
ONBOOT=yes
IPADDR=10.100.100.56
NETWORK=10.100.100.0
NETMASK=255.255.255.0
BRAODCAST=10.100.100.255


# Публичная сеть

[root@nginx-frontend-01 ~]#



nano /etc/sysconfig/network-scripts/ifcfg-eth3


DEVICE=eth3
BOOTPROTO=static
ONBOOT=yes
IPADDR=72.x.x.1
NETMASK=255.255.255.248
BRAODCAST=72.x.x.55
GATEWAY=72.x.x.49


То есть в моей публичной сети, маска /29 и значит мой broadcast x.x.x.55, если бы была сеть /24, то можно было бы указать x.x.x.255

Если это перепутать, то вы отгребете кучу проблем


# Устанавливаем keepalived



yum install keepalived -y

# Это очень плохо, этого делать не нужно! только в тестовых целях и на свой страх и риск, я предупредил. Выключаем selinux



sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux

# Настраиваем keepalived на первой ноде nginx-frontend-01, очень важно, знак коментария "!" а не "#"



mv /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.old && nano /etc/keepalived/keepalived.conf

[root@nginx-frontend-01 ~]#



nano /etc/keepalived/keepalived.conf


! Configuration File for keepalived

global_defs {
notification_email {
root@localhost
}
notification_email_from root@localhost
smtp_server localhost
smtp_connect_timeout 30
! Именное обозначение этого сервера
router_id nginx-frontend-01
}

vrrp_instance nginx2 {
! Состояние в котором стартует нода, в этом случае она резерв
state BACKUP

! Наш публичиный интерфейс
interface eth3

! Индификатор, в разных vrrp_instance он должен быть разным
virtual_router_id 102

! Это приоритет этой ноды перед другими, у BACKUP он всегда должен быть ниже чем у MASTER
priority 100

advert_int 1
dont_track_primary

! Тут можно на всякий случай указать наш broadcast
mcast_src_ip x.x.x.55

! Пароль можно указать любой, но одинаковый для серверов
authentication {
auth_type PASS
auth_pass b65495f9
}
! Этот адрес возмет себе сервер, если MASTER в сети упадет
virtual_ipaddress {
x.x.x.2/29 dev eth3
}

}
vrrp_instance nginx1 {
! Эта нода - мастер, она использует адрес из этой секции и ее заменит другая, если эта упадет
state MASTER

! Наш публичиный интерфейс
interface eth3

! Индификатор, в разных vrrp_instance он должен быть разным
virtual_router_id 101

! Для мастера это значение обязательно выше чем для backup
priority 200

advert_int 1
dont_track_primary

! Тут можно на всякий случай указать наш broadcast
mcast_src_ip x.x.x.55

! Пароль можно указать любой, но одинаковый для серверов
authentication {
auth_type PASS
auth_pass b65495f8
}
virtual_ipaddress {
! Нода стартует с этим адресом, если эта нода упадет, этот адрес подхватит другая
x.x.x.1/29 dev eth3
}
! Для мастера нужно прописать gateway
virtual_routes {
default via x.x.x.49 dev eth3 metric 2
}
}


# Настраиваем keepalived на второй ноде nginx-frontend-02 очень важно, знак коментария "!" а не "#"



mv /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.old && nano /etc/keepalived/keepalived.conf

[root@nginx-frontend-02 ~]#



nano /etc/keepalived/keepalived.conf


! Configuration File for keepalived

global_defs {
notification_email {
root@localhost
}
notification_email_from root@localhost
smtp_server localhost
smtp_connect_timeout 30
! Именное обозначение этого сервера
router_id nginx-frontend-02
}

vrrp_instance nginx1 {
! Состояние в котором стартует нода, в этом случае она резерв
state BACKUP

! Наш публичиный интерфейс
interface eth3

! Индификатор, в разных vrrp_instance он должен быть разным
virtual_router_id 101

! Это приоритет этой ноды перед другими, у BACKUP он всегда должен быть ниже чем у MASTER
priority 100

advert_int 1
dont_track_primary

! Тут можно на всякий случай указать наш broadcast
mcast_src_ip x.x.x.55

! Пароль можно указать любой, но одинаковый для серверов
authentication {
auth_type PASS
auth_pass b65495f9
}
! Этот адрес возмет себе сервер, если MASTER в сети упадет
virtual_ipaddress {
x.x.x.1/29 dev eth3
}

}
vrrp_instance nginx2 {
! Эта нода - мастер, она использует адрес из этой секции и ее заменит другая, если эта упадет
state MASTER

! Наш публичиный интерфейс
interface eth3

! Индификатор, в разных vrrp_instance он должен быть разным
virtual_router_id 102

! Для мастера это значение обязательно выше чем для backup
priority 200

advert_int 1
dont_track_primary

! Тут можно на всякий случай указать наш broadcast
mcast_src_ip x.x.x.55

! Пароль можно указать любой, но одинаковый для серверов
authentication {
auth_type PASS
auth_pass b65495f9
}
! Нода стартует с этим адресом, если эта нода упадет, этот адрес подхватит другая
virtual_ipaddress {
x.x.x.2/29 dev eth3
}
virtual_routes {
! Для мастера нужно прописать gateway
default via x.x.x.49 dev eth3 metric 2
}
}


# Добавляем в автозагрузку и запускаем



chkconfig keepalived on && service keepalived restart

# Добавляем разрешения фаервола, больше половина проблем, из за того что мы забываем про фаервол!



iptables -A INPUT -i eth3 -p vrrp -j ACCEPT
iptables -A OUTPUT -o eth3 -p vrrp -j ACCEPT
iptables -A INPUT -d 224.0.0.0/8 -i eth3 -j ACCEPT
iptables-save > /etc/sysconfig/iptables


# Это очень важный шаг



echo "net.ipv4.ip_nonlocal_bind=1" >> /etc/sysctl.conf && sysctl -p

# Проверяем



/etc/init.d/keepalived restart && tail -f -n 100 /var/log/messages

# Проверяем как между собой общаются наши ноды keepalived



tcpdump -vvv -n -i eth3 host 224.0.0.18

# Мы должны увидеть это



x.x.x.55 > 224.0.0.18: VRRPv2, Advertisement, vrid 102, prio 200, authtype simple, intvl 1s, length 20, addrs: x.x.x.2 auth "b65495f9"
07:50:50.019548 IP (tos 0xc0, ttl 255, id 5069, offset 0, flags [none], proto VRRP (112), length 40)
x.x.x.55 > 224.0.0.18: VRRPv2, Advertisement, vrid 101, prio 200, authtype simple, intvl 1s, length 20, addrs: x.x.x.1 auth "b65495f9"


Теперь можно попеременно выключать сервера, опускать интерфейсы, дергать провода итд

У нас в сети всегда будут присутствовать оба этих адреса и на них будет отвечать наш nginx



# Подключаем официальный репозиторий nginx для CentOS 6



rpm -Uhv http://nginx.org/packages/rhel/6/noarch/RPMS/nginx-release-rhel-6-0.el6.ngx.noarch.rpm

# Обновляем систему и устанавливаем nginx



yum update -y
yum install nginx


# Удаляем хосты поумолчанию



rm -f /etc/nginx/conf.d/default.conf
rm -f /etc/nginx/conf.d/virtual.conf
rm -f /etc/nginx/conf.d/ssl.conf


# Приводим главный конфиг к подобному виду



mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.old
nano /etc/nginx/nginx.conf



user nginx;

# Количество процессов ожидаюищих соединения
worker_processes 10;

pid /var/run/nginx.pid;

events {
# Максимальное количество обслуживаемых клиентов онлайн
worker_connections 1024;

# epoll — эффективный метод, используемый в Linux 2.6+ http://nginx.org/ru/docs/events.html
use epoll;

# Рабочий процесс за один раз будет принимать сразу все новые соединения
multi_accept on;

}
error_log /var/log/nginx/error.log warn;

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

connection_pool_size 256;
client_header_buffer_size 4k;
client_max_body_size 100m;
large_client_header_buffers 8 8k;
request_pool_size 4k;
output_buffers 1 32k;
postpone_output 1460;

# Все страницы будут ужиматься gzip
gzip on;
gzip_min_length 1024;
gzip_proxied any;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/xml application/xml application/x-javascript text/javascript text/css text/json;
gzip_comp_level 8;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";

sendfile on;
tcp_nopush on;
tcp_nodelay on;

keepalive_timeout 75 20;

server_names_hash_max_size 8192;
ignore_invalid_headers on;
server_name_in_redirect off;

proxy_buffer_size 8k;
proxy_buffers 8 64k;
proxy_connect_timeout 1000;
proxy_read_timeout 12000;
proxy_send_timeout 12000;

# Мы рассказываем где будет храниться кеш, но по умолчанию я его не использую
proxy_cache_path /var/cache/nginx levels=2 keys_zone=pagecache:5m inactive=10m max_size=50m;

# Передаем backend реальный адрес клиента для mod_rpaf
real_ip_header X-Real-IP;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

allow all;

include /etc/nginx/conf.d/*.conf;
}


# Теперь приведем в порядок наш универсальный vhost



nano /etc/nginx/conf.d/all.conf


upstream web {
# Перечисляем все backend между которыми nginx будет балансировать клиентов, говорим количество fail для баны backend ноды и таймаут
# back01
server 10.211.77.131 weight=10 max_fails=60 fail_timeout=2s;
# back02
server 10.211.77.136 weight=10 max_fails=60 fail_timeout=2s;

}
server {
listen 80;
location / {
proxy_pass http://web;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}



# И наш конфиг для работы сайта по SSL, для кажого сайта должен быть свой конфиг со своим сертификатом



nano /etc/nginx/conf.d/ssl.conf


upstream ssl {
# back01
# server 10.211.77.131 weight=10 max_fails=60 fail_timeout=2s;
# back02
server 10.100.100.63 weight=10 max_fails=60 fail_timeout=2s;

}
server {
listen 443;

ssl on;
ssl_certificate /etc/nginx/ssl/GeoTrustCA.crt;
ssl_certificate_key /etc/nginx/ssl/GeoTrustCA.key;

# Увеличиваем безопасность нашего SSL соединения
ssl_ciphers RC4:HIGH:!aNULL:!MD5:!kEDH;
ssl_session_cache shared:SSL:10m;
ssl_prefer_server_ciphers on;
ssl_protocols SSLv3 TLSv1;

location / {
proxy_pass http://ssl;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}


# Запускаем nginx и добавляем его в автозагрузку!



/etc/init.d/nginx start && chkconfig nginx on

Продолжение следует, спасибо за внимание!


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



Комментариев нет:

Отправить комментарий