Каждый, кто всерьёз погружался в анализ данных или машинное обучение, рано или поздно сталкивается с парадоксом совместимости библиотек. Одно приложение требует numpy строго определённой версии, другое не запустится без свежей сборки TensorFlow, третье вообще тянет за собой устаревший Python 3.7, потому что новые релизы языка ломают совместимость. Установка всего этого богатства в одну системную копию Python превращается в саморазрушающийся карточный домик, где каждое обновление одного пакета грозит уронить соседние проекты.

Anaconda была придумана именно для разрешения этой коллизии. Это менеджер пакетов, менеджер окружений и дистрибутив Python и R одновременно. В комплекте идёт больше полутора тысяч библиотек с открытым исходным кодом, охватывающих машинное обучение, обработку данных, научные вычисления, статистический анализ и прогнозное моделирование. Платформа доступна в бесплатной и платной редакциях. Ниже разобран процесс установки Anaconda на Ubuntu 20.04, создание изолированных окружений под разные версии Python, управление пакетами и удаление дистрибутива со всеми следами.

Подготовка свежего сервера Ubuntu и базовые требования перед началом работы с Anaconda

Для установки понадобится сервер с Ubuntu 20.04 LTS. Минимальные требования к ресурсам у Anaconda не самые скромные - дистрибутив весит около 3 гигабайт в распакованном виде, плюс окружения с библиотеками занимают сотни мегабайт каждое. Поэтому стоит планировать как минимум 10 гигабайт свободного места на диске и хотя бы 4 гигабайта оперативной памяти для комфортной работы. На совсем слабых машинах Anaconda тоже встанет, но обучение моделей или загрузка крупных датасетов будут упираться в нехватку ресурсов.

Работаем от имени обычного пользователя с правами sudo. Прямой вход под root для установки Anaconda не рекомендуется - дистрибутив прописывает свои настройки в домашний каталог пользователя, и от имени root он будет видеть только своё окружение, что нарушает логику работы.

Перед началом стоит освежить систему, чтобы избежать конфликтов со старыми пакетами.

$ sudo apt update
$ sudo apt upgrade

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

Скачивание установочного скрипта Anaconda с официального сайта и проверка целостности через SHA-256

В стандартных репозиториях Ubuntu пакета Anaconda нет, и не будет - дистрибутив поставляется напрямую через bash-скрипт с сайта разработчика. Это устоявшаяся практика для большинства научных платформ, поскольку версии обновляются быстрее, чем успевают добраться до системных репозиториев.

Скачиваем установщик через curl.

$ curl https://repo.anaconda.com/archive/Anaconda3-2021.05-Linux-x86_64.sh --output anaconda.sh

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

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

$ sha256sum anaconda.sh
2751ab3d678ff0277ae80f9e8a74f218cfc70fe9a9cdc7bb1c137d7e47e33d53  anaconda.sh

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

Запуск установочного скрипта Anaconda и прохождение интерактивного диалога настройки

Установщик представляет собой bash-скрипт, который разворачивает упакованный в него архив с дистрибутивом в выбранный каталог. Запускаем его.

$ bash anaconda.sh

Установщик начинает диалог с приветствия и предложения ознакомиться с лицензионным соглашением.

Welcome to Anaconda3 2021.05

In order to continue the installation process, please review the license
agreement.
Please, press ENTER to continue
>>>

Нажимаем Enter и листаем текст лицензии страницами клавишей Space или Enter построчно. После прочтения вводим yes для принятия условий.

Do you accept the license terms? [yes|no]
>>>

Следующий вопрос касается места установки. По умолчанию Anaconda устанавливается в подкаталог anaconda3 домашней папки пользователя, что разумно для подавляющего большинства сценариев. Можно указать другой путь, например на отдельный раздел с большим запасом места.

Anaconda3 will now be installed into this location:
/home/navjot/anaconda3

  - Press ENTER to confirm the location
  - Press CTRL-C to abort the installation
  - Or specify a different location below

[/home/navjot/anaconda3] >>>

