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

в 10:34, , рубрики: CentOS, linux, nginx, системное администрирование, метки: , , ,

«Идеальный» 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.

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

Важно! Для приведенного ниже решения, у нас должно быть 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
<b>! Именное обозначение этого сервера</b>
        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

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

# Подключаем официальный репозиторий 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 

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

Автор: SyCraft

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js