如何使用 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,它非常适合创建此图像。但是,当尝试安装 gensim
、pandas
等软件包时,我遇到了一些错误,例如: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?