Перейти к основному содержимому

Часть 6. Продвинутая работа с системой

к сведению

Основная задача: научиться управлять процессами и создавать простейшую автоматизацию.

Автоматизируем сбор данных о системе с bash

  1. Выведем LA:

    cat /proc/loadavg | awk '{ print $1,$2,$3" processes: "$4", last PID: "$5}'

    LA, Load average - среднее значение загрузки системы за некоторый период времени, как правило, отображается в виде трёх значений, которые представляют собой усредненные сглаженные величины за последние 1, 5 и 15 минут. Вычисляется как длина очереди выполнения в операционной системе, где единица означает, что очередь заполнена, а значение выше единицы — что есть процессы, которые ожидают своей очереди на выполнение. Содержатся в файле /proc/loadavg.

    Учитывает как running процессы, так и процессы в uninterraprable sleep (ожидают выполнения системного вызова, как правило долгие это read/write, т.е. IO).

  2. Выведем список сетевых интерфейсов в нужном формате

    ss -4tuln | подставьте что нужно, можно цепочку из нескольких команд | column -t
    127.0.0.53%lo  53
    127.0.0.53%lo 53
    0.0.0.0 22
  3. Выведем список IP-адресов на хосте:

    ip a | grep -E 'inet ' | awk '{ print $2 }'
  4. Обернем это все в bash-скрипт /root/beholder.sh, добавим date + "%d.%m.%Y %H:%M:%S" и информацию о занятом месте и списке пользователей (самостоятельно). Попробуем циклы, запишем в скрипт:

    for i in $@
    do
    echo "Next search by name:"
    ps aux | grep $i
    echo
    done
  5. Запустим. Должны получить что-то вроде:

    beholder

Делаем сбор данных регулярным с cron

  1. Впишем в cron новое правило и ждем минуту.

    echo '* * * * * root /root/beholder.sh >> /tmp/beholder-output' >
    /etc/cron.d/beholder
  2. Смотрим файл cat /tmp/beholder-output

    Можем попробовать поменять параметры, сервис crontab.guru в помощь.

    Краткое описание есть в файле конфига /etc/crontab:

    image57

    Исходя из этого конфига следует, что в /etc/cron.{hourly,daily, weekly,monthly}/ лежат скрипты, запускающиеся соответственно раз в день, в неделю и в месяц. Дополнительно Cron читает конфиги из /etc/cron.d/, где лежат общие файлы с расписанием запуска. Кроме того, для пользователей задаются персональные cron-конфиги. Их можно отредактировать с помощью утилиты crontab -e. Они отличаются от /etc/crontab тем, что там опускается поле пользователя, запускаться будет от того, который себе задал это в настройках.

Пишем свой systemd-сервис

Процесс не может взяться из ниоткуда: его обязательно должен запустить какой-то процесс. Процесс, запущенный другим процессом, называется дочерним (child) процессом или потомком. Процесс, который запустил процесс называется родительским (parent), родителем или просто - предком. У каждого процесса есть два атрибута - PID (Process ID) - идентификатор процесса и PPID (Parent Process ID) - идентификатор родительского процесса.

Процессы создают иерархию в виде дерева. Самым "главным" предком, то есть процессом, стоящим на вершине этого дерева, является процесс systemd или init (PID = 1). Условно можно считать, что планировщик ядра имеет PID = 0.

Собственно для управления древом процессов и создали systemd. Подробнее о процесса и их состояниях читайте в статье.

systemd — подсистема инициализации и управления службами в GNU/Linux, фактически вытеснившая в 2010-е годы традиционную подсистему init. Основная особенность — интенсивное распараллеливание запуска служб в процессе загрузки системы, что позволяет существенно ускорить запуск операционной системы. Основная единица управления — unit (модуль), одним из типов модулей являются "сервисы" — аналог демонов — наборы процессов, запускаемые и управляемые средствами подсистемы и изолируемые контрольными группами. Подробная статья об systemd-unit-ах.

Создадим свой systemd-unit:

nano /etc/systemd/system/myhttp.service

# Создадим для него WorkingDirectory
mkdir -p /root/www

# Перезагрузим конфигурацию
systemd systemctl daemon-reload

Содержимое .service файла:

[Unit]
Description=MyHTTP Server
Documentation=http://example.org/
After=network.target

[Service]
WorkingDirectory=/root/www
ExecStart=/usr/bin/python3 -m http.server 8000
KillMode=mixed
Restart=on-failure
Type=simple

[Install]
WantedBy=multi-user.target
Alias=myhttpd.service

