如何使用 python 和 Java 运行 Docker?

Posted

技术标签:

【中文标题】如何使用 python 和 Java 运行 Docker?【英文标题】:How to run Docker with python and Java? 【发布时间】:2018-12-09 20:06:10 【问题描述】:

我需要在我的 docker 容器中同时运行 java 和 python 来运行一些代码。

这是我的 dockerfile: 如果我不添加 FROM openjdk:slim

,它可以正常工作
#get python
FROM python:3.6-slim

RUN pip install --trusted-host pypi.python.org flask

#get openjdk

FROM openjdk:slim


COPY . /targetdir
WORKDIR /targetdir

# Make port 81 available to the world outside this container
EXPOSE 81

CMD ["python", "test.py"]

和test.py应用在同一个目录:

from flask import Flask

import os
app = Flask(__name__)


@app.route("/")

def hello():
    html = "<h3>Test:test</h3>"
    test = os.environ['JAVA_HOME']

    return html.format(test = test)


if __name__ == '__main__':
    app.run(debug=True,host='0.0.0.0',port=81)

我收到此错误:

D:\MyApps\Docker Toolbox\Docker Toolbox\docker.exe: Error response from daemon: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: \"python\": executable file not found in $PATH": unknown.

我到底做错了什么?我是 docker 新手,也许我错过了一步。

其他详情

我的目标

我必须运行一个运行 Java 文件的 python 程序。我使用的python库需要JAVA_HOME的路径。

我的问题:

我不懂Java,所以无法正常运行文件。

我的整个代码都是用 Python 编写的,除了这个 Java 位

Python 包装器以我需要的方式运行文件。

【问题讨论】:

通常你在一个容器中运行一个应用程序,在两个容器中运行两个应用程序。 【参考方案1】:

解决上述问题的一个更简单的方法是使用多阶段 docker 容器,您可以在其中将内容从一个复制到另一个。在上述情况下,您可以将openjdk:slim 作为基础容器,然后使用 python 容器中的内容复制到此基础容器中,如下所示:

FROM openjdk:slim
COPY --from=python:3.6 / /

... 

<normal instructions for python container continues>

...

此功能从 Docker 17.05 开始可用,您可以使用多阶段构建执行更多操作,例如仅将您需要的内容从一个复制到另一个。

Reference documentation

【讨论】:

这正是我想要的!当然,您需要使用兼容的图像和东西,但这比所有其他答案都更加清晰,其中一些不再有效,因为 openjdk 在背后很痛苦。 这实际上是进行多阶段构建的最佳实践。感谢您提供这个。 当我执行类似的步骤COPY --from=python:3.6 / /,但反过来,即我有一个 Java 基础映像,然后COPY --from=java_stage / / 尝试执行 Python 时出现 Python 错误pip3 install ... 我认为 Python 文件被 COPY 步骤覆盖? 将整个根目录从一个图像复制到另一个图像肯定会很麻烦。谁知道你在那儿捣乱什么?如果它确实有效,那么它是幸运的,除非你精确地固定那些图像版本,否则它可能会在更新发生时对你造成破坏。【参考方案2】:

好吧,我花了一点时间才弄明白。我要感谢answer。

我认为我的方法行不通,因为我没有 Linux 的基本版本。

原来是这样的:

    获取 Linux(我使用的是 Alpine,因为它是准系统) 通过包管理器获取 Java 获取 Python,PIP

可选:查找并设置 JAVA_HOME

    找到 JAVA_HOME 的路径。也许有更好的方法来做到这一点,但我是在运行容器时这样做的,然后我使用 docker exec -it [COINTAINER ID] bin/bash 查看容器内部并找到了它。 在 dockerfile 中设置 JAVA_HOME 并再次构建 + 运行它

这是最终的 Dockerfile(它应该与问题中的 python 代码一起使用):

### 1. Get Linux
FROM alpine:3.7

### 2. Get Java via the package manager
RUN apk update \
&& apk upgrade \
&& apk add --no-cache bash \
&& apk add --no-cache --virtual=build-dependencies unzip \
&& apk add --no-cache curl \
&& apk add --no-cache openjdk8-jre

### 3. Get Python, PIP

RUN apk add --no-cache python3 \
&& python3 -m ensurepip \
&& pip3 install --upgrade pip setuptools \
&& rm -r /usr/lib/python*/ensurepip && \
if [ ! -e /usr/bin/pip ]; then ln -s pip3 /usr/bin/pip ; fi && \
if [[ ! -e /usr/bin/python ]]; then ln -sf /usr/bin/python3 /usr/bin/python; fi && \
rm -r /root/.cache

### Get Flask for the app
RUN pip install --trusted-host pypi.python.org flask

####
#### OPTIONAL : 4. SET JAVA_HOME environment variable, uncomment the line below if you need it

#ENV JAVA_HOME="/usr/lib/jvm/java-1.8-openjdk"

####

EXPOSE 81    
ADD test.py /
CMD ["python", "test.py"]

我是 Docker 新手,所以这可能不是最好的解决方案。我愿意接受建议。

更新:常见问题

难以使用 python 包

正如Joabe Lucena 指出的here,Alpine 可能会遇到某些python 包的问题。 我建议您使用最适合您的 Linux 发行版,例如centos。

【讨论】:

这个答案展示了如何使用已安装的 Java 和 python 构建一个 docker 容器。运行 python 时,Java 进程不会启动。你可以 ssh 你的 docker 并查看正在运行的进程 (top) ***.com/questions/30172605/… 这是一个很好的解决方案!!!。真的帮助了我。我正在寻找将 Python 3 和 Java 8 放在同一个 docker 映像中,我通过上述方式实现了它。 我还需要 Java 和 Python3(但不需要 pip 和烧瓶)这个解决方案创建了一个 170mb 的 Docker 映像。使用 openjdk:slim 和 apt-getting python3 我得到了 >400mb。两个图像的构建速度大致相同。 即使在设置了 java home 之后,当我在 bash shell 中键入 java 或 javac 时 - 使用上面的 docker 文件找不到 exec。 (错误:找不到命令) PEP656 导致 cibuildwheel 现在支持使用 musl 的 Linux 发行版,即 Alpine Linux,因此现在可能有所不同,请参阅 discuss.python.org/t/… 和 cibuildwheel.readthedocs.io/en/stable/changelog/#v220【参考方案3】:

另一种选择是简单地使用来自 docker hub 的 docker-java-python 图像。 https://hub.docker.com/r/rappdw/docker-java-python

FROM rappdw/docker-java-python:openjdk1.8.0_171-python3.6.6
RUN java -version
RUN python --version

【讨论】:

请注意,这个包没有被积极维护,它是基于 java 8 构建的。 它已经很老了,但它的设计很合理,并且很容易更新和维护,请参阅github.com/rappdw/docker-java-python/blob/master/Dockerfile。 Python dockerfiles 很复杂,因此从 python 基础容器开始并在顶部安装 azul zulu openJDK - 就像它一样 - 看起来是一个好方法。【参考方案4】:

哦,让我加上我的五美分。我将 python slim 作为基础图像。然后我找到了 open-jdk-11(注意,open-jdk-10 将失败,因为它不受支持)基本图像代码!...并将其复制粘贴到我的 docker 文件中。

注意,复制粘贴驱动的开发很酷......只有当你理解你在代码中使用的每一行时!!!

就在这里!

<!-- language: shell -->
FROM python:3.7.2-slim

# Do your stuff, install python.

# and now Jdk
RUN rm -rf /var/lib/apt/lists/* && apt-get clean && apt-get update && apt-get upgrade -y \
    && apt-get install -y --no-install-recommends curl ca-certificates \
    && rm -rf /var/lib/apt/lists/*

ENV JAVA_VERSION jdk-11.0.2+7

COPY slim-java* /usr/local/bin/

RUN set -eux; \
    ARCH="$(dpkg --print-architecture)"; \
    case "$ARCH" in \
       ppc64el|ppc64le) \
         ESUM='c18364a778b1b990e8e62d094377af48b000f9f6a64ec21baff6a032af06386d'; \
         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.1%2B13/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.1_13.tar.gz'; \
         ;; \
       s390x) \
         ESUM='e39aacc270731dadcdc000aaaf709adae7a08113ccf5b4a045bc87fc13458d71'; \
         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11%2B28/OpenJDK11-jdk_s390x_linux_hotspot_11_28.tar.gz'; \
         ;; \
       amd64|x86_64) \
         ESUM='d89304a971e5186e80b6a48a9415e49583b7a5a9315ba5552d373be7782fc528'; \
         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.2%2B7/OpenJDK11U-jdk_x64_linux_hotspot_11.0.2_7.tar.gz'; \
         ;; \
       aarch64|arm64) \
         ESUM='b66121b9a0c2e7176373e670a499b9d55344bcb326f67140ad6d0dc24d13d3e2'; \
         BINARY_URL='https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.1%2B13/OpenJDK11U-jdk_aarch64_linux_hotspot_11.0.1_13.tar.gz'; \
         ;; \
       *) \
         echo "Unsupported arch: $ARCH"; \
         exit 1; \
         ;; \
    esac; \
    curl -Lso /tmp/openjdk.tar.gz $BINARY_URL; \
    sha256sum /tmp/openjdk.tar.gz; \
    mkdir -p /opt/java/openjdk; \
    cd /opt/java/openjdk; \
    echo "$ESUM  /tmp/openjdk.tar.gz" | sha256sum -c -; \
    tar -xf /tmp/openjdk.tar.gz; \
    jdir=$(dirname $(dirname $(find /opt/java/openjdk -name javac))); \
    mv $jdir/* /opt/java/openjdk; \
    export PATH="/opt/java/openjdk/bin:$PATH"; \
    apt-get update; apt-get install -y --no-install-recommends binutils; \
    /usr/local/bin/slim-java.sh /opt/java/openjdk; \
    apt-get remove -y binutils; \
    rm -rf /var/lib/apt/lists/*; \
    rm -rf $jdir /tmp/openjdk.tar.gz;

ENV JAVA_HOME=/opt/java/openjdk \
    PATH="/opt/java/openjdk/bin:$PATH"
ENV JAVA_TOOL_OPTIONS="-XX:+UseContainerSupport"

现在参考。 https://github.com/AdoptOpenJDK/openjdk-docker/blob/master/11/jdk/ubuntu/Dockerfile.hotspot.releases.slim

https://hub.docker.com/_/python/

https://hub.docker.com/r/adoptopenjdk/openjdk11/

我用它们来回答这个问题,这可能会对你有所帮助。 Running Python and Java in Docker

【讨论】:

更新,最终,我改用两个容器 - 让生活更简单一些。 嗯——切换到2个容器后,Java和Python容器之间如何通信? 说来话长。检查弹簧边车。它用作转发代理。【参考方案5】:

我发现 Sunny Pal 的回答非常有用,但我使副本更加具体,并添加了必要的环境变量和更新替代行,以便可以从 Python 容器中的命令行访问 Java。

FROM python:3.9-slim
COPY --from=openjdk:8-jre-slim /usr/local/openjdk-8 /usr/local/openjdk-8

ENV JAVA_HOME /usr/local/openjdk-8

RUN update-alternatives --install /usr/bin/java java /usr/local/openjdk-8/bin/java 1
...

【讨论】:

使用更具体的副本,添加 ENV 并使用更新替代方案是一种非常明智的方法。【参考方案6】:

我相信,通过添加FROM openjdk:slim 行,您可以告诉 docker 在 openjdk 容器(没有 python)中执行所有后续命令

我会通过为 openjdk 和 python 创建两个单独的容器并为它们指定单独的命令集来解决这个问题。

Docker 旨在模块化您的解决方案,将所有内容混合到一个容器中通常是一种不好的做法。

【讨论】:

我更新了问题并添加了其他详细信息部分。根据你的回答。我应该创建一个安装 Java 的新容器。然后我的 python 代码只需要 JAVA_HOME 的路径。我怎么做?我查看了 docker 文档here,真的很混乱。【参考方案7】:

你的 dockerfile 中应该有一个 FROM (除非你为 docker 使用多阶段构建)

【讨论】:

【参考方案8】:

我尝试了pajamas 的anwser,它非常适合创建此图像。但是,当尝试安装 gensimpandas 等软件包时,我遇到了一些错误,例如:don't know how to compile Fortran code on platform 'posix'。我搜索并尝试了this、this 和that,但没有一个对我有用。

因此,基于pajamas 的anwser,我决定将他的图像从Alpine 转换为Centos,效果很好。所以这里有一个 Dockerfile 可以帮助像我一样在这种情况下苦苦挣扎的人:

# Get Linux
FROM centos:7

# Install Java
RUN yum update -y \
&& yum install java-1.8.0-openjdk -y \
&& yum clean all \
&& rm -rf /var/cache/yum

# Set JAVA_HOME environment var
ENV JAVA_HOME="/usr/lib/jvm/jre-openjdk"

# Install Python
RUN yum install python3 -y \
&& pip3 install --upgrade pip setuptools wheel \
&& if [ ! -e /usr/bin/pip ]; then ln -s pip3 /usr/bin/pip ; fi \
&& if [[ ! -e /usr/bin/python ]]; then ln -sf /usr/bin/python3 /usr/bin/python; fi \
&& yum clean all \
&& rm -rf /var/cache/yum

CMD ["bash"]

【讨论】:

【参考方案9】:

您可以单独安装Java,而不是使用FROM openjdk:slim,请参考以下示例:

# Install OpenJDK-8
RUN apt-get update && \
apt-get install -y openjdk-8-jdk && \
apt-get install -y ant && \
apt-get clean;

# Fix certificate issues
RUN apt-get update && \
apt-get install ca-certificates-java && \
apt-get clean && \
update-ca-certificates -f;
# Setup JAVA_HOME -- useful for docker commandline
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64/
RUN export JAVA_HOME

【讨论】:

这对你有用吗?我得到这个:dpkg:错误处理包openjdk-8-jre:amd64(--configure):未安装包openjdk-7-jre-headless。未安装包 java7-runtime-headless。尚未配置提供 java7-runtime-headless 的软件包 openjdk-8-jre-headless:amd64。未安装软件包 openjdk-7-jre-headless。未安装包 java7-runtime-headless。包 openjdk-8-jre-headless:amd64 提供 java7-runtime-headless 尚未配置。

以上是关于如何使用 python 和 Java 运行 Docker?的主要内容,如果未能解决你的问题,请参考以下文章

spire.doc for java 如何实现多个地方使用相同的书签?

如何在命令行模式下查看Python帮助文档---dirhelp__doc__

sh 这个最小的设置允许你使用当前文件夹作为doc-root运行nginx.NOTE:python的simplehttpserver可能足够好f

如何使用python将txt文件或PDF转换为Word doc?

如何使用Python将某些字符串从文本文件复制到Word doc?

各种DOC+API