目录

如何配置一个跨 linux 发行版解压即用的 python 运行环境(Portable Python)

文章简介:如何配置一个跨 linux 发行版解压即用的 python 运行环境

场景分析

我们所处的工作环境偏 ToB 离线安装升级。python 在运维工具上有成熟的 ansible 等运维工具。而在实际生产使用过程中,需要适配不同的 linux 发行版。在这过程中,我们需要一个比较

  1. 稳定开箱即用的 python 运行环境
  2. 安装简单 (最好解压即可运行)
  3. 第三方包安装尽可能简单

我们所面向的问题:

  1. linux 发行版众多,一些为 python2,一些为 python3;代码可以兼容 python2 和 python3,但部分依赖不兼容 python2 和 python3;并且 python2 已经 EOL,不期望为它花费力气做适配
  2. linux 发行版 glibc 版本各不相同,高版本 glibc 下编译 python 放到低版本 glibc 运行环境下会 glibc 版本检查失败

解决办法

docker

第一个想到的是 docker. 基于 docker 的容器 python 运行环境,docker image 中包含所有的 python 运行时依赖,包括 python 代码及动态库(包括 glibc)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
FROM python:3.9-slim as base
FROM base as builder
RUN mkdir /install
WORKDIR /install
COPY requirements.txt /requirements.txt
RUN sed -E -i -e 's/deb.debian.org/mirrors.aliyun.com/g' -e 's/security.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list
RUN apt update --allow-insecure-repositories \
	&& apt install -y gcc python3.9-dev libffi-dev -y

RUN pip install --no-cache-dir --trusted-host mirrors.aliyun.com --prefix=/install -r /requirements.txt

# FROM gcr.io/distroless/python3
FROM base
COPY --from=builder /install /usr/local
WORKDIR /app
COPY hello.py /app/

CMD ["hello.py", "/etc"]

但这种方式也有缺陷,docker 采用 namespace 的方式将 / 与 宿主机的 / 隔离开,容器如果期望操作宿主机的 systemd/crond 会比较复杂,可能会需要 docker run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh 。另外一种方式是使用 ssh 免密操作宿主机 (ssh root@hostip sh), 同样操作复杂。

portable python

想法来自于 golang, 所有的依赖都以静态编译的方式编译到一个文件中,单文件复制到其他机器即可运行,之前在静态编译 chrony, 基于这个想法,调研下 python 有没有类似的能力.

将如下命令放到 Dockerfile 中

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# Dockerfile
FROM ubuntu:22.04
RUN sed -E -i -e 's/(archive|ports).ubuntu.com/mirrors.aliyun.com/g' -e '/security.ubuntu.com/d' /etc/apt/sources.list
RUN apt-get update && \
    apt-get install -y --no-install-recommends ca-certificates zstd wget && \
    rm -rf /var/lib/apt/lists/* && \
    update-ca-certificates

WORKDIR /opt/

ARG filename=cpython-3.10.13+20230826-x86_64-unknown-linux-gnu-debug-full
RUN wget https://github.com/indygreg/python-build-standalone/releases/download/20230826/${filename}.tar.zst \
	&& unzstd ${filename}.tar.zst \
	&& mkdir -p portable && tar -xvf ${filename}.tar -C portable \
	&& rm -rf ${filename}.tar.zst ${filename}.tar

ENV PYTHON_HOME=/opt/portable/python/

RUN ${PYTHON_HOME}/install/bin/pip3 install --debug --verbose requests psycopg2-binary ansible -i https://pypi.tuna.tsinghua.edu.cn/simple

生成的 python 包的命令

1
2
3
docker build -t portable-python:dev --build-arg HTTPS_PROXY="http://host.docker.internal:7890" .

docker run --rm -it -v "$(pwd):/host" --workdir=/opt/portable portable-python:dev tar -cvf /host/portable-python-3.10.13.tar python

当前已经测试过的操作系统:

  1. centos:7
  2. ubuntu:20.04
  3. ubuntu:22.04
  4. rockylinux:8-minimal
  5. rockylinux:9-minimal
  6. openeuler:20.03-lts
  7. openeuler:22.03-lts

测试过的 pip 包:

  1. requests
  2. psycopg2-binary
  3. ansible

总结

TODO: 这里缺一个总结

处理问题的思路决定了做事的效率.

参考