Python with docker 生產環境準備 – 初試啼聲

Python with docker 生產環境準備 – 初試啼聲

Docker Store上已經有提供許多指定版本的Python環境(連結)

因為對於Dockerfile自動化的不可掌控性高,因此我考慮先手動安裝過一次

相關步驟是:

在我本機linux vm的環境

1.安裝libray/python specific version image

bash進去

2.pip3 requirements.txt

3.創建對應app目錄,提供外部volumn掛載對應

4.加入執行語法啟動images除錯,直到排除環境因素(例如import相關平行目錄的module)

5.若正常,就commit一版,backup image到 dev server的vm 載入啟動

看看是否這樣可以無縫deploy~

 

首先先取得docker image

sudo docker pull python:3

依官網說明,python:3是3.5.3的版本(我開發是3.5.2,我猜不會有問題)

都抓好以後,啟動這個images bash進去看看

$ sudo docker run -i -t 955 bin/bash
root@46fe81cdc4b7:/#

Python 3.6.1 (default, Jul 8 2017, 05:00:20)
[GCC 4.9.2] on linux
Type “help”, “copyright”, “credits” or “license” for more information.
>>>

靠腰…怎麼是3.6.1的版本,應該是python:3.5版號才對…

重跑一次後,我發現,原來這個library/python的image也是透過組裝的方式集合而成,所以先前已經載過的linux核心(估計1xx MB)就不用再重新下載了

這一次跑的非常之快,進去後,看一下python -V,Python 3.5.3沒錯了

這個原生環境就有apt-get了,但若要裝一些像是nano 編輯器之類的,就要先apt-get update,否則會無法找到package

接著,我先透過requirements.txt安裝相關檔案

requirements.txt內容

grpcio==1.3.5
grpcio-tools==1.3.5
gevent==1.2.2
greenlet==0.4.12
WebHDFS==0.2.0
tornado==4.4.2
SQLAlchemy==1.1.10
cassandra-driver==3.10
pywebhdfs==0.4.1
urllib3==1.21.1
mysqlclient==1.3.10
python-memcached==1.58

若要執行一次套件安裝,就下以下指令

pip install –no-cache-dir -r requirements.txt

一般來說,linux原生環境是有分python2以及 python3,當執行pip的時候要分別走pip或pip3,否則會版本錯誤

同理,啟動程式的時候,也要決定是python or python3,而透過docker啟動的環境則python預設就會是你的版本,所以你這次要用python3也會找不到環境

同場加映,先前在同時有python2、python3的環境安裝套件的時候出現了錯誤訊息

Command “python setup.py egg_info” failed with error code 1 in /private/var/folders/r4/bkv_4t9s4r140pjkgv6lsq8w0000gn/T/pip-build-cdxcssp9/mysqlclient

因此需要安裝mysqlclient套件在python3上的話,請先執行:連結

sudo apt-get install python-dev python3-dev
sudo apt-get install libmysqlclient-dev
pip install pymysql
pip install mysqlclient

 

在這個安裝套件的過程中,cassandra-driver安裝的有點久,先耐心等候,以免前功盡棄…

全安裝好了以後,真的覺得這些環境準備的真的很佛心,讓我們真的不用考慮python2、3相容性的問題

接著快點存檔,把這個image commit記錄起來

sudo docker commit -m “python3.5 install requirements.txt” -a name ab8 python3-app:v1

 

接著就是要掛載我們的app程式來試試看

python-app目錄下有這些檔案,主要的檔案是在meso_collection_apiserver裡面

所以我預計啟動containner的指令如下:

sudo docker run  -it -v ~/python-app:/usr/src/app -p 40402:40402 8e2 python /usr/src/app/meso_collection_apiserver/servers/grpc_server.py

爆出來的Error明顯是Module參考問題

Traceback (most recent call last):
File “/usr/src/app/meso_collection_apiserver/servers/grpc_server.py”, line 25, in <module>
from meso_collection_apiserver.services.main_data_transfer_service import MainDataTransferService
ImportError: No module named ‘meso_collection_apiserver’

 