Кратко разберем что тут написано:

  • Секция [Unit]:

    • Description - описание, отображается в systemctl status [service]
    • Documentation - ссылка на документацию, обязательно в виде URL
    • After - после каких целей/сервисов следует запускать данный unit
  • Секция [Service]:

    • WorkingDirectory - вызовет системный вызов chdir перед исполнением каких-либо команд сервиса, должна существовать
    • ExecStart - команда, которая запустится при вызове systemctl start [service]
    • KillMode - управляет тем, как процесс должен быть завершен, mixed - посылает SIGTERM основному процессу и SIGKILL дочерним
    • Restart - необходимо ли перезапускатьсервис в случае завершения процесса (в примере - только при ненулевом rc)
    • Type - настраивает процедуру запуска и отслеживания процесса, simple ожидает, что основным станет процесс, запущенный ExecStart командой и сервис будет работать до тех пор, пока жив основной процесс.
  • Секция [Install]:

    • WantedBy - какая цель триггерит запуск, если сервис enabled.
    • Alias - альтернативное имя сервиса. systemctl status [alias] равнозначен systemctl start [service].

Запустим, добавим в автозапуск:

systemctl start myhttp
systemctl enable myhttp

Проверяем работу с помощью curl и ss.

curl http://127.0.0.1:8000/
ss -tl | grep 8000
к сведению

Для ответа на контрольный вопрос про процесс загрузки системы также нужно ознакомиться с материалом.

Запускаем процесс внутри нового пространства имен

Посмотрим список доступных пространств имен:

lsns
ip netns

Цикл статей на Habr про пространства имен.

Создаем сетевой namespace:

ip netns add myhttp

Теперь запустим внутри пару команд ip netns exec <netns> <cmd> ...:

ip netns exec myhttp ip link set dev lo up
ip netns exec myhttp /usr/bin/python3 -m http.server 8080 &

Проверим:

ss -tul4n
ip netns exec myhttp ss -tul4n

Запустим tcpdump внутри netns-а:

ip netns exec myhttp tcpdump -i any host 127.0.0.1

Проверим:

ip netns exec myhttp curl http://127.0.0.1:8080
ip netns exec myhttp curl http://127.0.0.1:8000
curl http://127.0.0.1:8080
curl http://127.0.0.1:8000

Таким образом, у нас получилось разнести 2 разных сервера в разные сетевые пространства имен. Мы даже можем запустить их на одинаковом порту.

Установка docker и запуск hello-world

Установка Docker в Ubuntu 20.04

sudo apt install apt-transport-https ca-certificates curl software-properties-
common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64]
https://download.docker.com/linux/ubuntu focal stable"
sudo apt update
sudo apt install docker-ce
sudo systemctl status docker

Запустим hello-world:

docker run hello-world

Дополнительное

  1. Показать soft-лимиты (ulimit) и hard-лимиты, пояснить как поняли, в чем разница, как изменить?

    Хорошая статья о лимитах.

    к сведению

    Примечание: это может оказаться жизненно важным знанием в случае появления высоких нагрузок на вашем сервере. Ошибка "Too Many Open Files" может появляться как раз из-за ограничений в лимитах, по-умолчанию они довольно небольшие (1024 для open files).

    Пример вывода ulimit для пары систем (ВМ и реальный Raspberry-Pi сервер):

    image59

    Посмотрим лимиты для конкретного процесса, тоже бывает полезно:

    # Некоторые программы кладут свой Process ID (PID) в /var/run
    cat /var/run/sshd.pid # Выведет PID sshd

    # Выведем лимиты процесса sshd с помощью procfs
    cat /proc/$(cat /var/run/sshd.pid)/limits
    # P.S. Про procfs подробно поговорим во второй лабораторной работе

    image60

    Занятное наблюдение работы лимитов:

    image62

  2. Настроить /root/.bashrc файл, применяющийся при создании новой оболочки для root пользователя.

    Хорошая статья о bash_profile и bashrc.

    Пример большого и сложного .bashrc файла.

    PS1 - переменная для изменения вида приглашения, например такое значение красит в красный:

    PS1='\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\
    [\033[01;31m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w \$\[\033[00m\] '

    Синонимы (alias-ы) для подкрашивания вывода команд:

    # enable color support of ls and also add handy aliases
    if [ -x /usr/bin/dircolors ]; then
    test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval
    "$(dircolors -b)"
    alias ls='ls --color=auto'
    alias dir='dir --color=auto'
    alias vdir='vdir --color=auto'
    alias grep='grep --color=auto'
    alias fgrep='fgrep --color=auto'
    alias egrep='egrep --color=auto'
    fi

    Просто удобные общепринятые сокращения:

    # some more ls aliases
    alias ll='ls -l'
    alias la='ls -A'
    alias l='ls -lA'

    Переопределения стандартных команд с ключами, чтобы спрашивали подтверждение:

    # Some more alias to avoid making mistakes:
    alias rm='rm -i'
    alias cp='cp -i'
    alias mv='mv -i'

    image64

    image65

  3. Создайте еще один мгновенный снимок ВМ, как в пункте 8 раздела 1.1. Чтобы не случалось "упс, у меня все работало, а вот сейчас перестало".

к сведению

Далее в лабораторных рекомендуется использовать способ работы с системой по ssh и запускать ВМ в фоновом режиме (без интерфейса вообще).