Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
---
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" 폴더 안에 들어있다고 가정합니다. <b>참고</b>: 아래 구조는 하나의 예이고, 폴더이름 및 구조는 사용자 임의로 생성할 수 있습니다.
```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를 통해 입력받을 데이터로, <b>문자열</b>형태입니다. `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` 에서 어떻게 사용할지는 <b>전적으로 사용자 자유</b>입니다. 물론, 입력으로 오는 `x`의 형태와 그를 처리하는 방식이 <b>잘 맞아야만</b> 합니다. 또한, `main_func` 은 마지막 줄에 보이는 것처럼, <b>반드시 문자열</b>형태의 결과를 `return` 해야합니다.
아래에서 설명하는 모든 내용들은 `x` 가 Json 문자열이라고 가정하고 작성된 코드를 사용합니다.
### 3. main_func 수행 실험하기
`ksb.dockerize` 를 이용하기 전에 `main_func` 이 성공적으로 수행되는지 <b>반드시</b> 테스트되야 합니다. 이를 위해, "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 코드들을 수정해야합니다.
<b>참고</b>: 실험 중 발생하는 에러는 주로, 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")에 저장됩니다. <b>참고</b>: 이 기능은 실험중인 기능으로, 차후에 다른 형태로 변경될 수 있습니다.
### 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 문자열입니다.