我們原始的程式是:

import sys
import time
from concurrent import futures

import grpc
from grpc._cython import cygrpc
meso_collection_apiserver.services.main_data_transfer_service import MainDataTransferService
from meso_utilities.models.entry_result_model import EntryResultModel
from meso_utilities.models.package_result_model import PackageResultModel
from meso_utilities.models.protos.datatransfer_pb2 import dataReply
from meso_utilities.models.protos.datatransfer_pb2_grpc import CollectionDataServicer, \
    add_CollectionDataServicer_to_server
....略

我google大神了一下,發現可以透過加入sys.path解決這個狀況

因此我在使用的module前面,加入了sys.path.append(“/usr/src/app”)

重新跑起來看看,終於跑起來了,即然可以跑,我們可以直接背景執行(改為-d)

sudo docker run -d -v ~/python-app:/usr/src/app -p 40402:40402 8e2 python /usr/src/app/meso_collection_apiserver/servers/grpc_server.py

但我立即測試發現無法通訊,看起來是ip binding的問題嗎?我猜想因為我程式binding在debug的時候綁的ip是localhost

因此我想到一招,就是透過/etc/hosts來綁定到指定的server name

def serve():
    server = grpc.server( futures.ThreadPoolExecutor( max_workers=1 ),
                          options=[(cygrpc.ChannelArgKey.max_receive_message_length, 100 * 1024 * 1024),
                                   (cygrpc.ChannelArgKey.max_send_message_length, 100 * 1024 * 1024)] )
    add_CollectionDataServicer_to_server( RPCService(), server )
    server.add_insecure_port( 'python-app-docker:40402' )

    server.start()
    try:
        while True:
            time.sleep( _ONE_DAY_IN_SECONDS )
    except KeyboardInterrupt:
        server.stop( 0 )

sudo docker -it exec /bin/bash

註:連到container後 ,先打入以下語法,以免不能使用nano

export TERM=xterm
root@c2a240882504:/# nano /etc/hosts

加入下面這行

172.17.0.5 python-app-docker

 

restart後,立即開啟rpc-client試連這個剛剛建立好的container的服務看看,結果還是失敗…telnet port還是被拒絕,看來在grpc這邊不論是server端還是client端,ip:port都還必須指定同樣具體的ip,且無法給定hostname,我還要再研究看看。直接先公佈解法其一,python程式段直接綁定docker container的ip,我們可以用python語法查找本機ip(連結)。這邊我陸陸續續試過幾組,若本機server、本機client,同一台主機的話是可以使用[::]:40402 ,若是隔一層的vm,那就指定到vm的ip,若是vm內又加一層docker,所以我們不可能每次都這樣調整程式,適必要動態取得本機ip,示例如下:

def serve():
    server = grpc.server( futures.ThreadPoolExecutor( max_workers=1 ),
                          options=[(cygrpc.ChannelArgKey.max_receive_message_length, 100 * 1024 * 1024),
                                   (cygrpc.ChannelArgKey.max_send_message_length, 100 * 1024 * 1024)] )
    add_CollectionDataServicer_to_server( RPCService(), server )
	import socket
	ip_address = socket.gethostbyname(socket.gethostname())
    server.add_insecure_port( '%s:40402' % ip_address )

    server.start()
    try:
        while True:
            time.sleep( _ONE_DAY_IN_SECONDS )
    except KeyboardInterrupt:
        server.stop( 0 )

這下跑一下grpc測試案例,終於通了

但是取得ip在vm的環境下有點小風險,若有多網卡的時候,還必須注意取到的介面是哪一張

不過至少這樣改寫後,ip在預設情況下是可以work的,離一鍵佈署,看起來愈來愈近了

今日時候不早了,待日後分曉

2 Replies to “Python with docker 生產環境準備 – 初試啼聲”

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *