Астрологи объявили месяц статей о домашних 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:
для этого используется HTML5 клиент noVNC
- OpenMediaVault в качестве системы управления хранилищем.
При выборе хранилища основным критерием была поддержка ZFS и работа на linux, а не на FreeBSD т.к. его хотелось установить на хостовую систему вместе с Proxmox а не на отдельную виртуальную машину.
Я рассматривал несколько софтин на эту роль, пробовал даже openATTIC — к сожалению поддержка ZFS там оказалась довольно слаба и на данный момент многих опций там просто нет, хотя я уверен что с CEPH дело предстоит несколько иначе.
В поисках я наткнулся на замечательный плагин добавляющмй поддержку zfs для OpenMediaVault — он даёт полный контроль над ZFS. Вместе с самим OpenMediaVault он полностью реализует все те функции, чего я так долго хотел получить от хранилища.
OpenMediaVault, как и Proxmox, целиком и полностью управляется через современный веб-интерфейс на ExtJS:
Proxmox и OpenMediaVault будут составлять ядро нашей системы, в результате чего мы получим многофункциональный комбайн продвинутой системы хранилища и продвинутой системы виртуализации в одной коробке, все данные при этом, как и диски виртуальных машин будут храниться на ZFS.
В случае если понадобится развернуть какой то новый сервис, всегда можно создать отдельную
виртуальную машину или контейнер для этого. Об этом я раскскажу чуть позже.
Обе системы поставляются и работают на Debian, что с одной стороны должно существенно упростить задачу, но с другой стороны обе системы несут в себе огромное количество пакетов и зависимостей, которые периодически могут пересекаться и конфликтовать между ссобой.
И специально для вас я написал небольшую инструкцию о том как сделать это.
Как установить OpenMediaVault на Proxmox
Установка Proxmox
Вам понадобится установочный диск, взять его можно на официальном сайте:
- https://www.proxmox.com/en/downloads/category/iso-images-pve
(нам нужна 4 версия, так как она основана на Debian 8 Jessie)
Установка проста и интуитивно понятна, так что думаю, не вызовет у вас лишних вопросов.
Скажу только что желательно иметь отдельный физический диск под систему, чтобы в случае чего её всегда можно было бы безболезненно переустановить, не затрагивая при этом диски с данными.
При установке Proxmox можно так же выбрать файловую систему ZFS или даже настроить програмный RAID.
После установки, не забудьте прописать pve-no-subscription
для репозитория Proxmox, чтобы иметь возможность устанавливать из него пакеты.
cat /etc/apt/sources.list.d/pve-enterprise.list
deb http://download.proxmox.com/debian jessie pve-no-subscription
Установка 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-essential
Скачаем исходники 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
.
Также необходимо удалить требование версии для doxygen
:
vim debian/control
# remove: watchdog
# remove version: doxygen (>= 1.8.9.1)
Проверим зависимости для сборки еще раз:
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 есть неплохая статья на русском языке:
- [https://www.debian.org/doc/manuals/maint-guide/build.ru.html](Глава 6. Сборка пакета)
На этом пожалуй все, теперь вы имеете 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
— для виртуальных машин Proxmoxtank/docker
— здесь будут храниться данные сервисов запущенных в dockertank/cloud
— для данных nextcloudtank/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.
Остальные строки подключают необходимые директории к файловой системе гостя.
Стоит обратить ваше внимание на то, что если внутри подключаемых в контейнер zfs-датасторов вы имеете другие, то их так же необходимо добавить в конфигурацию контейнера, иначе рискуете получить несколько неприятных багов. Приведу пример:
mp0: /tank/data,mp=/data
mp3: /tank/data/Music,mp=/data/Music
mp4: /tank/data/Pictures,mp=/data/Pictures
Внутри контейнера нам необходимо установить docker
и docker-compose
, а после этого я покажу как у меня все организованно.
Docker
В директории /docker
у меня созданы директории для каждого отдельного сервиса:
# ls /docker/
deluge emby nextcloud nginx-proxy wordpress
В каждой директории лежит отдельный docker-compose.yml
файл и данные каждого отдельного контейнера.
К примеру так выглядит docker-compose.yml
:
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, либо держать все сервисы в одном конфиге.
Теперь сами конфиги:
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:
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:
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:
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 и даже не на этом хосте.
Решение не заставило себя долго искать, для подключений такого типа можно создать еще один отдельный прокси контейнер:
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
С таким конфигом:
# 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.100.20:8096/;
}
}
# pve.example.org
server {
server_name pve.example.org;
listen 80 ;
location / {
proxy_pass https://192.168.100.10:8006/;
}
}
# nas.example.org
server {
server_name nas.example.org;
listen 80 ;
location / {
proxy_pass http://192.168.100.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
Спасибо за внимание и удачи в экспериментах :)