среда, 24 апреля 2024 г.

Docker compose. Запуск контейнеров при старте операционной системы

Воспользуемся systemd для запуска контейнеров при старте системы.

Для этого создадим юнит systemd:
# nano /etc/systemd/system/docker-compose-app.service

Содержимое файла:
[Unit]
Description=Docker Compose Application Service
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/docker compose -f /home/korolev/app-dev/docker-compose.yml up -d
ExecStop=/usr/bin/docker compose -f /home/korolev/app-dev/docker-compose.yml down
TimeoutStartSec=0
Restart=on-failure

[Install]
WantedBy=multi-user.target


В конфигурации предполагается, что разработка идет в директории
/home/korolev/app-dev/

Рестартуем демон systemd:

# systemctl daemon-reload

И запускаем docker compose как службу:
# systemctl start docker-compose-app
# systemctl enable docker-compose-app


воскресенье, 21 апреля 2024 г.

Статические маршруты в NetworkManager. Ошибка Unable to save connection: Cannot modify a connection that has an associated rule- or rule6- file

В новых версия Linux управление сетевой конфигурацией выполняется специальной службой - NetworkManager.
Ранее в старых версиях Linux служба «network» в своей работе опиралась на конфигурационные файлы, расположенные в каталоге
/etc/sysconfig/network-scripts/
Теперь служба «NetworkManager» опирается на конфигурационные файлы в каталоге
/etc/NetworkManager/system-connections/,
а также на скрипты, расположенные в директории
/etc/NetworkManager/dispatcher.d/

Для добавления статического маршрута в NetworkManager можно воспользоваться удобной псевдографической утилитой «nmtui»
# nmtui
После запуска утилиты мы видим меню для работы с сетевыми соединениями. Выбираем «Edit a connection» и нажимаем Enter

В следующем окне выбираем сетевой интерфейс, переходим вправо и выбираем действие «Edit...» (Можно просто выбрать интерфейс и нажать Enter).

Открывается окно редактирования сетевого соединения. Переходим в раздел Routing и в пункт «Edit...»

Откроется дополнительное окно редактирования статических маршрутов. Выбираем «Add...»

Пример заполнения данных о статическом маршруте:

После применения изменений по кнопке «OK», окно редактирования маршрутов должно закрыться и мы должны попасть обратно в панель редактирования настроек интерфейса. Перемещаемся по этому окну до кнопки «OK», нажимаем Enter. Затем в разделе меню выбора интерфейса перемещаемся на кнопку «Back...» и выходим в в основное меню утилиты nmtui. Тут выбираем раздел «Quit» и выходим в консоль.

Для применения настроек нужно выполнить перезапуск службы NetworkManager
# systemctl restart NetworkManager
Статический маршрут пропишется в файл
/etc/NetworkManager/system-connections/<ИМЯ_ИНТЕРФЕЙСА>.nmconnection
Проcмотр правил маршрутизации:
# ip route
default via 10.10.49.254 dev ens18 proto static metric 100
10.10.49.0/24 dev ens18 proto kernel scope link src 10.10.49.166 metric 100
10.200.5.216 via 10.10.49.254 dev ens18 proto static metric 100


Для удаления статического маршрута, нужно опять запустить псевдографический интерфейс nmtui, зайти в раздел конфигурации нужного интерфейса, перейти в раздел «Routing», выбрать не нужный маршрут и применить команду «Remove». После этого выйти из программы nmtuui и перезапустить NetworkManager
# systemctl restart NetworkManager
Из файла /etc/NetworkManager/system-connections/<ИМЯ_ИНТЕРФЕЙСА>.nmconnection
статический маршрут пропадет, но команда ip route по прежнему будет отображать этот удаленный маршрут.
Для того что бы удалить маршрут окончательно нужно или применить команду удаления
# ip route del 10.10.49.0/24 dev ens18
Или перезапустить сетевой интерфейс вот так, чтобы не потерять управление:
# nmcli connection down enp0s3 && nmcli connection up enp0s3
В данном случае enp0s3 – это имя интерфейса.
Ну или можно просто перезагрузиться.

Если в Linux работает старая версия службы управления сетью «network», которая использует скрипты в директории /etc/sysconfig/network-scripts/, в случае добавления статического маршрута через nmtui мы получим ошибку «Unable to save connection: Cannot modify a connection that has an associated ‘rule-’ or ‘rule6-’ file». Это говорит о том, что NetworkManager не может выполнить изменение информации в файлах, лежащих в директории /etc/sysconfig/network-scripts/, а в этих директориях как раз есть что-то нужное для маршрутизации (например, правила маршрутизации в файле /etc/sysconfig/network-scripts/rule-eth1). Данное поведение не считается ошибкой (см https://bugzilla.redhat.com/show_bug.cgi?id=1384799), а говорит о том, что изменение файлов /etc/sysconfig/network-scripts/rule-* и /etc/sysconfig/network-scripts/route-* не поддерживается функционалом NetworkManager.

В этом случае можно пойти следующими путями:

1) Добавлять статические маршруты через редактирование файла
/etc/sysconfig/network-scripts/route-<ИМЯ_ИНТЕРФЕЙСА>
Пример записи в файле:
default via 10.11.90.54 table eth0
10.11.0.0/24 via 10.11.90.16

После изменения файла нужно перезагрузить службу «network»
# systemctl restart network

2) Отказаться от службы «network» и перейти на NetworkManager полностью.
# systemctl stop network
# systemctl disable network
# systemctl enable NetworkManager

В этом случае (в случае использования полностью NetworkManager) так же рекомендуется использовать службу NetworkManager-dispatcher, которая предназначена для отлова событий в системе, таких как падение или поднятие интерфейса. После наступления подобного события, связанного с сетью, благодаря службе NetworkManager-dispatcher будет запускаться скрипт из директории /etc/NetworkManager/dispatcher.d/, связанный с этим событием. Например, после поднятия интерфейса eth2, будет автоматически монтироваться шара по NFC.
Запуск службы NetworkManager-dispatcher:
# systemctl start NetworkManager-dispatcher
# systemctl enable NetworkManager-dispatcher

