LoginSignup
11
13

More than 5 years have passed since last update.

マルチユーザ環境のための pyenv

Last updated at Posted at 2019-02-05

はじめに

概要

Python 本体およびライブラリをシステム管理者が一括で管理し、利用するバージョンのみをユーザ各自が管理できる環境を pyenv で構築する方法を紹介します。

背景

Python 2 系はいまだシステム標準として利用されていますが、2020年にサポートが切れることから、Python 3 系の利用環境を整えておくのが望ましいと考えられます。そこで、システム側に Python 3 系をインストールし、python コマンドを python3.x へのシンボリックリンクに変更したところ、常駐している tuned や yum コマンドに影響を及ぼします (tuned は syntax error で起動しませんし、また yum install ができなくなります)。

そのため pyenv や virtualenv の利用が推奨されております。それらはシステムに影響を及ぼさないように 3 系をインストールできますが、その設計思想が故に、それをセットアップしたユーザでしか利用できません。すなわち、マルチユーザ環境では、ユーザが増えるたびに pyenv のインストールからしなくてはならず面倒です (pyenv がセットアップされたホームディレクトリのテンプレートを作っておいて、それをコピーすればいいのかもしれませんが)。

ここで紹介する環境は、これらの問題を回避する一つの手段となります。

制限事項

通常の pyenv の環境とは異なり、管理者権限がなければ、様々なバージョンの Python を各自で自由にインストールできなくなる点がデメリットになります。

構築

対象プラットフォーム

  • CentOS 7

手順

必要なパッケージのインストール

pyenv は Python のソースパッケージを入手してビルドしますので、下記の開発用パッケージが必要となります。

sudo yum -y install gcc gcc-c++ make git openssl-devel bzip2-devel zlib-devel readline-devel sqlite-devel

pyenv のインストール

mkdir ~/tmp
cd ~/tmp
git clone https://github.com/yyuu/pyenv.git
sudo cp -rupv pyenv /usr/local
chown -R root:root /usr/local/pyenv

pyenv の修正

ユーザが利用する Python のバージョンは ${PYENV_ROOT}/version を参照することで管理されています。デフォルトのまま利用すると、この PYENV_ROOT をシステム共通の場所に設定することになるので、利用者各自でバージョン変更できるようにしようと思うと都合が悪くなります。そこで環境変数 PYENV_VERSION_FILE が設定されていたら、そちらを参照するように pyenv を変更します。

--- ./libexec/pyenv-global      2017-05-10 13:29:55.444777132 +0900
+++ /usr/local/pyenv/libexec/pyenv-global     2017-05-10 16:35:48.281371082 +0900
@@ -22,7 +22,14 @@
 fi

 versions=("$@")
-PYENV_VERSION_FILE="${PYENV_ROOT}/version"
+if [ -z "${PYENV_VERSION_FILE}" ]; then
+  PYENV_VERSION_FILE="${PYENV_ROOT}/version"
+else
+  PYENV_VERSION_FILE_DIR=${PYENV_VERSION_FILE%/*}
+  if [ ! -d ${PYENV_VERSION_FILE_DIR} ]; then
+    mkdir -p ${PYENV_VERSION_FILE_DIR}
+  fi
+fi

 if [ -n "$versions" ]; then
   pyenv-version-file-write "$PYENV_VERSION_FILE" "${versions[@]}"
--- ./libexec/pyenv-version-file        2017-05-10 13:29:55.444777132 +0900
+++ /usr/local/pyenv/libexec/pyenv-version-file       2017-05-10 16:31:36.042696438 +0900
@@ -19,10 +19,16 @@
   return 1
 }

+if [ -z "${PYENV_VERSION_FILE}" ]; then
+  PYENV_VERSION_FILE_DIR=${PYENV_ROOT}
+else
+  PYENV_VERSION_FILE_DIR=${PYENV_VERSION_FILE%/*}
+fi
+
 if [ -n "$target_dir" ]; then
   find_local_version_file "$target_dir"
 else
   find_local_version_file "$PYENV_DIR" || {
     [ "$PYENV_DIR" != "$PWD" ] && find_local_version_file "$PWD"
-  } || echo "${PYENV_ROOT}/version"
+  } || echo "${PYENV_VERSION_FILE_DIR}/version"
 fi
--- ./libexec/pyenv-rehash       2018-10-04 16:06:44.456347899 +0900
+++ /usr/local/pyenv/libexec/pyenv-rehash        2019-03-25 10:13:36.493066034 +0900
@@ -4,7 +4,7 @@
 set -e
 [ -n "$PYENV_DEBUG" ] && set -x

-SHIM_PATH="${PYENV_ROOT}/shims"
+SHIM_PATH="${HOME}/.pyenv/shims"
 PROTOTYPE_SHIM_PATH="${SHIM_PATH}/.pyenv-shim"

 # Create the shims directory if it doesn't already exist.
--- libexec/pyenv-init  2018-10-04 16:06:44.456347899 +0900
+++ /usr/local/pyenv/libexec/pyenv-init 2019-03-25 11:08:13.948005781 +0900
@@ -82,15 +82,16 @@
   exit 1
 fi

-mkdir -p "${PYENV_ROOT}/"{shims,versions}
+mkdir -p "${PYENV_ROOT}/versions"
+mkdir -p "${HOME}/.pyenv/shims"

 case "$shell" in
 fish )
-  echo "set -gx PATH '${PYENV_ROOT}/shims' \$PATH"
+  echo "set -gx PATH '${HOME}/.pyenv/shims' \$PATH"
   echo "set -gx PYENV_SHELL $shell"
 ;;
 * )
-  echo 'export PATH="'${PYENV_ROOT}'/shims:${PATH}"'
+  echo 'export PATH="${HOME}/.pyenv/shims:${PATH}"'
   echo "export PYENV_SHELL=$shell"
 ;;
 esac
--- libexec/pyenv-which 2019-03-15 16:34:52.087265948 +0900
+++ /usr/local/pyenv/libexec/pyenv-which        2019-03-26 10:57:13.635188148 +0900
@@ -19,10 +19,12 @@
   local path_to_remove="$1"
   local path_before
   local result=":${PATH//\~/$HOME}:"
+  shopt -s extglob
   while [ "$path_before" != "$result" ]; do
     path_before="$result"
-    result="${result//:$path_to_remove:/:}"
+    result="${result//:*([^:])$path_to_remove:/:}"
   done
+  shopt -u extglob
   result="${result%:}"
   echo "${result#:}"
 }
@@ -40,7 +42,7 @@

 for version in "${versions[@]}"; do
   if [ "$version" = "system" ]; then
-    PATH="$(remove_from_path "${PYENV_ROOT}/shims")"
+    PATH="$(remove_from_path "/.pyenv/shims")"
     PYENV_COMMAND_PATH="$(command -v "$PYENV_COMMAND" || true)"
   else
     PYENV_COMMAND_PATH="${PYENV_ROOT}/versions/${version}/bin/${PYENV_COMMAND}"

全ユーザ共通の設定

sudo vi /etc/profile.d/pyenv.sh
/etc/profile.d/pyenv.sh
export PYENV_ROOT="/usr/local/pyenv"
if [ -d "${PYENV_ROOT}" ]; then
    export PATH=${PYENV_ROOT}/bin:$PATH
    eval "$(pyenv init -)"
    export PYENV_VERSION_FILE=${HOME}/.pyenv/version
fi

ディレクトリ作成

最初に root でログインすれば自動的に作成されますが、ここでは手動で作成しておきます。

sudo mkdir /usr/local/pyenv/shims
sudo mkdir /usr/local/pyenv/versions

Python のインストール

ここでは Python 3.6.8 のみをインストールします。必要に応じて様々なバージョンをインストールすることになります。

sudo -E pyenv install 3.6.8

pip のアップデート

pyenv global 3.6.8
sudo -E pip install --upgrade pip

自分が利用する Python のバージョンを 3.6.8 に設定して、sudo -E で自分の環境変数を継承させれば、 root が利用する Python のバージョンを変更しなくても大丈夫です。

その他

pip の設定

pip のバージョンを 9.x 以降にアップデートするとリスト表示時に警告メッセージが出るので以下の設定をしておきます。

sudo vi /etc/pip.conf
/etc/pip.conf
[list]
format = columns

Python 3.7.x インストール時の追加対応

@hitochan777 さんの pyenvで3.7系のインストールに失敗したときのメモ を参考に以下のパッケージも事前にインストールしておきます。

yum install libffi-devel

ruby からの警告対応

もともと /usr/local/pyenv/shims ディレクトリは world writable にしていましたが、ruby の一部の gem から以下のような警告が出るようになりました。

/opt/td-agent/embedded/lib/ruby/gems/2.1.0/gems/ruby-progressbar-1.8.3/lib/ruby-progressbar/calculators/length.rb:76: warning: Insecure world writable dir /usr/local/pyenv/shims in PATH, mode 042777

そこで pyenv-init, pyenv-which, pyenv-rehash を修正して shims ディレクトリのみ個人で持たせるように修正し、/usr/local/pyenv/shims を使用しないようにしました。この修正に伴い、例えば管理者が awscli をインストールした場合、各自が

pyenv rehash

を実行しないと反映されないという副作用が生じます。もちろん再ログインすれば pyenv init から pyenv rehash が実行されるので問題はありません。

11
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
13