--- html: toc: true offline: true export_on_save: html: true --- # Python 모듈 사용하기: KSB Dockerize --- `ksblib.dockerize` 라이브러리는 사용자가 프로그래밍한 Python 코드를 Docker 이미지로 자동변환하는 기능을 제공합니다. 또한 REST API 기능을 자동으로 추가하여, 사용자 Python 코드로 입력자료를 보내고 결과를 받을 수 있도록 해줍니다. ## 필요 라이브러리 - Python 3.5+ - Docker 18+ - 명령창에서 `docker` 명령어가 실행되는지 확인 ## 테스트 환경 - Ubuntu 16.04 및 Mac OS X - Windows 에서는 테스트되지 않음 ## 사용방법 ### 1. 설치하기 `ksblib.dockerize`를 설치하기 위해, KSB 프레임워크 소스코드 폴더 안의 "ksblib" 폴더로 이동해 아래 명령어를 입력합니다. ```sh $> python setup.py install ``` KSB 프레임워크가 설치되어있지 않다면 설치매뉴얼 (https://csleoss.etri.re.kr/kor/sub05_01.do)을 참고하여 KSB 프레임워크를 설치합니다. ### 2. base.py 와 main_func 생성하기 사용자 Python 코드들이 아래처럼 "modules" 폴더 안에 들어있다고 가정합니다. 참고: 아래 구조는 하나의 예이고, 폴더이름 및 구조는 사용자 임의로 생성할 수 있습니다. ```sh # Example of user-provided folder structure. -+ modules - __init__.py - base.py - requirements.txt - user_python_file_01.py - datafile01.pkl - ... -+ libraries - library01.py - ... ``` `ksb.dockerize` 라이브러리를 이용하기위해서는 반드시 두개의 파일이 "modules" 폴더 안에 들어있어야 합니다. 하나는 `__init__.py` 이고 다른 하나는 `base.py` 입니다. `__init.py__` 는 비어있는 Python 파일이어도 상관없습니다 . `base.py` 는 `main_func` 이라는 함수를 포함하고 있어야 합니다. 예를 들면 아래와 같습니다. `ksb.dockerize` 라이브러리는 이 `main_func` 을 불러 수행합니다. `x` 는 REST API를 통해 입력받을 데이터로, 문자열형태입니다. `x` 는 단순한 Python 문자열이어도 되고 (예: `'Hello World'`), 혹은 Json 문자열이어도 됩니다 (예: `'{"input": 4}'`). 아래 보이는 예제코드는 입력값 `x`가 Json 문자열이라고 가정하고 작성된 코드입니다. ```python import json def main_func(x): # In this example, x is Python string containing Json data. x = json.loads(x) input = x['input'] # Do some work with the input data. added_input = input + input # Return results in Python string type. return str(added_input) ``` 아래 코드는 `x` 가 단순 문자열이라고 가정하고 작성된 코드입니다. ```python def main_func(x): # In this example, x is Python string. input = x # Do some work with the input data. added_input = input + input # Return results in Python string type. return str(added_input) ``` `x` 를 어떤 형태로 정의하고, 이를 `main_func` 에서 어떻게 사용할지는 전적으로 사용자 자유입니다. 물론, 입력으로 오는 `x`의 형태와 그를 처리하는 방식이 잘 맞아야만 합니다. 또한, `main_func` 은 마지막 줄에 보이는 것처럼, 반드시 문자열형태의 결과를 `return` 해야합니다. 아래에서 설명하는 모든 내용들은 `x` 가 Json 문자열이라고 가정하고 작성된 코드를 사용합니다. ### 3. main_func 수행 실험하기 `ksb.dockerize` 를 이용하기 전에 `main_func` 이 성공적으로 수행되는지 반드시 테스트되야 합니다. 이를 위해, "modules"의 상위 폴더에서 Python console을 열고 (e.g. `$> python` 혹은 `$> ipython`), 아래와 같이 입력합니다. ```python from modules.base import main_func x = '{"input": 4}' main_func(x) ``` 작성한 `main_func` 이 에러없이 수행되도록 `main_func` 및 사용자 Python 코드들을 수정해야합니다. 참고: 실험 중 발생하는 에러는 주로, 1) 해당 모듈이 없다거나 혹은 2) 해당 파일이 없다는 에러일 것입니다. 두 에러 모두 기본적인 Python 프로그래밍 에러로, Google 검색을 통해 해결할 수 있습니다. 간단하게 예를 들면, - 해당 모듈이 없는 경우 `import` 시에 "modules" (즉, 최상위 폴더이름) 로부터 시작하면 대부분 해결됩니다. 즉, `from modules.xxx import xxx` 혹은 `import modules.xxx.xxx` 와 같은 식이 됩니다. - 해당 파일이 없는 경우 `os.path.dirname(__file__)` 을 파일경로 앞에 붙여주면 대부분 해결됩니다. ### 4. Docker 이미지 생성하기 위 과정까지 문제없이 끝났다면, 아래 Python 코드와 같이 `ksb.dockerize` 를 실행합니다. ```python from ksblib.dockerize import Dockerize drize = Dockerize('docker_image_name', '/path/to/modules', requirements=['numpy:scipy>=1.1.0'], user_args='any_string_values') drize.build() drize.run() ``` 위 명령어는 "modules" 폴더에 있는 Python 코드들을 Docker 이미지로 만듭니다. 폴더경로 (`/path/to/modules`) 는 절대경로입니다. 생성되는 이미지의 이름을 변경하려면 `docker_image_name` 를 바꾸면 됩니다. `ksblib.dockerize` 는 8080 포트로 REST API를 제공합니다. 다른 포트로 변경하려면, 마지막 줄을 `drize.run(port=9090)` 처럼 변경하면 됩니다. 사용자 Python 코드에서 사용하는 Python 라이브러리가 있다면 Docker 이미지 생성시에 `requirements` 옵션을 이용해 설치할 수 있습니다. 각각의 라이브러리는 `:` 로 구분하면 되며, 버전 정보도 명시할 수 있습니다. 라이브러리를 설치하는 또 다른 방법은, "modules" 폴더 안에 "requirements.txt" 파일을 생성하는 것입니다. "requirements.txt" 의 내용은 아래처럼 작성하면 됩니다. ```sh numpy scipy>=1.1.0 ``` `ksb.dockerize` 는 "requirements.txt" 안의 라이브러리를 먼저 설치하고, 그 후에 `requirements` 로 명시된 라이브러리들을 설치합니다. 따라서 동일한 라이브러리가 두 곳에 모두 명시되었다면, `requirements` 에 명시된 라이브러리가 최종설치됩니다. 만일 이미 생성된 Docker 이미지가 있고, 다시 만들고 싶지 않다면 위 예제 코드에서 `drize.build()` 부분을 주석처리하면 됩니다. #### 사용자 변수사용 만일, 특수한 이유로, 입력값 (예: `x`) 에 정보를 담아보내지 않고 따로 전달하고 싶은 파라미터가 있다면, `user_args` 를 사용하면 됩니다. `user_args` 로 전달된 문자열값은 Docker 이미지 생성시에 "ksb_user_args.pkl" 파일로 저장되며, "modules" 폴더에 위치한 Python 코드에서 읽어올 수 있습니다. 예를 들면: ```python # Any python script in the "modules" folder. def read_user_args(): import os import pickle # Read the pickle file. dir_name = os.path.dirname(__file__) user_args = pickle.load(open(os.path.join(dir_name, 'ksb_user_args.pkl'), 'rb')) return user_args ``` "ksb_user_args.pkl" 은 최상위 폴더 (이 예제에서는 "modules")에 저장됩니다. 참고: 이 기능은 실험중인 기능으로, 차후에 다른 형태로 변경될 수 있습니다. ### 5. 생성된 Docker 이미지 실험하기 위 과정에 따라 Docker 이미지가 성공적으로 만들어지고 실행되었다면, 아래처럼 실험해 볼 수 있습니다. ``` $> curl -d '{"input": 4}' http://localhost:8080 ``` 위 명령어를 실행하면, 아래와 같은 작업이 순차적으로 수행됩니다. 1. `curl` 명령어가 문자열 `'{"input": 4}'` 를 REST API를 통해 Docker image 로 전송 2. `ksb.dockerize` 가 입력값을 `main_func` 에 전달 3. `main_func` 이 문자열 `16` 을 반환 혹은, 아래처럼 Python 명령어를 이용해 테스트해볼 수도 있습니다. ```python import requests r = requests.post('http://localhost:8080', data='{"input": 4}') status_code = r.status_code response = r.text ``` 반환되는 값 `response` 의 형식은 Python 문자열입니다.