Skip to main content

Конфигурация и модули

Модуль

Модуль — это блок, описывающий настройку одной из частей системы, используя параметры как способ взаимодействия с другими блоками, настройкой системы в целом или отдельными её частями.

Объявление этих параметров является его основным отличием от других блоков с настройками. Модули позволяют разбивать настройку системы на части, делая ее более структурированной, повторно используемой и масштабируемой.

Функции модуля

  1. Абстракция. Модули скрывают детали реализации, предоставляя стандартизированный интерфейс для настройки компонентов системы. В этом смысле он больше похож на описание функции в языке программирования.
  2. Повторное использование. Один и тот же модуль может использоваться в разных частях системы или в разных конфигурациях для однотипных настроек.
  3. Использование других модулей. Модули могут импортировать другие модули, позволяя создавать иерархическую структуру конфигурации.

Структура модуля

  1. Импорт других модулей (imports).
  2. Объявление параметров(options). 
  3. Определение параметров, а также другие настройки(config).
{
  imports = [
    # Пути к другим модулям.
    # Модули могут импортировать другие модули, позволяя
    # создавать иерархическую структуру настроек.
  ];

  options = {
    # Объявление параметров.
    # Объявляет какие настройки пользователь этого модуля может устанавливать.
    # Обычно это включает общий пункт "enable" изначально установленный в ложное значение.
  };

  config = {
    # Определение параметров.
    # Определяет какие другие настройки, службы и ресурсы должны быть задействованы.
    # Обычно это зависит от того выбрал ли пользователь этого модуля 
    # пункт "enable" используя объявление выше.
    # Параметры для модулей импортированных в секции "imports" могут быть установлены здесь.
  };
}

Каждый модуль может объявлять новые параметры, которые являются настройками для других частей системы. Например, модуль для настройки веб-сервера может иметь параметры порта и директории сайта.

Все модули получают доступ к переменной config, которая содержит текущие определения параметров из других модулей, что позволяет модулям взаимодействовать друг с другом и использовать ранее определенные настройки.

Поскольку модули описывают желаемое состояние системы, а не шаги по его достижению, NixOS является декларативной системой, где настройка системы осуществляется средствами модулей.

Пример:
Вот как может выглядеть упрощенный модуль для гипотетической службы my-service:

# ./my-module.nix
{ config, lib, pkgs, ... }: # Это функция, принимающая аргументы

{
  # 1. Объявляем опции, которые можно использовать в configuration.nix
  options = {
    services.my-service = {
      enable = lib.mkEnableOption "My cool service"; # Создает опцию enable с описанием
      port = lib.mkOption {
        type = lib.types.port;
        default = 8080;
        description = "Port for my-service";
      };
    };
  };

  # 2. Определяем, что делать, если служба включена
  config = lib.mkIf config.services.my-service.enable {
    # Это "вклад" модуля в общую конфигурацию системы
    environment.systemPackages = [ pkgs.my-service-pkg ]; # Добавляем пакет в окружение
    systemd.services.my-service = { # Создаем systemd юнит
      description = "My Service";
      after = [ "network.target" ];
      wantedBy = [ "multi-user.target" ];
      serviceConfig = {
        ExecStart = "${pkgs.my-service-pkg}/bin/my-service --port ${toString config.services.my-service.port}";
      };
    };
  };
}

Теперь в configuration.nix мы можем импортировать этот модуль и использовать его опции:

 

# /etc/nixos/configuration.nix
{ config, pkgs, ... }:

{
  imports = [ ./my-module.nix ]; # Импортируем модуль

  # Используем опции, объявленные в модуле
  services.my-service = {
    enable = true;
    port = 9000;
  };

  # ... остальная конфигурация системы
}

 

Теперь в configuration.nix мы можем включить этот модуль и использовать его опции:

# /etc/nixos/configuration.nix
{ config, pkgs, ... }:

{
  imports = [ ./my-module.nix ]; # Импортируем модуль

  # Используем опции, объявленные в модуле
  services.my-service = {
    enable = true;
    port = 9000;
  };

  # ... остальная конфигурация системы
}

Примеры использования модулей

Модули могут использоваться для:

  1. УправлениеУправления службами. Модуль может описывать настройку и запуск службы, например, веб-сервера nginx, включая его зависимости.
  2. Настройки пользователя. NixOS home-manager использует модули для управления настройками пользователя и содержимым его домашнего каталога, например, настройками оболочки или приложения.
  3. Пакеты.Описание пакетов. Модули могут описывать сборку и установку пакетов, а также управлять их зависимостями.

Преимущества модулей

  1. Воспроизводимость. Модули упрощают создание воспроизводимых настроек, которые можно легко применить на разных машинах.
  2. Управление. Разбиение настроек на модули делает ее более управляемой и понятной, даже для сложных систем.
  3. Повторное использование. Модули могут быть повторно использованы в разных настройках, что сокращает дублирование кода.

Вложенные модули

Вложенные модули это тип, позволяющий определять вложенные модули с собственным набором параметров. Он используется для структурирования сложных настроек, группируя связанные параметры в отдельный блок.

При использовании lib.types.submodule вы создаёте новый параметр, значением которого будет набор атрибутов, соответствующих другому, вложенному модулю. Этот вложенный модуль имеет свой собственный набор параметров, как и обычный модуль NixOS.

Пример:
Допустим, вы создаёте модуль для веб-сервиса, и хотите, чтобы опции для базы данных были сгруппированы.

  1. Объявление типа submodule:
    Вы определяете параметр database с типом submodule. Внутри submodule вы задаёте собственные параметры, например, host, port и user.


    # module.nix
    { config, lib, ... }:
    
    let
      types = lib.types;
    in
    {
      options.database = lib.mkOption {
        type = types.submodule {
          options = {
            host = lib.mkOption {
              type = types.str;
              default = "localhost";
            };
            port = lib.mkOption {
              type = types.int;
              default = 5432;
            };
            user = lib.mkOption {
              type = types.str;
              default = "admin";
            };
          };
        };
        description = "Настройки для базы данных.";
      };
    }
  2. Использование в настройке:
    Затем в вашей настройке вы можете определить значения для этих вложенных параметров.
    # configuration.nix
    { ... }:
    
    {
      imports = [
        ./module.nix
      ];
    
      database = {
        host = "db.example.com";
        port = 5433;
        user = "web_user";
      };
    }

В результате вы получите настройки, где config.database.host будет "db.example.com", config.database.port будет 5433 и config.database.user будет "web_user".

Преимущества вложенных модулей

  • Модульность: Позволяет разбивать сложные настройки на логические, повторно используемые блоки.
  • Структурирование: Повышает читаемость и удобство управления настройками.
  • Типобезопасность: Каждый параметр внутри submodule имеет свой тип и проверяется, что предотвращает ошибки настройки.
  • Совместимость с другими типами: Часто используется в сочетании с lib.types.attrsOf или lib.types.listOf для создания списков или наборов подмодулей. Например, можно создать listOf submodules для определения нескольких веб-сервисов с похожими настройками.

Конфигурация

Конфигурация – это блок, описывающий настройку системы в целом или отдельной её части.

В NixOS файл конфигурации /etc/nixos/configuration.nix предназначен для описания всех настроек системы. Он может включать другие файлы конфигурации, описывающие только часть настроек общей системы, а также модули, задействовать настройки которых можно через их параметры.
Например, вы можете указать, какие сайты разместить на nginx, используя для этого модуль.

Определения

  • Компонент — составляющая часть всей системы.

Список используемых источников

  1. NixOS modules
  2. Understanding NixOS Modules and Declaring Options