【问题标题】:How to use scl enable to run python3 app in dockerfile如何使用 scl enable 在 dockerfile 中运行 python3 应用程序
【发布时间】:2019-06-03 21:36:09
【问题描述】:

我试图在使用 CentOS 7 作为基础映像的 docker 容器中运行 python3 应用程序。所以如果我只是以交互方式玩它,我输入scl enable rh-python36 bash

这显然将我的标准 python2 环境切换到我之前安装的 python3.6 环境(在 Dockerfile 中)现在,在 dockerfile 中我运行以下命令:

SHELL ["scl", "enable", "rh-python36"](以及这个的许多变体)

这使我能够在这个 python3 环境中完成我所有的 pip 安装。但是,当我真的想用 CMD 运行我的 app.py 时,它默认为 python2。我尝试过使用 ENTRYPOINT 和 CMD 的变体,但是当容器最终运行时,我似乎无法激活 python3 环境。如何使用 python3 使其正确运行?

这是 dockerfile:

FROM centos:7
RUN mkdir -p /usr/src/app && \
  yum install -y centos-release-scl && \
  yum install -y rh-python36 && \
  yum install -y rh-python36-python-tkinter
SHELL ["scl", "enable", "rh-python36"]
WORKDIR /usr/src/app
COPY . .
WORKDIR /usr/src/app/codeBase
RUN pip install --no-cache-dir -r /usr/src/app/codeBase/requirements.txt
EXPOSE 9000
CMD ["python",  "run.py"]

我也尝试过别名解决方案,但恐怕它不会改变 CMD 的 python exe:这是完全可运行的版本,它仍然打印出 python 2.7.5:

FROM centos:7
RUN mkdir -p /usr/src/app && \  
  yum install -y centos-release-scl && \
  yum install -y rh-python36 && \
  yum install -y rh-python36-python-tkinter
WORKDIR /usr/src/app
RUN alias python=$(find / -type f -name "python*" | grep "python3.6$")
CMD ["python",  "-V"]

在使用 CMD 创建的新 shell 中似乎这些都不存在

【问题讨论】:

  • alias 放入您的Dockerfile 是完全错误的。无论如何,您可能应该完全避免使用别名;但是在 Dockerfile 中定义别名的方法是在 Docker 镜像中将别名定义添加到 shell 的初始化文件中。
  • @tripleee 是的,我真的不喜欢别名作为解决方案。我想会有一个对码头工人更友好的解决方案。我刚刚在下面发布了一个适合我的答案。不过,我没有看到任何不那么复杂的方法来实现这一点。

标签: python python-3.x docker dockerfile


【解决方案1】:

SHELL 是完全错误的 Dockerfile 命令。您可能希望将其放在 RUN 节中。

SHELL 的目的是定义用于执行RUN 命令的shell。所以像

SHELL ["sh", "-c"] # The default
RUN echo "foo"

结束运行

sh -c 'echo "foo"'

当然,将SHELL 替换为不支持此用例的命令只会破坏RUN 命令。

也许可以试试

FROM centos:7
RUN mkdir -p /usr/src/app && \
  yum install -y centos-release-scl && \
  yum install -y rh-python36 && \
  yum install -y rh-python36-python-tkinter
WORKDIR /usr/src/app
COPY . .
WORKDIR /usr/src/app/codeBase
RUN scl enable rh-python36 pip install --no-cache-dir -r ./requirements.txt
EXPOSE 9000
CMD ["scl", "enable", "rh-python36", "python",  "run.py"]

【讨论】:

  • 啊,这就解释了为什么所有软件包在运行 pip 后都能正确安装,而不是 CMD 本身
  • 不幸的是,将它全部放在 CMD 中对我不起作用。 scl 似乎创建了一个新的 shell,python 在 scl 运行的同一个 shell 中运行。
  • 等一下,试试CMD ["scl", "enable", "rh-python36", "sh", "-c", "python ./run.py"]
【解决方案2】:

多亏了 C.Nivs 的回答和here 的回答,我才明白了这一点。别名在交互式 shell 中有效,但不适用于 CMD。我最终做的是类似的,只是在我的情况下,我在 /usr/bin 中创建了一个新的可执行文件,它调用了特殊的 python36 exe:

RUN echo -e '#!/bin/bash\n$(find / -type f -name "python*" | grep "python3.6$") "$@"' > /usr/bin/py3 && \
    chmod +x /usr/bin/py3
CMD ["py3",  "-V"]

现在 py3 使用任何参数运行一个调用 python3 安装的脚本

【讨论】:

  • 但是因为你的PYYHONPATH 是错误的,所以你得到了你刚刚安装的模块的错误版本,不是吗?
  • @tripleee 有趣的是,它看起来与正确的目录相关联。看着sys.path['', "/usr/src/app/$(find / -type f -name 'python*' | grep 'python3.6$')", '/opt/rh/rh-python36/root/usr/lib64/python36.zip', '/opt/rh/rh-python36/root/usr/lib64/python3.6', '/opt/rh/rh-python36/root/usr/lib64/python3.6/lib-dynload', '/opt/rh/rh-python36/root/usr/lib64/python3.6/site-packages', '/opt/rh/rh-python36/root/usr/lib/python3.6/site-packages']。虽然第二个条目是......但似乎并没有抛出FileNotFoundError
  • 不,你可以在里面放任何你想要的垃圾,它会默默地忽略不存在的目录。
  • @tripleee 最终让这对我有用的是,在使用 pip 安装之前,我离开了SHELL ["scl", "enable", "rh-python36"],这似乎让所有东西都用正确的 pip 安装在正确的位置,因为我可以然后访问我在 py3 中下载的所有内容
【解决方案3】:

注意:

我将把这个答案作为问题的上下文,但这并没有解决问题。我的尝试是修改python 指向的位置,但如果在RUN 命令中执行,shell 将退出并且您将丢失alias。根据this question,通过 bash 修改 PYTHONPATH 也是不行的。感谢@tripleee 的收获

不幸的是,看起来 yum install -y rh-python36 将 python3.6 置于一个非常奇怪的位置:

find / -type f -name "python*" | grep "python3.6$"
/opt/rh/rh-python36/root/usr/bin/python3.6

您可以在Dockerfile 中将其用于alias 您的python 命令:

RUN mkdir -p /usr/src/app && \
  yum install -y centos-release-scl && \
  yum install -y rh-python36 && \
  yum install -y rh-python36-python-tkinter

# Here
RUN alias python=$(find / -type f -name "python*" | grep "python3.6$")

这应该允许您保留您的 CMD 并将其与正确的 site-packages 联系起来:

import sys

sys.path
['', '/opt/rh/rh-python36/root/usr/lib64/python36.zip', '/opt/rh/rh-python36/root/usr/lib64/python3.6', '/opt/rh/rh-python36/root/usr/lib64/python3.6/lib-dynload', '/opt/rh/rh-python36/root/usr/lib64/python3.6/site-packages', '/opt/rh/rh-python36/root/usr/lib/python3.6/site-packages']

看起来这也可能消除对scl enable那个python环境的需要,因为你可以只使用python -m pip...

# No scl has been run
python -m pip install requests
# running python in the terminal
import requests

r = requests.get('http://google.com')
# runs like a charm

【讨论】:

  • 看起来,对我来说,别名不起作用。使用我上面发布的新的最小 dockerfile 示例,当我运行 CMD 时,我仍然得到 python 2
  • 而且我猜仅仅覆盖 Python 可执行文件不会为您提供正确的PYTHONPATH 等(当然,正如其他地方所指出的那样,在 Dockerfile 中交互地定义别名只会简单地在sh ll 实例,然后立即退出)。
  • @tripleee 你是对的,对我有用,因为我在单个 bash 会话中运行该命令,而没有考虑到 RUN 将退出该 shell 以在不同的层。在这种情况下,您可以使用该目录中的环境变量修改 PYTHONPATH。我会编辑我的答案
  • 尽管您仍然需要对 确切 scl enable 所做的事情进行逆向工程并重新实现所有内容。所以我想更好地弄清楚如何使用命令本身。我不是 Red Hat / CentOS 的人,所以我对这个命令不太熟悉。
  • 我也不是,这就是我走这条路的原因
【解决方案4】:

通过覆盖所有 shell 环境变量以使用 scl_source 来配置 shell 环境变量,从 Austin Dewey 的 blog 中的“方法 #2”可以看出。

FROM centos:7
SHELL ["/usr/bin/env", "bash", "-c"]
RUN \
    yum install -y centos-release-scl && \
    yum install -y rh-python38-python-devel
ENV \
    BASH_ENV="/usr/bin/scl_enable" \
    ENV="/usr/bin/scl_enable" \
    PROMPT_COMMAND=". /usr/bin/scl_enable"
RUN echo -e "\n\
unset BASH_ENV PROMPT_COMMAND ENV\n\
source scl_source enable rh-python38\n\
" > /usr/bin/scl_enable
RUN \
    python3 -m ensurepip && \
    python3 -m pip install --upgrade pip && \
    python3 -m pip install setuptools wheel
docker build --tag python:3.8-centos7 - < Dockerfile
docker run --rm -i -t python:3.8-centos7
python3 --version

Python 3.8.11

注意:这在将python3 --version 作为命令时不起作用。我一直无法找到解决方法。

docker run --rm -i -t python:3.8-centos7 python3 --version

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-05
    • 2023-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多