docker--k8s---终端terminal和普通程序以及jupyter notebook-创建永久的静态环境变量--创建动态的环境变量

仲孙奇
2023-12-01

终端terminal和普通程序

linux系统的中主要有两种启用系统环境的情况,一种是 用户登录,比如进入bash或者sh等命令行操作shell界面,一种是 用户不登录,而是程序自动运行。

根据 两种情况,适用的创建永久的环境变量的方式就会有所不同。

创建永久的静态环境变量

静态环境变量 是指 内容不会变动的,是一个固定的值。

这种情况的环境变量 直接在Dockerfile种使用ENV 指定即可。

比如:

ENV JAVA_HOME=/spark/java/jre1.8.0_181  JRE_HOME=/spark/java/jre1.8.0_181  CLASSPATH=$JAVA_HOME/lib/:$JRE_HOME/lib/
ENV PATH $PATH:$JAVA_HOME/bin:/usr/local/python37/bin
ENV PYSPARK_PYTHON  python3
ENV PYSPARK_DRIVER_PYTHON   python3

创建永久的动态环境变量

有一种使用场景是 我们在这个镜像启动之前,是不知道 环境变量的值的,必须要等镜像启动之后才知道这个环境变量的值是什么,这种情况我们称为 动态环境变量。

比如 ${HOSTNAME} 或者 K U B E R N E T E S S E R V I C E H O S T , {KUBERNETES_SERVICE_HOST}, KUBERNETESSERVICEHOST{KUBERNETES_SERVICE_PORT},这几个变量都是需要 镜像启动后,在相应的pod种,才会有这几个变量的值。

解决方法是 在Dockerfile的 入口 endpoint.sh 中 再运行 环境变量 注入。

因为endpoint.sh是 每个镜像启动后 都会运行的 脚本,因为镜像已经启动,所以 可以获取到相关的 环境变量。

在Dockerfile的末尾使用代码如下:

ENV     MY_HOME /usr/local/zzq
COPY   entrypoint.sh ${MY_HOME}/entrypoint.sh
WORKDIR     ${MY_HOME}
ENTRYPOINT  ["./entrypoint.sh"]

entrypoint.sh代码如下:

echo 'export PYSPARK_SUBMIT_ARGS="--master k8s://https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}   --deploy-mode client   pyspark-shell" '  >> /etc/profile.d/spark.sh


echo  'export PATH=/usr/local/python37/bin:$PATH' >> /etc/profile.d/airflow.sh

echo  'ln -sf  /usr/bin/python  /usr/bin/python3' >> /etc/profile.d/airflow.sh

echo  'export PATH=$PATH:$AIRFLOW_HOME' >> /etc/profile.d/airflow.sh

source /etc/profile


echo "hail env:"
echo $PYSPARK_SUBMIT_ARGS

python3 -V

whereis  python

echo $PATH

echo "env:"

env 

echo "spark conf:"

cat $SPARK_HOME/conf/spark-defaults.conf


说明,我们这里注入的是/etc/profile所使用的环境变量注入脚本目录/etc/profile.d/ 。

/etc/profile 是负责全局的环境变量的,包括 终端和普通的程序运行,都会加载其中的环境变量。

/etc/profile 有两种用法,一种是把export 语句直接加在 /etc/profile文件中,一种是添加一个sh文本文件到 /etc/profile.d/目录,然后执行source /etc/profile 环境变量就会生效,下一次登陆也生效。

几种管理环境变量的文件区别

~/.bashrc

该文件包含专属于用户的bash shell的bash信息,当登陆bash shell时以及每次打开bash时执行。

使用方式

打开文件

vim ~/.bashrc

在文件末尾加上

export PATH=$PATH:/.../...    

使设置生效


source ~/.bashrc

/etc/bashrc

为每一个运行bash shell的用户执行此文件。当bash shell被打开时,该文件被读取。

~/.bash_profile

每个用户都可使用该文件输入专用于自己的shell信息,当用户使用bash shell登陆时,该文件仅仅被执行一次,默认情况下,其设置的一些环境变量,执行用户的.bashrc文件。

~/.profile

在Debian中使用.profile代替bash_profile文件。

~/.bash_logout

