All-In-One: Proxmox + OpenMediaVault или ещё одна идея для домашнего NAS

в 13:46, , рубрики: Deluge, docker, docker-compose, emby, freenas, freenas 10; обзор софта, kvm, LetsEncrypt, linux, lxc, NAS, nextcloud, nginx, open source, openmediavault, proxmox, proxmox 4, proxmox ve, SSL, ssl сертификаты, UNIX, zfs, zfsonlinux, виртуализация, Настройка Linux, системное администрирование, хранение данных, хранилище

All-In-One: Proxmox + OpenMediaVault или ещё одна идея для домашнего NAS - 1

Астрологи объявили месяц статей о домашних NAS на хабре, так что поделюсь и своей историей успеха...

Не так давно я попробовал новый FreeNAS Coral. Понравилось мне в нем если не все, то очень многое: это и новый гипервизор bhyve, и повсеместное использование 9P для проброса файловой системы на гостя, а так же идея с docker и многое другое.
Кроме того я ещё больше влюбился в ZFS со всеми её плюшками, такими как дедупликация и сжатие на лету.

Но к сожалению не все было так гладко как хотелось бы и, к тому же, флешка с установленной системой приказала долго жить, так что настало время для новых экспериментов!
На этот раз я задумал реализовать что-то похожее, но только лучше и целиком на Linux.

В статье так же будет немного рассказано про Docker и автоматический прокси с автоматическим получением сертификатов Letsencrypt.

Для начала расскажу что же мне все таки не понравилось в FreeNAS Corral:

  • Не готов для production. (недавно этот релиз вообще отозвали)
  • Работа с docker удобна только в случае единичных контейнеров, в случае когда контейнеров много управление через веб-морду становится крайне неэффективным.
  • Контейнеры запускаются внутри виртуальных машин с Linux, а порты проксируются через хост, что в принципе не плохо, но подразумевает некий оверхед в сравнении если бы они запускались прямо на хосте.
  • Гипервизор bhyve пока не поддерживает live-snapshots.
  • Нет возможности создавать виртуальные машины не из шаблонов. (по крайней мере в GUI)
  • Система установленая на флешку ужасно тормозила.

В принципе со всем этим можно было бы жить, но как я говорил флешка с системой сдохла и теперь у меня есть новые идеи:

  • Систему нужно устанавливать на жёсткий диск, пусть даже самый простой, но на диск, а не на флешку.
    Идея с установленной системы отдельно от данных хороша, но сколько я флешек не перепробовал (включая USB 3.0) всё равно работает очень плохо и безбожно тормозит. Так что ставить будем на отдельный HDD.

  • ZFS в качестве основанной файловой системы. ZFS позволяет не думать как мне распределять ресурсы хранилища между файловыми системами и виртуальными машинами, она поддерживает моментальные снимки (снапшоты), дедупликацию и сжатие на лету, а также известный RAIDZ.

  • Proxmox в качестве системы управления виртуализацией. Здесь есть все что необходимо: это поддержка как полной так и контейнерный виртуализации, снапшоты, автоматические бекапы и многое другое, а главное ZFS тут предлагается по умолчанию и работает прямо из коробки.
    Proxmox целиком и полностью управляется через современный веб-интерфейс на ExtJS:

All-In-One: Proxmox + OpenMediaVault или ещё одна идея для домашнего NAS - 2

Proxmox так-же позволяет подключаться к консоли виртуальной машины через веб-интерфейс:

All-In-One: Proxmox + OpenMediaVault или ещё одна идея для домашнего NAS - 3

для этого используется HTML5 клиент noVNC

  • OpenMediaVault в качестве системы управления хранилищем.

При выборе хранилища основным критерием была поддержка ZFS и работа на linux, а не на FreeBSD т.к. его хотелось установить на хостовую систему вместе с Proxmox а не на отдельную виртуальную машину.

Я рассматривал несколько софтин на эту роль, пробовал даже openATTIC — к сожалению поддержка ZFS там оказалась довольно слаба и на данный момент многих опций там просто нет, хотя я уверен что с CEPH дело предстоит несколько иначе.

В поисках я наткнулся на замечательный плагин добавляющмй поддержку zfs для OpenMediaVault — он даёт полный контроль над ZFS. Вместе с самим OpenMediaVault он полностью реализует все те функции, чего я так долго хотел получить от хранилища.
OpenMediaVault, как и Proxmox, целиком и полностью управляется через современный веб-интерфейс на ExtJS:

All-In-One: Proxmox + OpenMediaVault или ещё одна идея для домашнего NAS - 4

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

Обе системы поставляются и работают на Debian, что с одной стороны должно существенно упростить задачу, но с другой стороны обе системы несут в себе огромное количество пакетов и зависимостей, которые периодически могут пересекаться и конфликтовать между ссобой.
И специально для вас я написал небольшую инструкцию о том как сделать это.

Как установить OpenMediaVault на Proxmox

Установка Proxmox

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

Установка проста и интуитивно понятна, так что думаю, не вызовет у вас лишних вопросов.
Скажу только что желательно иметь отдельный физический диск под систему, чтобы в случае чего её всегда можно было бы безболезненно переустановить, не затрагивая при этом диски с данными.

При установке Proxmox можно так же выбрать файловую систему ZFS или даже настроить програмный RAID.

Установка OpenMediaVault

Установим репозитроий OpenMediaVault 3.0 Erasmus:

echo "deb http://packages.openmediavault.org/public erasmus main" > /etc/apt/sources.list.d/openmediavault.list 

Как я говорил ранее, пакет openmediavault имеет некоторые неразрешимые зависимости с компонентами Proxmox, в часности это качается пакета watchdog, который в Proxmox начиная с версии 4.0 является fencing-демоном по умолчанию. В нашем случае он установлен по умолчанию как зависимость от proxmox-ve, но мы его не используем т.к. не используем кластеризацию.

В любом случае эти зависимости нам нужно как-то разрешить, и поэтому мы пересоберем deb-пакет для openmediavault.

Подготовим окружение для сборки:

apt install build-essentials

Скачаем исходники OpenMediaVault 3.0 Erasmus, и перейдем в директорию для сборки:

wget https://github.com/openmediavault/openmediavault/archive/3.x.tar.gz -O - | tar xzvf -
cd openmediavault-3.x/deb/openmediavault

Эта команда покажет нам необходимые зависимости, которые мы должны установить в системе перед сборкой пакета:

dpkg-checkbuilddeps

Исходя из вывода предыдущей команды установим необходимые пакеты:

apt install debhelper fakeroot gettext dh-systemd doxygen

Теперь нам нужно удалить watchdog из зависимостей, для этого отредактируем debian/control и удалим оттуда watchdog:

vim debian/control
# remove: watchdog

Проверим зависимости для сборки еще раз:

dpkg-checkbuilddeps

И запустим саму сборку:

dpkg-buildpackage -us -uc 

После сборки вы получите готовый deb-пакет, который мы и установим в систему:

cd ..
dpkg -i openmediavault_*.deb

Теперь установим остальные зависимости, для этого запустим:

aptitude -f install

Теперь можно запустить скрипт для начальной конфигурации, поменять пароль администратора / порт веб-сервера и что-нибудь еще:

omv-firstaid

Установка плагина ZFS:

Плагин openmediavault-zfs устанавливается отдельно от OpenMediaVault и так как он тоже имеет неразрешимые зависимости мы тоже соберем его вручную:

Скачаем исходники, и перейдем в директорию для сборки:

wget https://github.com/OpenMediaVault-Plugin-Developers/openmediavault-zfs/archive/master.tar.gz -O - | tar xzvf - 
cd openmediavault-zfs-master

Подправим зависимости, удалим zfs-dkms так-как в Proxmox начиная с версии 4.0, ZFS уже идет в комплекте с ядром, до кучи за ненадобностью удалим так же linux-headers-* / pve-headers :

vim debian/control
# remove: zfs-dkms
# remove: linux-headers-amd64 | pve-headers | linux-headers-3.16.0-4-all

Проверим зависимости для сборки:

dpkg-checkbuilddeps

Запустим сборку:

dpkg-buildpackage -us -uc 

После сборки установим полученный пакет и зависимости для него:

cd ..
dpkg -i openmediavault-zfs_*.deb
aptitude -f install

Если возникнут трудности со сброкой пакетов, в документации Debian есть неплохая статья на русском языке:

На этом пожалуй все, теперь вы имеете Proxmox и OpenMediaVault установленные на одной системе, самое время перейти в GUI создать и настроить пулы ZFS и подключить их в Proxmox.
Как это сделать я описывать не буду, об этом и так полно информации в интернете.

Что дальше?

Дальше самое интересное, теперь можно приступить к настройке дополнительных сервисов.
Из них я хочу показать как настроить:

  • WordPress — это один из самых простых и распространненых движков для построения сайтов.
  • Nextcloud — ваше личное облако и интерфейс для доступа к файлам.
  • Deluge — на мой взгляд лучшая торрентокачалка.
  • Emby — свободный медиа сервер, позволяет стримить мультимедиа прямо в браузере или через DLNA.
  • nginx-proxy — который будет автоматически генерировать конфиг и все эти сервисы проксировать.
  • nginx-proxy-companion — будет получать и обновлять сертификаты в автоматическом порядке.

Каждый из этих сервисов будет доступен на субдомене и защищен SSL, с валидным сертификатом от Letsencrypt. На помощь нам придет Docker, думаю что это гораздо проще чем вы могли бы себе это представить.

