从 Dockerfile CMD 调用 sh 文件时无法在 docker 容器内设置环境变量
Unable to set environment variable inside docker container when calling sh file from Dockerfile CMD
我正在关注 this link 创建一个 spark 集群。我能够 运行 spark 集群。但是,我必须给出一个绝对路径开始spark-shell
。我正在尝试设置环境变量,即 PATH
和 start-shell.sh
中的一些其他变量。但是,它没有在容器内设置它。我尝试在容器内使用 printenv
打印它。但这些变量从未反映出来。
我是否尝试错误地设置环境变量?不过,Spark 集群已 运行ning 成功。
我正在使用 docker-compose.yml 构建和重新创建图像和容器。
docker-compose up --build
Docker 文件
# builder step used to download and configure spark environment
FROM openjdk:11.0.11-jre-slim-buster as builder
# Add Dependencies for PySpark
RUN apt-get update && apt-get install -y curl vim wget software-properties-common ssh net-tools ca-certificates python3 python3-pip python3-numpy python3-matplotlib python3-scipy python3-pandas python3-simpy
# JDBC driver download and install
ADD https://go.microsoft.com/fwlink/?linkid=2168494 /usr/share/java
RUN update-alternatives --install "/usr/bin/python" "python" "$(which python3)" 1
# Fix the value of PYTHONHASHSEED
# Note: this is needed when you use Python 3.3 or greater
ENV SPARK_VERSION=3.1.2 \
HADOOP_VERSION=3.2 \
SPARK_HOME=/opt/spark \
PYTHONHASHSEED=1
# Download and uncompress spark from the apache archive
RUN wget --no-verbose -O apache-spark.tgz "https://archive.apache.org/dist/spark/spark-${SPARK_VERSION}/spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz" \
&& mkdir -p ${SPARK_HOME} \
&& tar -xf apache-spark.tgz -C ${SPARK_HOME} --strip-components=1 \
&& rm apache-spark.tgz
我的 Dockerfile-spark
在 Dockerfile 中的 ENV 下使用 SPARK_BIN="${SPARK_HOME}/bin/
时,环境变量已设置。使用 printenv
在 docker 容器内可见
FROM apache-spark
WORKDIR ${SPARK_HOME}
ENV SPARK_MASTER_PORT=7077 \
SPARK_MASTER_WEBUI_PORT=8080 \
SPARK_LOG_DIR=${SPARK_HOME}/logs \
SPARK_MASTER_LOG=${SPARK_HOME}/logs/spark-master.out \
SPARK_WORKER_LOG=${SPARK_HOME}/logs/spark-worker.out \
SPARK_WORKER_WEBUI_PORT=8080 \
SPARK_MASTER="spark://spark-master:7077" \
SPARK_WORKLOAD="master"
COPY start-spark.sh /
CMD ["/bin/bash", "/start-spark.sh"]
开始-spark.sh
#!/bin/bash
. "$SPARK_HOME/bin/load-spark-env.sh"
export SPARK_BIN="${SPARK_HOME}/bin/" # This doesn't work here
export PATH="${SPARK_HOME}/bin/:${PATH}" # This doesn't work here
# When the spark work_load is master run class org.apache.spark.deploy.master.Master
if [ "$SPARK_WORKLOAD" == "master" ];
then
export SPARK_MASTER_HOST=`hostname` # This works here
cd $SPARK_BIN && ./spark-class org.apache.spark.deploy.master.Master --ip $SPARK_MASTER_HOST --port $SPARK_MASTER_PORT --webui-port $SPARK_MASTER_WEBUI_PORT >> $SPARK_MASTER_LOG.
我的文件结构是
- docker文件
- dockerfile-spark # 这使用由 dockerfile
创建的预构建图像
- start-spark.sh # 调用 buy dockerfile-spark
- docker-compose.yml # 使用构建参数从 dockerfile-spark
构建图像
从主容器内部
root@3abbd4508121:/opt/spark# export
declare -x HADOOP_VERSION="3.2"
declare -x HOME="/root"
declare -x HOSTNAME="3abbd4508121"
declare -x JAVA_HOME="/usr/local/openjdk-11"
declare -x JAVA_VERSION="11.0.11+9"
declare -x LANG="C.UTF-8"
declare -x OLDPWD
declare -x PATH="/usr/local/openjdk-11/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
declare -x PWD="/opt/spark"
declare -x PYTHONHASHSEED="1"
declare -x SHLVL="1"
declare -x SPARK_HOME="/opt/spark"
declare -x SPARK_LOCAL_IP="spark-master"
declare -x SPARK_LOG_DIR="/opt/spark/logs"
declare -x SPARK_MASTER="spark://spark-master:7077"
declare -x SPARK_MASTER_LOG="/opt/spark/logs/spark-master.out"
declare -x SPARK_MASTER_PORT="7077"
declare -x SPARK_MASTER_WEBUI_PORT="8080"
declare -x SPARK_VERSION="3.1.2"
declare -x SPARK_WORKER_LOG="/opt/spark/logs/spark-worker.out"
declare -x SPARK_WORKER_WEBUI_PORT="8080"
declare -x SPARK_WORKLOAD="master"
declare -x TERM="xterm"
root@3abbd4508121:/opt/spark#
在 Docker 中设置环境变量有几种不同的方法,运行 进程也有几种不同的方法。一个容器通常 运行 一个进程,由图像的 ENTRYPOINT
和 CMD
设置控制。如果您 docker exec
容器中的第二个进程,它不会 运行 作为主进程的子进程,并且不会看到由该主进程设置的环境变量。
在此处显示的设置中,start-spark.sh
脚本是主要的容器进程(它是图像的 CMD
)。如果您 docker exec your-container printenv
,它将看到 Dockerfile
中设置的内容,但看不到此脚本中设置的内容。
每次您 运行 容器时,文件系统路径之类的东西通常都会被修复,无论您在那里 运行 使用什么命令,因此您可以在 Docker文件
ENV SPARK_BIN=${SPARK_HOME}/bin PATH=${SPARK_BIN}:${PATH}
您可以在 Docker 文件中同时指定 ENTRYPOINT
和 CMD
;如果这样做,CMD
将作为参数传递给 ENTRYPOINT
。这导致了一个有用的模式,其中 CMD
是一个标准的 shell 命令,而 ENTRYPOINT
是一个包装器,它进行首次设置然后 运行s 它。您可以将脚本分成两部分:
#!/bin/sh
# spark-env.sh
. "${SPARK_BIN}/load-spark-env.snh"
exec "$@"
#!/bin/sh
# start-spark.sh
spark-class org.apache.spark.deploy.master.Master \
--ip "$SPARK_MASTER_HOST" \
--port "$SPARK_MASTER_PORT" \
--webui-port "$SPARK_MASTER_WEBUI_PORT"
然后在您的Docker文件中指定这两个部分
COPY spark-env.sh start-spark.sh /
ENTRYPOINT ["/spark-env.sh"] # must be JSON-array syntax
CMD ["/start-spark.sh"] # or any other valid CMD
这对您的调试很有用,因为可以直接覆盖 docker run
或 docker-compose run
指令中的 CMD
,而保留 ENTRYPOINT
。
docker-compose run spark \
printenv
这将基于所有相同的 Docker 文件设置启动一个新容器。当它 运行s 时,它 运行s printenv
而不是图像中的 CMD
。这将在 ENTRYPOINT
脚本中进行首次设置,然后最后的 exec "$@"
行将 运行 printenv
而不是启动 Spark 应用程序。这将向您显示应用程序启动时的环境。
我正在关注 this link 创建一个 spark 集群。我能够 运行 spark 集群。但是,我必须给出一个绝对路径开始spark-shell
。我正在尝试设置环境变量,即 PATH
和 start-shell.sh
中的一些其他变量。但是,它没有在容器内设置它。我尝试在容器内使用 printenv
打印它。但这些变量从未反映出来。
我是否尝试错误地设置环境变量?不过,Spark 集群已 运行ning 成功。
我正在使用 docker-compose.yml 构建和重新创建图像和容器。
docker-compose up --build
Docker 文件
# builder step used to download and configure spark environment
FROM openjdk:11.0.11-jre-slim-buster as builder
# Add Dependencies for PySpark
RUN apt-get update && apt-get install -y curl vim wget software-properties-common ssh net-tools ca-certificates python3 python3-pip python3-numpy python3-matplotlib python3-scipy python3-pandas python3-simpy
# JDBC driver download and install
ADD https://go.microsoft.com/fwlink/?linkid=2168494 /usr/share/java
RUN update-alternatives --install "/usr/bin/python" "python" "$(which python3)" 1
# Fix the value of PYTHONHASHSEED
# Note: this is needed when you use Python 3.3 or greater
ENV SPARK_VERSION=3.1.2 \
HADOOP_VERSION=3.2 \
SPARK_HOME=/opt/spark \
PYTHONHASHSEED=1
# Download and uncompress spark from the apache archive
RUN wget --no-verbose -O apache-spark.tgz "https://archive.apache.org/dist/spark/spark-${SPARK_VERSION}/spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz" \
&& mkdir -p ${SPARK_HOME} \
&& tar -xf apache-spark.tgz -C ${SPARK_HOME} --strip-components=1 \
&& rm apache-spark.tgz
我的 Dockerfile-spark
在 Dockerfile 中的 ENV 下使用 SPARK_BIN="${SPARK_HOME}/bin/
时,环境变量已设置。使用 printenv
FROM apache-spark
WORKDIR ${SPARK_HOME}
ENV SPARK_MASTER_PORT=7077 \
SPARK_MASTER_WEBUI_PORT=8080 \
SPARK_LOG_DIR=${SPARK_HOME}/logs \
SPARK_MASTER_LOG=${SPARK_HOME}/logs/spark-master.out \
SPARK_WORKER_LOG=${SPARK_HOME}/logs/spark-worker.out \
SPARK_WORKER_WEBUI_PORT=8080 \
SPARK_MASTER="spark://spark-master:7077" \
SPARK_WORKLOAD="master"
COPY start-spark.sh /
CMD ["/bin/bash", "/start-spark.sh"]
开始-spark.sh
#!/bin/bash
. "$SPARK_HOME/bin/load-spark-env.sh"
export SPARK_BIN="${SPARK_HOME}/bin/" # This doesn't work here
export PATH="${SPARK_HOME}/bin/:${PATH}" # This doesn't work here
# When the spark work_load is master run class org.apache.spark.deploy.master.Master
if [ "$SPARK_WORKLOAD" == "master" ];
then
export SPARK_MASTER_HOST=`hostname` # This works here
cd $SPARK_BIN && ./spark-class org.apache.spark.deploy.master.Master --ip $SPARK_MASTER_HOST --port $SPARK_MASTER_PORT --webui-port $SPARK_MASTER_WEBUI_PORT >> $SPARK_MASTER_LOG.
我的文件结构是
- docker文件
- dockerfile-spark # 这使用由 dockerfile 创建的预构建图像
- start-spark.sh # 调用 buy dockerfile-spark
- docker-compose.yml # 使用构建参数从 dockerfile-spark 构建图像
从主容器内部
root@3abbd4508121:/opt/spark# export
declare -x HADOOP_VERSION="3.2"
declare -x HOME="/root"
declare -x HOSTNAME="3abbd4508121"
declare -x JAVA_HOME="/usr/local/openjdk-11"
declare -x JAVA_VERSION="11.0.11+9"
declare -x LANG="C.UTF-8"
declare -x OLDPWD
declare -x PATH="/usr/local/openjdk-11/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
declare -x PWD="/opt/spark"
declare -x PYTHONHASHSEED="1"
declare -x SHLVL="1"
declare -x SPARK_HOME="/opt/spark"
declare -x SPARK_LOCAL_IP="spark-master"
declare -x SPARK_LOG_DIR="/opt/spark/logs"
declare -x SPARK_MASTER="spark://spark-master:7077"
declare -x SPARK_MASTER_LOG="/opt/spark/logs/spark-master.out"
declare -x SPARK_MASTER_PORT="7077"
declare -x SPARK_MASTER_WEBUI_PORT="8080"
declare -x SPARK_VERSION="3.1.2"
declare -x SPARK_WORKER_LOG="/opt/spark/logs/spark-worker.out"
declare -x SPARK_WORKER_WEBUI_PORT="8080"
declare -x SPARK_WORKLOAD="master"
declare -x TERM="xterm"
root@3abbd4508121:/opt/spark#
在 Docker 中设置环境变量有几种不同的方法,运行 进程也有几种不同的方法。一个容器通常 运行 一个进程,由图像的 ENTRYPOINT
和 CMD
设置控制。如果您 docker exec
容器中的第二个进程,它不会 运行 作为主进程的子进程,并且不会看到由该主进程设置的环境变量。
在此处显示的设置中,start-spark.sh
脚本是主要的容器进程(它是图像的 CMD
)。如果您 docker exec your-container printenv
,它将看到 Dockerfile
中设置的内容,但看不到此脚本中设置的内容。
每次您 运行 容器时,文件系统路径之类的东西通常都会被修复,无论您在那里 运行 使用什么命令,因此您可以在 Docker文件
ENV SPARK_BIN=${SPARK_HOME}/bin PATH=${SPARK_BIN}:${PATH}
您可以在 Docker 文件中同时指定 ENTRYPOINT
和 CMD
;如果这样做,CMD
将作为参数传递给 ENTRYPOINT
。这导致了一个有用的模式,其中 CMD
是一个标准的 shell 命令,而 ENTRYPOINT
是一个包装器,它进行首次设置然后 运行s 它。您可以将脚本分成两部分:
#!/bin/sh
# spark-env.sh
. "${SPARK_BIN}/load-spark-env.snh"
exec "$@"
#!/bin/sh
# start-spark.sh
spark-class org.apache.spark.deploy.master.Master \
--ip "$SPARK_MASTER_HOST" \
--port "$SPARK_MASTER_PORT" \
--webui-port "$SPARK_MASTER_WEBUI_PORT"
然后在您的Docker文件中指定这两个部分
COPY spark-env.sh start-spark.sh /
ENTRYPOINT ["/spark-env.sh"] # must be JSON-array syntax
CMD ["/start-spark.sh"] # or any other valid CMD
这对您的调试很有用,因为可以直接覆盖 docker run
或 docker-compose run
指令中的 CMD
,而保留 ENTRYPOINT
。
docker-compose run spark \
printenv
这将基于所有相同的 Docker 文件设置启动一个新容器。当它 运行s 时,它 运行s printenv
而不是图像中的 CMD
。这将在 ENTRYPOINT
脚本中进行首次设置,然后最后的 exec "$@"
行将 运行 printenv
而不是启动 Spark 应用程序。这将向您显示应用程序启动时的环境。