“Крылья, лапы и хвосты” нашего Linux-хостинга, часть 1: как мы автоматизировали развёртывание инфраструктуры

от автора

— Эй, птичка, летим со мной, там столько вкусного!!!
— Столько? [разводя руки]
— у-у [мотая головой и соединяя руки]

Одна из основных проблем, которая встаёт перед провайдерами shared-хостинга, ‒ это изолирование пользователей. Было бы, конечно, проще и надёжнее создавать для каждого пользователя контейнер, но это съедает лишние ресурсы и здорово уменьшает плотность упаковки сайтов на одну машину (я исхожу из комфортной для клиента упаковки, а не вариант “селёдки в бочке”, который всё ещё встречается на ультрадешёвых хостингах, когда открытие даже статичной страницы сайта клиента заметно тормозит из-за нагрузки на веб-бокс). Скажу больше, нередки ситуации, когда один клиент, случайно или намеренно, занимает слишком много ресурсов, в ущерб всем остальным.

Решить эти задачи, не тратя ресурсы серверов впустую, мы и намеревались при помощи CloudLinux. CloudLinux уже упоминался на Хабре. Это RHEL-совместимый дистрибутив, базирующийся на ядре OpenVZ. При помощи хитрых компонентов (CageFS и LVE) и модифицированного ядра позволяет ограничивать пользователей в ресурсах (процессор память диск) без создания контейнеров.

CageFS ‒ виртуальная файловая система, которая реализует Container-Based Virtualization (Operation System-Level Virtualization). Создаёт файловую структуру домашней директории и ограничивает пространство имён пользователя, изолируя его от других пользователей системы.
Структура домашней директории пользователя по умолчанию находится в /usr/share/cagefs-skeleton. В нашем случае используется своя структура директории home, путь к шаблону (skeleton) которой описывается в /etc/cagefs/cagefs.base.home.dirs.

LVE (Lightweight Virtual Environment) ‒ технология ограничения ресурсов на базе cgroups. Позволяет тонко ограничить ресурсы для конкретного пользователя на уровне ядра, таких как:

  • % мощности одного ядра CPU (может быть больше 100%);
  • физическая память;
  • виртуальная память;
  • число процессов, создаваемых внешними событиями (например новый HTTP-запрос);
  • число процессов внутри LVE;
  • производительность дисковой подсистемы;
  • количество операций ввода/вывода.

Причём применяются ограничения на основании хозяина процесса. Таким образом, сколько бы раз пользователь не зашёл на сервер по SSH, лимиты на ресурсы будут общими.

При полном исчерпании ресурсов активных серверов, мы заводим новый и создаём пользователей там. Конечно, можно всё это делать руками (тем более, что система мониторинга предупреждает об исчерпании ресурсов в текущей инфраструктуре). Но мы-то знаем, что самое дорогое в IT это время специалиста и лучше “день потерять, но потом за пять минут долететь” ‒ автоматизировать рутинные операции.
Для создания и подготовки новых серверов мы используем библиотеку Puppet fabric и Puppet.
Fabric позволит автоматизировать подключение к группам серверов и удалённый запуск команд, а Puppet используется для централизованного управления конфигурацией.

Приведу пример развертывания сервера на чистую версию CentOS 6.7 x64, которую мы превратим в CloudLinux. Разворачивать скрипты буду удалённо со своей машины (CentOS) на машину с IP 10.0.0.146. Создание чистых машин с заданной ОС у нас сделано шаблонами и не требует вообще никаких усилий. Настройка IP выполняется тоже автоматически, свободные адреса берутся из специальной системы учёта, которую мы называем “Инвентори”.

Ставлю на свою рабочую машину fabric и puppet:

yum install gcc python-devel python-pip puppet puppet-server pip install fabric

Скрипт начальной подготовки системы:

install_web.sh

#!/bin/sh  if ! grep --quiet "^SELINUX=disabled" /etc/selinux/config; then     echo "SELINUX=disabled" > /etc/selinux/config     echo "disabled SELINUX, please reboot server and run script again!"     exit fi  if ! grep --quiet "var" /etc/fstab; then     echo "please create separate mount point /var and run script again!"     exit fi  # fix fstab, activate quotas perl -p -i -e "s/\/var\s+ext4\s+defaults\s+0 0/\/var\t\t\text4\tdefaults,noatime,nosuid,usrjquota=aquota.user,jqfmt=vfsv0\t1 2/" /etc/fstab mount -vo remount /var quotacheck -vumaf quotaon -avu  set -e  # install cloudlinux if ! echo $(uname -r) | grep --quiet "lve"; then     wget http://repo.cloudlinux.com/cloudlinux/sources/cln/cldeploy     sh -x cldeploy -i # If use non-IP-based activation then execute cldeploy -k <activation key>     yum -y '--disablerepo=*' --enablerepo=cloudlinux* update     yum -y '--disablerepo=*' --enablerepo=cloudlinux* install mod_hostinglimits cagefs lve-wrappers     yum install libgcc.i686 glibc.i686 -y     rm -rf cldeploy     echo "installed CloudLinux, please reboot server and run script again!"     exit fi  # activate cloudlinux cagefs cagefsctl --init cagefsctl --set-min-uid 2000 /usr/sbin/cagefsctl --enable-all 

