В статье описан редкий случай использования сервера mysql (далее mysqld) с параметром memlock: на сервере с AlmaLinux8 развернут контейнер с Centos7 через systemd-nspawn, в котором надо запустить mysqld (в случае с Centos7 это штатный пакет mariadb-server-5.5.68) с параметром memlock.
Одним из условий параметра memlock является то, что mysqld должен быть запущен от пользователя root. В случае с Centos7 это говорит о том, что нужно создавать новый сервисный файл для systemd, т.к. в штатном запуск осуществляется от пользователя mysql. Также в новом сервисном файле придется отказаться от mysqld_safe, т.к. в ней тоже жестко прописан пользователь mysql.
# cat /etc/systemd/system/mariadb-memlock.service
[Unit]
Description=MariaDB database server with the parameter memlock
After=syslog.target
After=network.target
[Service]
Type=simple
ExecStart=/usr/libexec/mysqld --basedir=/usr --plugin-dir=/usr/lib64/mysql/plugin --log-error=/var/log/mariadb/mariadb.log --user=mysql --memlock
# Give a reasonable amount of time for the server to start up/shut down
TimeoutSec=300
# Place temp files in a secure directory, not /tmp
PrivateTmp=true
[Install]
WantedBy=multi-user.target
Ну вот вроде бы и все, создали сервисный файл. Осталось его запустить. Если бы mysqld запускался вне контейнера, то на этом можно было бы и закончить, т.к. параметр memlock применился бы без проблем (проверено). Но у нас же контейнер, и после запуска в логе mysqld пояляется вот такое сообщение.
[Warning] Failed to lock memory. Errno: 1
Хм... явно что-то нехорошее. И действительно, если посмотреть на переменную locked_in_memory, то она OFF.
# mysql -u root -e "SHOW VARIABLES LIKE 'locked_in_memory'"
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| locked_in_memory | OFF |
+------------------+-------+
Начинается самое интересное (на мой взгляд) - расследование причин такого поведения. Гугление по строке "Failed to lock memory. Errno: 1" ничего не дает, как и топтание вокруг ulimit -l (LimitMEMLOCK=infinity). Затем пробую "прыгнуть" в контейнер через nsenter и запустить mysqld без сервисного файла.
# nsenter -m -u -i -n -p -t $(machinectl show centos7-1 | grep Leader | awk -F'=' '{print $2}')
[root@localhost /]# /usr/libexec/mysqld --basedir=/usr --plugin-dir=/usr/lib64/mysql/plugin --log-error=/var/log/mariadb/mariadb.log --user=mysql --memlock &
И о чудо, параметр memlock применился без проблем. Получается, что если запускать mysqld через сервисный файл, memlock не применяется, а если "прыгнуть" через nsenter и запустить mysqld в консоли, то применяется. Это наводит на мысль о том, что systemd-nspawn при запуске контейнера задает какие-то ограничения. Обычно в таких случаях, когда нагуглить ответ не удалось, а чтение документации непонятно откуда начинать, остается один вариант: смириться и начать плакать незаменимый инструмент - strace. И вот что удалось увидеть в проблемном запуске mysqld.
mlockall(MCL_CURRENT) = -1 EPERM (Operation not permitted)
А вот так это выглядит в непроблемном запуске mysqld.
mlockall(MCL_CURRENT) = 0
Строка "Operation not permitted" подтверждает догадку о том, что есть какие-то ограничения у контейнера. Внимательное чтение документации приводит к тому, что глаза цепляются за параметр Capability. В файл настроек запуска контейнера добавляем этот параметр со значением CAP_IPC_LOCK.
# cat /etc/systemd/nspawn/centos7-1.nspawn
[Exec]
PrivateUsers=no
Capability=CAP_IPC_LOCK
[Files]
[Network]
VirtualEthernet=no
Перезапускаем контейнер и смотрим.
# mysql -u root -e "SHOW VARIABLES LIKE 'locked_in_memory'"
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| locked_in_memory | ON |
+------------------+-------+
Параметр memlock применён успешо!
PS:
После того как удалось решить проблему с контейнером запущенным через systemd-nspawn мне стало интересно как обстоят дела у docker. Буду краток - при запуске mysqld через docker run
нужно выставить параметр --ulimit memlock=-1:-1
, иначе strace покажет вот так
mlockall(MCL_CURRENT) = -1 ENOMEM (Cannot allocate memory)
а в логе mysqld будет такая строка
[Warning] Failed to lock memory. Errno: 12