ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Mac + Docker 에서 GUI 사용하기 (python matplotlib 사용하기)
    개발 환경/Docker 2020. 2. 23. 02:01
    반응형

    모든 개발 환경을 Docker로 넘어가고 있는 시점에서 계속 난관에 봉착한다. 이번 난관은 바로 Mac + Docker + matplotlib다. 우선 Docker는 리눅스 서버이기 때문에 GUI가 없다. 말이 조금 이상한데 리눅스에서 GUI는 리눅스 커널에 포함된 시스템이 아니라 프로그램이다.(신기) 우분투나 민트 등 리눅스 베포판들은 다 리누스 토발즈가 개발한 리눅스 커널위에 GUI 프로그램을 얹은 것이다. nvidia-smi를 자주 사용하는 사람은 Xorg라는 프로그램이 계속 돌아가는 것을 봤을텐데 그것이 바로 리눅스의 GUI 프로그램이다. 자세한 것은 구글링... 결론은 여튼 Docker에는 GUI 프로그램이 없고 그래서 matplotlib와 같은 GUI python 앱은 아무런 세팅 없이는 사용이 불가능하다. 그래서 열심히 구글링해서 방법을 알아냈고 블로그에 정리한다. 우선 열심히 검색한 결과 한글 글은 Linux + Docker + GUI만 있고 Mac은 아예 없다. 게다가 영어글 조차도 Mac + Docker + GUI는 있어도 matplotlib는 없다 ㅎㅎ 사실 머 같은 것이긴하다. 말이 길어졌고 이제 방법을 정리한다.

     

    0. 방법론

    우선 Linux + Docker + GUI 환경을 구축할 때는 local에 있는 Xorg를 docker container에 마운트해 공유하는 방법을 사용한다. 하지만 Mac은 그것이 불가능하다. 왜냐면 Mac은 Docker를 사용할 때 Mac OS 위에 가상 Linux를 만들고 그 위에 다시 Docker 시스템을 가동한다. 그래서 여튼 Mac OS에 있는 Xorg를 Docker container에까지 마운트를 통해 공유하는 것은 복잡하고 멀다. 그래서 XQuartz라는 Mac OS의 X window를 공유하는 프로그램을 사용한다. 무슨 말인지 이해가 잘 안갈 것이다. 링크를 참고하자.

    https://cntnr.io/running-guis-with-docker-on-mac-os-x-a14df6a76efc

    https://www.youtube.com/watch?v=PKyj8sbZNYw

    https://junn.net/archives/2323

    그리고 X window를 공유하기 위해 socat를 통해 tcp를 노출시켜줘야한다. 그럼 이제 차례를 밟아보자.

     

    1. Socat 설치 및 tcp 가상 시리얼 포트 노출

    brew install socat
    socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"

    설치 후 socat을 통해 포트를 노출시켜주면 그 command는 계속 작동중이기때문에 이후 작업은 새로운 터미널에서 진행한다.

     

    2. XQuartz 설치 및 세팅

    brew cask install xquartz

    brew를 통해 설치하고 나면 mac을 한번 재부팅해준다.

    open -a XQuartz

    재부팅했으면 위 명령어를 통해 XQuartz 프로그램을 연다. 사실 런치패드가서 앱을 마우스로 클릭해도 된다.

     

    이렇게 조금 이상한 GUI의 하얀색 터미널이 켜지면 성공적이다. 나는 .zshrc에 neofetch를 설정해둬서 저렇게 떴지 그냥 빈 터미널이 켜지면 정상이다. 이제 Preferences로 들어가자. 단축키는 command + ,

    위와 같이 Security에 들어가서 Allow connections from network clinets를 체크해준다. 우리는 socat을 이용해 가상 시리얼 포트를 노출시켜주었고 그곳을 통해 접속할 예정이니 network clinet가 맞다.

     

    3. Local IP 체크

    ifconfig en0

    output:

    en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
    	options=400<CHANNEL_IO>
    	ether a4:83:e7:47:c9:ed
    	inet6 fe80::c00:66bc:55f6:875a%en0 prefixlen 64 secured scopeid 0x6
    	inet xxx.xxx.xxx.xxx netmask 0xffffff00 broadcast xxx.xxx.xxx.255
    	nd6 options=201<PERFORMNUD,DAD>
    	media: autoselect
    	status: active

    중간에 inet xxx.xxx.xxx.xxx이 IP이니 기억해두자.

     

    4. Run 예제

    이제 돌려보자. 돌리기 전에 socat 명령어가 작동하고 있는지, XQuartz의 하얀 터미널이 켜져있는지 확인하자.

    docker run -e DISPLAY=xxx.xxx.xxx.xxx:0 gns3/xeyes

    xxx에 IP를 잘 입력하자. 이 예제는 위에 링크 걸었던 영어 글에서 가져온 예제이다. 실행하면 마우스를 따라 눈이 돌아간다.

     

    이런 프로그램이 실행되었으면 성공한 것이다.

     

    5. Run python matplotlib

    각자 돌리고자 하는 python 파일을 준비하자. matplotlib를 사용했으며 plt.show나 plt.figsave가 호출된 코드여야 테스트가 정확히 진행된다.

    docker run -it -v ~/ORFEO_project/ANC_projects:/opt/project -e DISPLAY=xxx.xxx.xxx.xxx:0 anc /bin/bash
    
    cd /opt/project
    python3 plot_anc.py

    터미널을 켜서 돌리기보단 바로 컨테이너로 돌리고 싶었는데 python 파일에 주소설정이 다르게 되어있어서 위와 같이 실행하였다.

    위와 같이 잘 작동하는 것을 확인할 수 있었다.

     

    6. 결론

    Docker의 장점은 바로 리눅스만 있다면 나의 코드를 어디서든 돌릴 수 있다는 것이다. 하지만 이번 프로젝트를 Docker 기반으로 옮기면서 든 생각은 과연 그럴까?이다. GUI가 있는 프로젝트상 이렇게 세팅해줘야할 것이 많아진다... 물론 나는 Mac 유저여서 그렇고 Ubuntu에서 한다면 이러한 세팅 필요없이 docker에 마운트 시키고 환경변수만 잘 설정해준다면 문제가 없을 것 같긴하다.

    매번 개발할 때마다 이렇게 전부 잡다하게 다 열어놓고 해야할까? 같은 동작은 3번 이상 하게 된다면 개발자로서 자동화에 대해 고민을 해봐야한다. 이러한 환경에서 자동화는 간단할 것 같다. Tmuxinator custom으로 한다면 config.yml 수정해서 pane 하나로는 socat 포트 열고, 다른 것으로 XQuartz 실행하고 이런식으로 작성하면 충분히 가능할 것 같다. tmuxinator custom은 https://hanseokhyeon.tistory.com/entry/tmuxinator-custom-layout-만들기를 참고하자.

    내 맥에 python을 지우는 그날까지 Dockerizing은 계속 된다.

    반응형
Designed by Tistory.