Я полагаю вы уже настроили хранилище ZFS и подключили его в интерфейс Proxmox.

В моем конкретном случае есть два пула:

  • rpool — это тот что создал proxmox при установке
  • tank — это RAIDZ пул из трех дисков с данными

Также я создал четыре основных датастора:

  • tank/pve — для виртуальных машин Proxmox
  • tank/docker — здесь будут храниться данные сервисов запущенных в docker
  • tank/cloud — для данных nextcloud
  • tank/data — основная файлопосойка, внутри есть еще несколько датасторов, таких как Music, Photos, Movies, каждый со своими настройками, например для Music и Photos включена дедупликация, так как у меня большое количество повторяющихся файлов, которые я неизвсестно когда разгребу...

Теперь я хочу создать отдельную виртуальную машину в Proxmox, а точнее контейнер и запускать все в нем, что бы больше не издеваться над основной системой, и по возможности изолировать эти сервисы от нее.
В конфигурацию контейнера я добавил следующий строки:

lxc.aa_profile: unconfined
lxc.cap.drop:
mp0: /tank/data,mp=/data
mp1: /tank/cloud,mp=/cloud
mp2: /tank/docker,mp=/docker

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

Внутри контейнера нам необходимо установить docker и docker-compose, а после этого я покажу как у меня все организованно.

В директории /docker у меня созданы директории для каждого отдельного сервиса:

# ls /docker/
deluge  emby nextcloud  nginx-proxy wordpress

В каждой директории лежит отдельный docker-compose.yml файл и данные каждого отдельного контейнера.

К примеру так выглядит docker-compose.yml:

для nginx-proxy и nginx-proxy-companion

nginx-proxy:
  restart: on-failure:5
  image: jwilder/nginx-proxy:alpine
  ports:
    - "80:80"
    - "443:443"
  volumes:
    - ./certs:/etc/nginx/certs:ro
    - ./vhost.d:/etc/nginx/vhost.d
    - ./html:/usr/share/nginx/html
    - /var/run/docker.sock:/tmp/docker.sock:ro
  labels:
    - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true"

nginx-proxy-companion:
  restart: on-failure:5
  image: jrcs/letsencrypt-nginx-proxy-companion
  volumes:
    - ./certs:/etc/nginx/certs:rw
    - /var/run/docker.sock:/var/run/docker.sock:ro
  volumes_from:
    - nginx-proxy

Вы можете зайти в директорию с nginx-proxy и выполнив docker-compose up вы проучите готовый запущенный сервис, это очень удобно!

  • Контейнер nginx-proxy в двух словах работает следующим образом, он запускается слушает docker.sock и в случае если обраружит запущенный контейнер с переменной VIRTUAL_HOST, то сгенерирует конфиг для этого виртуального хоста, с проксированием на виртуальный ip контейра.
  • Контейнер nginx-proxy-companion работает схожим образом, если обнаруживает запущенный контейнер с переменной LETSENCRYPT_HOST он автоматически получает для него сертификат.

Для более подробной информации совертую обратиться к официальной страничке проектов:

  • nginx-proxy — который будет автоматически генерировать конфиг и все эти сервисы проксировать.
  • nginx-proxy-companion — будет получать и обновлять сертификаты в автоматическом порядке.

Сразу должен предупредить, nginx-proxy не работает с Compose file version 2, т.к. требует чтобы между контейнерами была одна общая сеть.
Так что необходимо использлвать только Compose file version 1, либо держать все сервисы в одном конфиге.

Теперь сами конфиги:

для WordPress:

mysql:
  restart: on-failure:5
  image: mariadb:10.0
  hostname: mysql
  volumes:
    - /etc/localtime:/etc/localtime:ro
    - ./mysql:/var/lib/mysql
  environment:
    - MYSQL_ROOT_PASSWORD=seekac7aexoh2eithut6sie1eYaeNgei
    - MYSQL_DATABASE=example_org
    - MYSQL_USER=example_org
    - MYSQL_PASSWORD=imieth7iev4dah6eeraik6Ohz6oiVup7

wordpress:
  restart: on-failure:5
  image: wordpress
  hostname: example.org
  volumes:
    - /etc/localtime:/etc/localtime:ro
    - ./wordpress:/var/www/html
  links:
    - mysql:mysql
  environment:
    - "VIRTUAL_HOST=example.org,www.example.org"
    - "LETSENCRYPT_HOST=example.org,www.example.org"
    - "LETSENCRYPT_EMAIL=admin@example.org"

для Nextcloud:

nextcloud:
  restart: on-failure:5
  image: nextcloud
  hostname: cloud
  domainname: example.org
  volumes:
    - /etc/localtime:/etc/localtime:ro
    - ./nextcloud:/var/www/html
    - /cloud:/cloud
    - /data:/data
  links: 
    - mysql:mysql
    - redis:redis
  environment:
    - "VIRTUAL_HOST=cloud.example.org"
    - "LETSENCRYPT_HOST=cloud.example.org"
    - "LETSENCRYPT_EMAIL=admin@example.org"

redis:
  restart: on-failure:5
  image: redis
  hostname: redis
  volumes:
    - /etc/localtime:/etc/localtime:ro

mysql:
  restart: on-failure:5
  image: mariadb:10.0
  hostname: mysql
  volumes:
    - /etc/localtime:/etc/localtime:ro
    - ./mysql:/var/lib/mysql
  environment:
    - MYSQL_ROOT_PASSWORD=ei8aiWaeDaeDoo8aida0woaNaiy8deer
    - MYSQL_DATABASE=nextcloud
    - MYSQL_USER=nextcloud
    - MYSQL_PASSWORD=rahGhied8lei6ogh2keitie1chaiheex

для Deluge:

deluge:
  restart: on-failure:5
  image: linuxserver/deluge
  hostname: torrent
  domainname: example.org
  volumes:
    - /etc/localtime:/etc/localtime:ro
    - ./config:/config
    - /data:/data
  ports: 
    - 53160:53160
    - 53160:53160/udp
    - 8112:8112
    - 58846:58846
    - 6881:6881
  expose:
    - 8112
  environment:
    - PUID=33
    - PGID=33
    - "VIRTUAL_HOST=torrent.example.org"
    - "VIRTUAL_PORT=8112"
    - "LETSENCRYPT_HOST=torrent.example.org"
    - "LETSENCRYPT_EMAIL=admin@example.org"

для Emby:

emby:
  restart: on-failure:5
  image: emby/embyserver
  volumes:
    - /etc/localtime:/etc/localtime:ro
    - ./config:/config
    - /data:/data
  environment:
    - APP_UID=33
    - APP_GID=33
  net: host

Для emby я использлвал net: host — это означает что контейнер будет использовать хостовую сеть вместо виртуальной сети для docker. Этот шаг необходим для работы DLNA-сервера. По той же причине не указанны VIRTUAL_HOST и LETSENCRYPT_HOST переменные.

Но стойте, как же быть? — как добавить такой контейнер к nginx-proxy?
А как быть если я хочу иметь доступ к веб-интерфейсам Proxmox и OpenMediaVault снаружи? — а они запущены вообще не в docker и даже не на этом хосте.

Решение не заставило себя долго искать, для подключений такого типа можно создать еще один отдельный прокси контейнер:

docker-compose.yml

nginx-local:
  restart: on-failure:5
  image: nginx
  expose:
    - 80
  environment:
    - "VIRTUAL_HOST=media.example.org,pve.example.org,nas.example.org"
    - "LETSENCRYPT_HOST=media.example.org,pve.example.org,nas.example.org"
    - "LETSENCRYPT_EMAIL=admin@example.org"
  volumes:
    - ./local-config:/etc/nginx/conf.d

С таким конфигом:

local-config/default.conf

# If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the
# scheme used to connect to this server
map $http_x_forwarded_proto $proxy_x_forwarded_proto {
  default $http_x_forwarded_proto;
  ''      $scheme;
}

# If we receive X-Forwarded-Port, pass it through; otherwise, pass along the
# server port the client connected to
map $http_x_forwarded_port $proxy_x_forwarded_port {
  default $http_x_forwarded_port;
  ''      $server_port;
}

# Set appropriate X-Forwarded-Ssl header
map $scheme $proxy_x_forwarded_ssl {
  default off;
  https on;
}

access_log off;
# HTTP 1.1 support
proxy_http_version 1.1;
proxy_buffering off;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
# Mitigate httpoxy attack (see README for details)
proxy_set_header Proxy "";

server {
        server_name _; # This is just an invalid value which will never trigger on a real hostname.
        listen 80;
        return 503;
}

# media.example.org
server {
        server_name media.example.org;
        listen 80 ;
        location / {
                proxy_pass http://192.168.225.20:8096/;
        }
}

# pve.example.org
server {
        server_name pve.example.org;
        listen 80 ;
        location / {
                proxy_pass https://192.168.225.10:8006/;
        }
}

# nas.example.org
server {
        server_name nas.example.org;
        listen 80 ;
        location / {
                proxy_pass http://192.168.225.10:8080/;
        }
}

На этом все, теперь у вас есть NAS с виртуализацией и несколько отличных сервисов, защищенных SSL по последнему писку моды:

  • https://example.org
  • https://cloud.example.org
  • https://torrent.example.org
  • https://media.example.org
  • https://nas.example.org
  • https://pve.example.org

Спасибо за внимание и удачи в экспериментах :)

Автор: kvaps

Источник

* - обязательные к заполнению поля