Розділення робочих середовищ в Linux

Привіт, мене звати В’ячеслав. Я працюю інженером в компанії GlobalLogic. В даній статті я б хотів поділитись досвідом створення розділених робочих середовищ в Linux для випадків, коли ви працюєте на кількох проєктах одночасно. На пошук описаного тут рішення мене підштовхнула стаття на DOU із рубрики «як я працюю» (чи, можливо, коментарі до неї), де один з героїв розказував, що у нього на робочому столі завжди є два ноутбуки, оскільки він працює на двох різних клієнтів і тому зручніше розділяти роботу, використовуючи два девайси.

Загалом ідея сегрегації робочих середовищ у випадку, якщо ви працюєте на двох абсолютно різних клієнтів, або, наприклад, ви є студентом чи аспірантом і мусите поєднувати навчання і роботу, досить правильна і розумна. Як з точки зору безпеки, так і з точки зору зручності використання. Розділяючи середовища, ви підвищуєте безпеку, запобігаючи можливому витоку чутливої інформації, як-то паролів, ключів, різної NDA-документації від одного клієнта до іншого. Налаштування доступів, закладки в браузері, профілі в месенджерах, поштові скриньки і так далі. Також ви запобігаєте класичним факапам типу «переплутав вікна і відправив повідомлення не тому клієнту».

Але що робити, коли у вас з’являється третій, а потім четвертий клієнт? Виділяти окремий комп’ютер під кожного? Це зовсім не зручно і не практично. Чи не так? Це зовсім неінженерний підхід, подумав я і замислився над тим, що ж ми можемо зробити в даному випадку, маючи лише одну робочу машину.

На перший погляд рішення доволі просте, очевидне і лежить воно на поверхні. Ми можемо створити кілька різних користувачів в системі під кожен зі своїх «проєктів». Наприклад, ви є студентом і одночасно працюєте в компанії. Тоді ви можете створити користувачів student та emploee. Далі ви можете одночасно залогінитись в Х-сесію кожного з акаунтів і працювати в них паралельно, перемикаючись між «навчанням» і «роботою» в будь-який момент простою комбінацією Ctrl+Alt+F в Linux. Просто, зручно, безпечно.

А ви вже чули, що 21 червня DOU Mobile Day?

Але, як завжди, є одне «але». Що, якщо вам на роботі для доступу до корпоративних ресурсів необхідно підключатись до VPN? Підключившись до приватної мережі з акаунту emploee з великою ймовірністю ваш трафік з акаунту student теж буде йти через VPN-тунель. Що є недобре з точки зору безпеки і в деяких випадках може бути зовсім неробочим варіантом, адже корпоративні налаштування можуть блокувати велику кількість ресурсів, які вам потрібні для навчання.

Звісно, вам може пощастити, і у вас буде «демократичний» VPN-профіль, який не буде чіпати ваш default route і VPN буде використовуватись тільки для окремих корпоративних ресурсів. Але, як показує практика, переважно корпоративні VPN-налаштування є скоріше «авторитарними» (коли default route вашої таблиці маршрутизації направляється через VPN-тунель), або й «диктаторськими» (коли на додачу до зміни default route ваш VPN-клієнт ще й моніторить вашу таблицю маршрутизації, і щойно ви спробуєте внести туди зміни, він відкотить їх назад). Ну і зовсім складний випадок — вам також потрібен VPN для доступу до ресурсів університету. Тобто нам потрібно тримати запущеними обидва VPN-з’єднання.

Пошук рішення

Що ж ми можемо зробити? Чи можливо якось налаштувати наші середовища так, щоб можна було працювати одночасно?

Одним з можливих простих рішень може бути розгортання proxy-сервера в своїй локальній мережі, і далі налаштування своїх програм таким чином, щоб вони йшли в світ через проксі, коли ви хочете обійти VPN. Але в цього рішення є купа недоліків:

  • Необхідність додаткового сервера в локальній мережі.
  • При зміні локації (прийшли в кав’ярню чи співробітню) ваш proxy-сервер вже недоступний.
  • Необхідно налаштовувати кожну програму окремо для роботи з proxy. Не всі це можуть підтримувати.

Що ж, нам потрібне надійніше і більш універсальне рішення. І тут на допомогу можуть прийти namespaces. Так, саме ті namespaces-ядра Linux, на яких базуються контейнери Linux. Namespaces — це спосіб ізоляції ресурсів, доступних процесу. Так, процес запущений в namespace за умовчанням (default namespace) зазвичай має доступ до глобальних ресурсів доступних ядру. Водночас процес, запущений в новоствореному namespace, може мати свою окрему інстансу цих глобальних ресурсів, змінювати їх, не зачіпаючи глобальні ресурси. Так з поміж 8-ми namspace-ів, доступних в свіжому ядрі Linux, існує зокрема network namespace, який дозволяє створити окремий мережевий стек для процесу, включаючи окремі мережеві інтерфейси, таблицю маршрутизації, фаєрвол.

Іншими словами, якщо ми створимо окремий network namespace і запустимо наш VPN в ньому, то він змінить налаштування мережі виключно для тих процесів, які будуть запущені в цьому ж таки namespace. Процеси з інших namespace (в тому числі з default namespace) «не помітять» змін в мережі і будуть працювати як зазвичай. Під час запуску кожен новий процес успадковує namespace-и свого батьківського процесу.

Яким же чином нам це реалізувати? Ми можемо спробувати використати більш високорівневий інструмент, як-от firejail, або ж працювати на нижчому рівні, створюючи namespase-и і конфігуруючи мережу самостійно. З firejail нам необхідно буде запустити наш VPN-клієнт в «пісочниці» і далі домогтися того, щоб всі інші програми, яким потрібен доступ до мережі, запускались в тій самій «пісочниці». Даний підхід може бути заскладними в практичному використанні для нашої задачі. Тож спробуємо реалізувати її на нижчому рівні, забезпечуючи максимальну простоту і прозорість рішення. Отже спробуємо запустити X-сесію користувача в окремому namespace і побачимо, що з цього вийде.

Конфігурація network namespace

Для створення ізольованої мережі в namespace з доступом назовні нам необхідно реалізувати ось таку схему:

  +--------------------------------------------------------------+                            
  | Default network namespace                                    |                            
  |                                                              |                            
  |  +------------------------+                    +-----------+ |                            
  |  | Network namespace A    |                    |    lo     | |                            
  |  |   +---------+          |                    +-----------+ |                            
  |  |   |   lo    |          |                                  |                            
  |  |   +---------+          |                          +------------+                       
  |  |                        |                          |    eth0    |<--------------+       
  |  |   +---------+          |    +-----------+         +------------+               |       
  |  |   |  eth0   |<---------+--->|   vethA   |           ^     |                    v       
  |  |   +---------+          |    +-----------+           |     |            +-------------+ 
  |  +------------------------+          ^                 |     |            |             | 
  |                                      |                 |     |            |             | 
  |                                      v                 |     |            |   Internet  | 
  |  +------------------------+    +-----------+           |     |            |             | 
  |  | Network namespace B    |    |  bridge   |<----------+     |            |             | 
  |  |   +---------+          |    +-----------+           |     |            |             | 
  |  |   |   lo    |          |          ^                 |     |            +-------------+ 
  |  |   +---------+          |          |                 v     |                    ^       
  |  |                        |          v               +------------+               |       
  |  |   +---------+          |    +-----------+         |    wlan0   |<--------------+       
  |  |   |  eth0   |<---------+--->|   vethB   |         +------------+                       
  |  |   +---------+          |    +-----------+                 |                            
  |  +------------------------+                                  |                            
  +--------------------------------------------------------------+                            

В default namespace нам необхідно створити bridge-інтерфейс, який буде забезпечувати комунікацію між підмережами новостворених namespace та підмережею хоста, а також по одному віртуальному ethernet-інтерфейсу, який буде іншим «кінцем» інтерфейсу з відповідного namespace. В кожному з новостворених namespace буде свій loopback та ethernet.

Надалі ми будемо оперувати лише користувачем student. Подібну конфігурацію потрібно виконати для кожного користувача, якого ми хочемо ізолювати.

Створимо bridge на хості:

root # ip link add name br-netns type bridge
root # ip addr add 192.168.8.1/24 brd 192.168.8.255 dev br-netns
root # ip link set br-netns up

Створимо новий network namespace для користувача student з відповідними інтерфейсами всередині:

root # ip netns add student
root # ip link add veth-student type veth peer name eth0 netns student
root # ip netns exec student ip link set lo up
root # ip netns exec student ip link set eth0 up
root # ip netns exec student ip addr add 192.168.8.2/24 brd 192.168.8.255 dev eth0
root # ip netns exec student ip route add default via 192.168.8.1 dev eth0
root # ip netns exec student ip route add 192.168.1.0/24 via 192.168.8.1 dev eth0

Зауважте, що при створенні namespace автоматично створився відповідний файл в /run/netns, який можна використовувати для переключення в цей namespace, наприклад, використовуючи команду nsenter (дивіться далі).

Зв’яжемо наш namespace з хостом:

root # ip link set veth-student master br-netns
root # ip link set veth-student up

Додатково, щоб наш хост міг форвардити трафік в світ і пакети, які приходять у відповідь, знаходили шлях до відповідної підмережі namespace, нам потрібно зробити наступне:

root # sysctl -w net.ipv4.ip_forward = 1
root # iptables -t nat -A POSTROUTING -s 192.168.8.0/24 -j MASQUERADE

Перевіримо, що у нас вийшло. На хості в default namespace маємо:

root # ip addr show br-netns
60: br-netns: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 26:70:40:10:05:a8 brd ff:ff:ff:ff:ff:ff
    inet 192.168.8.1/24 brd 192.168.8.255 scope global br-netns
       valid_lft forever preferred_lft forever
    inet6 fe80::2470:40ff:fe10:5a8/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever

root # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.0.1     0.0.0.0         UG    600    0        0 wlan0
192.168.0.0     0.0.0.0         255.255.255.0   U     600    0        0 wlan0
192.168.8.0     0.0.0.0         255.255.255.0   U     0      0        0 br-netns

root # curl icanhazip.com
xxx.xxx.14.162

Перейдемо в новостворений network namespace:

root # nsenter --net=/run/netns/student bash

root # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host proto kernel_lo 
       valid_lft forever preferred_lft forever
2: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0
3: eth0@if61: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether f6:56:c9:89:c2:f5 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.8.2/24 brd 192.168.8.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::f456:c9ff:fe89:c2f5/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever

root # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.8.1     0.0.0.0         UG    0      0        0 eth0
192.168.1.0     192.168.8.1     255.255.255.0   UG    0      0        0 eth0
192.168.8.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0

root # traceroute 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
 1  192.168.8.1 (192.168.8.1)  0.547 ms  0.434 ms  0.409 ms
 2  192.168.0.1 (192.168.0.1)  4.956 ms  5.729 ms  6.641 ms
 3  * * *
 4  * * *
 5  * * *
 6  * * *
 7  * * *
 8  * * *
 9  * * *
10  * * *
11  * * *
12  * * *
13  dns.google (8.8.8.8)  17.450 ms *  19.890 ms

Як бачимо, ми маємо eth0-інтерфейс з відповідною IP-адресою, а також default route, який веде нас через створений br-netns bridge інтерфейс.

Тепер можемо спробувати запустити VPN в нашій «пісочниці»:

root # openvpn /tmp/119.82.254.66_tcp_1735.ovpn 
2025-05-20 14:36:21 OpenVPN 2.6.12 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [MH/PKTINFO] [AEAD]
2025-05-20 14:36:21 library versions: OpenSSL 3.5.0 8 Apr 2025, LZO 2.10
.........................................................................
2025-05-20 14:36:24 net_route_v4_best_gw query: dst 0.0.0.0
2025-05-20 14:36:24 net_route_v4_best_gw result: via 192.168.8.1 dev eth0
2025-05-20 14:36:24 ROUTE_GATEWAY 192.168.8.1/255.255.255.0 IFACE=eth0 HWADDR=f6:56:c9:89:c2:f5
2025-05-20 14:36:24 TUN/TAP device tun0 opened
2025-05-20 14:36:24 net_iface_mtu_set: mtu 1500 for tun0
2025-05-20 14:36:24 net_iface_up: set tun0 up
2025-05-20 14:36:24 net_addr_ptp_v4_add: 10.211.1.121 peer 10.211.1.122 dev tun0
2025-05-20 14:36:24 net_route_v4_add: 119.82.254.66/32 via 192.168.8.1 dev [NULL] table 0 metric -1
2025-05-20 14:36:24 net_route_v4_add: 0.0.0.0/1 via 10.211.1.122 dev [NULL] table 0 metric -1
2025-05-20 14:36:24 net_route_v4_add: 128.0.0.0/1 via 10.211.1.122 dev [NULL] table 0 metric -1
2025-05-20 14:36:24 Initialization Sequence Completed
2025-05-20 14:36:24 Data Channel: cipher 'AES-128-CBC', auth 'SHA1'
2025-05-20 14:36:24 Timers: ping 3, ping-restart 10

В сусідній консолі ще раз заходимо в нашу «пісочницю»:

root # nsenter --net=/run/netns/student bash

root # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.211.1.122    128.0.0.0       UG    0      0        0 tun0
0.0.0.0         192.168.8.1     0.0.0.0         UG    0      0        0 eth0
10.211.1.122    0.0.0.0         255.255.255.255 UH    0      0        0 tun0
119.82.254.66   192.168.8.1     255.255.255.255 UGH   0      0        0 eth0
128.0.0.0       10.211.1.122    128.0.0.0       UG    0      0        0 tun0
192.168.1.0     192.168.8.1     255.255.255.0   UG    0      0        0 eth0
192.168.8.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0

root # curl icanhazip.com
119.82.254.66

Бачимо, що трафік тепер іде через VPN-тунель за умовчанням і наша публічна адреса змінилась.

Перевіримо ще раз конфігурацію на хості:

root # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.0.1     0.0.0.0         UG    600    0        0 wlan0
192.168.0.0     0.0.0.0         255.255.255.0   U     600    0        0 wlan0
192.168.8.0     0.0.0.0         255.255.255.0   U     0      0        0 br-netns

root # curl icanhazip.com
xxx.xxx.14.162

Чудово, на хості все без змін. Хост «не бачить» VPN.

Отже все має працювати, але є ще один важливий момент. Часто при підключенні до VPN нам необхідно використовувати окремі DNS-сервери для доступу до приватних ресурсів. Додавши їх до нашого /etc/resolv.conf, ми можемо зламати/погіршити name resolution на хост-машині. Тут на допомогу можуть прийти ті самі namespace. Але тепер mount namespace.

Конфігурація mount namespace

Наша задача ізолювати /etc/resolv.conf таким чином, щоб зміни, які вносяться в цей файл в нашій «пісочниці», не міняли оригінальний файл, який використовується на хості. Для цього ми створимо свій mount namespace, в якому у вибрану директорію змонтуємо tmpfs, в яку скопіюємо наш resolv.conf файл. Далі нам потрібно зробити bind-mount цієї копії у відповідне місце в файловій системі. Тут слід зауважити, що зазвичай, в системах, де мережа керується за допомогою NetworkManager, файл /etc/resolv.conf є символічним посиланням на /run/NetworkManager/resolv.conf, тому ми можемо ізолювати /run/NetworkManager директорій і правити resolv.conf файл там.

Для створення і оперування namespace ми будемо використовувати файл, створений в /run/mountns/<name> наступним чином:

root # mkdir -p /home/student/.config/sandbox
root # mkdir -p /run/mountns
root # touch /run/mountns/student
root # unshare --mount=/run/mountns/student true

root # nsenter --net=/run/netns/student --mount=/run/mountns/student bash
root # mount -t tmpfs tmpfs /home/student/.config/sandbox
root # mkdir -p /home/student/.config/sandbox/NetworkManager
root # cp -r /run/NetworkManager/* /home/student/.config/sandbox/NetworkManager
root # mount -o bind /home/student/.config/sandbox/NetworkManager /run/NetworkManager

Перевіримо, що у нас вийшло в «пісочниці»:

root # nsenter --net=/run/netns/student --mount=/run/mountns/student bash

root # mount | grep -e student -e NetworkManager
nsfs on /run/netns/student type nsfs (rw)
tmpfs on /home/student/.config/sandbox type tmpfs (rw,relatime)
tmpfs on /run/NetworkManager type tmpfs (rw,relatime)

Тепер спробуємо поредагувати /etc/resolv.conf в «пісочниці»:

root # cat /etc/resolv.conf 
# Generated by NetworkManager
nameserver 192.168.0.1

root # nsenter --net=/run/netns/student --mount=/run/mountns/student sh -c "echo 'nameserver 8.8.8.8' >> /etc/resolv.conf"
root # nsenter --net=/run/netns/student --mount=/run/mountns/student sh -c "cat /etc/resolv.conf"
# Generated by NetworkManager
nameserver 192.168.0.1
nameserver 8.8.8.8

root # cat /etc/resolv.conf 
# Generated by NetworkManager
nameserver 192.168.0.1

Чудово, як бачимо, зміни в «пісочниці» не впливають на конфігурацію на хості.

Для автоматизації описаної конфігурації можна скористатись скриптами з namespacer репозиторію. Там наявні скрипти для OpenRC. Достатньо їх скопіювати в /etc/local.d/ і зробити символічні посилання, вказуючи в назві посилання імена користувачів, для яких ви хочете створювати namespace при старті системи. Наприклад:

# ln -s /etc/local.d/20-ns{,-student}.start
# ln -s /etc/local.d/20-ns{,-student}.stop

Тепер у нас все готово для запуску X-сесії користувача в новостворених network namespace та mount namespace.

На жаль, документованої опції, як саме це зробити в Xfce DE, я не знайшов, тому скористався наступним хаком:

student $ mkdir -p ~/.config/xfce4/
student $ cp /etc/xdg/xfce4/xinitrc ~/.config/xfce4/

І зробити наступні зміни:

146,147c146,155
<   # start xfce4-session normally
<   exec ${XFCE4_SESSION_COMPOSITOR:-xfce4-session}
---
>   # if network and mount namespaces present run in it
>   if [ -f /run/netns/$USER -a -f /run/mountns/$USER ]; then
>     # unset some sensitive env
>     unset DBUS_SESSION_BUS_ADDRESS
>     unset XDG_RUNTIME_DIR
>     exec sudo -E nsenter --net=/run/netns/$USER --mount=/run/mountns/$USER su $USER -c "${XFCE4_SESSION_COMPOSITOR:-xfce4-session}"
>   else
>     # start xfce4-session normally
>     exec ${XFCE4_SESSION_COMPOSITOR:-xfce4-session}
>   fi

Додатково за необхідності можна додати нашого користувача в sudoers, оскільки nsenter доступний тільки для root:

# echo "student     ALL = (root) NOPASSWD:SETENV: /usr/bin/nsenter --net=/run/netns/student --mount=/run/mountns/student su student -c xfce4-session" >> /etc/sudoers.d/student

Логінимось в X-сесію користувача student і перевіряємо результат. Тепер всі процеси, починаючи від xfce4-session, мають запускатись в наших namespace.

Запустимо термінал і подивимось на конфігурацію мережі:

student $ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host proto kernel_lo 
       valid_lft forever preferred_lft forever
2: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0
3: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether f6:15:60:55:f6:77 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.8.2/24 brd 192.168.8.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::f415:60ff:fe55:f677/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever

Як бачимо, ми маємо окрему підмережу, відмінну від мережі хоста, і у нас немає ні Wi-Fi, ні Ethernet інтерфейсу хоста. Хоча якщо ми подивимось в налаштування мережі в Xfce, то там є всі інтерфейси хоста. Чому так? Справа в тому, що NetworkManager був запущений як сервіс при старті системи, і тому він працює в default network namespace. Тобто у нас зберігається можливість керувати мережею хоста через графічний інтерфейс або використовуючи команду nmcli і водночас ми можемо вільно змінювати налаштування мережі «пісочниці», не зачіпаючи загальні налаштування системи. У випадку VPN нам потрібно його запускати не через NetworkManager, а з консолі (як ми робили це вище) або через свого клієнта, запущеного в нашому namespace.

Також слід звернути увагу на те, що якщо нам потрібно працювати з Docker, то dockerd (а також containerd) теж потрібно запускати з нашого namespace, а не з default namespace. Зазвичай в Linux не є проблемою запускати кілька інстансів Docker. У вищезгаданому namespacer репозиторії можна знайти додаткові інструкції, як це зробити в Gentoo. Після запуску окремого dockerd нам необхідно визначити відповідну змінну середовища, яка має вказувати на правильний сокет нашого dockerd сервісу. Щось типу:

export DOCKER_HOST=unix:///var/run/docker-student.sock

Зрозуміло, що рішення не є ідеальним, і потенційно можуть бути проблеми з тим, що деякі сервіси працюють в default namespace, тоді як вся X-сессія в окремому. Хоча на своєму сетапі я серйозних проблем не спостерігав. Можу припустити, що systemd може не бути «щасливим», побачивши такий сетап. Не тестував. Діліться в коментарях власними лайфхаками, як ви вирішуєте подібні задачі.

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось12
До обраногоВ обраному6
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Щоб робити те ж саме «на конвейрі» парою команд, можна поставити proxmox і клонувати LXC під кожний деплоймент. Бонусом будуть бекапи, примитивный моніторинг...

Шикарна стаття, дякую, саме таких технічних статей не вистачає на ДОУ імхо

А мені подобається: атмосферно, тру лінукс, всяке таке, а не ось ця пластмаса з віртуалками.

При довколанульовій вартості віртуалок займатись таким ідейним насиллям, це рівень. Вже й шаред хостинг мабуть вимер, білі адреси закінчуються і все ніяк не закінчаться. А для внутрішніх тестів хоч тисячу тих віртуалок за натом

я б сказав що шаред хостинг як і адреси тисячі віртуалок повз каси (коли net namespaces використовують і без віртуалок)

Так а нашо це все?

Чим не догодили VM з парочкою базових імеджей де весь специфічний бойлерплейт вже зроблений і треба тільки клонувати і трішки підкрутить?

Для разових задач — так, віртуалка це варіант. Для постійної роботи — не дуже раціонально.

Про віртуалки статтю не напишеш...

В цілому від простих задач з різними типами namespace до віртуалок є достатньо всього (і snap/flatpak, і докери, ...), кожен чих закривати віртуалкою — теж не кращий варіант.

Не бачу проблем мати віртуалку на кожний чих. Не сподобалося чи не потрібна — в смітник відправив та й годі.

Там де є ресурси на те, як і час додати відповідний енвайрмент у віртуалці, — теж проблем нема. А для чогось простого-чи-разового нп з мережею — net-namespaces достатньо. Одне інше не відміняє.

Зазвичай у вас є віртуалка-донор, яка має всі оновлення, налаштування, з якої потім робиться клон. Це дуже примітивна операція, доволі швидко зробити. Не хочеться колупатися з віртуальними машинами? Тоді докер на допомогу, або аналогічні програми.

У вас свої задачі, у когось інші (нп — якщо мені софт перевірити разово в деякій емуляції мережі то нп зручніше в net-namespaces це зробити — ніж запускати віртуалку/докер і там збирати велику частину яка і так вже є на хост системі. Ще інший «нп» різноманіття — разберрі з мін пам’яті). Тобто не у всіх і не завжди той «зазвичай».

Нарешті ми чуємо умови задачі...

я взагалі не про чиюсь конкретику (бо без net-namespaces нп і з дефолтом можливо є легші опції вирішення, і з dns view, etc.), а відносно того що на любий чих пропонувати універсальний 42 (р̶о̶б̶и̶м̶о̶ ̶е̶л̶е̶к̶т̶р̶о̶н̶-̶а̶п̶п̶ чи закриваємо питання віртуалкою — неважливо яке саме універсальне рішення)

Для пересічного середньостатистичного розробника підняти віртуалку в рази простіше, ніж розбиратися з особливостями мережевого стеку ОС.

Тобто це читається як — у пересічного вебпрограмера є проблем з мережевим стеком і він тільки п̶и̶ш̶е̶ ̶у̶н̶і̶в̶е̶р̶с̶а̶л̶ ̶а̶п̶п̶с̶ чуть що ставить віртуалку. — я правильно зрозумів?

Хіба, в наші дні, пересічний фронт вєб программер знає, що існує щось низкорівневіше за http ?

хто знає хто здогадується — вебпрограмінг зацікавив?

Мені з 2003, як універ закінчив, від нього блювати хочется... якщо чесно.

Але що робити, коли у вас з’являється третій, а потім четвертий клієнт? Виділяти окремий комп’ютер під кожного? Це зовсім не зручно і не практично. Чи не так? Це зовсім неінженерний підхід, подумав я

Кастомери знають про таку практику?
Security Officer кастомера знає про таку практику?
Як це пройшло цензуру компанії? ))

не пофиг ли? большинство кастомеров вообще ненавидят линукс на десктопах, покупают для сесурити груду корпоративного софта, который поддерживает только винду и мак, а с линуксом посылают нах.
На большой галере аналогичной скотолоджику, на поддержку линукса вообще ложили болт, индусы с саппорта только если слышат что на десктопе линукс, сразу отмахиваются и доступ в корпоративную сеть запрещен с линуксов, то что на него невозможно воткнуть MDM

Сподобалось, хоч і не тестував бо небуло таких потреб.

Додам:
Якщо vpn client такий що жити не може без зміни дефолту — можна спробувати просто додати 0/1 128/1 на default gateway.
Якщо в цілому як окреме середовище з купою інших ресурсів — найпростіше підняти звичайну віртуалку для того.
Варіанти з тонким розподілом namespace всіх ресурсів (мережа, диск, ...) - можна легко десь помилитися в скриптовці чи з сервісами які потрібні (і невпевнений чи автоматизація для згаданих sysv/openrc легко переноситься на systemd який зараз у більшості мейнстрім лінукс).

p.s. «переплутав вікна і відправив повідомлення не тому клієнту» — частіше напевно переплутав консолі і бутнув не той сервер/рутер )

pps. net namespaces використовував в основному для тестування мережевого софта

Якщо vpn client такий що жити не може без зміни дефолту — можна спробувати просто додати 0/1 128/1 на default gateway.

можна про це детальніше?

і невпевнений чи автоматизація для згаданих sysv/openrc легко переноситься на systemd який зараз у більшості мейнстрім лінукс

є така підозра і у мене. systemd занадто складний, щоб зробити щось просте на ньому. Це той варіант коли enterprise developrs добрались і до Linux

0/1 128/1

можна про це детальніше?

приблизно так — якщо якимось чином отримано нп default який перебиває інший default, то є варіанти як тому завадити — нп 0/0 розбити на дві частини 0.0.0.0/1 128.0.0.0/1 і додати куди треба (тоді маршрутизуватись буде через більш specific /1). У випадку з vpn треба щоб через впн інтерфейс залишились directly connected або підмережі які доступні через той vpn — чи це так чи ні — треба дивитись деталі по префіксам route table після підняття vpn. Якщо не підходить (що доволі таки можливо) чи там ще додаткові задачі є — тоді з net namespaces з яким є також інші додаткові плюси.

systemd занадто складний

є трохи такого — поглинає все що рядом — його під свої дистро задачі певно все розширюють і розширюють
(деякі речі виглядають привабливо — нп уніфікований апдейт системних частин з updated/updatectl в immutable oses, деякі не так привабливо в рамках «все в одному» і ускладнення)

Для правильного розділення робочих середовищ є віртуальні машини. ;)

За умови обмежених ресурсів розділення робочого середовища буде більш оптимальним варіантом, аніж підняття кількох віртуалок.

note: це залежить від яких саме ресурсів порозподіляти — може бути від мінімуму (щось типу «не дати міняти дефолт») — до максимуму все і вся (віртуалка). Всі рішення мають право на життя — але оптимальність залежить як від початкових constraints «яких саме ресурсів» так і їх наявності )

Ви не працюєте у всіх середовищах водночас. Та про які обмеження ресурсів йде мова?

Якщо немає необхідності одночасної роботи в кількох середовищах, то запропоноване рішення вироджується в щось типу
```
useradd yetanotheruser
```
Логінитесь почергово в потрібний акаунт і працюєте.
Як результат: завжди використовуєте всі наявні ресурси машини і немає необхідності обслуговувати кожну віртуалку. У вас одна ОС. Один раз оновлюємось, один раз щось налаштовуємо, фіксимо, і т.п.

Це суттєво засмічує систему зайвими бібліотеками, налаштуваннями, які потім доволі складно випилювати. В решті решт це може вплинути на стабільність. Перевага віртуалки — ізоляція.

Тобто, додавання користувача в систему

суттєво засмічує систему зайвими бібліотеками
В решті решт це може вплинути на стабільність

це яким чином? не розумію.

це яким чином? не розумію.

Прямим. Конфлікти версій.

засмічує систему зайвими бібліотеками ... Перевага віртуалки ...

as you asked for

% dpkg -l 'qemu*' 'libvirt*' | grep '^ii' | while read ii p r; do dpkg -L $p; done | grep -c '\.so$'

52
you knew that, didn’t you?

Отакої. Віртуалки в даній статі не став приводити як приклад, оскільки думав, що їх недоліки для описаної задачі очевидні. Серед них:
1. Неможливість гнучкого і раціонального використання ресурсів. Для віртуалки потрібно «відрізати» ресурси кожен раз. Як результат: запустити 2-3 віртуалки одночасно з повноцінним робочим енвом дуже складно. Рано чи пізно опиняєшся в ситуації «і сам не гам і іншим не дам».
2. Кожну віртуалку потрібно обслуговувати окремо. Накатувати апдейти, інсталювати новий софт. В деяких випадках, якщо софт вимагає ліцензію, поставити його на кілька віртуалок з одним ключем може не вийти.
Для разових задач — згоден. Віртуалка це варіант. Хоча в лінуксі докер може бути ще простішим і швидшим варіантом.
Тут же я розглядав варіант повноцінного робочого середовища на постійній основі і з необхідністю одночасної роботи в кількох середовищах

Кожну віртуалку потрібно обслуговувати окремо. Накатувати апдейти, інсталювати новий софт.

Це навпаки, перевага, коли софту потрібно різко відмінні вимоги, наприклад, робота у Windows.

можна погодитись якщо в цілому — то так — віртуалки багато що вирішують, але якісь задачі з net-namespaces не зрозуміло як можна вирішувати оптимально з віртуалками — тому net-namespaces в тих випадках і зручні як і вміння з ними працювати

тому net-namespaces в тих випадках і зручні як і вміння з ними працювати

Для мене це звучить як «я щось там вивчив, тепер буду крізь використовувати, доречно це чи ні». ;)

я щось там вивчив

