Docker란 프로그램을 들어보신적이 있으실겁니다. 이놈의 정제가 뭐냐하면 특정 리눅스 컨테이너를 만들고 필요에 따라서 가상화하여 올렸다 내렸다 하는 총체적인 솔루션입니다.


기본적으로 lxc를 이용하고 있고 여기에 관리용 hub를 덧붙여서 이용하고 있습니다. VirtualBox나 VMware의 저수준 가상화가 아닌 일종의 Sandbox가상화입니다.


한번 컨테이너를 만들어 놓으면 해당 컨테이너를 쓰다가 그냥 컨테이너를 내리는 것으로 초기화를 한번에 할 수 있어서 편합니다. 그리고 Sandbox가상화이기 때문에 성능상 손해가 없다고 봐야 합니다.


그런데 이런건 보통 서버에서 필요한 것인데 데스크탑인 우분투에서 대체 어떤 용도로 이 녀석이 필요한 것일까요?


여러가지가 있지만 대표적인 몇가지만 알려드리겠습니다.


우분투에서 소스 컴파일을 통해 설치를 하려고 하면 이것저것 패키지를 많이 설치해야하고 설치후에도 이것 저것 쓰레기가 많이 남습니다. 그리고 컴파일한 패키지를 배포하려고 해도 우분투의 버전이 좀 많습니까? 각각의 배포판에 맞게 패키징을 해야하는데 그럼 각각의 버전을 또 설치해야합니다. 이걸 하나하나 한다고 생각해보세요. 미쳐 돌아갈 지경입니다.


또 다른 것으로는 바이너리 형태로 배포되는 프로그램 중에서 특정 배포판만을 지원하는 경우가 있습니다. 지금은 억지로나마 설치를 하지만 어쨌건 삽질하면서 설치하는 한글2008이나 Redhat 계열만을 지원하는 Abacus, 혹은 우분투와 페도라만을 지원하는 구글 크롬등이 있습니다. 이런 경우에는 해당 배포판을 설치해야하지만 Docker를 이용해서 해당 프로그램을 설치한다면 아무런 문제없이 설치를 할 수 있게 됩니다.


하지만 이런 Docker사용시 한가지 문제가 있는데 GUI 프로그램을 쓰려면 Xorg가 호스트에서 실행되고 있어야 한다는 것입니다. 당연하다면 당연한 이야기입니다.


하지만 컨테이너에서는 Xorg가 없어도 됩니다. 호스트의 Xorg가 모든 것을 대신해 주거든요. 그 말은 호스트의 자원을 이용할 수 있다는 의미입니다.


docker를 설치하고 설정하고 컨테이너를 빌드하는 것은 다른 곳에 더 좋은 내용이 많기 때문에 이 부분은 넘어가고 저는 컨테이너에 설치된 GUI프로그램을 실행하는 방법에 대해 알려드리겠습니다.


docker의 컨테이너를 실행할 때 대부분 여러분들은 이 명령으로 시작할 겁니다.


sudo docker run ~~ /bin/bash


그런데 GUI를 하시려면 여기에 몇가지가 더 들어가야 합니다.


sudo docker run --rm -it -v /run/user/1000:/run/user/1000 -v /dev:/dev -v /tmp/.X11-unix:/tmp/.X11-unix:ro --privileged --ipc=host --shm-size=256m --net=host -e DISPLAY=$DISPLAY -e XDG_RUNTIME_DIR=/run/user/1000 /bin/bash


이렇게 하시면 pid 1000으로 Docker가 실행되면서 X가 함께 실행이 되고 256m의 공유메모리가 함께 만들어지며 쉘로 bash가 실행되게 됩니다.


그럼 바로 GUI 프로그램의 명령을 내려볼까요? firefox같은 것이 좋겠네요.


그럼 데스크탑을 못 찾는다면서 에러가 날 겁니다.


호스트에서도 한가지 더 설정을 해야 하거든요. 호스트 컴퓨터에서 터미널을 열고 다음 명령을 내리도록 합시다.


xhost +local:docker


이렇게 하면 docker로 실행되는 프로그램이 호스트의 X를 통해서 실행이 되게 됩니다. 이제 한번 다시 컨테이너에서 명령을 내려보세요. 컨테이너의 설정에 맞춰서 프로그램이 실행될겁니다. 자그마치 호스트 프로그램과 함께 말이지요!


복잡하게 움직이기는 했지만 생각보단 쉽지 않나요? 이렇게 사용하시면 Docker의 프로그램에서 어떤짓을 하더라도 깔끔하게 다시 돌아올 수 있답니다. 참 쉽죠?


P.S 우분투에서 Docker 설치는 굉장히 쉽습니다.

sudo apt-get update
sudo apt-get install docker.io
sudo ln -sf /usr/bin/docker.io /usr/local/bin/docker 

Windows에서 설치하려들면 미쳐돌아가는 반면 우분투는 리눅스라 Docker가 굉장히 쉽지요. 책에서보면 몇 페이지에 걸쳐서 설명하던데 Docker는 역시 리눅스에서 돌리는 것이 가장 좋습니다.


P.S-2 Docker가 굉장히 유용한 배포판으로 Arch와 FreeBSD가 있습니다. Arch는 롤링릴리즈 특성상 구버전 설치가 힘든데 구버전을 길게 지원하는 Debian이나 Ubuntu LTS를 Docker에 올려놓고 해당 배포판용 프로그램을 사용하는 경우가 많다고 합니다. FreeBSD는 Linux가 아닌 BSD이므로 Linux전용 프로그램을 요구할 때 사용한다고 합니다.


P.S-3 호스트의 X를 사용하는 것으로 굉장한 강점이 있는데 컨테이너에서 그래픽가속도 됩니다. 보통 가상화는 오버헤드가 많은데 이쪽은 오버헤드 자체가 없습니다.

,

리눅스에서 폰트를 쓰다보면 Windows의 폰트가 필요할 때가 은근히 있습니다. Wine으로 프로그램을 굴릴 때 말 그대로 굴림폰트나 Times Roman폰트가 필요한 경우가 있지요.


이를 편하게 하기 위해서 우분투에서는 ttf-mscorefonts-installer란 패키지를 통해 EULA동의하에 설치할 수 있도록 해놓았습니다.


그런데 ttf-corefonts를 설치하다보면 


Can't drop privileges for downloading as file '/var/lib/update-notifier/package-data-downloads/partial/andale32.exe' couldn't be accessed by user '_apt'. - pkgAcquire::Run : 허가 거부 

위의 메시지를 띄우면서 설치가 거부되기도 합니다. 이런 경우 원인은 의외로 간단한데요.


ttf-mscorefonts-installer 패키지 버전이 낮아서 생기는 문제입니다. MS폰트는 sourceforge를 통해서 다운로드 받게 되어있는데 이전 버전에서는 이 부분이 갱신이 덜 되어서 너무 오래된 인증서를 통해 다운로드 받기 때문에 그렇습니다. 그럼 새로운 버전의 패키지를 쓰면 되겠지요?


우분투는 데비안의 패키지리스트를 받아온다는 사실은 알고 계실겁니다. 그럼 해당 패키지를 Debian sid에서 가져오면 되는 것이지요.


wget http://httpredir.debian.org/debian/pool/contrib/m/msttcorefonts/ttf-mscorefonts-installer_3.6_all.deb
sudo dpkg -i ttf-mscorefonts-installer-*


이렇게 하시면 2017년 현재 MS폰트를 아무 문제없이 설치 할 수 있을 겁니다.



,

채팅봇이란 물건이 있습니다. 일종의 인공지능 대화상대인데 특정 대화방(채팅룸)에서 특정 키워드가 나오면 해당 키워드에 맞는 대답을 해주는 물건입니다.


이미 잘 이용되는 물건으로는 간단하게는 심심이가 있고 Youtube와 TwitchTV에서 사용하는 NightBot, MooBot등이 있고 인공지능 대화용으로 만들어진 MS의 테이(Tay)나 구글의 채팅봇도 있습니다. 카카오톡을 통해 알려주는 채팅봇도 있습니다.


사실 인공지능까지는 아니더라도 간단하게 유튜브나 TwitchTV등에서 방송하는 사람들을 도와주는 봇들은 이미 많이 쓰이고 있지요. 이들의 조상은 IRC에 플러그인 방식으로 사용되어서 해당 채팅방에서 물을 흐리는 몇몇 또라이들을 추방하거나 욕설등을 가려주는 등 IRC의 심판으로 쓰였던 그런 물건이 시초라고 보고 있습니다. 여기에 몇가지 키워드를 더 추가해서 특정 키워드가 나오면 대신 대답을 해주거나 간단한 대화기능을 넣는 등 발전을 했고 이후 지금의 시리같은 인공지능 기술과 음성인식 기술이 접목되어 굉장히 편리해졌지요.


지금 많이 이용되는 채팅봇 혹은 전자비서의 조상은 IRC의 플러그인들로 부터 시작되었다고 본다. 사진은 IRC클라이언트 중 제일 유명한 mIRC의 로고



이런 쪽에 제가 관심을 갖게 된 원인은 한 때 유명했지만 지금은 그저그런 Twitch Plays Pokemon때문이었습니다.

Twitch Plays Pokemon은 말 그대로 TwitchTV방송의 채팅을 통해 직접 게임을 움직여서 게임을 하는 특이한 방송이었습니다. 지금은 시들하지만 처음에는 방송을 보려는 사람들로 붐볐었습니다. 문제는 그만큼 컨트롤이 산으로 갔다는 것이지만...


당시 이슈가 되었던 Twitch Plays Pokemon 방송. 사공들의 수많은 채팅들을 봇이 읽어들여서 게임을 하는 그런 방송이었다.


해당 방송의 방식은 아주 간단합니다. 사람들이 채팅방에 특정 키워드(right, left, up, down, a, b, start, select 등)을 치면 게임과 함께 연동되는 봇이 해당 명령에 맞는 기능을 게임에 전달하여 움직이게 하는 것입니다.


이것이 가능했던 이유는 TwitchTV의 채팅이 기존의 IRC를 그대로 이용하기 때문이었습니다. TwitchTV는 채팅방식을 공개된 IRC프로토콜을 이용하되 약간의 보안을 적용해서 사용했기 때문에(그나마 그 보안도 알려진 방식입니다.) 기존의 IRC봇을 만들기 쉬웠습니다. 실제로 여기에 쓰인 플러그인과 비슷하게 구현된 소스코드도 공개되어 있지요.


https://github.com/hzoo/TwitchPlaysX

https://github.com/sunshinekitty/TwitchPlaysPokemon


위 github가 해당 플러그인을 구현한 소스코드입니다. IRC를 기반으로 키보드 혹은 마우스 명령을 내릴 수 있게 되어있지요.


채팅을 할 수 있는 방송은 TwitchTV만 있는 것은 아니지요. Twitch외에도 Youtube가 있고 국내에서는 DaumTV팟도 있습니다. (아프리카TV는 너무 구식이기 때문에 예외로 합시다.)


1. 실시간 방송이 가능하고

2. 동시에 채팅도 할 수 있으며

3. 여러명이 달려들어도 서버상태가 괜찮다면

이런 류의 봇을 직접 만들 수 있지 않을까?


라는 생각이 들더군요.


네, 사실은 안일한 생각이었습니다. 대다수 서비스는 IRC기반이 아닌 다른 방식을 사용하고 있었고 해당 프로토콜을 알아내는 것은 굉장히 어려웠습니다. TwitchTV가 알려진 방식을 사용한 특이 케이스였던 것입니다.


그런데 Youtube는 API를 통해 채팅봇을 만들 수 있게끔 공개가 되어있었고 실제로 NightBot이란 봇이 이미 만들어져 있었습니다. 즉, Youtube는 충분히 이러한 봇제작이 가능하다는 의미였지요.

https://developers.google.com/youtube/v3/live/docs/liveChatMessages/list


"그래! 그럼 나도 ChatBot이란 것을 한 번 만들어보자!"라는 생각으로 시작을 해봤습니다.


결과는...당연하게도 참패.


YoutubeAPI는 생각보다 요구하는 것이 너무 많았습니다. 저는 그저 채팅 내용을 읽어들인다음 키워드분석을 하는 것을 원했는데 해당 채팅방의 전반적인 것을 다 API로 세팅하게 만들어져 있더군요. 전반적인 IRC봇이 그렇기는 하지만 위의 TwitchPlaysPokemon의 소스코드는 그렇게 복잡하게 만들어지지는 않았습니다.


즉, 예상을 뛰어넘는 수준의 설정을 요구했던 것입니다. 


처음에는 그냥 장난으로 시작한 것인데 이런식으로 흘러가다간 올해안에 ChatBot은 커녕 비슷한 것도 만들기 어렵겠다는 생각이 들었습니다. 하지만 세상은 넓고 꼼수는 많습니다. 그리고 그 꼼수는 간단한 아이디어부터 시작되었습니다.


"Youtube나 TwitchTV나 웹페이지에서 채팅이 가능하다."


특히 Youtube는 어딘가의 방송시스템 처럼 클라이언트를 설치하지 않고 웹브라우저에서 볼 수 있게 만들어져 있습니다. 그렇다는 것은 웹페이지 분석을 하면 채팅의 키워드를 읽을 수 있다는 의미입니다!


Youtube는 편의를 위해 채팅창만 따로 빼서 쓸 수 있게 할 수 있는데 즉, 채팅페이지를 따로 찾을 필요없이 해당 채팅창만 분석, 확인하면 채팅창으로 올라오는 키워드를 읽을 수 있다는 의미가 됩니다. 게다가 해당 페이지의 주소를 긁어내는 것도 어려운 일이 아닙니다. 당장 위 스크린샷만 봐도 창 주소를 바로 읽을 수 있게 되어있습니다. 그리고 저 페이지주소는 어떤 웹브라우저를 사용해도 똑같습니다. (어딘가의 무언가와 다르게 말입니다.)