Подтверждаем расположение через Enter и наблюдаем за процессом распаковки. Установщик копирует тысячи файлов, что на медленном диске может занять до 10 минут. Прогресс отображается строками вида installing: имя_пакета.

По завершении основной части установки идёт финальный вопрос про инициализацию.

Preparing transaction: done
Executing transaction: done
installation finished.
Do you wish the installer to initialize Anaconda3
by running conda init? [yes|no]

Отвечаем yes. Команда conda init пропишет в файл ~/.bashrc небольшой блок кода, который автоматически активирует среду Anaconda при каждом входе в систему. Без этого пришлось бы каждый раз вручную добавлять путь к conda в переменную PATH.

После успешного завершения установщик выводит финальное сообщение.

==> For changes to take effect, close and re-open your current shell. <==

If you'd prefer that conda's base environment not be activated on startup,
   set the auto_activate_base parameter to false:

conda config --set auto_activate_base false

Thank you for installing Anaconda3!

Подсказка про auto_activate_base полезная. Если не хочется, чтобы при каждом входе в shell активировалось окружение base (это иногда мешает работе других инструментов, ожидающих системный Python), можно отключить автоактивацию указанной командой. Активировать base всегда получится вручную.

Активация изменений в текущей сессии и проверка работоспособности установленной Anaconda

Чтобы не разлогиниваться и не входить снова, можно перезагрузить файл инициализации bash в текущей сессии.

$ source ~/.bashrc

Команда source выполняет содержимое указанного файла в контексте текущей оболочки. После этого приглашение терминала меняется и начинает показывать активное окружение в скобках перед именем хоста.

(base) navjot@howtoforge:~$

Префикс (base) подсказывает, что сейчас активна базовая среда программирования Anaconda. Это окружение по умолчанию, в нём уже стоят все базовые пакеты дистрибутива. Однако работать прямо в base считается дурным тоном - под каждый проект стоит создавать отдельное изолированное окружение, чтобы избежать конфликтов зависимостей и иметь возможность безболезненно экспериментировать.

Проверка корректности установки делается командой conda info, которая выводит исчерпывающую информацию о текущей конфигурации.

(base) navjot@howtoforge:~$ conda info

Вывод подробно описывает текущее состояние.

     active environment : base
    active env location : /home/navjot/anaconda3
            shell level : 1
       user config file : /home/navjot/.condarc
 populated config files :
          conda version : 4.10.1
    conda-build version : 3.21.4
         python version : 3.8.8.final.0
       virtual packages : __linux=5.4.72=0
                          __glibc=2.31=0
                          __unix=0=0
                          __archspec=1=x86_64
       base environment : /home/navjot/anaconda3  (writable)
      conda av data dir : /home/navjot/anaconda3/etc/conda
  conda av metadata url : https://repo.anaconda.com/pkgs/main
           channel URLs : https://repo.anaconda.com/pkgs/main/linux-64
                          https://repo.anaconda.com/pkgs/main/noarch
                          https://repo.anaconda.com/pkgs/r/linux-64
                          https://repo.anaconda.com/pkgs/r/noarch
          package cache : /home/navjot/anaconda3/pkgs
                          /home/navjot/.conda/pkgs
       envs directories : /home/navjot/anaconda3/envs
                          /home/navjot/.conda/envs
               platform : linux-64
             user-agent : conda/4.10.1 requests/2.25.1 CPython/3.8.8 Linux/5.4.72-microsoft-standard-WSL2 ubuntu/20.04.2 glibc/2.31
                UID:GID : 1000:1000
             netrc file : None
           offline mode : False

Здесь видно версию самой conda, версию Python в базовом окружении, расположение каналов для загрузки пакетов, кеш загруженных пакетов и многое другое. Особенно полезны строки channel URLs - они показывают, откуда conda будет тянуть пакеты по умолчанию. По адресу main лежат стабильные релизы основных библиотек, по адресу r отдельный канал для пакетов языка R.

Создание изолированных окружений Anaconda под разные версии Python для разделения проектов