У NetworkManager-dispatcher есть расширение NetworkManager-dispatcher-routing-rules, которое может использовать в скриптах диспетчера старые правила описанные в файлах
/etc/sysconfig/network-scripts/route-*
/etc/sysconfig/network-scripts/rule-*
и прописывать маршруты на основе этих правил при событиях up и down интерфейсов
Установка этого расширения:
# yum makecache
# yum -y install NetworkManager-dispatcher-routing-rules





пятница, 12 апреля 2024 г.

Решение проблемы сбойного триггера в базе Mariadb. Trigger does not exist

Есть база данных Mariadb.
При бэкапе базы я получаю ошибку триггера:
mysqldump: Couldn't execute 'SHOW CREATE TRIGGER `orders_after_delete`': Trigger does not exist (1360)
При дампе таблиц базы поочередно, все же удается сохранить дамп базы частями, но при развертывании таблицы order опять фикируем ошибку:
ERROR 1359 (HY000) at line 13313: Trigger 'al.orders_after_delete' already exists

Подключаюсь к основной базе и командой SHOW TRIGGERS; смотрю, что такой триггер есть orders_after_delete.
Хочу его пересоздать (удалить и добавить заново), но при удалении триггера, его как буд-то нет:
MariaDB [al]> DROP TRIGGER orders_after_delete;
ERROR 1360 (HY000): Trigger does not exist


Проверка базы на ошибки проходит успешно, но триггер все равно висит у таблицы orders и не удаляется ни через консоль, ни через phpmyadmin.
# mysqlcheck -u**** -p -r al orders
al.orders OK


РЕШЕНИЕ ПРОБЛЕМЫ:

1) Необходимо создать одноименный триггер из консоли mariadb для этой же таблицы
При этом SHOW TRIGGERS будет показывать два триггера orders_after_delete.
Но зато команда выполнения дампа базы и восстановления базы будут идти без сбоев.

2) В час наименьшей нагрузки выполняем удаление сбойного триггера так:

2.1) Подключаемся к базе

# mysql -hlocalhost --user <ПОЛЬЗОВАТЕЛЬ> -p<ПАРОЛЬ>
>USE al;

2.2) Вводим команду удаления триггера:
DROP TRIGGER orders_after_delete;
Удаляется при этом один триггер (который создали ранее для решения проблемы создания дампа), а второй сбойный триггер остается в системе.
Попытки его удалить вновь не удачные:
MariaDB [al]> DROP TRIGGER orders_after_delete;
ERROR 1360 (HY000): Trigger does not exist

2.3) Переименовываем таблицу orders
MariaDB [al]> ALTER TABLE orders RENAME TO orders2;
Query OK, 0 rows affected (0.07 sec)


2.4) Удаляем сбойный триггер. Теперь он удаляется без проблем:
MariaDB [al]> DROP TRIGGER orders_after_delete;
Query OK, 0 rows affected (0.01 sec)


2.5) Возвращаем таблице исходное название:
MariaDB [al]> ALTER TABLE orders2 RENAME TO orders;
Query OK, 0 rows affected (0.00 sec)


2.6) Создаем триггер

Теперь в системе отображается один триггер, дампы выполняются успешно, восстановление - тоже.

понедельник, 8 апреля 2024 г.

Изменение пользовательского приветствия (banner) при подключении к консоли Linux.

При подключении к серверу по SSH пользователю можно выводить приветствие.
Приветствие бывает:
1) Перед вводом логина и пароля
2) После успешной авторизации

Добавление пользовательского приветствия перед авторизацией.
Нужно создать файл приветствия. Например: /etc/login.warn
# touch /etc/login.warn
Открываем файл и вписываем туда приветствие
# nano /etc/login.warn
Пример:
 *** Тестовый сервер Королева В.С. ***
 *** Самарская область, г. Самара ***
 *** Необходима авторизация ***

Теперь данный файл /etc/login.warn необходимо прописать в настройках SSH.
Находим строки:
# no default banner path
#Banner none

Прописываем путь до файла приветствия:
Banner /etc/login.warn
Перезапускаем демон SSHD
# systemctl restart sshd

Добавление приветствия после авторизации:
Приветствие после авторизации прописывается в файле /etc/motd
motd - это сокращение от Message Of The Day (Приветствие дня).
# nano /etc/motd
Пример текста:
*** Добро пожаловать ***
Теперь при авторизации будут выдаваться приглашения:
$ ssh korolev@10.10.49.166
*** Тестовый сервер Королева В.С. ***
*** Самарская область, г. Самара ***
*** Необходима авторизация ***
korolev@10.10.49.166's password:
*** Добро пожаловать ***
Web console: https://KVS:9090/ or https://10.10.49.166:9090/
Last login: Sun Apr 7 11:53:30 2024 from 10.10.49.252








понедельник, 1 апреля 2024 г.

Установка web-сервера nginx с отдельными модулями php и mariadb с помощью docker

Создаем главную директорию проекта, где будут сложены все необходимые файлы и базы
# mkdir web-server
# cd web-server/

Создаем директории для проекта.
Под каждый контейнер своя директория для конфигов, и плюс директория data - для файлов и datadb для файлов базы данных.
# mkdir nginx
# mkdir php-fpm
# mkdir mariadb
# mkdir data
# mkdir datadb


Скачиваем образ nginx и php-fpm
# docker pull nginx
# docker pull bitnami/php-fpm
# docker pull mariadb


В директорию data кладем тестовые файлы index.html (любая страничка) и info.php (с функцией phpinfo();)
Пример файла index.html
<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Заголовок</title>
  <link rel="stylesheet" href="./styles/style.css">
</head>
<body>
  <header>
    <h1>Сайт-тест HTTP NGINX-1</h1>
    <p>Просто какая-то информация</p>
  </header>
  <main>
     12345 АБВГДЕ, Основной блок информации
   </main>
   <footer>
       <p>footer (подвал), нижняя часть сайта</p>
   </footer>
    <!--подключение скриптов <script src="app.js"></script> -->
</body>
</html>


Содержимое файла info.php
<?php
    phpinfo();
?>


Нам необходимо выстроить конструкцию контейнеров, показанную на рисунке ниже

Основная папка с файлами проекта – это папка data, куда будем складывать файлы html и php.

В директорию nginx кладем типовой файл nginx.conf конфига nginx.

Главное, что нужно указать, это параметры директивы fastcgi_pass в блоке location ~ \.php$:
fastcgi_pass php-fpm:9000;
Директива fastcgi_pass задаёт адрес FastCGI-сервера, которому сервер nginx будет передавать php файлы для обработки. Тут указывается доменное имя и порт. 9000 – это стандартный порт, на котором работает сервер php-fpm. А доменное имя «php-fpm» - это доменное имя сервера php-fpm. В системе doker при старте контейнеров в каждом контейнере автоматически пропишутся все имена запущенных сервисов. И если будет запущен контейнер сервиса «php-fpm», то nginx будет знать его внутренний адрес по имени «php-fpm».
Второй важный момент – это директива
fastcgi_param SCRIPT_FILENAME /app$fastcgi_script_name;
Тут необходимо указать правильный путь до местонахождения файлов php. В контейнере, созданном на основе образа bitnami/php-fpm, это будет папка /app. Поэтому переменная SCRIPT_FILENAME должна начинаться с «/app».
В конфигурационном файле важные изменяемые значения выделены красным.
worker_processes 1;
pid /run/nginx.pid;
events {
  worker_connections 1024;
}
http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 4096;
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    server {
        listen 80;
        server_name localhost;
        root /usr/share/nginx/html;
        error_log /var/log/nginx/error.log;
        access_log /var/log/nginx/access.log;
        location / {
             index index.php index.html index.htm;
        }
        location ~ \.php$ {
            fastcgi_pass php-fpm:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME /app$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
        }
    }
}

Директива «error_log /var/log/nginx/error.log;» определяет, куда сервер nginx будет складывать логи ошибок. Контейнер bitnami/php-fpm по умолчанию настроен так, что логи для записи передает для записи web-серверу, в данном случае nginx. И искать логи ошибок php нужно тоже в этом же файле /var/log/nginx/error.log.

Создаем файл docker-compose.yml, который описывает контейнеры nginx и php-fpm.
# touch web-server/docker-compose.yml
version: '3'
services:
    nginx:
        image: nginx
        container_name: nginx1
        ports:
            - 8080:80
        volumes:
            - ./data:/usr/share/nginx/html
            - ./nginx/nginx.conf:/etc/nginx/nginx.conf
            - ./nginx/logs:/var/log/nginx/
        depends_on:
            - php-fpm
        networks:
            - internal
    
    php-fpm:
        image: bitnami/php-fpm
        container_name: php1
        volumes:
            - ./data:/app
         networks:
             - internal
    
networks:
    internal:
        driver: bridge
Из директории web-server запускаем контейнеры
# docker compose up --build
Параметр --build означает, что перед запуском контейнеров произойдет их сборка.

Теперь можно обратиться к web-серверу и прочитать тестовые файлы:
http://<IPадрес>:8080/
http://10.10.49.166:8080/info.php

Останавливаем контейнеры, нажав CTRL+C в командной строке, где запускали контейнеры (docker compose up --build)

Теперь запускаем контейнеры вместе с контейнером Mariadb. Для этого в docker-compose.yml добавляем новый сервис, работающий в новом контейнере:
    mariadb:
        image: mariadb
        container_name: mariadb1
        environment:
            MYSQL_ROOT_PASSWORD: rootpasswd
            MYSQL_DATABASE: mydb
            MYSQL_USER: user1
            MYSQL_PASSWORD: secret1
        command: mariadbd --log_error="/var/log/mysql/error.log"
        ports:
            - 3309:3306
        volumes:
            - ./datadb:/var/lib/mysql
            - ./mariadb/error.log:/var/log/mysql/error.log
        networks:
            - internal

Директива MYSQL_ROOT_PASSWORD: rootpasswd определить пароль для root пользователя базы данных SQL. Директивы MYSQL_DATABASE: mydb создаст базу данных mydb. Создание базы выполняется командой CREATE DATABASE IF NOT EXIST, поэтому если база mydb уже есть, она не будет создана снова.
Директивы MYSQL_USER: user1 и MYSQL_PASSWORD: secret1 создадут пользователя user1 с паролем secrtet1 и сделают его администратором базы, заданной в MYSQL_DATABASE.
Регистрация ошибок контейнера mariadb осуществляется по умолчанию через системный journal. Для того, что бы запись ошибок велась в отдельный файл, нужно в контейнере
в файле /etc/mysql/mariadb.conf.d/50-server.cnf раскомментировать строку:
log_error = /var/log/mysql/error.log. Но при пересборке контейнера это изменение потеряется. Поэтому пойдем другим путем. Создадим в основной системе файл для логов и разрешим писать туда пользователю из docker контейнера:
# touch mariadb/error.log
# chmod 777 mariadb/error.log

В секции command: пропишем команду, которая заставит демон mariadb включить запись лого в файл: mariadbd --log_error="/var/log/mysql/error.log"
И затем в секции volumes примонтируем внутренний файл контейнера «/var/log/mysql/error.log» к файлу основной операционной системы «mariadb/error.log»
Теперь логи mariadb будут записываться в файл в основной операционной системе.

После редактирования файла docker-compose.yml запускаем контейнеры:
# docker compose up --build
Из другой консоли пытаемся подключиться к базе:
# /usr/bin/mariadb -h127.0.0.1 --port=3309 -uroot –p
Вводим пароль из директивы MYSQL_ROOT_PASSWORD и мы в консоли mariadb под рутом.
Можно так же подключиться под именем user1 и паролем secret1
# /usr/bin/mariadb -h127.0.0.1 --port=3309 -u user1 -psecret1
Проверяем, создалась ли база mydb?
MariaDB [(none)]> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mydb |
+--------------------+
2 rows in set (0.001 sec)
Все в порядке, база есть.
Создадим простую таблицу и внесем туда одну строку для теста
> USE mydb;
> CREATE TABLE table_test (a int, b varchar(10));
> INSERT table_test VALUES(1,'mytext');

Эта информация останется в базе даже после перезагрузки контейнеров, так как файлы базы подключаются при старте контейнера из основной системы

Создадим файл dbtest.php в папке data, который будет подключаться к базе данных и выводить данные из таблицу table_test
<?php
    $mysqli = new mysqli("mariadb", "user1", "secret1", "mydb");
    if (mysqli_connect_errno()) {
        echo "Ошибка: ", mysqli_connect_error();
        exit;
    } else {
        echo "Соединение установлено<br>";
    }
   $query="SELECT a, b FROM table_test ";
   $result = $mysqli->query($query) or die("Ошибка запроса");
   echo "Данные из базы:<br>";
   while($z=$result->fetch_row()) {
       echo "a: ".$z[0].", b: ".$z[1];
   }
?>

В качестве имени сервера, к которому нужно обращаться в php указываем имя сервиса из описания контейнера в файле docker-compose.yml.
$mysqli = new mysqli("mariadb", "user1", "secret1", "mydb");
Теперь обратившись по URL мы увидим информацию из базы данных:
http://10.10.49.166:8080/dbtest.php

Следующие запуски можно выполнять так

# docker compose up
Запуск в режиме демона:
# docker compose up –d

Остановка контейнеров:

# docker stop mariadb1

Запуск контейнера:

# docker start mariadb1

Остановка всех контейнеров:

# docker compose down

Просмотр состояния контейнеров

# docker compose ps

Вход в контейнеры:

# docker exec -it nginx1 /bin/bash
# docker exec -it php1 /bin/bash
# docker exec -it mariadb1 /bin/bash


Просмотр логов контейнеров:
# docker compose logs -f nginx
# docker compose logs -f mariadb
# docker compose logs -f php-fpm


среда, 27 марта 2024 г.

Установка WEB-сервера nginx с поддержкой php, mariadb, php-apc и memcached

Установка NGINX:
# yum install nginx
В конфигурации по умолчанию nginx работает на 80 порту
Конфигурация лежит тут: /etc/nginx/nginx.conf
Каталог сервера: /usr/share/nginx/html
Запускаем сервер:
# systemctl start nginx
Открываем порт 80 в фарволл
# firewall-cmd --add-port=80/tcp --permanent
# firewall-cmd --reload

Если на данном этапе появляется ошибка связанная с невозможностью занять порт 80,
то вероятнее всего в системе уже есть другой web-сервер, например apache.
В этом случае сервер apache нужно выключить и включить nginx
# systemctl stop httpd
# systemctl start nginx


Устанавливаем php-fpm — это fastcgi process manager, Интерфес языка php для работы с web-серверами (apache или nginx)
# yum install php php-fpm
Перезапускам nginx.
# systemctl restart nginx

Создаем файл /usr/share/nginx/html/info.php с содержимым:
<?php phpinfo(); ?>
Для проверки перейдем по URL http://<IPадрес>/info.php
Мы должны увидеть web-страницу с выводом информации phpinfo.

Установка Mariadb
# yum install mariadb-server
# systemctl start mariadb

Устанавливаем пароль:
# mysqladmin -u root password
Вводим пароль два раза
Устанавливаем расширение php для работы с Mariadb через библиотеку Mysqli
# yum install php-mysqlnd
# systemctl restart nginx

Теперь на странице http://<IPадрес>/info.php будет представлена информация о модулях mysqli и mysqlnd для работы с базой MySQL

Установка php-apc, расширения, обеспечивающего кеширование php скриптов и их ответов для увеличения производительности.
# yum install php-pecl-apcu
# systemctl restart nginx


Устанавливаем сервис кеширования memcached:
# yum install memcached
# systemctl start memcached
# memcached --version

Файл конфигурации сервиса - /etc/sysconfig/memcached
# dnf --enablerepo=crb install libmemcached-awesome
# firewall-cmd --add-port=11211/tcp --permanent
# firewall-cmd --reload
# yum install php-pecl-memcache php-pecl-memcached
# systemctl restart nginx


Сервер nginx готов к эксплуатации
Для запуска в продакшен все установленные сервисы нужно добавить в аввтозагрузку
# systemctl enable memcached
# systemctl enable mariadb
# systemctl enable nginx


Утилита sqlcmd для работы с базой MS-SQL

Установка утилиты:
# wget https://packages.microsoft.com/config/rhel/7/prod.repo
# mv prod.repo /etc/yum.repos.d/msprod.repo
# yum install -y mssql-tools unixODBC-devel

Потребуется подтвердить, что мы согласны с условиями лицензий:
Do you accept the license terms? (Enter YES or NO)
вводим
yes

Будут установлены утилиты sqlcmd и bcp для работы с MS-SQL сервером.
Установка будет выполнена с директорию:
# /opt/mssql-tools/bin

Для соединения с базой используем команду:
/opt/mssql-tools/bin/sqlcmd -S <IP адрес> -U <логин> -P <пароль>
Соединение по умолчанию выполняется по порту 1433

Пример использования процедуры на сервере MS-SQL
/opt/mssql-tools/bin/sqlcmd -S 10.0.4.180 -U User1 -P password1 -d DВName -Q "exec MyProcedure"

четверг, 14 марта 2024 г.

Активизация рабочего стола на сервере Linux

Задача: Потребовалось иметь место, куда тонкий клиент THIN CLIENT HP T610 TPC-W006-TC смог бы подключаться по RDP и мониторить аварии в браузере. Одни из вариантов - это подключаться на какой-то действующий виртуальный сервер Linux.

Для этого задействуем на сервере графическое рабочее окружение Xfce, установим службу xrdp и позволим определенному пользователю подключаться к системе.

Проводим обновление и установим репозитарий EPEL.
# dnf update -y
# dnf install epel-release -y


Устанавливаем xrdp:
# dnf install xrdp -y
# systemctl enable xrdp --now
# systemctl status xrdp


Устанавливаем Xfce окружение:
# dnf group install "Xfce"
# systemctl set-default graphical.target


Открываем порт 3389, по которому принимаются подключения по RDP.
# firewall-cmd --add-port=3389/tcp --permanent
(или, если используется определенная зона
# firewall-cmd --zone=internal --add-port=3389/tcp --permanent)
# firewall-cmd --reload

Установка браузера Firefox:
# yum install firefox

Добавляем пользователя operator1 сервера Linux
# adduser operator1
# passwd operator1

И задаем пароль (2 раза)

К сожалению, тонкий клиент имеет ОС на базе урезанной Windows, которая не обладает возможностью подключаться к серверу Linux используя современные безопасные протоколы шифрования.
При попытке подключения тонкий клиент выдает ошибку:
«Connected to IPaddress:3389 SSL_connect: Failure in SSL library (protocol error?)»
На сервере в логах при этом:
[20240312-13:07:53] [INFO ] Socket 12: AF_INET6 connection received from ::ffff:10.0.9.63 port 42912
[20240312-13:07:53] [INFO ] Using default X.509 certificate: /etc/xrdp/cert.pem
[20240312-13:07:53] [INFO ] Using default X.509 key file: /etc/xrdp/key.pem
[20240312-13:07:53] [INFO ] Socket 12: AF_INET6 connection received from ::ffff:10.0.9.63 port 42913
[20240312-13:07:53] [ERROR] libxrdp_force_read: header read error
[20240312-13:07:54] [ERROR] [ITU-T X.224] Connection Sequence: CR-TPDU (Connection Request) failed
[20240312-13:07:53] [INFO ] Using default X.509 certificate: /etc/xrdp/cert.pem
[20240312-13:07:54] [INFO ] Using default X.509 key file: /etc/xrdp/key.pem
[20240312-13:07:54] [ERROR] xrdp_sec_incoming: xrdp_iso_incoming failed
[20240312-13:07:54] [ERROR] libxrdp_force_read: header read error
[20240312-13:07:54] [ERROR] [ITU-T X.224] Connection Sequence: CR-TPDU (Connection Request) failed
[20240312-13:07:54] [ERROR] xrdp_rdp_incoming: xrdp_sec_incoming failed
[20240312-13:07:54] [ERROR] xrdp_process_main_loop: libxrdp_process_incoming failed
[20240312-13:07:54] [ERROR] xrdp_sec_incoming: xrdp_iso_incoming failed
[20240312-13:07:54] [ERROR] xrdp_rdp_incoming: xrdp_sec_incoming failed
[20240312-13:07:54] [ERROR] xrdp_iso_send: trans_write_copy_s failed
[20240312-13:07:54] [ERROR] Sending [ITU T.125] DisconnectProviderUltimatum failed
[20240312-13:07:54] [ERROR] xrdp_process_main_loop: libxrdp_process_incoming failed
[20240312-13:07:54] [ERROR] xrdp_iso_send: trans_write_copy_s failed
[20240312-13:07:54] [ERROR] Sending [ITU T.125] DisconnectProviderUltimatum failed
[20240312-13:07:54] [INFO ] Socket 12: AF_INET6 connection received from ::ffff:10.0.9.63 port 42914
[20240312-13:07:54] [INFO ] Using default X.509 certificate: /etc/xrdp/cert.pem
[20240312-13:07:55] [INFO ] Using default X.509 key file: /etc/xrdp/key.pem
[20240312-13:07:55] [INFO ] Security protocol: configured [SSL|RDP], requested [SSL|HYBRID|RDP], selected [SSL]
[20240312-13:07:55] [ERROR] SSL_accept: Failure in SSL library (protocol error?)
[20240312-13:07:55] [ERROR] SSL: error:14209102:SSL routines:tls_early_post_process_client_hello:unsupported protocol
[20240312-13:07:55] [ERROR] trans_set_tls_mode: ssl_tls_accept failed
[20240312-13:07:55] [ERROR] xrdp_sec_incoming: trans_set_tls_mode failed
[20240312-13:07:55] [ERROR] xrdp_rdp_incoming: xrdp_sec_incoming failed
[20240312-13:07:55] [ERROR] xrdp_process_main_loop: libxrdp_process_incoming failed


К сожалению решение проблемы заключается в понижении уровня безопасности сервера.
Первое действие – это активация старых протоколов, которые в 2024 году уже устарели (например RSA шифрование)
# update-crypto-policies --set LEGACY
После этого требуется перезагрузка
Второе действие – включение протоколов TLSv1 в настройках xrdp
# nano /etc/xrdp/xrdp.ini
В строку
ssl_protocols=TLSv1.2, TLSv1.3
Добавляем настройки TLSv1:
ssl_protocols=TLSv1.2, TLSv1.3, TLSv1, TLSv1.1
После этого ресторуем сервис xrdp
# systemctl restart xrdp

Теперь проблем подключения по RDP у тонкого клиента THIN CLIENT HP T610 TPC-W006-TC нет.

воскресенье, 4 февраля 2024 г.

Grafana Loki. Сервис promtail. Прием логов из файлов и по syslog. Просмотр информации Loki в оболочке Gragana.

Promtail - это утилита-агент, который отправляет содержимое файлов логов операционной системы Linux в Grafana Loki. Для того чтобы собирать данные логов со всех серверов, promtail нужно установить на каждом сервере.
Promtail умеет не только считывать логи из файлов, но и прослушивать порт tcp для приема сообщений syslog. К сожалению, возможность приема сообщений syslog по udp сразу демоном promtail у меня не заработала, поэтому принимать syslog сообщения напрямую от сетевого оборудования не получилось. Пришлось на сервере вместе с promtail поставить еще syslog-сервер, который принимает сообщения syslog по стандартному порту udp 514 и пересылает на порт tcp 1514, который уже просматривает promtail. Это оказалась рабочая конструкция.
Для просмотра информации из базы Loki самым естественным инструментом является Grafana. Схематически рассматриваемую модель взаимодействия можно представить так:

Установка Promtail.

Promtail можно установить в систему разными путями. Например, promtail скачивается в систему вместе с кодами loki и собирая loki можно так же собрать и исполняемый файл promtail
Порядок сборки Promtail из исходных кодов с установленным интерпретаторов go в Linux:
# cd /usr/src
# git clone https://github.com/grafana/loki
# cd loki/
# go build ./clients/cmd/promtail

В результате в директории /usr/src/loki появиться исполняемый файл promtail, который нужно переместить на постоянное место:
# mv promtail /usr/local/bin/promtail

Promtail можно развернуть из образа Docker. Это рекомендуемый способ, описанный в документации (https://grafana.com/docs/loki/latest/send-data/promtail/installation/), тут данный способ не рассматривается.

И можно скачать готовый исполняемый файл, собранный под типовые операционные системы. На странице текущего релиза (https://github.com/grafana/loki/releases/) ищем ссылку на файл promtail. Дистрибутив с утилитой называется promtail-linux-amd64.zip. Копируем ссылку на этот файл. 31.01.2024 это релиз 2.9.4 и ссылка https://github.com/grafana/loki/releases/download/v2.9.4/promtail-linux-amd64.zip
Порядок получения готового дистрибутива promtail с сайта:
Скачиваем архив с Promtail, распаковываем и перемещаем на постоянное место:
# cd /usr/src
# curl -O -L https://github.com/grafana/loki/releases/download/v2.9.4/promtail-linux-amd64.zip
# unzip promtail-linux-amd64.zip
# rm -f promtail-linux-amd64.zip
# mv promtail-linux-amd64 /usr/local/bin/promtail


Создаем конфигурационный файл сервиса promtail:
# mkdir /etc/promtail
# touch /etc/promtail/promtail.yaml

Для рассматриваемого случая считывания системных логов и получения информации syslog файл конфигурации будет выглядеть так:
# nano /etc/promtail/promtail.yaml
server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients:
  - url: 'http://192.168.1.166:3100/loki/api/v1/push'

scrape_configs:
  - job_name: secure
    static_configs:
      - targets:
        - localhost
      labels:
        job: secure
        __path__: /var/log/secure
        host: "192.168.1.166"
  - job_name: audit
    static_configs:
      - targets:
        - localhost
      labels:
        job: audit
        __path__: /var/log/audit/audit.log
        host: "192.168.1.166"
  - job_name: php
    static_configs:
      - targets:
        - localhost
      labels:
        job: php
        __path__: /var/log/php-fpm/*.log
        host: "192.168.1.166"
  - job_name: journal
    journal:
    max_age: 24h
    labels:
      job: systemd-journal
      host: "192.168.1.166"
  - job_name: syslog
    syslog:
      listen_address: 0.0.0.0:1514
      idle_timeout: 60s
      listen_protocol: tcp
      label_structured_data: yes
    labels:
      job: "syslog"
    relabel_configs:
      - source_labels: [__syslog_message_hostname]
         target_label: host
      - source_labels: [__syslog_message_severity]
         target_label: level


Немного о директивах конфигурационного файла.
Директива http_listen_port: 9080 раздела server говорит о том, что сервис Promtail на порту 9080 будет иметь web-морду показа основных данных сервиса.
Раздел positions определяет место, где сервис Promtail будет хранить метки (позиции) уже считанной информации из лог-файлов, чтобы в процессе работы не перечитывать файлы заново и не отправлять в Loki дублирующую информацию.
В разделе clients переменная url определяется путь отправки собранных сервисом данных. Это IP и порт приема данных сервисом Loki.
Раздел scrape_configs описывает задания по считыванию файлов и приема информации сервисом promtail. Задания (job) имеют имя (job_name), тип и метки. Путь считывания файла(ов) задается в подразделе labels оператором __path__.
Одно задание promtail выглядит так:
Каждому событию из файла будет присвоено три метки:
• «job» = «audit»
• «host» = «192.168.1.166»
• «filename» = «название файла»
С помощью этих меток впоследствии в интерфейсе grafana можно будет выполнять поиск в базе Loki. Чем больше меток – тем больше в Loki будет объем индексов и тем медленнее будет поиск. В документации Loki рекомендуют создавать новые метки только тогда, когда Вы точно поймете, что они Вам нужны для выборки данных.
В приведенном выше примере конфигурационного файла будут считываться и отправляться в loki данные из файлов.
/var/log/secure
/var/log/audit/audit.log
/var/log/php-fpm/*.log
Каждый файл логов (группа файлов) описана своим заданием.
Для того, чтобы promtail мог обращаться к файлам логов безопасности системы, важно что бы сервис promtail работал от имени пользователя root.
В рассматриваемом файле конфигурации так же определено задание типа journal. Это задание обязывает Promtail подключаться к системному журналу systemd-journal Linux и считывать оттуда информацию для передачи в Loki.
Для каждого задания по считыванию файлов или данных журнала systemd рекомендую всегда формировать метку, указывающую на IP адрес сервера, откуда поступило лог-сообщение. Благодаря этой информации в базе Loki впоследствии можно будет фильтровать сообщения по хостам.
Директивы конфигурации сервиса приема syslog выглядят так:

Здесь запускается служба на всех IP адресах сервера на порту 1514 и по протоколу tcp выполняется прием сообщений syslog. Каждому сообщению присваиваются метки:
«job» = «syslog»
«level» = «значение Severity»
«host» = «hostname» (или IP адрес)
Дополнительно если в сообщении syslog будет какая-то структура похожая на ключ=значение, то этот фрагмент текста будет преобразован в метку «Ключ (имя метки)»= «Значение»

Для автозапуска Promtail создаем Systemd Unit.
# nano /etc/systemd/system/promtail.service
Содержимое файла:
[Unit]
Description=Promtail service
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/promtail-linux-amd64 -config.file /etc/promtail/promtail.yaml
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target

В файле юнита systemd не указан пользователь, который будет владеть процессом. Это сделано умышленно, для того что бы сервис запускался от имени root (это необходимо для считывания логов безопасности Linux, доступных только пользователю root).
После редактирования файла юнита выполняем:
# systemctl daemon-reload
Запускаем сервис и проверяем его работу
# systemctl start promtail
# systemctl enable promtail
# systemctl status promtail
# ss -nltup | grep 9080


Открываем порт 9080 в файрволле и проверяем применение правил:
# firewall-cmd --permanent --add-port=9080/tcp
# firewall-cmd --reload
# firewall-cmd --list-all

Теперь обратившись к Url http://<IP-адрес>:9080 мы увидим информацию о работе сервиса Promtail:

Для отладки конфигурации promtail можно запускать в тестовом режиме вот так:

# /usr/local/bin/promtail --dry-run --inspect --config.file=/etc/promtail/promtail.yaml
Опция --dry-run означает, что данные, полученные promtail не будут отправляются в Loki и лог файл будет читаться с одного и тоже места. Опция --inspect заставит promtail выводить отладочную информацию в консоль. При поступлении новых логов информация и назначаемые информации метки будут в консоли:

Установка и настройка rsyslog.

Rsyslog необходим для того, что бы принимать syslog сообщения по стандартных портам оборудования (514 порт по tcp и udp) и передавать в Loki на порт 1514 tcp. При этом rsyslog форматирует сообщения, которые могут иметь различный формат у разных вендоров. В Loki данные попадают в едином формате.
В системе уже может быть установлен rsyslog по умолчанию, или вместо rsyslog может быть установлен syslog-ng. Поэтому перед установкой rsyslog, необходимо удалить старые версии rsyslog и syslog-ng. Затем провести установку rsyslog в систему:
# yum install rsyslog
# systemctl start rsyslog
# systemctl enable rsyslog

Главный конфигурационный файл rsyslog лежит тут: /etc/rsyslog.conf
Для того что бы rsyslog принимал сообщения по 514 порту (tcp и udp) и перенаправлял их на порт 1514 tcp в едином формате, необходимо добавить следующие директивы в файл конфигурации:
# nano /etc/rsyslog.conf
После директивы include(file="/etc/rsyslog.d/*.conf" mode="optional") нужно вставить:
module(load="imudp")
input(type="imudp" port="514" ruleset="sendRemote")
module(load="imtcp")
input(type="imtcp" port="514" ruleset="sendRemote")
#module(load="omfwd")
ruleset(name="sendRemote") {
    action(type="omfwd" target="10.10.49.166" port="1514" protocol="tcp"
    action.resumeRetryCount="-1"
    Template="RSYSLOG_SyslogProtocol23Format"
    TCP_Framing="octet-counted" KeepAlive="on" RebindInterval="60"
    queue.type="linkedList"
    queue.saveOnShutdown="on"
    queue.maxDiskSpace="1g"
    queue.fileName="fwdRule1")
}
В конфигурации закомментирована одна строчка - #module(load="omfwd"). Дело в том, что в некоторых версиях rsyslog, требуется прописывать данную строку явно, в современных версиях rsyslog модуль перенаправления omfwd загружается при старте rsyslog и отдельное указание на загрузку этого модуля не требуется.

Примечание 1. Если модуль интегрирован в rsyslog, его не нужно загружать, а мы пытаемся это сделать директивой module(load="omfwd") возникнет ошибка:
could not load module 'omfwd', errors: trying to load module /usr/lib64/rsyslog/omfwd.so: /usr/lib64/rsyslog/omfwd.so: /usr/lib64/rsyslog/omfwd.so: cannot open shared object file: No such file or directory [v8.2102.0-117.el9 try https://www.rsyslog.com/e/2066 ]

Примечание 2. Директива RebindInterval="60", описанная в конфигурации, обязывает демон rsyslog каждые 60 секунд пересоздавать соединение tcp с удаленным сервером, куда выполняется перенаправление. Если этого не делать, Loki, если не будет видеть активности на приеме, закроет Tcp соединение через 2 минуты (120 секунд по умолчанию). В логах rsyslog при этом можно будет наблюдать: 
omfwd: remote server at 10.10.49.166:1514 seems to have closed connection. This often happens when the remote peer (or an interim system like a load balancer or firewall) shuts down or aborts a connection. Rsyslog will re-open the connection if configured to do so (we saw a generic IO Error, which usually goes along with that behaviour). [v8.2102.0-117.el9 try https://www.rsyslog.com/e/2027 ]

Grafana. Настройка представления данных Loki.

После установки Gragana, для отображения данных Loki в интерфейсе необходимо выполнить подключение источника данных – Loki и создать дашборд, показывающий эти данные.
Для подключения источника, выбираем в меню «Connections» —> «Data sources»
Затем нажимаем кнопку «Add data source»
Теперь необходимо выбрать тип источника данных. В поисковой строке набираем «loki» и кликаем по найденному драйверу:
В открывшейся форме добавления нового источника вписываем имя источника, например «loki», затем в поле URL вписываем путь до порта, прослушиваемого сервисом loki. Например http://192.168.1.166:3100. Остальные настройки можно оставить по умолчанию. Прокручиваем страницу вниз и нажимаем кнопку «Save & test». После этого произойдет соединение с базой Loki и новый источник данных отобразиться в меню Grafana.
Если что-то пойдет не так и соединение не будет установлено, возникнет ошибка «Unable to connect with Loki. Please check the server logs for more details»
При удачном соединении мы должны увидеть:
В меню «Connections» будет представлен новый источник данных:

Теперь нужно создать типовой Dashboard для показа данных о логах. Для этого заходим в меню Dashboards и нажимаем кнопку «Create Dashboars»
Затем нажимаем кнопку «Add visualization»
На следующем этапе нужно выбрать источник данных. В нашем случае – это источник «loki», который мы подключили ранее
Откроется окно создания нового представления для дашборда:
На нижней панели добавляются запросы, которые будут работать с источником данных «Loki». Для отображения количества лог-записей системного журнала systemd, поступивших за 1 минуту в базу Loki нужно задать следующее:
Метки (Label filter): job=system-journal,
Операции: Count over time, Range, 1m
То есть тут задается фильтр меток по которым из базы Loki будут извлечены только записи, обладающие меткой «job»=«system-journal», а затем указывается операция преобразования этой выборки – показывать количество записей за указанный временной интервал.
Для проверки работы выборки справа представлена кнопка «Run query».
При нажатии на эту кнопку сверху будет показан график, построенный на основе нашего запроса к базе.
Для сохранения этого представления на дашборде на правой панели нужно задать имя представления (Title), например «system-journal count», и нажать «Apply»:
После этого представление добавиться на дашбоард. Представление не будет занимать все пространство дашбоарда:
Что бы растянуть представление на всю ширину, нужно ухватить мышкой за правый нижний угол панели представления и растянуть картинку во всю ширину:
Теперь нужно сохранить дашборд в памяти Grafana. Для этого нужно нажать на панели вверху справа кнопку сохранения «Save dashboard»
После этого нужно ввести имя (Title) дашборда, например «Logs», и нажать кнопку сохранения «Save»
Добавим на дашборд кроме графика количества логов еще и таблицу с записями логов. Для этого сверху на панели инструментов нажимаем «Add»--> «Visualization»
Для того что бы добавить панель представления с таблице логов нужно выбрать тип представления. Тип представления выбирается справа из выпадающего списка. Для показа логов нужно выбрать тип «Logs»:
Затем задаем имя представления (Title), например «systemd-journal logs». Для показа времени события (времени прихода лога) делаем активным переключатель Time. Для того что бы длинные записи лога переносились на новую строку активируем переключатель «Wrap lines»:
После этого в нижней панели слева формируем запрос к базе, который будет работать на этом представлении.
Указываем, что нужно отображать записи, обладающей меткой «job»=«system-journal». Для проверки отображения данных нажимаем «Run query»
На панели сверху должны отобразиться логи. Для сохранения этого представления нужно нажать кнопку «Apply», расположенную сверху справа:
После добавления нового представления на дашборд нужно еще раз сохранить дашборд нажав «Save dashboard» и еще раз «Save»
Теперь внешний вид дашбора будет выглядеть так:

Для удобства работы с dashboard можно ввести сразу на этом дашборде доступ к показу данных с конкретного сервера и фильтр поиска по тексту лога, так как сейчас нет возможности отделить в потоке логов логи от разных серверов и искать информацию внутри логов.
Для этого нужно на дашборд добавить переменные. Это делается в настройках дашборад. Нужно нажать кнопку «Dashboard settings»:
И затем выбрать пункт меню «Variables»
Далее нажимаем кнопку добавления переменной «Add variable»
Нам нужно добавить две переменные. Первая переменная будет являться выпадающим списком, который содержит все IP адреса хостов, откуда в Loki валяться логи. Вторая переменная будет обычным текстовым полем, чтобы задавать текст, который нужно искать в теле лог-сообщения.
Для добавления выпадающего списка хостов (IP адресов источника логов) тип переменной должен быть «Query». Затем нужно задать:
Имя переменной - «Name», например «host»
Метку переменной (ту что будет отображаться на дашборде) – «Label», например «host».
Источник данных, как будет заполняться переменная. В нашем случае выпадающий список будет формироваться из уникальных меток «host» источника «Loki». Для значения переменной будет браться значение меток («Label values»)
Остальные поля можно оставить по умолчанию и нажать «Apply»
После этого в панели свойств дашборда появиться созданная переменная «host»
Для добавления второй переменной нажимаем «New variable». Для добавления простой переменной, которую будем использовать для поиска внутри лог-сообщения нужно добавить переменную типа «Text box». Затем нужно задать
Имя переменной - «Name», например «search_txt»
Метку переменной (ту что будет отображаться на дашборде) – «Label», например «search»
Остальное оставляем по умолчанию и нажимаем «Apply»
Теперь в списке переменных дашборад должно появиться две переменные:
Сохраняемся, чтобы не потерять изменения (добавление переменных).
Теперь переменные нужно внедрить на дашборд. Сами поля для выбора-задания переменных уже появились на дашборде, но пока они не работают. Для вплетения переменных в запросы данных Loki на дашборде справа на панели представления количества логов в минуту вызываем меню и выбираем «Edit»
Теперь необходимо отредактировать цепочку запроса добавив условие, связанное с переменными. В цепочку меток добавляем «host» = «$host», для поиска внутри логов вписываем имя переменной в поле Line contains – «$search_txt». Упоминание переменных в запросах нужно делать добавляя к именам переменных символ доллара.
После изменений запросов представления не забываем нажимать «Apply».
Для второго представления, показывающего сами логи, нужно сделать аналогичное действие. Выбрать меню редактирования представления и добавить в запрос переменные $host и $search_txt следующим образом. Затем сохраниться нажав «Apply»
После данных манипуляций необходимо сохранить изменения в дашборде нажав «Save Dashboard» и затем «Save».
Теперь на дашборде можно проводить поиск логов по IP адресу источника и по произвольному тексту в логах

Дашборд – это панель, на которой должно показываться укрупненно ход текущей работы системы. Если что-то пойдет не так, на графиках, в цифрах и пр, оператор, как правило это видет и переходит к детальному анализу логов. Детальный анализ логов и поиск по базе локи удобно проводить не на дашборде, а в специально предназначенном разделе Grafana – Explore. Перейти в этот раздел можно из меню слева:
Откроется окно составления запросов к базе Loki.
Результат запросов – график количества записей логов и список логов, соответствующий запросу будет представлен ниже на этой же странице