그렇다면 소스보기를 통해 채팅창의 코드 분석이 가능하다는 의미이므로 어떤 Element(요소)가 채팅 메시지 요소인지 확인하는 작업이 필요했습니다. 해당 작업에는 크롬의 개발자도구가 유용하게 쓰였습니다. 분석 시작 15분만에 코드를 찾아냈으니까요. 하지만 이후는 노가다로 귀결된 것은 어쩔 수 없었습니다.


채팅 메시지는 해당 페이지에서 content라는 이름으로 찾으면 (아이디)+(메시지)형태의 리스트로 되어있었고 author-name이라는 이름으로 찾으면 채팅창에 떠있는 아이디를 리스트형태로 찾을 수 있었습니다. 그렇다면 두 리스트를 이용해서 메시지만 뽑아낼 수 있다는 의미이기도 하지요.


그런데 채팅은 실시간으로 이루어지는데 새로운 메시지는 어떻게 아냐고요? 위 작업을 그냥 계속 하면 됩니다. 그리고 이전 리스트와 새 리스트를 비교한 다음 추가된 것만 뽑으면 되는 것이지요.


그런데 이걸 만들까요? Selenium이란 우리가 실제로 사용하는 웹브라우저에 덧붙여서 사용하는 웹 자동화 모듈이 있는데 이것을 Youtube채팅페이지를 띄워서 해당 요소를 찾으면 되는 것입니다.


(http://www.seleniumhq.org/projects/webdriver/)


Chrome, Firefox, Safari 등 유명 웹브라우저와 함께 PhantomJS란 따로 UI를 제공하지 않지만 WEB접속을 해주는 Selenium을 위한 웹브라우징 엔진도 지원합니다. 저는 Firefox에 Selenium을 설치한 후 읽어들이기로 했습니다.


그리고 문장처리는 Python으로 처리를 했습니다. Selenium의 예제는 JAVA로 되어있지만 Python이 문자열 처리는 월등하기 때문에(대신 느린것은 어쩔 수 없지요.) Python Wrapper를 찾았더니 있더군요. pip로 쉽게 설치 할 수 있었습니다.


sudo pip install selenium

혹은

sudo pip3 install selenium


만약 pip(Python2)나 pip3(Python3)가 없으시면 우분투의경우 저장소에서 설치할 수 있습니다. 아무래도 2017년 현재에는 Python3가 낫겠지요.


그리고 WebDriver를 설치해야 하는데

Firefox는 https://github.com/mozilla/geckodriver/releases

여기서 geckodriver를

Chrome은 https://sites.google.com/a/chromium.org/chromedriver/

여기서 파일을 다운로드 받은 다음 /usr/bin에 넣어주시면 알아서 활성화가 됩니다.

PhantomJS는 그냥 PhantomJS를 저장소에서 설치하시면 알아서 활성화가 되므로 상관이 없습니다.


from selenium import webdriver
driver = webdriver.Firefox()
#Firefox가 싫음 PanthomJS나 Chrome도 상관없다.

#Youtube chat room's page URL
driver.get(' 유튜브 채팅창 URL')
driver.implicitly_wait(10) 


요렇게 코드를 작성하고 실행하면 웹브라우저가 하나 실행되면서 Webdriver를 통해 자동화가 가능하게 됩니다.


위 코드 다음

id_msg = driver.find_elements_by_xpath('//*[@id="content"]')
id_l = driver.find_elements_by_xpath('//*[@id="author-name"]')


이렇게 하면 id_msg란 리스트에는 content항목인 요소들이 들어가고 id_l이란 리스트에는 author-name이란 이름의 요소들이 들어가게 됩니다. xpath란 것은 W3C에서 요소들을 쉽게 쓸 수있도록 XML형태로 만든 규약인데 자세한 것은 따로 찾아보시길 추천드립니다.


그리고

print (id_msg[0].text)

print (id_l[0].text)

이렇게 하시면 해당 채팅창의 제일 첫 메시지의 아이디와 문장이 콘솔창에 뜨는 것을 알 수 있습니다!!!!


즉, 채팅창의 메시지를 읽어들이는데에 성공한 것이지요. 그렇다면 문자열을 조작하고 Tokenizer를 통해 단어별로 자른다음 키워드를 분석하면 봇을 충분히 만들 수 있겠지요?


일단 오늘은 Youtube의 채팅창의 내용을 읽어들이는 것까지만 하고 나머지는 넘어가도록 하겠습니다.


다음 예시는 위의 방식을 이용해서 Youtube의 채팅창의 내용을 콘솔창에 계속 띄우는 소스코드입니다.


https://colorscripter.com/s/h7ME3n7

,