При первом запуске скрипт отключит SELinux, установит необходимые репозитории, активирует репозитории CloudLinux и устанавливает необходимые компоненты CloudLinux, включая ядро:

ssh 10.0.0.146 < install_web.sh

После перезагрузки системы повторный запуск скрипта проинициализирует шаблон домашней директории (cagefs-skeleton), установит UID, с которого начинаются учётные записи пользователей CageFS, равным 2000 и включит CageFS.

Для установки и настройки необходимого ПО воспользуюсь fabric и puppet.
Добавлю наш сервер с IP 10.0.0.146 и hostname web.domain.com в конфигурацию Puppet — манифест web.pp, который описывает наш новый сервер:

node /^web.domain.com/ {     include base_web }

Класс base_web включает в себя всю настройку нашего сервера. О том, как детально настраивать систему с помощью Puppet, в том числе примеры классов настройки, есть во множестве мест в Интернете, включая замечательный CookBook.
Скрипт конфигурации fabric:

fabfile.py

#!/usr/bin/python  from fabric.api import env, sudo, roles, settings from fabric.contrib.project import rsync_project  env.roledefs['production'] = ['10.0.0.146'] env.roledefs['development'] = []  def shell_env():     env.port = 22     env.deploy_path = './puppet'  def deploy_puppet():     shell_env()     with settings(warn_only=True):         result = sudo('rpm -q rsync')         if not result.succeeded:             sudo('yum install -y rsync')     rsync_project(         remote_dir=env.deploy_path,         local_dir='./',         exclude=['.svn', '*.pyc', 'fabfile.py', 'install_*.sh'],         extra_opts='--delete-after'     )     with settings(warn_only=True):         result = sudo('rpm -q epel-release')         if not result.succeeded:             sudo('rpm -Uvh http://mirror.yandex.ru/epel/6/x86_64/epel-release-6-8.noarch.rpm')          result = sudo('rpm -q puppet')         if not result.succeeded:             sudo('yum install puppet -y')     sudo('puppet apply --modulepath {0}/modules/ {0}/manifests/site.pp'.format(env.deploy_path))  @roles('production') def deploy_p():     deploy_puppet()  @roles('development') def deploy_d():     deploy_puppet()  def deploy():     deploy_puppet()

Наконец, запускаю fabric production, который установит клиент puppet и доплонительное ПО, и система готова:

fab deploy_p

При помощи puppet на сервер будут залиты единые настройки, которые мы используем для всех серверов одного типа.

Вся конфигурация (заливаемая на сервера через puppet) у нас хранится централизованно во внутреннем SVN-репозитории, что очень удобно, когда конфигурированием и поддержкой занимаются несколько человек. Допустим, нужно изменить конфигурацию по-умолчанию для sysctl. Идём в puppet/modules/sysctl/files/default/sysctl.conf и редактируем его по своему усмотрению.

Манифест puppet/modules/sysctl/manifests/init.pp будет выглядеть следующим образом:

init.pp

class sysctl::params {     $template = "default" }  class sysctl (     $template = $sysctl::params::template     ) inherits sysctl::params {      file { "/etc/sysctl.conf":         ensure  => present,         owner   => root,         group   => root,         mode    => 0640,         source  => [ "puppet:///modules/sysctl/$template/sysctl.conf" ],         notify  => Exec["sysctl_reload"];     }      exec { "sysctl_reload":         command => $kernel ? {             FreeBSD     => "/etc/rc.d/sysctl reload",             Linux       => "/sbin/sysctl -q -p /etc/sysctl.conf",         },         refreshonly => true     } }

После чего снова запускаем fabric, который сделает puppet apply на нужных нам серверах:

fab deploy_p

Вот так, благодаря полной автоматизации Linux-хостинга, наши админы не тратят время на рутинные задачи, а решают действительно нестандартные проблемы. Это я вам как админ говорю. 🙂

ссылка на оригинал статьи http://habrahabr.ru/post/273733/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *