tux in egg in python

Hello, {{username}}

Я DevOps и очень люблю Linux. Понятное дело, что с такой связкой я просто не мог не полюбить LinuX Containers (тем более, что BSD и Solaris давно радуют аналогичными возможностями своих пользователей).

Естественно, бизнес тоже увидел привлекательную возможность и программы для управления контейнерами стали расти и множиться: docker , rocket, vagga, lxc, systemd-nspawn, etc…

Docker стал стандартом де-факто в первую очередь благодаря системе создания и доставки контента. Но главный демон докера запускается от root, и, на мой взгляд, это минус этого проекта (Пруф).

Rocket и vagga пошли другим путем, и путь этот носит название unprivileged containers. Вам больше не нужны root привилегии, чтобы запустить процесс в новых namespaces, и это открывает интересные перспективы для построения тестовых площадок и безопасного окружения.

Но во всех этих проектах есть один фатальный недостаток: они все написаны с использованием c, go и rust, а я люблю python и не могу поучаствовать в их разработке. Согласитесь, довольно обидно пропускать все веселье.

Так что под катом вас ждет библиотека для запуска процессов в новых linux user namespaces:

Pyspaces


Детка, Ты просто космос

Goals

Сейчас нет удобного способа работать с linux namespaces из python:
  • можно использовать asylum — проект выглядит мертвым и хостится непонятно где
  • или можно попробовать python-libvirt биндинги с большим уровнем абстракции
  • использовать код на c, как это делают vagga и lxc
  • или дергать glibc вызовы с помощью ctypes
  • в противном случае остается subprocess.Popen

Я хочу изменить это: я хочу создать native python bindings к билбиотеке glibc с интерфейсом как в multiprocessing.Process. И еще немножко целей:
  • популяризировать linux
  • популяризировать python
  • поучаствовать в создании популярного open source проекта
  • прославиться
  • популярность и девушки будут приятным бонусом

ЗЫ: так же посмотрите на python-nsenter — выглядит здорово!

Example

import os
from pyspaces import Container


def execute(argv):
    os.execvp(argv[0], argv)

cmd = "mount -t proc proc /proc; ps ax"
c = Container(target=execute, args=(('bash', '-c', cmd),),
              uid_map='0 1000 1',
              newpid=True, newuser=True, newns=True
              )
c.start()
print("PID of child created by clone() is %ld\n" % c.pid)
c.join()
print("Child returned: pid %s, status %s" % (c.pid, c.exitcode))

PID of child created by clone() is 15978

PID TTY      STAT   TIME COMMAND
1   pts/19   S+     0:00 bash -c mount -t proc proc /proc; ps ax
3   pts/19   R+     0:00 ps ax

Child returned: pid 15978, status 0

CLI

space -v execute --pid --fs --user --uid '0 1000 1' bash -c 'mount -t proc /proc; ps ax'
space chroot --pid --uid '0 1000 1' ~/.local/share/lxc/ubuntu/rootfs/ /bin/ls /home/

TODO

  1. [x] clone & Container
  2. [x] CLI
  3. [x] Chroot
  4. [ ] process list
  5. [ ] inject
  6. [ ] move CLI to separate package
  7. [ ] addons
  8. [ ] support for lxc, vagga, rocket, docker, etc...
  9. [ ] ...
  10. [ ] one tool for rule them all!!1

Links

github pypi docs

Лицензия — MIT, но так же собираюсь добавить BSD и Apache 2.0

It's not the end

Работы предстоит очень много: нужны нормальные тесты, документация, новые фичи и приятное cli. Откладывание анонса в долгий ящик прервали ребята из Minsk Python Meetup, за что им большое спасибо. Теперь я надеюсь на поддержку и интерес у сообщества ;)

И в завершение хотелось бы привести цитату создателя scipy & numpy:
Keys to success: Hard work — specially up front
Often lonely — initially nobody believes in your idea more than you do. Others need some 'proof' before they join you.
The more complicated what you are doing is the lonelier it will be initially.

I spent 18 months not publishing papers to write NumPy
(despite many people telling me it was foolish)
Travis Oliphant

ЗЫ: в живую со мной можно пообщаться по теме и не только на очередном Minsk Python Meetup

Комментарии (7)


  1. amarao
    27.04.2015 03:07

    А я namespaces юзаю «as is», из баша. Для локальных нужд хватает за глаза и за уши. Тем паче, что чаще всего нужно всего лишь mount namespace и network namespace, а всякие изоляции pid'ов и пользователей — постольку-поскольку.


    1. MrFrizzy Автор
      27.04.2015 11:30

      А что именно дергаете, если не секрет?


      1. amarao
        27.04.2015 13:36
        +2

        Чаще всего нужно изолировать приложение по сети.

        ip net create foo
        ip link set netns foo dev eth3
        ip net exec foo ip link set up dev eth3
        ip net exec foo ip a a 192.168.2.2/24
        ip net exec foo ip route add default via 192.168.2.1

        Ну и вариации по вкусу.

        Mount/user/pid namespaces нужны много реже, потому что большинство приложений отлично вкурсе, что не их собачье дело, под каким пользователем их запустили и какие mountpoint'ы в системе.

        Так что следующее:

        ip net exec foo sudo -u APP_USER /usr/bin/app

        и приложение работает.

        Если надо залогиниться:

        ip net exec foo login -f APP_USER


        1. ValdikSS
          28.04.2015 00:24
          +2

          А если нужна изоляция не только сети, то:

          unshare — run program with some namespaces unshared from parent
          nsenter — run program with namespaces of other processes
          И просто мой любимый firejail


  1. estum
    27.04.2015 03:37
    -5

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


    1. Klukonin
      27.04.2015 08:08
      +5

      Производительность самого контейнера весьма слабо зависит от обертки. Будь она на питоне, на си или другом языке.


    1. amarao
      27.04.2015 13:39
      +3

      Если бы вы знали, как медленно современные ядра работают на большом числе интерфейсов/адресов в системе… Любой питон по сравнению со скоростью соответствующего кода на Си, работающего с правами ядра, будет просто летать.

      Не верите?

      for a in {{1..255}};do for b in {{1..255}}; do time ip a a 172.16.$b.$a/32 dev eth0;done;done

      и любуйтесь цифрами через пол-часика. Одинокое «повесить IP на интерфейс» до 30 с доходить будет.