每次退出bash shell时,执行该文件。

/etc/profile

此文件为系统的每个用户设置环境信息,当用户第一次登陆时(无论是shell登录还是程序运行),该文件被执行。以上几种文件都是 用户使用bash shell 命令shell界面的时候才会加载环境变量,但是程序运行的时候 可能就读取不到环境变量了,只有/etc/profile是全局的,即负责shell登录也在程序运行时生效。

并从/etc/profile.d目录的配置文件中搜集shell的设置。

jupyter notebook

上面我们已经 记录了如下设置程序的环境变量,比如使用ENV 或者 /etc/profile 。

但是jupyter notebook因为它并不是一个普通的程序,它有自己的运行原理和内核,所以启动jupyter notebook之后,它的环境变量时跟 linux系统的环境变量是 不完全一致的。

我们来探索一下 如何 设置 jupyter notebook中的环境变量

创建 永久的静态变量

设置 永久的静态变量 可以使用 Dockerfile 的ENV的方式

比如:

ENV JAVA_HOME=/spark/java/jre1.8.0_181  JRE_HOME=/spark/java/jre1.8.0_181  CLASSPATH=$JAVA_HOME/lib/:$JRE_HOME/lib/
ENV PATH $PATH:$JAVA_HOME/bin:/usr/local/python37/bin
ENV PYSPARK_PYTHON  python3
ENV PYSPARK_DRIVER_PYTHON   python3

这样设置的系统环境变量 jupyter noterbook是可以同步到的。

在jupyter noterbook中使用命令

!env

可以输出所有的环境变量

发现ENV方式设置的环境变量 可以被 jupyter noterbook 识别到。

创建永久的动态变量

但是 如果我们有一些动态变量,是在启动了jupyter的镜像之后才有值的环境变量,!env就获取不到了,也不能通过Dockfile的ENV方式设置,那么 有么有其他的方法设置动态的环境变量让 jupyter notebook 识别到呢

方案如下

在 jupyter notebook 初始化的源代码中修改 增加

比如在/etc/init.d/poststart.sh文件中增加

export PYSPARK_SUBMIT_ARGS="--master k8s://https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}  --deploy-mode client --conf spark.executor.memory=8g --conf spark.executor.cores=2 --conf spark.executor.instances=2 --conf spark.executor.pyspark.memory=1g --conf spark.driver.memory=2g pyspark-shell"

或者修改 /lib/systemd/system/jupyer-notebook.service 文件

增加环境变量如下:

Environment=MYOWN_VAR=theVar

在输入框cell中使用命令

这种方式不能自动设置,只能手动设置,比如在cell的框中输入:

%env MY_VAR=MY_VALUE 


%env  PYSPARK_SUBMIT_ARGS="--master k8s://https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}  --deploy-mode client --conf spark.executor.memory=8g --conf spark.executor.cores=2 --conf spark.executor.instances=2 --conf spark.executor.pyspark.memory=1g --conf spark.driver.memory=2g pyspark-shell"

或者

import os
os.environ['PYSPARK_SUBMIT_ARGS'] ="--master k8s://https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}  --deploy-mode client --conf spark.executor.memory=8g --conf spark.executor.cores=2 --conf spark.executor.instances=2 --conf spark.executor.pyspark.memory=1g --conf spark.driver.memory=2g pyspark-shell"

或者把多个环境变量写在文件中,比如把 VARIABLE_NAME=VARIABLE_VALUE 写入到.env文件中。

使用命令

import os
env_vars = !cat ../script/.env
for var in env_vars:
    key, value = var.split('=')
    os.environ[key] = value

还可以借助python-dotenv

新建一个命名为.env的文件,使用如下命令加载

使用命令

%load_ext dotenv
%dotenv

创建的yaml中使用命名

如果是k8s方式部署的hub或者jupyter book。可以在yaml中使用extraConfig 或者 lifecycleHooks的方式

extraConfig

