2020년 2월 27일 목요일

Konlpy 설치하기 (ppc64le 환경, AC922 서버)

한국어 분석용 KoNLPy(코엔엘파이) 패키지를 ppc64le 에 설치하기 위한 방법입니다.
http://konlpy.org/ko/latest/

해당 패키지는 아직 ppc64le용 Anaconda 채널에 포함되어 있지 않습니다. 따라서 pypi 사이트(https://pypi.org/)에서 제공하고 있는 whl 파일을 이용하여 설치해야 하는데, 설치 자체는 pip 명령어로 간단하게 수행할 수 있습니다.
다만, 이 패키지를 설치할때, JPype1 패키지도 필수로 필요한데, JPype1 패키지는 ppc64le용 whl도 제공되지 않고, 기본 Anaconda 채널에 포함되어 있지 않기 때문에 직접 소스코드를 빌드하고 설치하는 작업을 선행 후, KoNLPy 패키지를 설치해보겠습니다. (기타 요구 패키지는 Anaconda3 에서 conda install 명령어로 설치 가능하며, 구성 시 자동 설치됩니다.)

Konlpy whl 파일 다운로드 링크 https://files.pythonhosted.org/packages/85/0e/f385566fec837c0b83f216b2da65db9997b35dd675e107752005b7d392b1/konlpy-0.5.2-py2.py3-none-any.whl

JPype1 소스코드 다운로드 링크
https://files.pythonhosted.org/packages/d7/62/0f312d578e0165e9b5e8fcae0291f7ee83783b3805f59071006b21229d55/JPype1-0.7.1.tar.gz


아래 환경에서는 Python 3.6 사용자 기준으로 패키지를 빌드합니다.
먼저 Jpype1 패키지의 소스코드를 다운로드 받아서 서버에 올려둡니다.

[root@p625-kvm1 cecuser]# tar -xvf JPype1-0.7.1.tar.gz
[root@p625-kvm1 cecuser]# cd JPype1-0.7.1/

현재 사용하는 Python은 Anaconda3에 포함된 Python 3.6.9 버전이고, GCC 7.3.0 으로 빌드되어 있습니다. 따라서, JPype1 을 빌드할때도 gcc 7.3.0 버전 이상을 사용해주어야 합니다.

[root@p625-kvm1 JPype1-0.7.1]# /opt/anaconda3/bin/python
Python 3.6.9 |Anaconda, Inc.| (default, Jul 30 2019, 19:18:58)
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

제가 작업한 서버의 기본 환경은 gcc 버전이 4.8.5 입니다.
[root@p625-kvm1 cecuser]# gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

gcc 7.3.x 버전을 설치하기 위해서, 아래의 devtoolset을 설치합니다. 이후, 기본 PATH를 잠시 변경하여 gcc 7.3.x 버전이 먼저 사용되도록 합니다.
[root@p625-kvm1 JPype1-0.7.1]# yum install devtoolset-7-gcc-c++.ppc64le
[root@p625-kvm1 JPype1-0.7.1]# export PATH=/opt/rh/devtoolset-7/root/usr/bin:$PATH

[root@p625-kvm1 cecuser]# gcc --version
gcc (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

이제 Anaconda에 포함된 Python3으로 JPype1을 빌드합니다.
[root@p625-kvm1 JPype1-0.7.1]# /opt/anaconda3/bin/python setup.py build
/opt/anaconda3/lib/python3.6/distutils/dist.py:261: UserWarning: Unknown distribution option: 'use_scm_version'
  warnings.warn(msg)
running build

g++ -pthread -shared -B /opt/anaconda3/compiler_compat -L/opt/anaconda3/lib -Wl,-rpath=/opt/anaconda3/lib -Wl,--no-as-needed -Wl,--sysroot=/ build/temp.linux-ppc64le-3.6/build/src/jp_thunk.o build/temp.linux-ppc64le-3.6/native/common/jp_array.o build/temp.linux-ppc64le-3.6/native/common/jp_arrayclass.o build/temp.linux-ppc64le-3.6/native/common/jp_baseclasses.o build/temp.linux-ppc64le-3.6/native/common/jp_booleantype.o build/temp.linux-ppc64le-3.6/native/common/jp_boxedclasses.o build/temp.linux-ppc64le-3.6/native/common/jp_bytetype.o build/temp.linux-ppc64le-3.6/native/common/jp_chartype.o build/temp.linux-ppc64le-3.6/native/common/jp_class.o build/temp.linux-ppc64le-3.6/native/common/jp_classloader.o build/temp.linux-ppc64le-3.6/native/common/jp_doubletype.o build/temp.linux-ppc64le-3.6/native/common/jp_encoding.o build/temp.linux-ppc64le-3.6/native/common/jp_env.o build/temp.linux-ppc64le-3.6/native/common/jp_exception.o build/temp.linux-ppc64le-3.6/native/common/jp_field.o build/temp.linux-ppc64le-3.6/native/common/jp_floattype.o build/temp.linux-ppc64le-3.6/native/common/jp_inttype.o build/temp.linux-ppc64le-3.6/native/common/jp_jniutil.o build/temp.linux-ppc64le-3.6/native/common/jp_longtype.o build/temp.linux-ppc64le-3.6/native/common/jp_method.o build/temp.linux-ppc64le-3.6/native/common/jp_methodoverload.o build/temp.linux-ppc64le-3.6/native/common/jp_monitor.o build/temp.linux-ppc64le-3.6/native/common/jp_primitivetype.o build/temp.linux-ppc64le-3.6/native/common/jp_proxy.o build/temp.linux-ppc64le-3.6/native/common/jp_reference_queue.o build/temp.linux-ppc64le-3.6/native/common/jp_shorttype.o build/temp.linux-ppc64le-3.6/native/common/jp_stringclass.o build/temp.linux-ppc64le-3.6/native/common/jp_tracer.o build/temp.linux-ppc64le-3.6/native/common/jp_typemanager.o build/temp.linux-ppc64le-3.6/native/common/jp_value.o build/temp.linux-ppc64le-3.6/native/common/jp_voidtype.o build/temp.linux-ppc64le-3.6/native/python/jp_pythonenv.o build/temp.linux-ppc64le-3.6/native/python/jp_pythontypes.o build/temp.linux-ppc64le-3.6/native/python/jpype_memory_view.o build/temp.linux-ppc64le-3.6/native/python/pyjp_array.o build/temp.linux-ppc64le-3.6/native/python/pyjp_class.o build/temp.linux-ppc64le-3.6/native/python/pyjp_field.o build/temp.linux-ppc64le-3.6/native/python/pyjp_method.o build/temp.linux-ppc64le-3.6/native/python/pyjp_module.o build/temp.linux-ppc64le-3.6/native/python/pyjp_monitor.o build/temp.linux-ppc64le-3.6/native/python/pyjp_proxy.o build/temp.linux-ppc64le-3.6/native/python/pyjp_value.o -ldl -o build/lib.linux-ppc64le-3.6/_jpype.cpython-36m-powerpc64le-linux-gnu.so

위 메시지를 끝으로 빌드 완료됩니다. 빌드가 완료되었으니 설치를 해봅니다.

[root@p625-kvm1 JPype1-0.7.1]# /opt/anaconda3/bin/python setup.py install
creating dist
creating 'dist/JPype1-0.7.1-py3.6-linux-ppc64le.egg' and adding 'build/bdist.linux-ppc64le/egg' to it
removing 'build/bdist.linux-ppc64le/egg' (and everything under it)
Processing JPype1-0.7.1-py3.6-linux-ppc64le.egg
creating /opt/anaconda3/lib/python3.6/site-packages/JPype1-0.7.1-py3.6-linux-ppc64le.egg
Extracting JPype1-0.7.1-py3.6-linux-ppc64le.egg to /opt/anaconda3/lib/python3.6/site-packages
Adding JPype1 0.7.1 to easy-install.pth file

Installed /opt/anaconda3/lib/python3.6/site-packages/JPype1-0.7.1-py3.6-linux-ppc64le.egg
Processing dependencies for JPype1==0.7.1
Finished processing dependencies for JPype1==0.7.1

위와 같이 종료되면 현재 경로의 /opt/anaconda3 에 JPype1 이 잘 설치된 것입니다.
이제 konlpy를 whl파일로 설치합니다.

[root@p625-kvm1 cecuser]# pip install konlpy-0.5.2-py2.py3-none-any.whl
Processing ./konlpy-0.5.2-py2.py3-none-any.whl
Requirement already satisfied: JPype1>=0.7.0 in /opt/anaconda3/lib/python3.6/site-packages/JPype1-0.7.1-py3.6-linux-ppc64le.egg (from konlpy==0.5.2) (0.7.1)
Requirement already satisfied: colorama in /opt/anaconda3/lib/python3.6/site-packages (from konlpy==0.5.2) (0.3.9)
Requirement already satisfied: lxml>=4.1.0 in /opt/anaconda3/lib/python3.6/site-packages (from konlpy==0.5.2) (4.2.1)
Requirement already satisfied: beautifulsoup4==4.6.0 in /opt/anaconda3/lib/python3.6/site-packages (from konlpy==0.5.2) (4.6.0)
Requirement already satisfied: tweepy>=3.7.0 in /opt/anaconda3/lib/python3.6/site-packages (from konlpy==0.5.2) (3.8.0)
Requirement already satisfied: numpy>=1.6 in /opt/anaconda3/lib/python3.6/site-packages (from konlpy==0.5.2) (1.17.2)
Requirement already satisfied: requests-oauthlib>=0.7.0 in /opt/anaconda3/lib/python3.6/site-packages (from tweepy>=3.7.0->konlpy==0.5.2) (1.3.0)
Requirement already satisfied: PySocks>=1.5.7 in /opt/anaconda3/lib/python3.6/site-packages (from tweepy>=3.7.0->konlpy==0.5.2) (1.6.7)
Requirement already satisfied: requests>=2.11.1 in /opt/anaconda3/lib/python3.6/site-packages (from tweepy>=3.7.0->konlpy==0.5.2) (2.22.0)
Requirement already satisfied: six>=1.10.0 in /opt/anaconda3/lib/python3.6/site-packages (from tweepy>=3.7.0->konlpy==0.5.2) (1.12.0)
Requirement already satisfied: oauthlib>=3.0.0 in /opt/anaconda3/lib/python3.6/site-packages (from requests-oauthlib>=0.7.0->tweepy>=3.7.0->konlpy==0.5.2) (3.1.0)
Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /opt/anaconda3/lib/python3.6/site-packages (from requests>=2.11.1->tweepy>=3.7.0->konlpy==0.5.2) (1.24.2)
Requirement already satisfied: certifi>=2017.4.17 in /opt/anaconda3/lib/python3.6/site-packages (from requests>=2.11.1->tweepy>=3.7.0->konlpy==0.5.2) (2019.9.11)
Requirement already satisfied: idna<2.9,>=2.5 in /opt/anaconda3/lib/python3.6/site-packages (from requests>=2.11.1->tweepy>=3.7.0->konlpy==0.5.2) (2.6)
Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /opt/anaconda3/lib/python3.6/site-packages (from requests>=2.11.1->tweepy>=3.7.0->konlpy==0.5.2) (3.0.4)
Installing collected packages: konlpy
Successfully installed konlpy-0.5.2

conda 명령어로 확인해보면, konlpy 가 설치되어 있음을 보실수 있습니다.
[root@p625-kvm1 cecuser]# conda list | grep konlpy
konlpy                    0.5.2                    pypi_0    pypi

konlpy 를 제대로 실행하기 위해, 우선 java-1.8.0-openjdk 가 설치되어있는지 확인해야 합니다. 만약 설치되어 있지 않으면, 아래 명령어로 설치합니다.

[root@p625-kvm1 ~]# yum install java-1.8.0-openjdk-devel.ppc64le
==============================================================================================
 Package                     Arch    Version                 Repository                  Size
==============================================================================================
Installing:
 java-1.8.0-openjdk-devel    ppc64le 1:1.8.0.222.b10-0.el7_6 local-rhn-server-os        7.9 M
Installing for dependencies:
 giflib                      ppc64le 4.1.6-9.el7             local-rhn-server-iso-media  41 k
 java-1.8.0-openjdk          ppc64le 1:1.8.0.222.b10-0.el7_6 local-rhn-server-os        266 k
 java-1.8.0-openjdk-headless ppc64le 1:1.8.0.222.b10-0.el7_6 local-rhn-server-os         31 M
 libICE                      ppc64le 1.0.9-9.el7             local-rhn-server-iso-media  67 k
 libSM                       ppc64le 1.2.2-2.el7             local-rhn-server-iso-media  39 k
 libfontenc                  ppc64le 1.1.3-3.el7             local-rhn-server-iso-media  32 k
 lksctp-tools                ppc64le 1.0.17-2.el7            local-rhn-server-iso-media  89 k
 pcsc-lite-libs              ppc64le 1.8.8-8.el7             local-rhn-server-iso-media  36 k
 ttmkfdir                    ppc64le 3.0.9-42.el7            local-rhn-server-iso-media  49 k
 tzdata-java                 noarch  2019b-1.el7             local-rhn-server-os        187 k
 xorg-x11-font-utils         ppc64le 1:7.5-21.el7            local-rhn-server-iso-media 108 k
 xorg-x11-fonts-Type1        noarch  7.5-9.el7               local-rhn-server-iso-media 521 k

(위 파일들이 설치됨)

[root@p625-kvm1 ~]# java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (build 1.8.0_222-b10)
OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)

이제 Python을 실행하여 konlpy 를 이용해봅니다.
[root@p625-kvm1 ~]# /opt/anaconda3/bin/python
Python 3.6.9 |Anaconda, Inc.| (default, Jul 30 2019, 19:18:58)
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from konlpy.tag import Kkma
>>> from konlpy.utils import pprint
>>> kkma=Kkma()
>>> pprint(kkma.sentences(u'네, 안녕하세요. 반갑습니다.'))
['네, 안녕하세요.', '반갑습니다.']
>>> pprint(kkma.nouns(u'질문이나 건의사항은 깃헙 이슈 트래커에 남겨주세요.'))
['질문', '건의', '건의사항', '사항', '깃헙', '이슈', '트래커']

이제 Konlpy를 사용하기 위한 준비가 되었습니다. 자세한 가이드는 Konlpy를 참조하여 사용하시면 됩니다. http://konlpy.org/ko/latest/

2020년 2월 9일 일요일

LSF-Kubernetes Integration 테스트하기 (Option #2)

최근 IBM Spectrum LSF의 서비스팩 9 버전이 나왔습니다. 이 버전에는 이전부터 Github를 통해 Technical Preview 형태로 테스트하고 있었던, LSF-Kubernetes Integration을 위한 기능이 공식적으로 포함되어 있습니다.

LSF-Kubernetes를 어떻게 함께 쓸 수 있는 지에 대해서, 아래의 Github을 살펴보시면 두가지 배포 형태로 정의하여 설명하고 있습니다.
https://github.com/IBMSpectrumComputing/lsf-kubernetes/

Option #1. LSF as a scheduler for ICP/Kubernetes

기존에 Kubernetes를 사용하던 환경에서, Kubernetes의 스케쥴링 기능을 강화시키는 목적으로 LSF의 스케쥴링 기능을 차용하는 형태의 Integration 방안입니다. IBM Cloud Private과 같은 Kubernetes distribution을 사용하는 경우나, 기타 다른 K8S 기반 오케스트레이터(ex. Openshift)에서도 사용하실 수 있습니다. 
위 Github에서는 기본적으로 Openshift를 사용하도록 권고하고 있습니다. Spectrum Computing Cloud PAK 을 함께 설치하여, 클러스터내에서 포함하고 있는 LSF agent를 활성화시키는 방법을 소개합니다.
* 2020/02/10 현재까지 Technical Preview 버전으로 제공중입니다.

Option #2. Kubernetes add-on for LSF

다음 방법은 기존 IBM Spectrum LSF 기반의 On-premise Cluster 환경을 사용하는 고객이 LSF Native 환경을 그대로 사용하면서, 클러스터 내의 일부 영역을 K8S로 운영하고자 하는 경우, 이를 지원하는 방법입니다. 사용자는 LSF 명령어(bsub) 혹은 K8S에서의 Job 제출(YAML)을 모두 수행할 수 있으며, 수행된 작업은 관리자에 의하여 LSF/K8S 양측에서 모두 모니터링됩니다.
* LSF 10.1.0.9 버전부터 LSF connector for Kubernetes를 공식 지원하고 있습니다.

------------------------------------------------------------------

아래에서는 Deployment Option #2 를 구축하는 방법을 소개합니다.

저는 테스트 환경을 구성할 예정이므로, all-in-one 으로 GPU가 장착된 Baremetal 서버 1대로 구성합니다. 우선 아래의 환경이 기본으로 설정되어 있어야 합니다.

- 기본 NVIDIA driver 설정 및 Docker Engine 설치
- Kubernetes distribution 설치 (아래 테스트 에서는 IBM Cloud Private(ICP) 3.2.1 버전을 설치해서 사용) 및 kubectl 명령어 사용 가능 환경
- LSF Standard edition 설치 (Suite 버전도 K8S integration 지원)


* 위 각각을 수행하는 방법은 별도 포스팅으로 링크를 걸어두겠습니다.
* 테스트 환경 (IBM Power AC922 서버, V100 GPU 4개, Redhat 7.6, CUDA 10.0)

LSF connector for kubernetes 수행 방법은 아래 링크를 보시면, IBM Knowledge center에 나와있습니다.

LSF가 구성된 환경을 확인합니다. 서버에는 LSF-K8S integration 이 지원되는 10.1.0.9 버전이 이미 설치되어 있습니다.

[root@p613-met1 ~]# lsid
IBM Spectrum LSF Standard 10.1.0.9, Oct 16 2019
Copyright International Business Machines Corp. 1992, 2016.
US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedul

My cluster name is cluster1
My master name is p613-met1
[root@p613-met1 ~]# lshosts
HOST_NAME      type    model  cpuf ncpus maxmem maxswp server RESOURCES
p613-met1   LINUXPP   POWER9  25.0    40 637.1G   3.9G    Yes (mg)
[root@p613-met1 ~]# bhosts
HOST_NAME          STATUS       JL/U    MAX  NJOBS    RUN  SSUSP  USUSP    RSV
p613-met1          ok              -     40      0      0      0      0      0

LSF가 설치되면, $LSF_BINDIR/../../misc/kubernetes 경로에 병렬 작업을 위한 CRD(Custom Resource Definition) 템플릿 파일이 미리 정의되어 있습니다. 이를 이용하여 관련 내용을 구성합니다. (parallelJob-v1alpha1.yaml)

[root@p613-met1 ~]# echo $LSF_BINDIR
/usr/share/lsf/10.1/linux3.10-glibc2.17-ppc64le/bin
[root@p613-met1 ~]# kubectl create -f $LSF_BINDIR/../../misc/kubernetes/parallelJob-v1alpha1.yaml
customresourcedefinition.apiextensions.k8s.io/paralleljobs.ibm.com created

이후, LSF의 각 설정 파일을 수정하여 GPU 및 Kubernetes를 인식하게끔 합니다.
lsf.conf 파일에 아래 내용을 새로 추가해줍니다.
[root@p613-met1 ~]# vi /usr/share/lsf/conf/lsf.conf
# kubernetes
LSB_KUBE_ENABLE=Y
LSF_ENABLE_EXTSCHEDULER=Y
LSB_KUBE_CONFIG=/usr/share/lsf/conf/kubernetes.config
LSB_MAX_PACK_JOBS=500
LSB_GPU_NEW_SYNTAX=extend
LSF_GPU_AUTOCONFIG=Y

lsb.modules에서 kubernetes 항목을 활성화 시킵니다.
[root@p613-met1 ~]# vi /usr/share/lsf/conf/lsbatch/cluster1/configdir/lsb.modules
schmod_kubernetes              ()                              ()

lsb.resources에서 gpu를 task별 할당 가능한 리소스 항목으로 추가합니다.
[root@p613-met1 ~]# vi /usr/share/lsf/conf/lsbatch/cluster1/configdir/lsb.resources
Begin ReservationUsage
RESOURCE             METHOD        RESERVE
ngpus_physical       PER_TASK      N
End ReservationUsage
END
lsb.params에서 아래 항목을 설정(없으면 추가)합니다.
[root@p613-met1 ~]# vi /usr/share/lsf/conf/lsbatch/cluster1/configdir/lsb.params
RELAX_JOB_DISPATCH_ORDER = N # enable relaxed job dispatch order in the cluster
MAX_USER_PRIORITY=1000

/etc/lsf.sudoers 파일에 lsfadmin을 LSB_IMPERSONATION_USERS로 추가합니다.
[root@p613-met1 ~]# echo 'LSB_IMPERSONATION_USERS="lsfadmin"' > /etc/lsf.sudoers
[root@p613-met1 ~]# chown root /etc/lsf.sudoers
[root@p613-met1 ~]# chmod 500 /etc/lsf.sudoers

lsf.shared 파일의 kubernetes 항목을 활성화 시킵니다.
[root@p613-met1 ~]# vi /usr/share/lsf/conf/lsf.shared
  kubernetes    Boolean    ()       ()       (Kubernetes node)

lsf.cluster.cluster이름 파일에서, 마스터 서버(mg)를 kubernetes mg 로 설정합니다.
[root@p613-met1 ~]# vi /usr/share/lsf/conf/lsf.cluster.cluster1
p613-met1   !   !   1   (kubernetes mg)

LSF 패키지 설치 시 기본으로 내장되어 있는 예제 템플릿 파일을 /usr/share/lsf/conf/lsbatch/cluster1/configdir/kube-template.yaml 경로에 copy합니다.
kube-template.yaml 파일은 추후 사용자가 Pod을 생성 시, 기본 적용되는 metadata, namespace, container image 등의 정보가 적용되어 있는 템플릿으로 사용됩니다. 따라서, 이후 내부의 내용을 적합하게 변경해주어야 합니다.

[root@p613-met1 ~]# cp $LSF_BINDIR/../../misc/kubernetes/example-template.yaml /usr/share/lsf/conf/lsbatch/cluster1/configdir/kube-template.yaml

lsb.applications 를 수정하여, 새로운 Application "kube"를 정의합니다. bsub으로 job 제출 시, -app 옵션으로 사용할 수 있는 어플리케이션이 정의됩니다. (-app kube)
CONTAINER는 위에서 복사한 kube-template.yaml 파일 경로를 지정하여, 해당 텡ㅁ플릿 내에 포함된 기본 컨테이너 이미지가 사용되도록 합니다. 사용자가 다양한 컨테이너 이미지 사용을 요구하는 경우, app 을 여러개 정의하여 각기 다른 템플릿 파일을 mapping 시킬 수 있습니다.
[root@p613-met1 lsf]# vi /usr/share/lsf/conf/lsbatch/cluster1/configdir/lsb.applications
Begin Application
NAME = kube
DESCRIPTION = K8S job container
CONTAINER = kubernetes[template(/usr/share/lsf/conf/lsbatch/cluster1/configdir/kube-template.yaml)]
End Application
[root@p613-met1 configdir]# chown lsfadmin /usr/share/lsf/conf/lsbatch/cluster1/configdir/kube-template.yaml

LSF의 구성 관련 내용을 모두 변경하였으므로, LSF modules을 재구성/재시작합니다.
[root@p613-met1 lsf]# lsadmin reconfig
[root@p613-met1 lsf]# badmin reconfig
[root@p613-met1 lsf]# badmin mbdrestart

(LSF가 down되어 있었던 경우)
[root@p613-met1 lsf]# lsadmin limstartup
Starting up LIM on <p613-met1> ...... done
[root@p613-met1 lsf]# lsadmin resstartup
Starting up RES on <p613-met1> ...... done
[root@p613-met1 lsf]# badmin hstartup
Starting up slave batch daemon on <p613-met1> ...... done

여기까지 구성이 되면, 아래와 같이 LSF cluster에서 GPU 리소스를 자동으로 감지할 수 있습니다.

p613-met1 서버에 장착된 4개의 V100 GPU 정보가 자동 감지됩니다.
[root@p613-met1 conf]# bhosts -gpu
HOST_NAME              ID           MODEL     MUSED      MRSV  NJOBS    RUN   SUSP    RSV
p613-met1               0 TeslaV100_SXM2_       61M        0M      0      0      0      0
                        1 TeslaV100_SXM2_       32M        0M      0      0      0      0
                        2 TeslaV100_SXM2_       33M        0M      0      0      0      0
                        3 TeslaV100_SXM2_       32M        0M      0      0      0      0

또한 p613-met1 서버는 kubernetes 동작 가능한 서버로 확인됩니다.
[root@p613-met1 conf]# lshosts
HOST_NAME      type    model  cpuf ncpus maxmem maxswp server RESOURCES
p613-met1   LINUXPP   POWER9  25.0    40 637.1G   3.9G    Yes (mg kubernetes)

-bash-4.2$ bhosts -R kubernetes
HOST_NAME          STATUS       JL/U    MAX  NJOBS    RUN  SSUSP  USUSP    RSV
p613-met1          ok              -     40      0      0      0      0      0

새로 정의한 kube라는 이름의 application 도 확인됩니다.
[root@p613-met1 conf]# bapp -l kube

APPLICATION NAME: kube
-- K8S job container

STATISTICS:
   NJOBS     PEND      RUN    SSUSP    USUSP      RSV
       0        0        0        0        0        0

PARAMETERS:

CONTAINER: kubernetes[template(/usr/share/lsf/conf/lsbatch/cluster1/configdir/kube-template.yaml)]


이제 Kubernetes에서 LSF가 사용할 Namespace, Service account 등을 자동 스크립트를 이용하여 생성해줍니다. 설치된 LSF 내부에 이미 create-lsf-k8s-config.sh 이 포함되어 있습니다. 이 shell은 "./create-lsf-k8s-config.sh create <custom namespace> <custom serviceaccount>" 로 실행시킬 수 있으며, 새로 생성할 namespace, service account를 정해주지 않으면 기본으로 mylsfns, mylsfsa가 생성됩니다. (또한 위의 kube-template.yaml 파일도 namespace, service account 등이 기본 mylsfns, mylsfsa로 이미 정의되어 있으므로, 다른 이름으로 임의 생성시에는 템플릿의 내용도 동일하게 변경해주어야 합니다.)

[root@p613-met1 lsf]# cd /usr/share/lsf/10.1/misc/kubernetes
[root@p613-met1 kubernetes]# ./create-lsf-k8s-config.sh create mylsfns mylsfsa

User "mylsfsa" set.
Running: kubectl config --kubeconfig=kubernetes.config set-context forlsf --cluster=kubernetes --namespace=mylsfns --user=mylsfsa
Context "forlsf" created.
Running: kubectl config --kubeconfig=kubernetes.config use-context forlsf
Switched to context "forlsf".
The Kubernetes configuration file has been generated and named kubernetes.config
Copy this file to the LSF conf directory, typically $LSF_ENVDIR
Change the file permissions to 400, and owned by the LSF administrator, typically lsfadmin.

*********************************************************************
NOTE: THIS FILE MUST BE PROTECTED.  IT PROVIDES ACCESS TO
      KUBERNETES RESOURCES MOST USERS SHOULD NOT HAVE!
*********************************************************************

----------------------------------------------------------------------------------------
간혹, create-lsf-k8s-config.sh로 create 구성을 했음에도, 추후 pod 생성 등에서 제대로 동작이 안되는 경우가 있습니다.(이미 동일한 SA, NS가 있는 경우 등)
Service account(SA), Namespace(NS) 생성 및 이들간의 config map 등이 제대로 생성되지 않아서 그런 경우가 있는데, 이럴 때에는 아래의 명령어로 기존 생성한 SA, NS를 삭제하고 재생성 합니다. 

[root@p613-met1 kubernetes]# ./create-lsf-k8s-config.sh delete
---- Delete Clusterrolebindings and ClusterRole ----
clusterrole.rbac.authorization.k8s.io "ibm-lsf-cr" deleted
clusterrolebinding.rbac.authorization.k8s.io "ibm-lsf-crb" deleted
clusterrolebinding.rbac.authorization.k8s.io "ibm-lsf-kubesched-crb" deleted
---- Deleting Service account "mylsfsa" in namespace "mylsfns" ----
serviceaccount "mylsfsa" deleted
---- Deleting namespace "mylsfns" ----
namespace "mylsfns" deleted
-----------------------------------------------------------------------------------------

create-lsf-k8s-config.sh 로 관련 설정을 생성하고 나면, /usr/share/lsf.10.1/misc/kubernetes 경로에 kubernetes.config 파일이 생성됩니다. 이 파일을 /usr/share/lsf/conf 로 copy하고, lsfadmin 이 사용할 수 있도록 권한을 변경합니다. 해당 파일은 lsf 와 kubernetes 간의 구성정보를 포함하고 있습니다.

[root@p613-met1 lsf]# ls -al /usr/share/lsf/10.1/misc/kubernetes/kubernetes.config
-rw-------. 1 root root 1510 Feb  5 05:40 /usr/share/lsf/10.1/misc/kubernetes/kubernetes.config
[root@p613-met1 lsf]# cp /usr/share/lsf/10.1/misc/kubernetes/kubernetes.config /usr/share/lsf/conf
[root@p613-met1 lsf]# chown lsfadmin /usr/share/lsf/conf/kubernetes.config
[root@p613-met1 lsf]# chmod 400 /usr/share/lsf/conf/kubernetes.config

변경내용을 lsf에 적용합니다.
[root@p613-met1 conf]# lsadmin reconfig
[root@p613-met1 conf]# badmin reconfig
[root@p613-met1 conf]# badmin mbdrestart

문제가 발생할 경우, 관련된 로그들은 아래의 경로에서 확인합니다.
[root@p613-met1 conf]# ls -al /usr/share/lsf/log/
total 40
drwxr-xr-x. 2 lsfadmin root         4096 Feb  5 05:58 .
drwxr-xr-x. 8 root     root         4096 Feb  4 20:37 ..
-rw-r--r--. 1 lsfadmin domain users 3600 Feb  5 06:24 batch-driver.log
-rw-r--r--. 1 lsfadmin root         2505 Feb  5 06:23 lim.log.p613-met1
-rw-r--r--. 1 lsfadmin root         8533 Feb  5 06:25 mbatchd.log.p613-met1
-rw-r--r--. 1 lsfadmin domain users 1818 Feb  5 06:24 mbschd.log.p613-met1
-rw-r--r--. 1 lsfadmin root            0 Feb  4 20:41 pim.log.p613-met1
-rw-rw-rw-. 1 lsfadmin root          956 Feb  5 06:02 res.log.p613-met1
-rw-r--r--. 1 lsfadmin root         1117 Feb  5 06:02 sbatchd.log.p613-met1


실제 gpu를 사용하는 작업의 동작 테스트를 해보기 전, 아래의 내용을 추가로 수정해줍니다.
  1. ICP 콘솔 메뉴 상에서 리소스 보안 -> 이미지 정책 -> 이미지 정책 작성으로 lsf namespace에서 사용할수 있는 정책을 만들어줍니다. 테스트 용으로 사용할 docker image가 public docker hub에 위치한다면, 아래의 이미지 정책 작성 시 해당 docker registry 정보를 추가해주어야 합니다.
     예) 이름 : mylsfimgpol, 네임스페이스 : mylsfns, 범위 : 네임스페이스, 레지스트리 정책(레지스트리 추가 : docker.io/*)
    * 만약 ICP를 사용하는 것이 아니라, 기타 K8S distribution를 사용하는 경우, Image policy 를 각 distribution에서 제공하는 방법으로 작성해주어야 합니다.
  2. 이미 생성된 /usr/share/lsf/conf/lsbatch/cluster1/configdir/kube-template.yaml 파일을 열어서, Namespace 및 image 관련 내용을 수정해줍니다. 별도의 Custom namespace를 지정해준 경우 해당 이름으로 변경하고, image는 bsub 제출 시, 기본으로 불러올 컨테이너 image 이름 및 태그를 설정합니다. 아래 예제에서는 Public docker hub(docker.io)에서 제공하는 nvidia/cuda-ppc64le:10.1-base-centos7 이미지를 사용합니다.
      namespace: mylsfns
        image: nvidia/cuda-ppc64le:10.1-base-centos7



이제 실제로 gpu를 사용하는 작업을 LSF에 제출할때, 서버에 장착된 GPU 서버 수량 이상으로 요구되는 작업이 어떻게 처리되는지, 관련하여 Pod이 생성되는 지 등을 테스트합니다.

현재의 테스트 서버는 별도 사용자를 생성해두지 않았으므로, lsfadmin 계정으로 변경하여 bsub을 수행합니다. 간단한 sleep 30 명령어를 실행하되, 각 Job은 GPU 2개를 exclusive process mode로 요구합니다. 아래의 테스트는 GPU가 4개 있는 서버 1대에서, GPU를 2개씩 요구하는 sleep job을 3개 제출한 후, 1개 job이 대기하는지 확인합니다. 

[root@p613-met1 conf]# su lsfadmin
bash-4.2$ bsub -gpu "num=2:mode=exclusive_process" sleep 30
bash-4.2$ bsub -gpu "num=2:mode=exclusive_process" sleep 30
bash-4.2$ bsub -gpu "num=2:mode=exclusive_process" sleep 30

2개의 작업은 GPU를 할당받을 수 있으므로 RUN 상태로 수행되고, 나머지 1개 작업은 PEND 상태로 대기합니다.
bash-4.2$ bjobs
JOBID   USER    STAT  QUEUE      FROM_HOST   EXEC_HOST   JOB_NAME   SUBMIT_TIME
102     lsfadmi RUN   normal     p613-met1   p613-met1   sleep 30   Feb  5 06:34
103     lsfadmi RUN   normal     p613-met1   p613-met1   sleep 30   Feb  5 06:34
104     lsfadmi PEND  normal     p613-met1               sleep 30   Feb  5 06:34

이제  ICP를 통해 테스트 해보기 위해, 간단한 docker 이미지 하나를 pull 합니다. (위의 kube-template.yaml 파일에서 미리 정의했던 Container image입니다.)
[root@p613-met1 conf]# docker pull nvidia/cuda-ppc64le:10.1-base-centos7
Status: Downloaded newer image for nvidia/cuda-ppc64le:10.1-base-centos7

작업 제출 시, -app 옵션으로 kube을 설정하면, 앞서 설정해둔 kube-template.yaml 파일에 정의된 컨테이너 환경을 호출하여 Pod을 생성, 요청한 작업을 실행하게 됩니다. sleep 1 을 실행하여, 실제 컨테이너가 동작하는지를 확인합니다.

-bash-4.2$ bsub -app kube sleep 1
-bash-4.2$ bjobs -l 222
Job <222>, User <lsfadmin>, Project <default>, Application <kube>, Status <DONE
                     >, Queue <normal>, Job Priority <500>, Command <sleep 1>,
                     Share group charged </lsfadmin>
Wed Feb  5 08:39:06: Submitted from host <p613-met1>, CWD </usr/share/lsf/10.1/
                     misc/kubernetes>;
Wed Feb  5 08:39:10: Dispatched 1 Task(s) on Host(s) <p613-met1>, Allocated 1 S
                     lot(s) on Host(s) <p613-met1>, Execution Home <VirtualHome
                     >, Execution CWD </usr/share/lsf/10.1/misc/kubernetes>;
Wed Feb  5 08:39:24: Done successfully. The CPU time used is 0.0 seconds.
 SCHEDULING PARAMETERS:
           r15s   r1m  r15m   ut      pg    io   ls    it    tmp    swp    mem
 loadSched   -     -     -     -       -     -    -     -     -      -      -
 loadStop    -     -     -     -       -     -    -     -     -      -      -
 EXTERNAL MESSAGES:
 MSG_ID FROM       POST_TIME      MESSAGE                             ATTACHMENT
 132    _system_   Feb  5 08:39   Pods names set for job                  N
 133    _system_   Feb  5 08:39   Pod manifests generated                 Y
 134    _system_   Feb  5 08:39   Pod allocation ready for binding        N
 135    _system_   Feb  5 08:39   Pod status                              N
 RESOURCE REQUIREMENT DETAILS:
 Combined: select[type == local] order[r15s:pg]
 Effective: select[type == local] order[r15s:pg]
 KUBERNETES:
 NAMESPACE  POD                     PHASE      NODE       GPU
 mylsfns    lsf-cluster1-222-0-0-0  Succeeded  p613-met1  -

위의 작업 정보를 확인해보면, -app kube로 제출한 작업이므로, 미리 정의한 mylsfns 라는 Namespace에 lsf-cluster1-222-0-0-0 이름으로 Pod이 생성되고 실행되는 것을 볼 수 있습니다.

이번에는 kubernetes로 작업을 제출하되, GPU 할당이 되는지 테스트해봅니다.
각 작업은 sleep 5 명령어를 수행하되, -app kube 옵션을 설정하고 -gpu 로 2개씩 gpu를 할당하도록 합니다. 이러한 작업을 동시에 5개 제출하여, 3개 Job이 대기하는지 확인합니다.
-bash-4.2$ bsub -app kube -gpu "num=2:mode=exclusive_process" sleep 5
-bash-4.2$ bsub -app kube -gpu "num=2:mode=exclusive_process" sleep 5
-bash-4.2$ bsub -app kube -gpu "num=2:mode=exclusive_process" sleep 5
-bash-4.2$ bsub -app kube -gpu "num=2:mode=exclusive_process" sleep 5
-bash-4.2$ bsub -app kube -gpu "num=2:mode=exclusive_process" sleep 5

2개의 작업은 GPU를 할당받을 수 있으므로 즉각 배치되고, 나머지는 PEND 됩니다.
-bash-4.2$ bjobs
JOBID   USER    STAT  QUEUE      FROM_HOST   EXEC_HOST   JOB_NAME   SUBMIT_TIME
224     lsfadmi RUN   normal     p613-met1   p613-met1   sleep 5    Feb  5 08:48
225     lsfadmi RUN   normal     p613-met1   p613-met1   sleep 5    Feb  5 08:48
226     lsfadmi PEND  normal     p613-met1               sleep 5    Feb  5 08:48
227     lsfadmi PEND  normal     p613-met1               sleep 5    Feb  5 08:48
228     lsfadmi PEND  normal     p613-met1               sleep 5    Feb  5 08:48

아래 RUN으로 실행중인 작업의 정보를 확인해봅니다. 기본 정의된 Queue, Job Priority 에 따라서 작업이 배치되었습니다. 이러한 상세 배치 조건들은 kube-template.yaml에 미리 정의하여 변경할 수 있습니다. 
-bash-4.2$ bjobs -l 226
Job <226>, User <lsfadmin>, Project <default>, Application <kube>, Status <RUN>
                     , Queue <normal>, Job Priority <500>, Command <sleep 5>, S
                     hare group charged </lsfadmin>
Wed Feb  5 08:48:32: Submitted from host <p613-met1>, CWD </usr/share/lsf/10.1/
                     misc/kubernetes>, Requested GPU <num=2:mode=exclusive_proc
                     ess>;
Wed Feb  5 08:48:58: Dispatched 1 Task(s) on Host(s) <p613-met1>, Allocated 1 S
                     lot(s) on Host(s) <p613-met1>, Execution Home <VirtualHome
                     >, Execution CWD </usr/share/lsf/10.1/misc/kubernetes>;
 SCHEDULING PARAMETERS:
           r15s   r1m  r15m   ut      pg    io   ls    it    tmp    swp    mem
 loadSched   -     -     -     -       -     -    -     -     -      -      -
 loadStop    -     -     -     -       -     -    -     -     -      -      -
 EXTERNAL MESSAGES:
 MSG_ID FROM       POST_TIME      MESSAGE                             ATTACHMENT
 0      lsfadmin   Feb  5 08:48   p613-met1:gpus=1,2;                     N
 132    _system_   Feb  5 08:48   Pods names set for job                  N
 133    _system_   Feb  5 08:48   Pod manifests generated                 Y
 134    _system_   Feb  5 08:48   Pod allocation ready for binding        N
 135    _system_   Feb  5 08:49   Pod status                              N
 RESOURCE REQUIREMENT DETAILS:
 Combined: select[(ngpus>0) && (type == local)] order[gpu_maxfactor] rusage[ngp
                     us_physical=2.00]
 Effective: select[((ngpus>0)) && (type == local)] order[gpu_maxfactor] rusage[
                     ngpus_physical=2.00]
 GPU REQUIREMENT DETAILS:
 Combined: num=2:mode=exclusive_process:mps=no:j_exclusive=yes
 Effective: num=2:mode=exclusive_process:mps=no:j_exclusive=yes
 KUBERNETES:
 NAMESPACE  POD                     PHASE    NODE       GPU
 mylsfns    lsf-cluster1-226-0-0-0  Running  p613-met1  1 2



위의 테스트에서는 LSF 명령어를 통하여 작업을 K8S로 제출하였고, LSF의 batch driver가 K8S의 API server를 호출하여 정책에 따른 Pod이 생성되게끔 하는 것을 확인하였습니다. 더불어 GPU를 리소스로 인지하고, 가용한 GPU 양에 따라 스케쥴링 정책을 적용합니다.

이렇게 생성된 Job은 LSF 명령어 혹은 kubectl 명령어(ICP 웹콘솔)를 통해, 양측에서 모두 확인이 가능하고 모니터링 됩니다.

마찬가지로, K8S(ICP) 상에서 YAML 파일을 정의하여 제출되는 작업/Pod의 경우에도, lsf에서 정의한 namespace를 사용하고, schedulerName을 lsf로 지정하면, LSF 명령어를 통해서도 해당 Pod을 모니터링 할 수 있습니다. 

YAML 파일에 scheduler 로서 lsf를 적용 시, 사용할 수 있는 Pod spec field 정보는 아래의 링크에서 확인할 수 있습니다.