вивчили віртуалки? і після цього ліпити їх скрізь де попало і можливо не дуже ліпиться?)

Може тому що це самий дешевий спосіб?

вже бачив зверху про ліби — тому навіть гадати не стану в якому сенсі «самий дешевий»

p.s. якщо відносно ресурсів залізки — то булоб цікаво

Ви сприймаєте роботу як одноразову. Один раз зробив та користуєшся потім. Я ж рахую не стільки першу стадію, скільки всі наступні кроки: підтримка, модифікація, час розгортання наступного оточення, видалення, тощо. А там вже працюють трохи інші правила. Наприклад, чим більша ізоляція тим краще.

Візьмемо тупий приклад. Java JRE. Один проект вимагає одну версію, інший — другу. Все, припливли. Так, ви можете сказати, що це взагалі не проблема, це легко розрулити, все там вирішується правильними аліасами, софтлінками або ще чимось, але по факту це призводить в решті решт до кропіткої роботи, а інколи до вельми диких багів, на які треба вбити купу часу, щоб тільки розібратися, чому щось не летить так, як очікується.

Або візьмемо іншу проблему — рутові сертифікати для SSL. Якщо програми побудовані адекватними спеціалістами то особливих проблем не мусить бути. Але інколи прийдеться засмічувати систему щоб воно хоч якось полетіло. Вичищати потім це все ніхто вже не буде, воно, скоріше за все, помре разом з хост-системою.

Ще одна перевага віртуалок — їх можна легко шарити з іншими працівниками. Пів години та все полетіло. Найпростіший онбордінг, який я тільки зустрічав.

Але, я можу назвати й недоліки віртуалок. Не треба думати, що там все як в світі рожевих поні. Наприклад, деякі програми детектять віртуалки та не дають на них запускатися. Або є проблеми з певним обладнанням, хоча воно підключається по стандартному USB протоколу. З прямим доступом до заліза можуть виникати проблеми, хоча останнім часом все стає набагато кращим, але тут вже виробники заліза попрацювали, а не розробники систем віртуалізації.

Ви сприймаєте роботу як одноразову

робота як таски яки вирішуються відповідними до задач тулзами (а не навпаки), вирішення деяких інженерних мережевих задач вебпрограмастськими «універсальними» методами наводить на думку про шлях від тулзи а не від задачі

Візьмемо тупий приклад. Java ...

джава не цікавить від слова зовсім, навіть коли вирішують ті жахи шляхом запихання однієї віртуалізації в іншу

Ще одна перевага віртуалок ...

у віртуалок багато переваг є, але це ніяк не робить їх універсальним рішенням для всіх задач навіть у випадку тільки net namespaces

вирішення деяких інженерних мережевих задач вебпрограмастськими «універсальними» методами наводить на думку про шлях від тулзи а не від задачі

Стаття не про інженерні мережеві задачі. Прочитайте вступ. Там ані слова не сказано про це. А ви чомусь зводите це все до цього.

джава не цікавить від слова зовсім

Ви спрощуєте все до відомого.

навіть у випадку тільки net namespaces

Хтось тут тільки йно писав, що треба йти не від інструменту. Нагадую, що задача стояла розділити робочі оточення, а не використати net namespaces щоб мати можливість розділити потоки трафіку.

Як результат: запустити 2-3 віртуалки одночасно з повноцінним робочим енвом дуже складно.

Навіщо вам це? Людина однозадачна.

2. Кожну віртуалку потрібно обслуговувати окремо.

Це не є проблемою, якщо ви шарите конфіги між багатьма віртуалками шляхом софтлінків файлової системи.

Під обслуговуванням я маю на увазі оновлення системи. Встановлення нового софту, видалення старого, і тп.
Взагалі, стаття про віртуалки не завадила б. Поділіться своїми конкретними лайфхаками.

Оновлення системи не є проблемою взагалі. Це нейтральний процес який не впливає на роботоспроможність абсолютно ніяк. Ви можете не оновлювати OS.

Навіщо видаляти софт? Видаліть потім віртуалку та й годі. В них немає ніякого рокет-сайнса чи чогось там супер-пупер складного.

Найбільше «проблем» буде з крос-системними віртуалками, коли хост на одній ОС працює, а віртуалка на іншій. Тоді деякі прості штуки як то розшарити конфігурацію між всіма віртуалками, може бути трохи проблематично реалізувати. Більше залежить від ПЗ, ніж від самої ОС.

Сприймайте віртуалку як щось тимчасове. Сьогодні є, завтра нема.

Підписатись на коментарі