В статье я расскажу, как можно устанавливать пакеты для python с помощью pip, если на этом сервере нет интернета. Поможет нам в этом DevPI.
Теория
Когда вам нужно установить дополнительный модуль для python, то вы обычно выполняете команду pip install <имя модуля>
.
pip — это установщик пакетов для python. Он их скачивает из определённого репозитория и устанавливает.
Репозитории для python называют индексами и по умолчанию pip использует индекс PyPI (Python Package Index). Но для pip можно указать и другой индекс.
В этой статье мы познакомимся с инструментом DevPI (github), который позволяет создать свой индекс (root/pypi), который синхронизован с индексом PyPI. Документация по этому инструменту доступна здесь.
Постановка задачи
В этой статье будем реализовывать следующую схему:
На рисунке выше, сервера Server2 и Server3 не имеют выхода в интернет, зато у них есть доступ к серверу Server1.
Server1 имеет доступ в интернет, поэтому на нём можно установить программу DevPI. С его помощью можно создать свой индекс (root/pypi) и синхронизировать его с индексом PyPI.
Server2 и Server3 смогут устанавливать пакеты с помощью pip из индекса, который мы создадим на Server1.
Практика
У меня все сервера на Debian 10.
В самом начале у меня есть интернет на всех серверах. Это необходимо, чтобы установить pip. Для python3 это пакет python3-pip. Его нужно поставить и на всех трёх серверах.
# apt install python3-pip
Теперь можете отключить интернет на серверах Server2 и Server3. Я просто удаляю на них шлюз по умолчанию.
Следующие действия будем выполнять на Server1 (на нём интернет остался).
Сервер devpi требует установки libffi-dev, установим его. Затем используя pip установим devpi-server и devpi-web.
# apt install libffi-dev # pip3 install -U devpi-server # pip3 install -U devpi-web
Дальше вам нужно добавить в переменную PATH путь /usr/local/bin. Туда были установлены следующие утилиты:
# ls -l /usr/local/bin | grep devpi -rwxr-xr-x 1 root root 237 Apr 19 13:15 devpi-clear-search-index -rwxr-xr-x 1 root root 231 Apr 19 13:12 devpi-export -rwxr-xr-x 1 root root 219 Apr 19 13:12 devpi-fsck -rwxr-xr-x 1 root root 234 Apr 19 13:12 devpi-gen-config -rwxr-xr-x 1 root root 231 Apr 19 13:12 devpi-gen-secret -rwxr-xr-x 1 root root 233 Apr 19 13:12 devpi-import -rwxr-xr-x 1 root root 219 Apr 19 13:12 devpi-init -rwxr-xr-x 1 root root 225 Apr 19 13:12 devpi-passwd -rwxr-xr-x 1 root root 219 Apr 19 13:12 devpi-server
Чтобы добавить путь в переменную PATH нужно в файле .bashrc (расположен в домашней директории пользователя) дописать две строчки:
# nano .bashrc ***** оставляем без изменения а снизу дописываем ***** PATH="/usr/local/bin/:$PATH" export PATH
А затем, чтобы применить изменения, выполните:
# . .bashrc
Теперь вы можете посмотреть версию вашего сервера:
# devpi-server --version 6.5.0
Управлять сервером devpi можно с помощью ещё одного модуля на python, который называется supervisor. Установим его:
# pip3 install supervisor
Теперь вы можете инициализировать devpi, сгенерировать конфиг и запустить сервер!
Инициализируем:
# devpi-init INFO NOCTX Loading node info from /root/.devpi/server/.nodeinfo INFO NOCTX generated uuid: 8d832c2dab2248c3ae18a6a088a9befd INFO NOCTX wrote nodeinfo to: /root/.devpi/server/.nodeinfo INFO NOCTX DB: Creating schema INFO [Wtx-1] setting password for user 'root' INFO [Wtx-1] created user 'root' INFO [Wtx-1] created root user INFO [Wtx-1] created root/pypi index INFO [Wtx-1] fswriter0: commited at 0 # cat /root/.devpi/server/.nodeinfo { "role": "standalone", "uuid": "8d832c2dab2248c3ae18a6a088a9befd" }
Выше вы видите, что был сгенерирован uuid для нашего индекса, информация об узле была добавлена в файл /root/.devpi/server/.nodeinfo. А также был создан пользователь индекса (root), его пароль (по умолчанию он пустой). И был создан индекс root/pypi.
Теперь сгенерируем конфиги:
# devpi-gen-config --port 4040 --host 0.0.0.0 It is highly recommended to use a configuration file for devpi-server, see --configfile option. wrote gen-config/crontab wrote gen-config/net.devpi.plist wrote gen-config/launchd-macos.txt wrote gen-config/nginx-devpi.conf wrote gen-config/supervisor-devpi.conf wrote gen-config/supervisord.conf wrote gen-config/devpi.service wrote gen-config/windows-service.txt # cat gen-config/supervisord.conf [supervisord] [unix_http_server] file=/tmp/devpi-supervisor.sock [supervisorctl] serverurl=unix:///tmp/devpi-supervisor.sock [rpcinterface:supervisor] supervisor.rpcinterface_factory=supervisor.rpcinterface:make_main_rpcinterface [include] files = %(here)s/supervisor-devpi.conf # cat gen-config/supervisor-devpi.conf [program:devpi-server] command=/usr/local/bin/devpi-server --port 4040 --host 0.0.0.0 user = root priority = 999 startsecs = 5 redirect_stderr = True autostart = True
Выше вы видите что создалась директория gen-config с конфигами для devpi сервера. Основной конфиг — это supervisord.conf, и дополнительный supervisor-devpi.conf. В последнем конфиге можно увидеть строку запуска сервера — /usr/local/bin/devpi-server —port 4040 —host 0.0.0.0.
Запустим сервер с помощью supervisord используя основной конфиг:
# supervisord -c gen-config/supervisord.conf
Теперь из server2 проверим что server1 отвечает на веб запросы с помощью curl:
# curl http://192.168.0.62:4040 <!doctype html> <html> <head> <title>devpi</title> <link rel="stylesheet" type="text/css" href="http://192.168.0.62:4040/+static-4.0.8/style.css" /> <script src="http://192.168.0.62:4040/+static-4.0.8/jquery-1.11.1.min.js"></script> <script src="http://192.168.0.62:4040/+static-4.0.8/moment-2.8.2.min.js"></script> <script src="http://192.168.0.62:4040/+static-4.0.8/common.js"></script> </head> <body> ********* </body> </html>
Также эту страничку можно открыть в браузере:
Сервер у нас пока в состоянии degraded, это потому что он ещё не успел синхронизоваться с Pypi:
После синхронизации статус станет «OK»:
Убедимся что на Server2 нет интернета и пробуем что-нибудь установить с помощью pip используя Server1:
# ping 8.8.8.8 connect: Network is unreachable # pip3 install -i http://192.168.0.62:4040/root/pypi/+simple/ simplejson --trusted-host 192.168.0.62 Looking in indexes: http://192.168.0.62:4040/root/pypi/+simple/ Collecting simplejson Downloading http://192.168.0.62:4040/root/pypi/+f/65b/998193bd7b0c7/simplejson-3.17.6-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (130kB) 100% |████████████████████████████████| 133kB 1.0MB/s Installing collected packages: simplejson Successfully installed simplejson-3.17.6
Всё работает!
Управление с помощью supervisord и supervisorctl
Теперь запускать и останавливать ваш devpi сервер, а также посмотреть его статус можно с помощью supervisorctl:
# supervisorctl -c gen-config/supervisord.conf stop devpi-server # supervisorctl -c gen-config/supervisord.conf start devpi-server # supervisorctl -c gen-config/supervisord.conf status devpi-server
Но после перезагрузки сервера вам нужно будет выполнить:
# supervisord -c gen-config/supervisord.conf
А затем управлять службой с помощью supervisorctl.
Управление с помощью systemd
Если ваша система использует systemd, то есть более удобный способ управлять сервером devpi. Для этого нужно скопировать файл службы gen-config/devpi.service в каталог /etc/systemd/system/, и выполнить команду systemctl daemon-reload:
# cp gen-config/devpi.service /etc/systemd/system/ # systemctl daemon-reload
А дальше вы можете запустить службу, добавить её в автозагрузку и управлять с помощью systemctl:
# systemctl start devpi # systemctl enable devpi # systemctl status devpi # systemctl stop devpi
Облегчаем процесс установки пакетов
Как вы помните, нам приходится устанавливать пакеты с помощью такой команды:
# pip3 install -i http://192.168.0.62:4040/root/pypi/+simple/ simplejson --trusted-host 192.168.0.62
То есть нужно указывать адрес индекса и написать --trusted-host
так как наш сервер не использует https.
Чтобы pip по умолчанию использовал нужный индекс, нужно создать в домашней директории каталог и конфиг для pip:
# mkdir .pip # nano .pip/pip.conf [global] index-url = http://192.168.0.62:4040/root/pypi/+simple/ [search] index = http://192.168.0.62:4040/root/pypi/
Теперь вы можете не указывать индекс:
# pip3 install getmac --trusted-host 192.168.0.62
Чтобы избавится от —trusted-host нужно на сервер поставить какой-нибудь веб-сервер (apache2 или nginx). Настроить на нём https и использовать в качестве прокси. Кстати, конфиг для nginx уже лежит в каталоге gen-config:
# cat gen-config/nginx-devpi.conf server { server_name localhost $hostname ""; listen 80; gzip on; gzip_min_length 2000; gzip_proxied any; gzip_types application/json; proxy_read_timeout 60s; client_max_body_size 64M; # set to where your devpi-server state is on the filesystem root /root/.devpi/server; # try serving static files directly location ~ /+f/ { # workaround to pass non-GET/HEAD requests through to the named location below error_page 418 = @proxy_to_app; if ($request_method !~ (GET)|(HEAD)) { return 418; } expires max; try_files /+files$uri @proxy_to_app; } # try serving docs directly location ~ /+doc/ { # if the --documentation-path option of devpi-web is used, # then the root must be set accordingly here root /root/.devpi/server; try_files $uri @proxy_to_app; } location / { # workaround to pass all requests to / through to the named location below error_page 418 = @proxy_to_app; return 418; } location @proxy_to_app { proxy_pass http://localhost:4040; proxy_set_header X-outside-url $scheme://$http_host; proxy_set_header X-Real-IP $remote_addr; } }
На этом всё, спасибо за внимание!