2021년 5월 31일 월요일

RefSeq Masher, 편리한 것은 좋은데...

RefSeq Masher는 Mash MinHash 기법을 이용, 내가 갖고 있는 시퀀싱 데이터가 54,925개의 RefSeq Genome 중 어느 것에 해당하는지를 찾아주는 유틸리티이다. Mash를 직접 쓰는 것에 비하면 훨씬 편리하다. 문제점은 Mash sketch DB가 좀 오래되었다는 점이다. 오늘 날짜로 RefSeq에서 박테리아의 assembly summary file을 받아 보니 216,709 줄이나 된다. 첫 두 줄은 코멘트이므로 제거한다 해도 RefSeq Masher가 제공하는 기본 DB의 거의 4배가 된다. 게다가 bacteria 이외의 것은 아직 확인해 보지도 않았다. 최신 유전체 자료를 이용하여 custom Mash sketch DB를 만든다 해도 문제가 해결되지는 않는다. RefSeq Masher는 distance를 계산한 결과를 다시 'ncbi_refseq_taxonomy_summary.csv'라는 파일과 연결하여 taxonomy를 뽑아내는 것으로 끝을 맺기 때문이다. Custom DB를 만들어 봐야 taxonomy 파일까지 준비하지 않으면 소용이 없다. RefSeq Masher의 개발자들도 아직 여기까지는 신경을 쓰고 있지 않은데 내가 아쉬워하는 것이 무슨 의미가 있을까 싶다.

검색을 거듭해 보니 Mash의 공식 매뉴얼 문서(PDF)에서는 RefSeq release 88로 만든 sketch DB를 제공하고 있음을 확인하였다. 그러나 언제적 release인가! RefSeq의 가장 최근 배포판은 5월 27일, 그러니까 4일 전에 배포된 Release 206이다. 내 컴퓨터에는 miniconda 설치 위치의 다음 위치에 두 개의 파일을 제공하고 있다.

  • pkgs/refseq_masher-0.1.2-py_0/site-packages/refseq_masher/data
  • Files: RefSeqSketches.msh  ncbi_refseq_taxonomy_summary.csv

54,925개의 genome이 포함된 RefSeq은 언제적 release일까? 이것이 RefSeq 88보다 예전 것임은 명백하다. 왜냐하면 파일 사이즈가 94M와 1002M로 크게 차이가 나기 때문이다. Min-hash size도 400개에 지나지 않는다. 요즘은 1만개 기준으로 분석을 빈번히 하는 것과 비교한다면 한참 시대에 뒤떨어진 것이 아닌가하는 생각이 든다.

$ mash info RefSeqSketches.msh | more
Header:
  Hash function (seed):          MurmurHash3_x64_128 (42)
  K-mer size:                    16 (32-bit hashes)
  Alphabet:                      ACGT (canonical)
  Target min-hashes per sketch:  400
  Sketches:                      54925

2년 정도 주기로 누군가에 의해 RefSeq Mash sketch DB가 만들어져서 세상에 공개된다면 참 좋을 것이다. KRAKEN2처럼 말이다. 안타깝게도 custom DB를 만드는 방법은 매뉴얼에서 확인하기 어렵다. Minikraken2의 2019년 4월 업데이트는 메모리에 올라가는 용량(8G)에 대해서만 강조하고 있을 뿐, 몇 건의 genome sequence로부터 만들어진 것에 대해서는 자세히 적어 놓지를 않았다. 

Mash의 예전 문서에서 Building a custom RefSeq database라는 섹션을 찾기는 했지만 이대로 따라서 할만 한 일인지 확신이 서지 않는다... Mash 1.0 documentation에는 존재하다가 지금은 사라진 이유가 있을 것이다. 

2021년 9월 6일 업데이트

캐나다에서 개발하여 배포하는 갤럭시 기반의 IRIDA(Integrated Rapid Infectious Disease Analysis)에 RefSeq masher가 포함되어 있음을 확인하였다(관련 문서 링크).

B&W DM10 스피커를 들여놓다

처남이 중고로 구입하여 사용하던 B&W DM10 스피커를 둘 곳이 마땅치 않아 그냥 주겠다고 하여 서울에 다녀오는 김에 잠시 들러서 차에 싣고 왔다. 그냥 받아 오기는 미안하여 카카오톡으로 아이스크림 기프티콘을 하나 보내 주었다.

음악과 오디오를 좋아하면서도 정작 유명한 오디오 기기 브랜드는 잘 알지 못한다. B&W라... Bowers & Wilkins(위키백과, 현 웹사이트)의 약자로서 영국 브랜드이다. 영국 스피커 회사라면 탄노이, 하베스, 로더 정도만 겨우 아는 수준이었다. 구글을 뒤져보니 앵무조개 모양의 스피커 시스템이 바로 B&W의 작품이었다. 아! 이 모습은 너무나 유명하지 않던가.

Nautilus: The ultimate loudspeaker(출처)
DM10은 1981-83 사이에 제조해서 판매한 B&W의 염가형 스피커 시스템이라고 한다. 당시 판매 가격은 180 달러 정도였다고 한다. HiFi Classic이라는 웹사이트에 꽤 상세한 리뷰 기사가 실렸다(링크). 구글을 뒤지면 발매 당시의 브로셔도 쉽게 구할 수 있다(링크).
What we heard was generally consistent with what we had measured... The bass was surprisingly strong and clean, despite the low-frequency power limitations evident in our distortion measurements...  At any listening level that most people would reasonably use at home, it was completely clean... It is unquestionably one of the better speaker-system values in today's market. (HiFi Classic 마지막 줄)
전면 그릴은 달려 있지 않고, 인클로저도 군데군데 까진 상태였다. 특이하게도 트위터의 보이스 코일에서 나오는 선이 인클로저 내부가 아니라 외부에서 납땜을 해야 하는 구조였다. 전면 그릴이 없으니 잘못 건드리면 끊어지기 쉽다. 처남도 이를 직접 수리를 했었다는데, 어제 집에 들고 와 보니 나도 뭘 잘못 건드렸는지 한쪽 선이 끊어져 있는 것 아닌가. 딱 코털(?) 정도의 길이로 돌출한 가냘픈 선을 다루면서 만약 이것이 코털 뽑히듯 끊어지면 되살릴 방법이 없다고 생각했다. 아주 조심스럽게 납땜 작업으로 트위터를 되살렸다.
원으로 표시한 곳 내부가 직접 납땜하여 수선한 곳이다. 피복에 해당하는 것은 잘못하여 떨어져 나갔다. 이 가냘픈 선이 엣지 부근에서 끊어지면 정말로 낭패다!

TDA7265 앰프로 소리를 들어보고 있다.

공간이 부족하여 임시로 이렇게 배치하였다.
최초로 앰프를 연결하여 소리를 듣는데 영 이상하다. 한쪽 채널의 극성이 반대로 연결되었을 때에 나는 전형적인 소리이다. 분명히 색깔을 맞추어 연결했는데 왜 이런담? 혹시 인클로저 내부에서 +/-선을 반대로 연결하였나? 시험삼아 한쪽 채널의 극성을 반대로 연결하니 편안한 소리가 난다. 명료하고도 두툼한 소리가 듣기 좋다. 극성 확인을 위해 건전지를 가져다가 스피커에 연결해 보았다. 왼쪽은 적-(+), 흑-(-) 연결에서 우퍼가 앞으로 쑥 튀어나온다. 그런데 오른쪽 채널은 반대로 쑥 들어가는 것이 아닌가. 흠... 아마도 처남 이전의 소유주가 수리를 하면서 단자에 극성을 반대로 납땜한 것이 틀림이 없다. 어떻게 이런 실수를 했을까? 만약 공임을 받고 수리를 하는 기사의 실수였다면 정말 한심한 일이 아닐 수 없다.

경량 구조이지만 우퍼는 8인치이다. 트위터는 1인치 돔 타입. 카탈로그에 의하면 주파수 재생 특성은 75 to 20,000 Hz ±3 dB, 민감도는 87 dB이다. 

나의 오디오 취미에서 스피커쪽은 상대적으로 관심이 덜 가는 분야였다. 스피커는 소리의 최종적인 출구로서 투자 대비 만족도가 가장 높은 곳인데 말이다. 아마 초기에 스피커 DIY를 조금 해 보다가 흥미가 지속되지 못해서 그만 둔 것에도 원인이 있을 것이다. 당시 내 블로그에는 이런 덧글이 있었다. 제대로 즐기기 위해 할 수 있는 시도가 있음에도 불구하고 주변부만 맴돌고 있는 것 같아 안타깝다고... 나는 그때 스피커 유닛을 처음으로 구입하여 두꺼운 종이로 만든 통에 넣고는 마음에 들어하지 않고 있었다. 그 덧글을 남긴 분의 시각에서는 한심해 보였을지도 모르는 일이다.

취미란 것이 원래 그런 것 아닌가. 효율과는 관계없이 많은 비용을 들이면서 먼 길을 돌아오기도 하고, 무지의 장막 한 겹만 걷으면 곧 새로운 세계가 펼쳐지는데 그 앞에서 발걸음을 멈추기도 하고..

내가 어설프게 만든 소출력 진공관 앰프를 잘 울리기 위해 스피커를 맞추고 싶은 생각은 별로 없다. 진공관 앰프는 그저 만드는 과정을 즐기는 재미와 전원을 넣었을 때 빨갛게 달아오르는 불빛을 바라보는 재미를 위한 것이다. 우연한 기회에 처남으로부터 얻은 스피커(이를 빈티지 스피커라 하기에는 아직 젊은 것 같은데)가 취미의 범위를 조금 더 확장해 준 것 같아서 즐겁다.


2021년 5월 28일 금요일

antiSMASH v5가 이렇게 설치하기 어려운 소프트웨어였던가?

antiSMASH는 유전체 서열로부터 이차대사물의 생합성 유전자군(BGC, biosynthetic gene cluster)를 예측하는 도구이다. 현재 버전은 5.x까지 나온 상태이다. 버전 3과 4에서는 지금 KAIST에 재직 중인 김현욱 교수가 개발에 참여하였던 것으로 안다.

파이썬 2.7 시절의 버전인 antiSMASH 4.x는 무난히 설치하여 잘 쓰고 있었다. 최신 버전을 설치하려니 생각보다 매우 어렵다. 설치 시 나오는 메시지를 구글에 때려넣고 검색을 거듭하여 해결 방법을 찾아 보았다. antiSMASH GitHub 웹사이트의 issue #234번에서 힌트를 얻어서 다소 복잡한 설치 명령어를 입력하여 겨우 설치에 성공하였다. GitHub의 파이썬 소스를 가져다가 저렇게 한 줄의 명령어로 설치하는 방법은 이번에 처음 써 보는 것이다.

$ conda create -n antismash5 "python>3" pip numpy "biopython=1.76" \
    helperlibs jinja2 pysvg-py3 bcbio-gff pyscss matplotlib scipy "scikit-learn>=0.19" \
    "diamond==0.9.*" "fasttree==2.1.*" "glimmerhmm==3.0.*" hmmer2 \
    "hmmer==3.1b2" "meme<=4.11.2" "muscle==3.8.*" "blast=2.2.*" prodigal
$ conda activate antismash5
$ python -m pip install git+https://github.com/antismash/antismash.git@5-1-2 OK!
$ download-antismash-databases # 일부만 성공, SSL 인증서 관련 에러 발생!

문제는 이것으로 전부가 아니라는 것. 위에서 보인 명령어 중 가장 마지막 것('download-antismash-database')를 실행할 때 SSL 인증서와 관련한 urllib의 에러가 난다. 짜증스러울 정도로 자주 만나던 에러다.

urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1131)

REQUESTS_CA_BUNDLE 환경변수를 수정하는 것으로도 해결이 되지 않는다. 드디어 파이썬 소스 코드를 고쳐서 시도할 순간이 되었다. 이에 대한 해결 방법은 구글링을 하면 어렵지 않게 찾을 수 있다. 내가 참조한 글은 urllib request.py urlopen SSL 인증서 에러 문제 해결 SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED]이다. 파이썬 문법을 잘 모르는 상태에서 소스 코드를 고치려니 참 부자연스럽다. download-antismash-database에서 호출하는 download_databases.py 스크립트를 vi로 열어서 앞부분에 import ssl을 적당히 삽입하고, 다음의 빨간색 줄에 해당하는 코드를 삽입한 것이 전부였다. urlopen() 안에 한 줄로 넣어 버리는 방법도 어디선가 읽은 적이 있었다.


이렇게 한 다음 문제의 스크립트를 재실행하면 에러가 났었던 clusterblast_20190415 데이터베이스의 다운로드 및 설치가 무사히 끝난다. antiSMASH용 데이터베이스의 위치는 다음과 같으므로, SSL 인증서 문제가 발생하지 않는 다른 전산망의 컴퓨터에서 받은 파일을 가져다가 덮어씌워도 될 것이다.

antismash5/lib/python3.8/site-packages/antismash/databases

새롭게 설치한 antiSMASH를 이용하여 Acineobacter baumannii의 complete genome sequence를 분석해 보았다. 분석 소요 시간은 얼마 되지 않는다. 결과 화면은 다음과 같다.


PYTHONHTTPSVERIFY라는 환경 변수를 0으로 설정하면 된다는 글도 있었다. 위에서 소개한 방법을 이용하여 다른 서버에 antiSMASH 프로그램을 설치한 뒤 'export PYTHONHTTPSVERIFY=0'을 실행하고 나서 download-antismash-database를 실행해 보았다. 그랬더니... 되긴 뭐가 돼! 결론적으로는 download_databases.py 스크립트를 수정하여 데이터베이스 설치를 완료하였다.

(antismash5) $ export PYTHONHTTPSVERIFY=0
(antismash5) $ download-antismash-databases
/opt/miniconda3/envs/antismash5/lib/python3.8/site-packages/scss/selector.py:26: FutureWarning: Possible nested set at position 329
  SELECTOR_TOKENIZER = re.compile(r'''
Downloading PFAM version 27.0
Downloading Pfam-A.hmm.gz: 100.00% downloaded.
Creating checksum of Pfam-A.hmm.gz
Extraction of Pfam-A.hmm.gz finished successfully.
Downloading PFAM version 31.0
Downloading Pfam-A.hmm.gz: 100.00% downloaded.
Creating checksum of Pfam-A.hmm.gz
Extraction of Pfam-A.hmm.gz finished successfully.
Downloading Resfam database
Downloading Resfams.hmm.gz: 100.00% downloaded.
Creating checksum of Resfams.hmm.gz
Extraction of Resfams.hmm.gz finished successfully.
Ensuring all cutoffs are present
Downloading ClusterBlast database.
Traceback (most recent call last):
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/urllib/request.py", line 1354, in do_open
    h.request(req.get_method(), req.selector, req.data, headers,
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/http/client.py", line 1252, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/http/client.py", line 1298, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/http/client.py", line 1247, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/http/client.py", line 1007, in _send_output
    self.send(msg)
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/http/client.py", line 947, in send
    self.connect()
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/http/client.py", line 1421, in connect
    self.sock = self._context.wrap_socket(self.sock,
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/ssl.py", line 500, in wrap_socket
    return self.sslsocket_class._create(
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/ssl.py", line 1040, in _create
    self.do_handshake()
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/ssl.py", line 1309, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1131)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/site-packages/antismash/download_databases.py", line 82, in download_file
    req = request.urlopen(url)
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/urllib/request.py", line 222, in urlopen
    return opener.open(url, data, timeout)
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/urllib/request.py", line 525, in open
    response = self._open(req, data)
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/urllib/request.py", line 542, in _open
    result = self._call_chain(self.handle_open, protocol, protocol +
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/urllib/request.py", line 502, in _call_chain
    result = func(*args)
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/urllib/request.py", line 1397, in https_open
    return self.do_open(http.client.HTTPSConnection, req,
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/urllib/request.py", line 1357, in do_open
    raise URLError(err)
urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1131)>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/miniconda3/envs/antismash5/bin/download-antismash-databases", line 8, in <module>
    sys.exit(_main())
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/site-packages/antismash/download_databases.py", line 352, in _main
    download(args)
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/site-packages/antismash/download_databases.py", line 330, in download
    download_clusterblast(args.database_dir)
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/site-packages/antismash/download_databases.py", line 307, in download_clusterblast
    download_if_not_present(CLUSTERBLAST_URL, archive_filename, CLUSTERBLAST_ARCHIVE_CHECKSUM)
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/site-packages/antismash/download_databases.py", line 207, in download_if_not_present
    download_file(url, filename)
  File "/opt/miniconda3/envs/antismash5/lib/python3.8/site-packages/antismash/download_databases.py", line 84, in download_file
    raise DownloadError("ERROR: File not found on server.\nPlease check your internet connection.")
antismash.download_databases.DownloadError: ERROR: File not found on server.
Please check your internet connection.

2021년 5월 23일 일요일

전주 한옥마을을 거닐다가 완판본 문화관을 한참 구경하고 잠시 전주천 변에 앉아 쉬고 있었다.


'전기수'란 소설책을 청중들에게 읽어주는 사람을 말한다. 조선 후기에 생긴 직업적인 이야기꾼이다.

멀리서 농악 소리가 들리더니 점점 가까이 다가온다. 참 오랜만에 듣는 장단이다.

그네터 옆에 마련된 약간 넓은 곳에 농악대가 멈추더니 큰 깃발을 든 사람 셋이서 번갈아 화려한 묘기를 펼쳐 보였다. 생전 처음 보는 장관이라서 한참을 구경하였다. 어깨에 끈을 연결하여 지탱한 항아리 모양의 물건을 다리 사이에 놓고 여기에 깃대를 꽂은 상태로 기를 펼쳐서 빙빙 돌린다. 깃대 꼭대기에 달린 줄을 팔로 지탱하면서 쓰러질락말락 수평으로 돌리기도 하고, 한 손이나 이마에 올려 놓고 중심을 잡기도 한다.

풍물패는 치배(악기를 연주하는 사람)와 잡색(각기 배역을 가지고 춤을 추며 흥을 돋구는 사람)으로 구성된다고 한다. 깃발을 들고 퍼포먼스를 펼치는 사람도 잡색의 일종일까? 지금까지 풍물패에 대하여 아는 것이라고는 꽹과리를 치며 전체를 지휘하는 '상쇠'뿐이었다.

전통 예술의 일종이니 퍼포먼스라고 표현하는 것은 옳지 않고, '연희(演戲)'라고 하는 것이 더 나을 것이다. 그러나 연희의 사전적 의미는 '말과 동작으로 여러 사람 앞에서 재주를 부리는 것"(네이버 사전)이므로 노래나 악기 연주는 이 범주에 들어가지 않는 것 같다. 한국예술종합학교 전통예술원에서도 음악과와 연희과는 다르다. 

흠... 풍물은 연희의 하나로 취급된다. 악기 연주와는 분명히 다르게 취급되는 것이 맞고, 그럴 만한 이유가 있을 것이다. 대학 동기인 이진원 교수(한국예술종합학교)에게 백만 년 만에 카톡을 보내어 물어 봐야 되겠다.



2013년에 구입한 낡은 서버에 CentOS 7을 새로 설치하다

2008년부터 2015년까지 총 4대의 서버를 구입하였다. 주력으로 쓰는 것은 2015년에 구입한 것('tube' server)이니 결코 최신 모델이라고 할 수는 없다. 지금까지 쓰는 Synology NAS는 이보다 조금 더 오래 되었다. 이들은 모두 쌩쌩 날아다니는 속도는 아니지만 특별한 문제를 일으키지 않으니 가끔 먼지를 털어내며 사용을 하고 있다. 

네 대의 서버 중 가장 저렴한 제품이었던 Tyan Korea의 완제품 1U 서버(2013년 구입)에 최신 OS를 설치하기로 하였다. 제품 형번은 KXT14 (S7002G35-W213)이다. 웹사이트를 방문하면 형번을 구성하는 숫자 및 알파벳의 의미를 알 수 있다. 가장 중요한 부품이라 할 수 있는 마더보드의 형번은 Tyan S7200G2NR-LE이다. 마지막으로 전원을 넣은 것은 언제였을까? 아마도 2018년? 2019년 4월부터 2년 동안은 내가 다른 곳에서 근무를 하느라 tube와 NAS를 공식 반출하여 들고 가면서 나머지 것들은 전부 전원을 내려 놓은 상태였다.

한동안 우분투를 편식했으니 이번에는 CentOS를 설치해 보기로 했다. ISO 이미지 파일(다운로드 사이트)을 찾아보니 CentOS Stream이라는 것이 보인다. 기존의 CentOS 7은 2024년 6월까지만 지원이 된다고 한다. RHEL(Red Hat Enterprise Linux)로부터 공개 커뮤니티용으로 다시 만들어져 나온 것이 기존의 CentOS라면, CentOS Stream은 페도라에서 (완벽하지 않은?) 테스트를 거친 뒤 곧바로 공개되는 것처럼 보인다. 가능하다면 유료 서비스인 RHEL를 많이 써 달라는 취지인 것으로 보인다. 우분투도 매번 공짜로 쓰는 처지인데, 어떻게 대비를 해야 될지 조금 걱정이 된다.

워낙 오래 된 컴퓨터라서 USB를 이용하여 간편하게 부팅 매체를 바꿀 수 있는 메뉴를 제공하지는 않는다. 일단 바이오스 셋업에 들어가서 몇 가지를 건드려 주어야 한다.

2009년 AMIBIOS!

Advanced → USB configuration으로 진입한다.

USB 드라이브를 꽂은 상태에서만 맨 아래의 USB mass storage device configuration 메뉴가 나타난다.

몇 번 테스트를 해 보니 Auto나 Hard disk 무엇으로 설정하는 다 된다.

Boot → Boot device priority로 진입한다.
아, 중간 과정을 하나 빼먹은 것 같다. Boot setting 메뉴에서 맨 하단의 Hard disk drives로 들어가서 USB 드라이브를 가장 상위로 가게 만들었었나? 그럴 필요가 없었나? 별로 복잡한 세팅 변경도 아닌데 그것 하나 기억을 못하다니.
1st boot device를 USB(ScanDisk)로 설정한다.

여기까지 하고 저장 후 재부팅을 하면 비로소 USB 드라이브를 통한 부팅이 이루어진다.

이 서버는 ePrism SSL VA의 영향을 받지 않는 '안전한(?) 곳에' 당분간 두면서 테스트용으로 사용해 보련다. 오늘까지 SSL 인증서 문제로 씨름을 하면서 완벽한 해결책에 거의 다가갔다고 생각하지만 전혀 방심을 할 수가 없는 상황이다. 두 곳의 환경을 비교하되 직장 전산망 환경에서 도저히 설치가 되지 않는 파일이나 애플리케이션의 경우는 안전한 곳의 서버에서 설치한 뒤 복사하여 이식하는 편법을 동원하는 수밖에는.


Bactopia test - 방황의 끝(2)

Bactopia(공식문서, GitHub, mSystems 2020년 논문)란 세균 유전체의 분석을 위한 파이프라인이다. TORMES 파이프라인과 유사하면서도 다른 점이 많다. 동일 종에 속하는 여러 균주의 시퀀싱 결과물(fastq)이 있다면, tormes는 이를 조립하여 taxonomic assignment를 실시하고, genome annotation을 실시하면, roary에 의한 pan-genome 분석 및 항생제 내성/병원성 유전자를 검색하여 보기 좋은 리포트를 생성한다.

Bactopia는 로컬 컴퓨터에 연구하려는 species의 DB를 먼저 만드는 것에서 시작한다. 예를 들어 Staphylococcus aureus가 연구 대상이라면, NCBI에서 complete genome 서열(max = 1000)을 다운로드하여 protein DB(이것은 prokka에서 쓰인다)와 genome size 분포 등의 기본 수치를 확보해 놓는다. 항생제 내성/병원성 유전자 DB를 미리 만드는 것은 TORMES와 같다. 분석에 사용할 fastq 파일은 사용자가 제공하거나 SRA/ENA에서 다운로드할 수 있다. 유전체 조립을 하여 minhas skectch에 의해 reference 중 가장 가까운 유전체를 찾고, 이를 기준을 SNP analysis를 실시한다. 그 외의 분석 내용은 TORMES와 유사하다. 단, 그대로 보고용 자료로 쓸 수준의 리포트를 만들어 주지는 않는 것 같다. Nextflow를 쓴다는 것은 bactopia만의 특징이다. Nextflow가 뭔지도 모르면서 벌써 NanoCLUST와 Bactopia라는 애플리케이션을 통히 이를 쓰게 되었다.

Bactopia를 설치하고 테스트 런을 실시하는 과정도 순탄하지는 않았다. Conda 환경에서 돌아가게 만들어져 있지만 DB를 만들기 위한 파일 또는 튜토리얼용 SRA 파일을 내려받는 과정에서 또 SSL 인증서와 관한 문제를 수두룩하게 겪었기 때문이다. 

5월 20일에 작성한 글(Conda 환경이 참조하는 SSL 인증서의 위치는 어디에 있는가? - 방황의 끝)은 어쩌면 방황의 '시작'이었는지도 모른다. 집에서 노트북 컴퓨터에 우분투를 설치하고 bactopia를 테스트하면 아무런 문제가 없다. 그러나 연구소로만 오면 안 된다. 5월 20일 글에서 특정 conda 환경이 참조하는 공식 SSL certificate에 SSLPrisim.crt가 포함된 파일의 위치를 살짝 덮어 쓰는 편법으로 해결을 해 보고자 하였으나, 여의치 않았다.

일요일에 사무실에 나와서 다시 이 문제를 해결하고자 씨름하였다. 결국은 시스템에서 공식적으로 설치한(물론 내가 SSLPrism.crt를 추가하였지만) 인증서의 위치를  두 환경변수 REQUESTS_CA_BUNDLE와 CURL_CA_BUNDLE에 동일하게 설정하는 것이 가장 깔끔한 해결책이라는 결론을 내리게 되었다. 내 블로그에 달린 댓글을 통해서 이러한 환경변수를 통한 해결 방법을 처음 알게 되었지만, 이 변수가 어떤 의미가 있고 어떤 프로그램류에서 쓰이는지에 대해서는 별로 깊게 생각을 하지 않았었다. 검색에 의하면 REQUESTS_CA_BUNDLE는 파이썬을, CURL_CA_BUNDLE은 curl 및 관련 프로그램을 위한 것이다. 이 변수를 제대로 선언했다면 파이썬 패키지의 설치 작업에서 '--trusted-host pypi.org --trusted-host files.pythonhosted.org' 옵션을 줄 필요가 없다. 

모든 애플리케이션이 시스템에 공식적으로 설치된 SSL 인증서를 자동적으로 인식하지는 않는다는 점이 지금까지 이렇게 고생을 하게 만든 이유인 것 같다. 어떤 리눅스 배포판을 쓰느냐에 따라서 시스템에 설치된 인증서의 위치는 조금 다르다.

CentOS라면 이렇게 하면 된다.

export REQUESTS_CA_BUNDLE=/etc/pki/tls/cert.pem

export CURL_CA_BUNDLE=/etc/pki/tls/cert.pem

다음은 우분투의 경우이다.

export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt

export CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt

Bactopia는 참조 유전체 서열을 다운로드할 때 ncbi-genome-download를 사용한다. 이 스크립트는 예전에 설치하여 조금 쓰다가 어느 순간부터 작동이 잘 안되어서 손을 대지 않고 있었는데(역시 SSL 인증서 문제였음), 이번에 bactopia 테스트를 위하여 애를 쓰는 과정에 덩달아 문제가 해결되었다! Bactopia와 database 설치가 모두 완료되어 다음과 같이 첫 명령을 실행하였다.

$ bactopia --accession SRX4563634 \
>          --datasets datasets/ \
>          --species "Staphylococcus aureus" \
>          --coverage 100 \
>          --genome_size median \
>          --cpus 2 \
>          --outdir ena-single-sample

Raw data를 다운로드하는 'gather_fastqs' 단계(fastq-dl 사용)에서 에러가 난다. 인증서 문제는 다 해결한 것 같은데 이유가 뭘까? '--use_ena'를 써서 fastq 파일을 SRA 대신 ENA에서 다운로드하면 될지도 모른다는 생각이 들어서 이 옵션을 주어 보았다. 그랬더니 비로소 bactopia 실행이 에러 없이 완료되었다. 후!

총 3대의 컴퓨터에 몇 번씩 재설치를 해 가면서 문제를 재현하고 한 단계씩 나아가면서 이를 해결하고자 노력하여 여기까지 왔다...

2021년 5월 20일 목요일

Conda 환경이 참조하는 SSL 인증서의 위치는 어디에 있는가? - 방황의 끝

SSL 인증서와 관련한 문제로 2년이 넘게 고생을 해 왔고 이제야 어렴풋하게 이해를 했다고 생각했지만, 오늘 무릎을 치면서 '유레카!'를 외치는 발견을 또 하게 되었다. 늘 눈앞을 가로막고 있는 듯했던 무식의 장막을 하나 더 걷어냈다는 기쁨을 나 혼자 간직할 수가 없어서 이렇게 블로그에 기록을 남긴다. 2년이라는 시간 동안 걷어낸 장막 뒤에는 이보다 훨씬 더 두꺼운 콘크리트 벽이 자리를 잡고 있을지도 모르는 일이지만..

한국생명공학연구원의 전산망 내에서 일을 하는 사람이라면 수산 아이앤티라는 회사에서 제공하는 SSLPrism.crt라는 파일을 웹브라우저에 설치해야 한다. 윈도우에서만 일을 한다면 이것으로 대부분의 업무를 다 볼 수 있다. 리눅스도 웹브라우저에서 SSLPrism.crt 파일을 설치하면 된다. 생명(연)에서 컴퓨터를 구입하여 처음으로 인터넷에 접속을 하면 이 과정이 거의 자동으로 이루어지니 보통은 별로 신경을 쓰지 않아도 된다. 생명(연)에서 안내하는 것은 딱 여기까지이다. 아래에 분홍색으로 표시한 텍스트는 수많은 시행착오와 검색으로 알아낸 사실이다.

소만사니 수산 아이앤티니 하는 회사의 장비가 하는 일은 https://로 시작하는 웹사이트와 내부 사용자가 주고받는 정보를 복호화(즉 암호를 푸는)하는 일이다. 사용자를 보호해 주는 것이 아니라, 사용자가 기관의 민감한 정보를 유출하는지를 감시하기 위한 것이다!(내가 이해하는 것이 100% 정확한 것은 아닐 수도 있음). 다시 말하자면 기관 차원의 보안을 위한 솔루션인 것이다. 만약 접속하고자하는 외부 사이트가 자체 서명한 인증서를 쓰는 경우, 이 장비를 거치면서 최상위 인증서가 SSLPrism.crt인 것으로 바뀌어서 내부로 전달된다. 왜 이렇게 되어야 하는지는 내가 알지 못한다. 이때 전산망 내부에 있는 사용자가 SSL 인증서와 관련한 수많은 오류를 만나게 되는 것이다. 특히 nanopore 구동 관련 software를 설치하면서 많은 어려움을 겪을 것이다. 이것은 방화벽에서 포트를 여는 문제로 완벽하게 해결되지 않을 것이다. 단, 윈도우 환경에서 일반적인 업무를 보는 사람은 별다른 문제를 접하지 않는다...

하지만 리눅스에서는 웹브라우저만을 이용하여 https:// 위치에 있는 파일을 가져오는 것이 아니다.  wget, curl,  그리고 파이썬의 urlopen() 등 많은 애플리케이션이 웹브라우저를 경유하지 않고 직접 외부의 자료를 갖고오게 만든다. 웹브라우저에서 설치한 인증서는 이러한 상황에서 다른 애플리케이션에게 도움을 주지 못한다. 따라서 SSLPrims.crt는 CentOS의 경우 update-ca-trust라는 별도의 프로그램을 이용하여 시스템 전체에 걸쳐 작동하도록 설치해야 한다. 방법은 단순하다. SSLPrism.crt 파일을 /etc/pki/ca-trust/source/anchors/ 디렉토리에 복사한 뒤 update-ca-trust 명령을 실행하면 된다. 물론 이 두 단계의 작업을 하려면 관리자 권한이 필요하다. 이렇게 하면 /etc/pki/tls/cert.pem과 /etc/pki/tls/certs/ca-bundle.crt 두 개의 파일 제일 앞에 SSLPrism.crt 인증서가 위치하게 될 것이다.

이렇게만 해 놓으면, wget 명령에서 '--no-check-certificate', 그리고, curl 명령에서 '--cacert' 등의 파라미터를 설정할 필요가 없다.

그런데 conda 환경 내에서는 system-wide한 인증서 위치를 참조하지 않는 것을 뒤늦게 발견하였다. SILVA database를 다운로드하는 다음의 사례를 보자. 위의 것은 conda 환경에 설치된 wget 명령을(다운로드 실패), 아래는 시스템에 존재하는 /usr/bin/curl을 이용한 것이다(다운로드 성공). 

(base) $ curl https://ftp.ncbi.nlm.nih.gov/genomes/all/GCA/014/706/575/GCA_014706575.1_ASM1470657v1/GCA_014706575.1_ASM1470657v1_genomic.fna.gz > test.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
curl: (60) SSL certificate problem: self signed certificate in certificate chain
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

(base) $ /usr/bin/curl https://ftp.ncbi.nlm.nih.gov/genomes/all/GCA/014/706/575/GCA_014706575.1_ASM1470657v1/GCA_014706575.1_ASM1470657v1_genomic.fna.gz > test.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 1576k  100 1576k    0     0   578k      0  0:00:02  0:00:02 --:--:--  578k

그렇다면 conda 환경에서 참조하는 SSL 인증서의 위치는 도대체 어디인가? 'Conda +  SSL + 에러'라는 키워드로 구글 검색을 하면 대부분 .condarc 파일에서 'ssl_verify: false'라고 설정을 하라는 답이 얻어진다. 이것은 conda package를 설치 또는 업데이트할 때의 문제이다. Conda 환경 내에서 개별적으로 돌아가는 애플리케이션이 외부 파일을 가져오고자 할 때 겪는 인증서 문제와는 다른 이야기이다.

테스트를 위해 새로 설치한 miniconda 디렉토리의 하위를 뒤져 보았다. ca-certificates라는 conda package가 설치된 곳을 찾아야 한다. 그것은 바로 다음의 위치였다. 그리고 개별적인 conda 환경은 env/환경명/conda-meta/ca-certificates-2020.12.5-ha878542_0.json 파일을 통해서 자기가 어떤 인증서를 참조하고 있는지를 명시하였다.

/opt/miniconda3/pkgs/ca-certificates-2020.12.5-ha878542_0/ssl

여기에는  cacert.pem과 cert.pem(cacert.pem의 심볼릭 링크) 파일이 존재한다. 당연히 이 파일은 SSLPrisim 인증서를 전혀 알지 못한다. 시스템 전체에 적용되는 /etc/pki/tls/cert.pem 파일을 이 위치의 cacert.pem으로 덮어 씌워버렸다. 

결과는 예상한 바와 같다. Conda 환경에 설치한 wget으로 SILVA database가 무사히 다운로드되었다. 오늘 얻은 하나의 깨달음이 또 다른 '무지의 늪'을 재발견하도록 나를 이끌지도 모르는 일이지만...

TORMES-1.2.1 재설치 테스트

오늘 확인한 바를 최종 점검하기 위해 miniconda3에 tormes-1.2.1을 새롭게 설치해 보았다. SSL 인증서와 관련하여 손을 댄 것은 바로 위에서 언급한 ca-certificates 디렉토리 이하를 고쳐서 system-wide하게 설치된 인증서를 쓰도록 만든 것이 전부이다. quast-download-busco를 실행할 때 BUSCO DB의 위치가 영구적으로 바뀌어서 다운로드가 되지 않는다는 에러를 제외하면 R 패키지 설치까지 전부 완벽하게 끝났다. 아래에 보인 에러는 SSL 인증서와는 관계가 없다. 좀 이상한 것은 세 개의 tar.gz 파일을 wget(/usr/bin/wget이 아니라 tormes 환경에서 설치한 것)으로 다운로드하면 문제가 생기지 않는다는 것이다.

Downloading BUSCO database...
Downloading bacteria database (file: bacteria.tar.gz)...

ERROR! Failed downloading bacteria database (url: https://busco.ezlab.org/v2/datasets/bacteria_odb9.tar.gz), QUAST functionality will be limited! Exception caught: HTTP Error 301: Moved Permanently
You can try to download the file manually, place it in /opt/miniconda3/envs/tormes-1.2.1/lib/python3.6/site-packages/quast_libs/busco/bacteria.tar.gz and restart QUAST
WARNING: Failed to download bacteria database from https://busco.ezlab.org/v2/datasets/bacteria_odb9.tar.gz and unpack it into /opt/miniconda3/envs/tormes-1.2.1/lib/python3.6/site-packages/quast_libs/busco
  Downloading BUSCO database...
Downloading eukaryota database (file: eukaryota.tar.gz)...

ERROR! Failed downloading eukaryota database (url: https://busco.ezlab.org/v2/datasets/eukaryota_odb9.tar.gz), QUAST functionality will be limited! Exception caught: HTTP Error 301: Moved Permanently
You can try to download the file manually, place it in /opt/miniconda3/envs/tormes-1.2.1/lib/python3.6/site-packages/quast_libs/busco/eukaryota.tar.gz and restart QUAST
WARNING: Failed to download eukaryota database from https://busco.ezlab.org/v2/datasets/eukaryota_odb9.tar.gz and unpack it into /opt/miniconda3/envs/tormes-1.2.1/lib/python3.6/site-packages/quast_libs/busco
  Downloading BUSCO database...
Downloading fungi database (file: fungi.tar.gz)...

ERROR! Failed downloading fungi database (url: https://busco.ezlab.org/v2/datasets/fungi_odb9.tar.gz), QUAST functionality will be limited! Exception caught: HTTP Error 301: Moved Permanently
You can try to download the file manually, place it in /opt/miniconda3/envs/tormes-1.2.1/lib/python3.6/site-packages/quast_libs/busco/fungi.tar.gz and restart QUAST
WARNING: Failed to download fungi database from https://busco.ezlab.org/v2/datasets/fungi_odb9.tar.gz and unpack it into /opt/miniconda3/envs/tormes-1.2.1/lib/python3.6/site-packages/quast_libs/busco

만일 tormes 환경 설치 과정 중에 'ClobberError: This transaction has incompatible packages due to a shared path.'라는 보기 싫은 에러 메시지가 나온다면, 'conda clean --all'을 실행하라. 이 명령은 index cache, lock file, 쓰지 않는 cache package 및 tarball을 삭제하여 깔끔한 환경을 만들어 준다.

이것만 기억해 두자. conda에서 새로운 환경을 설치했다면, 어느 버전의 ca-certificates를 참조하는지를 확인하여 이것을 고치면 된다. 지금 설치되어 있는 것만 하여도 이렇게 많으니 말이다...


2021년 5월 24일 업데이트

Conda의 ca-certificates가 제공하는 인증서 파일을 바꿔치기하는 것은 임시방편은 될 수 있지만 그렇게 현명한 방법은 아니다. 이렇게 하여 일부 패키지의 설치 또는 파일의 다운로드에는 성공할 수 있을지 모르나, 'conda update conda'를 실시하게 되면 인증서 파일의 크기가 맞는지 꼼꼼하게 확인하기 때문이다.

SafetyError: The package for ca-certificates located at /opt/miniconda3/pkgs/ca-certificates-2020.12.5-ha878542_0
appears to be corrupted. The path 'ssl/cacert.pem'
has an incorrect size.
  reported size: 263774 bytes
  actual size: 217320 bytes

따라서 2021년 5월 23일에 작성한 글 Bactopia test - 방황의 끝(2)에서 설명한 방법을 따르는 것이 현명할 것이다.