Главная сила Anaconda - возможность держать рядом несколько Python-окружений с разными версиями языка и разными наборами библиотек. Перед созданием окружения логично посмотреть, какие версии Python вообще доступны.

(base) navjot@howtoforge:~$ conda search "^python$"

Команда выводит длинный список всех Python 2 и Python 3 версий, доступных через каналы Anaconda. Регулярное выражение в кавычках использует якоря - символ ^ означает начало строки, $ означает конец строки. Без них поиск бы вытащил все пакеты, в названии которых встречается слово python, включая python-dateutil, python-graphviz и десятки других. Якоря ограничивают совпадение строго именем python.

Создаём окружение с последней доступной версией Python 3.

(base) navjot@howtoforge:~$ conda create --name py3env python=3

Параметр --name (короткая форма -n) задаёт имя нового окружения. Указание python=3 означает установить любую свежую сборку из третьей ветки. Можно прописать точнее, например python=3.10.4, тогда conda поставит ровно эту сборку.

Установщик покажет список пакетов, которые будут установлены, и спросит подтверждение. Вводим y, и через минуту-другую новое окружение готово.

Активируем созданное окружение.

(base) navjot@howtoforge:~$ conda activate py3env

Приглашение терминала меняется - префикс (base) уступает место (py3env), сигнализируя о смене активного контекста.

(py3env) navjot@howtoforge:~$  

Проверяем, какая версия Python теперь активна.

(py3env) navjot@howtoforge:~$ python --version
Python 3.10.0

В точности та версия, которая стояла на момент создания окружения. Деактивация возвращает в предыдущее окружение.

(py3env) navjot@howtoforge:~$ conda deactivate

Создадим ещё одно окружение, но уже с фиксированной более старой версией Python - удобно для проектов, которые ещё не мигрировали на свежие релизы.

(base) navjot@howtoforge:~$ conda create -n py37env python=3.7

Здесь использована короткая форма параметра -n вместо --name - в командной строке Linux это вопрос вкуса, обе формы работают одинаково.

Полный список созданных окружений выводится отдельной командой.

(base) navjot@howtoforge:~$ conda info --envs
# conda environments:
#
base                  *  /home/navjot/anaconda3
py37env                  /home/navjot/anaconda3/envs/py37env
py3env                   /home/navjot/anaconda3/envs/py3env 

Звёздочка рядом с base помечает текущее активное окружение. Каждое окружение лежит в отдельном подкаталоге внутри envs - это полностью независимая копия Python со своим набором установленных пакетов. Размер каталога окружения обычно 200-500 мегабайт даже при минимальном наборе библиотек.

Удаление ненужного окружения делается следующим образом.

(base) navjot@howtoforge:~$ conda --name py37env --all

Возврат к базовому окружению предпочтительно делать через conda activate без указания имени, а не через conda deactivate. Дело в том, что выход из base через deactivate может временно сломать команду conda, поскольку сама утилита тоже использует Python из base. Лёгкое неудобство, но запомнить стоит.

Управление пакетами внутри окружения Anaconda и работа с библиотеками для научных вычислений

Переключимся в созданное ранее окружение py3env для экспериментов с пакетами.

(base) navjot@howtoforge:~$ conda activate py3env

При создании любого окружения conda сразу ставит минимальный набор системных библиотек. Посмотреть полный список можно командой list.

(py3env) navjot@howtoforge:~$ conda list

Вывод покажет все установленные пакеты с их версиями и каналом, из которого они пришли.

# packages in environment at /home/navjot/anaconda3/envs/py3env:
#
# Name                    Version                   Build  Channel
_libgcc_mutex             0.1                        main
_openmp_mutex             4.5                       1_gnu
bzip2                     1.0.8                h7b6447c_0
ca-certificates           2021.9.30            h06a4308_1
certifi                   2020.6.20          pyhd3eb1b0_3
ld_impl_linux-64          2.35.1               h7274673_9
libffi                    3.3                  he6710b0_2
libgcc-ng                 9.3.0               h5101ec6_17
libgomp                   9.3.0               h5101ec6_17
libstdcxx-ng              9.3.0               hd4cf53a_17
libuuid                   1.0.3                h7f8727e_2
ncurses                   6.2                  he6710b0_1
openssl                   1.1.1l               h7f8727e_0
pip                       21.2.4          py310h06a4308_0
python                    3.10.0               h12debd9_1
readline                  8.1                  h27cfd23_0
setuptools                58.0.4          py310h06a4308_0
sqlite                    3.36.0               hc218d9a_0
tk                        8.6.11               h1ccaba5_0
tzdata                    2021a                h5d7bf9c_0
wheel                     0.37.0             pyhd3eb1b0_1
xz                        5.2.5                h7b6447c_0
zlib                      1.2.11               h7b6447c_3

Здесь видно интересную особенность conda - в окружение ставятся не только Python-пакеты, но и системные библиотеки уровня openssl, libgcc или sqlite. Это сделано для полной изоляции окружения от системных версий, которые могут отличаться между разными дистрибутивами Linux. Благодаря такому подходу Anaconda-окружения остаются работоспособными даже при обновлении операционной системы.

Установка дополнительного пакета в текущее окружение делается командой install. Поставим numpy - фундаментальную библиотеку для работы с массивами и линейной алгеброй в Python.

(py3env) navjot@howtoforge:~$ conda install numpy

Conda проанализирует зависимости, покажет, что будет установлено или обновлено, и спросит подтверждение. У numpy довольно много зависимостей включая компилятор Fortran и оптимизированные библиотеки BLAS, так что списка не нужно пугаться - всё это нужное.

Можно ставить пакеты в неактивное окружение, не переключаясь в него. Параметр --name указывает целевую среду.

(py3env) navjot@howtoforge:~$ conda install --name py37env numpy

При создании окружения можно сразу указать набор нужных пакетов вместе с версией Python.

(py3env) navjot@howtoforge:~$ conda create --name py3env1 python=3 numpy

Это удобно для одношагового развёртывания среды под конкретный проект, когда заранее известны требования. Несколько пакетов разом ставятся перечислением через пробел.

(py3env) navjot@howtoforge:~$ conda install scipy curl

Anaconda работает не только с Python, но и с языком R, популярным в статистике. Создание окружения для R-проектов выполняется указанием соответствующих метапакетов.

(base) navjot@howtoforge:~$ conda create --name renv r-essentials r-base

Метапакет r-essentials тянет за собой около 80 самых популярных R-библиотек включая ggplot2, dplyr и shiny. Установка займёт больше времени, чем у обычного Python-окружения, поскольку загружается значительный объём.

Активация R-окружения идёт по тем же правилам.

(base) navjot@howtoforge:~$ conda activate renv

Проверка установленных пакетов в нём.

(renv) navjot@howtoforge:~$ conda list

Обновление компонентов Anaconda и поддержание дистрибутива в актуальном состоянии

Anaconda развивается быстро, и периодическое обновление - часть нормального обслуживания установки. Первым делом обновляется сама утилита conda, поскольку новые версии могут уметь то, что не умели старые.

(base) navjot@howtoforge:~$ conda update conda

Подтверждаем обновление вводом y. После обновления самой утилиты можно обновить весь дистрибутив одной командой.

(base) navjot@howtoforge:~$ conda update anaconda

Команда подтянет все обновлённые пакеты, входящие в основную поставку Anaconda. Процесс может занять заметное время, особенно если давно не обновлялись - изменений накапливается много, и часть пакетов потребует пересборки зависимостей.

Обновление отдельных пакетов выполняется указанием их имени. Обновим numpy.

(base) navjot@howtoforge:~$ conda update numpy

Команда применяется к текущему активному окружению. Если нужно обновить пакет в конкретном окружении без переключения в него, добавляется параметр --name.

(base) navjot@howtoforge:~$ conda update --name py37env numpy

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

Полное удаление Anaconda с сервера через утилиту anaconda-clean и подчистка следов в конфигурации bash

Когда Anaconda больше не нужна или возникла потребность переустановить дистрибутив с нуля, потребуется аккуратное удаление со всеми хвостами. Простое удаление каталога ~/anaconda3 оставит в системе кучу разбросанных конфигурационных файлов и поломанный ~/.bashrc. Правильный путь начинается с установки специального модуля для чистого удаления.

(base) navjot@howtoforge:~$ conda install anaconda-clean

Подтверждаем установку вводом y. Модуль anaconda-clean знает, где какие конфиги лежат, и умеет их корректно удалять.

Запуск чистки.

(base) navjot@howtoforge:~$ anaconda-clean

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

(base) navjot@howtoforge:~$ anaconda-clean --yes

При первом запуске потребуется ещё одно подтверждение yes для начала процесса. Утилита автоматически создаёт резервную копию удаляемых файлов в каталоге ~/.anaconda_backup - на случай, если потребуется что-то восстановить. Если удаление действительно окончательное, эту папку тоже можно потом удалить.

Теперь удаляем основной каталог дистрибутива.

$ rm -rf ~/anaconda3

Команда rm с флагами -rf удаляет каталог со всем содержимым без вопросов. Будьте осторожны с этой командой - опечатка в пути может стереть совсем не то, что планировалось.

Последний штрих - очистка блока инициализации в ~/.bashrc, который добавила сама Anaconda при установке.

$ nano ~/.bashrc

Прокручиваем файл до конца и находим характерный блок.

# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/home/navjot/anaconda3/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/home/navjot/anaconda3/etc/profile.d/conda.sh" ]; then
        . "/home/navjot/anaconda3/etc/profile.d/conda.sh"
    else
        export PATH="/home/navjot/anaconda3/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda initialize <<<

Удаляем весь блок целиком и сохраняем файл через Ctrl + X и подтверждение Y. После этого при следующем входе в shell приглашение терминала вернётся к обычному виду без префикса (base), а попытка вызвать conda выдаст сообщение о ненайденной команде.

Чтобы закончить удаление в текущей сессии без выхода из системы, можно либо разлогиниться и зайти снова, либо вручную перезагрузить файл инициализации командой source ~/.bashrc.

Практические соображения по работе с окружениями и типичные сценарии использования conda в реальных проектах

Освоение conda на бумаге это одно, а уверенная работа в повседневной практике - другое. Несколько советов из опыта помогут избежать типичных граблей.

  1. Создавайте отдельное окружение под каждый сколь-нибудь серьёзный проект. Даже если кажется, что два проекта могут жить в одном окружении, через полгода один из них захочет обновить версию какой-нибудь библиотеки, и сразу полезут конфликты.
  2. Экспортируйте список зависимостей окружения в YAML-файл командой conda env export > environment.yml и храните этот файл вместе с кодом проекта в системе контроля версий. Восстановить точную копию окружения на другой машине можно командой conda env create -f environment.yml.
  3. Для пакетов, которых нет в каналах Anaconda, используйте pip внутри активированного окружения. Современная conda нормально уживается с pip-пакетами в одном окружении, хотя раньше это было источником проблем.
  4. Удаляйте старые окружения регулярно. Каждое из них занимает сотни мегабайт, и забытые окружения от давно заброшенных экспериментов разрастаются неконтролируемо.
  5. Канал conda-forge содержит огромное количество пакетов, которых нет в основном канале Anaconda. Его подключение через conda config --add channels conda-forge расширяет арсенал доступных библиотек в разы.

Освоение инструмента такого уровня меняет сам подход к Python-разработке. Вместо рискованных экспериментов с системным Python появляется привычка работать в изолированных пространствах, где любой эксперимент можно безболезненно откатить простым удалением окружения. Для специалистов по данным и машинному обучению это превращается в обязательный элемент рабочего инструментария наравне с git и редактором кода. Anaconda заметно снижает порог входа в эти области, поскольку избавляет от мучительной возни с настройкой научных библиотек, где компиляция numpy из исходников могла занять у новичка целый день. С Anaconda весь стек ставится за несколько минут и работает предсказуемо на любой машине, что превращает фокус с инфраструктурного ковыряния на собственно работу с данными.