由于公司线上安全要求,不能直接使用pip安装,也没有自行部署pypi源,于是有了此篇文章。本文主要以etcd3插件为示例。

     要求:

         python插件需要附属在自己的软件包程序中,以os.path.append的方式加载

     实现步骤:

     1、搜索找到etcd3的pthon插件

        A)通过找pypi插件界面:https://pypi.org/project/etcd3/并下载最新软件包

        B)  在pypi插件界面进入项目的homepage地址:https://github.com/kragniz/python-etcd3

        C) 在homepage中找到关联插件包说明:https://github.com/kragniz/python-etcd3/blob/master/requirements.txt

             关联插件:grpcio>=1.2.0  tenacity==4.10.0   protobuf==3.5.2.post1

   

    2.1、搜索etcd3关联插件grpcio

       A)  下载相关包 https://pypi.org/project/grpcio/

       B)   进入homepage地址:https://grpc.io ,找到python相关:https://grpc.io/docs/quickstart/python.html,找到源码地址:https://github.com/grpc/grpc

      C)   在软件版本中找到关联插件包说明:https://github.com/grpc/grpc/blob/master/requirements.txt

             关联插件:coverage>=4.0 cython>=0.27 enum34>=1.0.4 protobuf>=3.5.0.post1 six>=1.10 wheel>=0.29


  2.2、搜索etcd3关联插件tenacity

   A) 下载相关包 https://pypi.org/project/tenacity/

   B) 进入homepage地址:https://github.com/jd/tenacity/

        C)关联插件包说明:https://github.com/jd/tenacity/blob/master/requirements.txt

              关联插件:six>=1.9.0 futures>=3.0;python_version=='2.7' monotonic>=0.6;python_version=='2.7'

 

  2.3、搜索etcd3关联插件protobuf


   A) 下载相关包 https://pypi.org/project/protobuf/

   B) 进入homepage地址https://developers.google.com/protocol-buffers/ 找到源码地址:https://github.com/google/protobuf/tree/master/python

   C) 确认无关联插件


   3、 搜索grpcio、tenacity关联插件....至确认无相关关联

 

   4、安装时,软件安装时诸如grpcio插件,作者在写pypi插件时,有些必要的软件包会及时提示,直接下载过来安装即可;

     但有些依赖性错误找不到方向,跟自己写代码一样,总有些写好了依赖,在交付时运行代码不一定检查,所以有必要结合源码的关联插件信息,诸如:

 gcc: error: src/python/grpcio/grpc/_cython/cygrpc.c: No such file or directory

gcc: fatal error: no input files

compilation terminated.

creating tmp/tmpe125oS

gcc -pthread -fno-strict-aliasing -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/usr/include/python2.7 -c /tmp/tmpe125oS/a.c -o tmp/tmpe125oS/a.o

Traceback (most recent call last):

  File "setup.py", line 310, in

    cmdclass=COMMAND_CLASS,

  File "/usr/lib64/python2.7/distutils/core.py", line 152, in setup

    dist.run_commands()

  File "/usr/lib64/python2.7/distutils/dist.py", line 953, in run_commands

    self.run_command(cmd)

  File "/usr/lib64/python2.7/distutils/dist.py", line 972, in run_command

    cmd_obj.run()

  File "/usr/lib/python2.7/site-packages/setuptools/command/install.py", line 73, in run

    self.do_egg_install()

  File "/usr/lib/python2.7/site-packages/setuptools/command/install.py", line 93, in do_egg_install

    self.run_command('bdist_egg')

  File "/usr/lib64/python2.7/distutils/cmd.py", line 326, in run_command

    self.distribution.run_command(command)

  File "/usr/lib64/python2.7/distutils/dist.py", line 972, in run_command

    cmd_obj.run()

  File "/usr/lib/python2.7/site-packages/setuptools/command/bdist_egg.py", line 185, in run

    cmd = self.call_command('install_lib', warn_dir=0)

  File "/usr/lib/python2.7/site-packages/setuptools/command/bdist_egg.py", line 171, in call_command

    self.run_command(cmdname)

  File "/usr/lib64/python2.7/distutils/cmd.py", line 326, in run_command

    self.distribution.run_command(command)

  File "/usr/lib64/python2.7/distutils/dist.py", line 972, in run_command

    cmd_obj.run()

  File "/usr/lib/python2.7/site-packages/setuptools/command/install_lib.py", line 20, in run

    self.build()

  File "/usr/lib64/python2.7/distutils/command/install_lib.py", line 111, in build

    self.run_command('build_ext')

  File "/usr/lib64/python2.7/distutils/cmd.py", line 326, in run_command

    self.distribution.run_command(command)

  File "/usr/lib64/python2.7/distutils/dist.py", line 972, in run_command

    cmd_obj.run()

  File "/usr/lib/python2.7/site-packages/setuptools/command/build_ext.py", line 52, in run

    _build_ext.run(self)

  File "/usr/lib64/python2.7/distutils/command/build_ext.py", line 339, in run

    self.build_extensions()

  File "/tmp/grpcio-1.12.0/src/python/grpcio/commands.py", line 297, in build_extensions

    "Failed `build_ext` step:\n{}".format(formatted_exception))

commands.CommandError: Failed `build_ext` step:

Traceback (most recent call last):

  File "/tmp/grpcio-1.12.0/src/python/grpcio/commands.py", line 292, in build_extensions

    build_ext.build_ext.build_extensions(self)

  File "/usr/lib64/python2.7/distutils/command/build_ext.py", line 448, in build_extensions

    self.build_extension(ext)

  File "/usr/lib/python2.7/site-packages/setuptools/command/build_ext.py", line 186, in build_extension

    _build_ext.build_extension(self,ext)

  File "/usr/lib64/python2.7/distutils/command/build_ext.py", line 498, in build_extension

    depends=ext.depends)

  File "/usr/lib64/python2.7/distutils/ccompiler.py", line 574, in compile

    self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)

  File "/usr/lib64/python2.7/distutils/unixccompiler.py", line 132, in _compile

    raise CompileError, msg

CompileError: command 'gcc' failed with exit status 4

   

 5、由于是将python插件直接copy至软件目录再import的方式使用,期间遇到类似这样的问题:

无grpc类等模块问题

ImportError: No module named grpc   

将site-packages的grpcio-1.12.0-py2.7-linux-x86_64.egg文件拷贝至存放第三方包目录下后用unzip解压出来即可

   unzip  grpcio-1.12.0-py2.7-linux-x86_64.egg 会解压出grpc目录,sys.path.append('第三方目录'),import grpc -->help() -->grpc查看对应类方法等


有类,方法不存在问题

Traceback (most recent call last):

  File "test.py", line 25, in

    import tuplesync

  File "/root/test/src/lcp/tuplesync.py", line 11, in

    import link_master as lm

  File "/root/test/src/lcp/link_master.py", line 26, in

    import etcd3

  File "/root/test/py_third/etcd3/__init__.py", line 3, in

    import etcd3.etcdrpc as etcdrpc

  File "/root/test/py_third/etcd3/etcdrpc/__init__.py", line 1, in

    from .rpc_pb2 import *

  File "/root/test/py_third/etcd3/etcdrpc/rpc_pb2.py", line 18, in

    from etcd3.etcdrpc import auth_pb2 as auth__pb2

  File "/root/test/py_third/etcd3/etcdrpc/auth_pb2.py", line 217, in

    import grpc

  File "/root/test/py_third/grpc/__init__.py", line 192, in

    class ChannelConnectivity(enum.Enum):

  File "/root/test/py_third/grpc/__init__.py", line 203, in ChannelConnectivity

    IDLE = (_cygrpc.ConnectivityState.idle, 'idle')

AttributeError: 'module' object has no attribute 'ConnectivityState'


这个问题比较困惑,毕竟软件包等都是安装成功的而且也能看到相关方法,后经同事提醒他之前安装需要拷贝一个pkg_resources的目录,然后去查了查,这个目录是用来管理ptyon插件信息的,于是将编译机的pkg_resources.py也拷贝至第三方包目录运行软件后一切正常,这个pkg_resources.py文件是setuptools-39.1.0生成的。

     

    5、在试验中,都通过了验证后,将流程串联起来。

         平台发起打包命令docker build  build-arg用于传递版本参数(区分打包版本),ftp密码(上传到对应内部yum源),ftp目录等(区分测试包、正式包)

         大概流程:

         角色:打包平台;jenkins任务;git代码仓库;特定打包机;yum源

         a、流水线平台界面操作,触发jenkins任务->拉取代码,执行特定脚本传递参数等

         b、jenkins任务在特定一台机上执行docker build,安装相关依赖,拉取内部代码,build成rpm包,上传到内部yum源

         在docker build的时候发现一个问题,纯手工操作,或者docker run个基础镜像后手动执行python插件安装一步步操作毫无问题;可是让自动build的grpcio总是提示CompileError: command 'gcc' failed with exit status 4,毫无头绪,后来先将grpcio相关依赖包很打了一个镜像B后,再执行安装grpcio插件也是如此;在镜像B的基础上验证测试无果后,随机重新安装了一次无相关的插件,再次执行安装grpcio就通过了;于是在docker build自动安装的过程中执行grpcio安装前,再执行一次其他插件的安装,这样编译就通过了,怀疑是插件未及时更新,但验证镜像B时所有的相关包都可以正常用python引用,神奇的问题。

   后记:

      本次自动安装python插件(先后顺序,dnspython重复)

      six-1.11.0

      setuptools-39.1.0

      dnspython-1.15.0

      ullib3-1.22

      pyDatalog-0.17.1

      pbr-4.0.3

      tenacity-4.12.0

      enum34-1.1.6

      monotonic-1.5

      futures-3.2.0

      protobuf-3.5.2

      dnspython-1.15.0

      grpcio-1.12.0

      etcd3-0.8.0