hub:
  nodeSelector:
    kops.k8s.io/instancegroup: nodes
  extraEnv:
    JUPYTER_ENABLE_LAB: 1
    HOST: "jp.test.com"
  resources:
    requests:
      cpu: 100m
      memory: 2Gi
    limits:
      cpu: 200m
      memory: 4Gi
  extraConfig: |
    import os
    c.JupyterHub.authenticator_class = 'oauthenticator.gitlab.GitLabOAuthenticator'
    #c.KubeSpawner.cmd = ['jupyter-labhub']
    #c.GitLabOAuthenticator.scope = ['api read_repository write_repository']
    c.GitLabOAuthenticator.oauth_callback_url = "http://git.test.com/hub/oauth_callback"
    c.GitLabOAuthenticator.client_id = "123"
    c.GitLabOAuthenticator.client_secret = "123"
    c.GitLabConfig.access_token = "123"
    c.GitLabConfig.url = "http://git.test.com"

    async def add_auth_env(spawner):
      auth_state = await spawner.user.get_auth_state()
      if not auth_state:
          spawner.log.warning("auth failed %s", spawner.user)
          return
      spawner.environment['GITLAB_ACCESS_TOKEN'] = auth_state['access_token']
      spawner.environment['GITLAB_USER_LOGIN'] = auth_state['gitlab_user']['username']
      spawner.environment['GITLAB_USER_ID'] = str(auth_state['gitlab_user']['id'])
      spawner.environment['GITLAB_USER_EMAIL'] = auth_state['gitlab_user']['email']
      spawner.environment['GITLAB_USER_NAME'] = auth_state['gitlab_user']['name']
      spawner.environment['ENV'] = 'prod'
      spawner.environment['PYSPARK_SUBMIT_ARGS']='--master k8s://https://'+os.environ.get("KUBERNETES_SERVICE_HOST","10.1.0.1")+':'+os.environ.get("KUBERNETES_SERVICE_PORT",443)+'  --deploy-mode client --conf spark.executor.instances=2 pyspark-shell'

或者

  lifecycleHooks:
    postStart:
      exec:
        command:
          - "sh"
          - "-c"
          - >
            sed -i "1ispark.master k8s://https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}" $SPARK_HOME/conf/spark-defaults.conf ;
            echo "spark.driver.pod.name ${HOSTNAME}" >> $SPARK_HOME/conf/spark-defaults.conf ;
            echo "spark.driver.host `hostname -i`" >> $SPARK_HOME/conf/spark-defaults.conf ;
            if [ -x /etc/init.d/poststart.sh ] ; then
              /etc/init.d/poststart.sh prod;
            fi;
            if [ -x /usr/bin/git ]; then
                echo "https://oauth2:${GITLAB_ACCESS_TOKEN}@git.test.com" > ~/.git-credentials;
                mkdir -p $HOME/.config/git ;
                echo -e 'hail*.log\n.ipynb_checkpoints\n__pycache__/\n*.egg-info/\n.eggs/\n.cache/\n.mypy_cache/\n.DS_Store' > $HOME/.config/git/ignore;
                /usr/bin/git config --global credential.helper store;
                /usr/bin/git config --global user.email "${GITLAB_USER_EMAIL}";
                /usr/bin/git config --global user.name "${GITLAB_USER_LOGIN}";
            fi;

修改内核文件

还有一种设置方式是 修改内核文件,kernel.json,jupyter notebook的原理就是依赖与kernel启动不同的语言环境,所以 环境变量与 kernel息息相关。

如果我们希望 每次启动 jupyter notebook的环境,环境变量都生效,可以尝试修改kernel.json

首先需要创建一个ipython的kernel,其中设置我们的环境变量。

步骤如下:

1、阅读文档 https://jupyter-client.readthedocs.io/en/stable/kernels.html#kernel-specs
2、在linux系统shell中使用命令jupyter kernelspec list 查看 已经安装了哪些kernels 和 它们的文件存储在哪里
3、复制其中我们需要的文件kernel.json,比如python3环境的
4、修改文件命名和其中的部分内容,再复制回去,主要修改 display_name和env如下:

{
 "display_name": "Python 3 with environment",
 "language": "python",
 "argv": [
  "/usr/bin/python3",
  "-m",
  "ipykernel_launcher",
  "-f",
  "{connection_file}"
 ],
 "env": {"LD_LIBRARY_PATH":""}
}

参考资料:
how to set variable in jupyter notebook

 类似资料: