2018년 6월 23일 토요일

Droid Sans Fallback 폰트 버그

http://cjonmart.net 라는 데를 들어가서 이것저것 장바구니에 담는데 중간중간 잘못 적힌 글자가 보였다. 처음 몇 번은 주말에 바빠서 오타를 냈나 싶었지만 같은 패턴이 반복되고 있었다.
가령 "건강식품관"이 "건가ㅈ식품관"처럼. "떡갈비"는 "떡가ᄅᅠ비"로. "밀감"이 "밀가ㅁ"로.

잘못 적힌 글자를 긁어다 복사해서 다른 창에 붙여보니 멀쩡하게 나왔다. 크롬이 폰트를 깨먹거나, 폰트가 잘못 만들어졌을 터였다.

브라우저에서 F12를 눌러 개발자 도구를 열고 잘못된 글자가 보이는 HTML 요소를 선택했다. 개발자 도구에서는 글자가 멀쩡하게 보였다.
 str=document.querySelector('[title="건강식품관"]').childNodes[0].text; for(i=str.length;i-->0;){console.log(str.charAt(i), str.charCodeAt(i), str.charCodeAt(i).toString(16));}
라고 가져다가 찍어봐도 "강"은 AC15로 잘 나왔다. 어쩌다 입력된 NFD가 잘못 표시되는 것도 아니란 얘기였다.

document.querySelector로 그 요소를 가져다가 window.getComputedStyle(x).fontFamily를 봤다. AppleSDGothicNeo-Medium, "Apple SD Gothic Neo Medium", "Noto Sans CJK Korean", "Noto Sans", "Droid Sans Fallback", "Malgun Gothic", sans-serif - 한켠에 gedit 설정창을 띄워서 폰트 이름을 찾아봤지만 애플도 Noto도 나오지 않았다. 잘못 표시되는 글자를 gedit 폰트 설정의 미리보기 칸에 넣고 차례로 폰트를 봤더니 Droid Sans Fallback이 깔려있었고, 실제로 글자도 크롬에서와 같이 잘못 나왔다.


하지만, 크롬이 gtk를 쓰던가? 폰트 파일의 잘못일 수도 있지만, 리눅스 세계이니만큼 폰트 래스터라이저를 먼저 의심해볼 필요가 있었다.

다시 파이어폭스에서 같은 주소를 열어봤다. 글자가 멀쩡하게 나왔다. F12를 눌러 요소를 선택하고 오른쪽에 어떤 폰트가 적용되었다는 설명을 열어보았다. 이번엔 Noto가 적용된 걸로 나왔다. Korean이라는 꼬리표가 붙은 폰트가 없기는 하지만 자동으로 KR로 적용하는 건지, 아니면 항상 Noto로 적용하는 건지. 이래서야 비교가 안 됐다. 다른 한글 폰트를 몽땅 제거해서 영문만 나오는 상태로 만든다면 확인이 되겠지만 그렇게까지 하고 싶지는 않았다.
혹시나 해서 Droid Sans Fallback을 웹폰트로 보여준다는 웹페이지도 몇 개 열어봤지만 증상을 재현해줄만한 상황은 아닌 것 같았다.

찾아보니 Droid Sans Fallback은 구글 안드로이드 때문에 배포되는 폰트인 것 같았다. 널리 쓰이는 걸 고려한 폰트인만큼 다국어 부문에서 잘못된 정보를 포함할 수도 있겠다 싶었다. gedit 설정창에 한글 AC00부터 11184글자를 모두 긁어다 붙여봤다. (설정창을 닫고 본문창에서는 증상이 나타나지 않았다) 과연, "가" 다음에 "각-갛" 범위의 글자가 모두 받침이 떨어진 상태로 나오고 있었다. "나" 이후로는 폰트 영역이 없을 때 나오는 채움 표시가 나오고 있었고 중간은 너무 많아서 다 못 봤지만, 끝에서는 다시 "힢힣" 두 글자가 나오는 걸로 끝이 났다. 빈 영역이 대부분인 걸로 봐서, 의도적으로 채워진 걸로는 보이지 않는다.

dpkg -l | grep -i droid 해보니 fonts-droid-fallback 패키지가 나온다. dpkg L fonts-droid-fallback 해보면 ttf 파일이 2개. fontstools 패키지의 ttx 명령으로 풀어보니 과연 HANGUL 어쩌고 하는 줄이 잔뜩 있다.

아마도 폰트가 잘못 만들어진 것 같긴 한데, 이걸 어디에 어떻게 전달을 할 수 있으려나 모르겠네.

https://github.com/google/fonts/issues/1352 첫번째 반응을 보면 Droid는 이제 Noto로 대체되었으니 그냥 바꾸고 말라는 얘기다. 그것도 2017년 말.
그래서 그냥 지웠다. apt remove fonts-droid-fallback -y

2018년 6월 17일 일요일

리눅스에서 5.1채널 스피커 테스트

이리저리 물건을 정리하다 보니 스피커 연결선을 모두 뽑았다가 다시 꽂았다.

맞게 연결했는지 확인하려고 늘 쓰는 검사 동영상을 틀었는데 smplayer + mpv 조합으로 음분리가 잘 되지 않았다. speaker-test 명령이 있는 건 알고 있어서 몇 가지로 실행해봤는데 딱히 이거다 싶은 결과가 나오지 않았다.

그래서 아래와 같이 성공한 방법을 적어둔다.
  • aplay -L | grep -i pdif -B2 | grep MAYA -B1 -A1
  • pasuspender -- speaker-test -Ddca:CARD=U5,DEV=0 -c6 -l1 -twav -s1

MAYA U5 외장 사운드에서 광출력을 뽑아 야마하 TSS-10 쪽으로 신호가 넘어간다.
https://github.com/darealshinji/dcaenc 에서 dcaenc를 가져다 설치한 상태라서 dca 장치를 썼다.
pulseaudio가 기본으로 구동되는 환경이다 보니 pasuspender를 씌워서 pulseaudio를 거치지 않고 장치에 직접 접근했다.
s 옵션뒤의 숫자를 하나씩 바꿔주면 각 스피커 이름을 담은 음성이 재생된다. 스피커가 맞게 연결된 걸 알 수 있다.

자, 이제 smplayer + mpv에서 뭐가 문제인지 알아볼 차례구나(...)
왜인지 모르지만, 껐다 켜고 나니 /etc/pulse/ 설정 하나 건드린 거 없고 smplayer는 모든 오디오 옵션을 기본, 자동 혹은 끈걸로 뒀을 때 mpv에서 샘플 영상으로 음 분리가 잘 된다. mplayer를 통해서는 소리가 깨지는 걸로 봐서 뭔가 다른 게 있긴 한가본데.
패스쓰루 옵션을 켜면 안 되는 건 이상하긴 한데, 일단 잘 되니까 넘어간다.

2018년 6월 9일 토요일

kubectl을 다른 호스트에서도

k8s 클러스터를 3개 가상머신으로 구성한 뒤에 항상 master에 직접 들어가 kubectl 명령을 실행해왔다.

최근 vscode를 쓰고 있는데, terraform 확장을 테스트해볼 겸 해서, kubectl은 우분투 snap으로 설치하고 master의 ~/.kube 디렉토리를 몽땅 복사해서 로컬로 가져왔다. kubectl을 실행하니 과연 잘 된다. .kube/config 파일에 적힌 IP가 192인 걸 보니 master 안에서도 127.0.0.1이 아니라 DHCP가 부여하는 IP를 써서 접속하는 구조였던 것 같다.

이렇게 되니 로컬에서 terraform 테스트하는 건 그냥 가능하게 되었다. 문제는 master에서라면 어떻게든 접속할 수 있었던 k8s 내부 네트워크에 접근할 길이 없어졌다는 것. external loadbalancer 대응 문제가 좀 더 크게 느껴진다.

kubectl expose --type=LoadBalancer

traefik 설치 과정에서도 검토해봤지만, 외부 접속을 k8s 내부로 어떻게 끌어올지가 여전히 문제다. 여러 서비스가 k8s 세계 안에서 조화롭게 돌아가고 ingress controller를 traefik으로 설정해서 특정 도메인과 포트로 접속하면 k8s 내부의 원하는 리소스에 접근할 수 있게 되어 있다 한들, 실제 공인IP의 세계로 연결하는 게 오리무중인 상황이어서야 의미가 없다.

terraform 설명 글을 찾아봐도 당연스럽게 LoadBalancer 타입을 사용하도록 되어 있을 뿐, on-premise 환경에서 어떤 처방이 있는지를 언급하는 데가 없다.
(https://www.hashicorp.com/blog/managing-kubernetes-applications-with-hashicorp-terraform 를 보고 복붙만 해봤는데 plan에서 주루룩 지정될 항목이 나오는 점은 좋았다. apply가 끝이 나질 않아서 살펴보니 LoadBalancer를 사용하고 있어서 중단했을 뿐)

https://github.com/kubernetes/kubernetes/issues/36220#issuecomment-351782407 얘기에 https://kubernetes.io/docs/tasks/administer-cluster/developing-cloud-controller-manager/ 같이 CCM을 직접 만들면 될 거라는 얘기가 그럴듯해 보인다. type:LoadBalancer에 대응하는 구현체가 있으면 되는 건 맞을 테니까.

CCM은 
https://zetawiki.com/wiki/%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4_%EC%9A%A9%EC%96%B4 설명을 보면 k8s system의 일부로 돌아가면서 해당 환경에 맞는 관리 동작을 하는 정도로 이해가 된다. ingress controller가 k8s 안쪽으로 진입한 트래픽을 다루는 거라면 CCM은 k8s 가장 바깥이 그 밖의 세계와 어떻게 이어져야 하는지를 처리해야 하겠지.

https://www.reddit.com/r/kubernetes/comments/a0vrw7/metallb_and_traefik_decision_on_premise/ealnhun/
MetalLB가 여기 대응하는 물건이라고 한다. (ingress controller와는 다르다는 걸  명시해줘서 이해에 도움이 된다)

https://medium.com/@JockDaRock/metalloadbalancer-kubernetes-on-prem-baremetal-loadbalancing-101455c3ed48
https://medium.com/@JockDaRock/kubernetes-metal-lb-for-on-prem-baremetal-cluster-in-10-minutes-c2eaeb3fe813
여기 좀 더 내용이 있다.

2018년 6월 6일 수요일

Blogger 첫 페이지에 글 노출하지 않기

커스텀 도메인이나 HTTPS 적용 등 여러 면에서 블로그 서비스로는 구글의 Blogger가 가장 무난해서 쓰고 있다.

하지만 도메인으로 처음 들어왔을 때 무턱대고 글을 보여주는 게 마음에 들지 않아서, 첫 페이지라는 개념을 적용할 수 있는지 찾아봤다. https://www.quora.com/How-can-I-edit-a-home-page-on-blogger-com/answer/Elliyas-Ahmed 이런 답이 나온다.

Blogger 테마도 XML 수준에서 직접 편집하면서 필요한 부분에 조건문을 넣으라는 거다.
  • https://support.google.com/blogger/answer/46995?hl=ko&ref_topic=6321969
  • https://support.google.com/blogger/answer/47270?hl=ko
 아래와 같은 태그를 필요한 위치 앞뒤에 넣으면 첫 페이지가 아닐 때만 영역이 보이게 된다.
<b:if cond='data:blog.url != data:blog.homepageUrl'>
</b:if>

하지만 아무 데나 되는 건 아니고 넣을 수 있는 위치에 제약이 있다. 테마 마크업 구조를 조금 알아야 이해가 되는데, 크게 봐서 b:section과 b:widget 태그가 페이지에 표시되는 단위라고 할 수 있고 b:includable 태그로 영역을 잡아주면 그걸 b:include 태그로 가져가서 쓰는 식이다. 그리고 모바일 레이아웃이 따로 있는 테마라면 b:if 태그로 data:mobile 값을 검사해 어떤 경우에 블럭을 표시할지 말지 결정하는 부분도 있을 것이다.

그래서 지금은 일단 모바일 접근이 아닐 때 글을 표시하는 영역이 안 나오도록만 해놨다. 본문과 본문 위에 날짜 나오는 부분 2개를 막는 걸로 처리가 됐다.

비워둔 영역은 따로 안내 페이지를 하나 만들고 그 본문을 가져오는 수준에서 채우고 싶었는데 이건 방법이 있는지 어떤지도 모르겠다. 아마 안될 것 같긴 한데.

Firefox CSD 기능을 쓰려고 시작한 모험

CSD란?

client-side decoration이라고 해서, 창 관리자가 그려주는 창 테두리와 버튼들 대신 프로그램이 직접 그런 부분들을 창 안에 표시하는 기능이 있다. decoration을 없애는 거야 일찌감치 가능했다. Openbox 같은 경우엔 창 메뉴를 열어서 "Un/Decorate" 기능으로 끄고 켤 수 있다. 프로그램이 창을 띄울 때 undecorate 창이라고 선언할 수도 있다. (wmctrl로도 될 줄 알고 찾아봤는데 그런 거 없나보다)

그렇게 없앤 영역이 담당해야 할 기능 그러니까 창의 크기를 바꾸고 창을 닫거나 옮기는 걸 어떻게 처리하는지가 문제가 되는 건데, 개별 프로그램들이 알아서 잘 할 방법을 찾아보자는 얘기가 본격적으로 나오는 거다.

CSD 도입 상황

얼마전까지 CSD가 두드러지게 적용된 건 구글 크롬이었다. 처음 깔았을 때는 탭이 맨 위에 오는 크롬 특유의 모습이지만 설정에서 '시스템 제목 표시줄 및 테두리 사용' 옵션을 켜면 창 관리자가 그려주는 테두리가 붙는 걸 볼 수 있다.

그리고 csd에 대한 건 아니지만 gtk3에 (OS X의 동작 같이) '창 메뉴바를 분리해서 최상단 패널에 몰아서 보여주는' 패치가 들어간 것도 맥을 같이 하는 흐름이었다고 생각한다. 그 뒤로 Unity나 gnome-shell이 '창 관리자' 역할을 넘어 프로그램 안쪽의 기능들과 긴밀하게 연계하면서 창 관리자가 중간에 끼는 게 데스크탑 환경을 만들어가는 입장에서 거추장스럽게 느껴졌을 것 같기도 하다.
 그러다가 (클라이언트 창이 뜰 수 있도록 해주는 공간 자체를 만들어내는 게 서버인데) 창 시스템 서버가 X, X.org의 틀을 벗어나 Wayland라는 걸로 넘어가면서 CSD를 진지하게 다뤄야 하는 상황이 되었나보다. 아래는 참고할만한 글이다.
  • (영어) https://blogs.gnome.org/tbernard/2018/01/26/csd-initiative/
  • (영어) https://blog.martin-graesslin.com/blog/2018/01/server-side-decorations-and-wayland/
  • (영어) https://kver.wordpress.com/2014/10/25/presenting-dwd-a-candidate-for-kde-window-decorations/
  • (한국어) https://nemoux00.wordpress.com/2014/10/29/wayland-csd-ssd-dwd/

사실 윈도우 동네에서는 WIN16 API 운운하는 시절부터도 이미 나온 얘기였다. 윈도우 환경이 제공하는 기본 모양이 워낙 고정적이다 보니 프로그램마다 자기 취향대로 창을 그려대는 통에 전반적인 통일감이 없고 사용성이 떨어지고 윈도우가 발전해도 개별 프로그램은 발전을 따라가지 못해 구닥다리가 된다는 거였다. 꼭 데스크탑 얘기만이 아니라 웹이나 모바일 앱 환경에서도 OS가 제공하는 환경을 따를지 말지에 대해서 논란이 많다.

Firefox와 CSD

한편, 이런 '주어진 환경을 따를지 아니면 직접 해결할지'를 더 많이 고민해온 게 Firefox 같이 여러 환경을 지원하는 프로그램이다. 크롬이야 워낙 독창적인 인터페이스를 들고 나왔기 때문에 모든 걸 무시하고 바닥부터 시작할 수 있었지만 파이어폭스는 오랜 기간을 거치면서 그때그때 OS의 변화와 UI의 유행을 고스란히 따라와야 했다.

그리고 드디어 파이어폭스가 CSD 옵션을 포함한 게 60 버전부터다. 방침이나 당부를  따지지 않더라도, 어떤 식으로 동작할지 궁금하긴 했다. 실은 58 버전 정도부터도 개발 버전에는 들어갔었기 때문에 일찌감치 깔아서 CSD 옵션을 켜봤지만 왜인지 탭이 있는 줄의 공간 배치가 조금 변하는 것 말고 실제로 창 테두리가 없어지거나 하지는 않았다.

Openbox 때문일 거라고 생각하지는 않았다. 그냥 아직 도입 초반이니까 뭔가 문제가 있는 거라고만 짐작했다. 하지만 정식 버전에 포함이 된 뒤에도 여전히 창 테두리가 남아있는 건 이상했다.

CSD 적용된 Firefox를 향한 모험

그러다가 Openbox가 아닌 다른 세션을 잠깐 썼을 때 파이어폭스에 온전히 CSD가 적용된 걸 확인했다. gnome-session의 변종으로 존재하는 것들에선 모두 CSD가 잘 동작하는 것 같았다. 특이하다면 어떤 환경에선 (윈도우에서의 크롬처럼) 탭 위에 여백이 하나도 없고 어떤 환경에서는 (OS X에서의 크롬처럼) 약간 여백이 생겼다. 나는 여백이 없는 걸 선호하기 때문에 이것저것 바꿔가면서 띄워봤다.

하지만 그대로 Openbox를 버리고 데스크탑 환경을 갈아타기에도 문제가 있었다. 애초에 단촐한 구성이라 Openbox를 쓰고 있던 터에 다시 이런저런 프로그램이 잔뜩 뜨고 구성에도 제약이 있는 환경으로 가는 게 손에 딱 맞질 않았다.

가장 걸림돌이 된 건 여러 모니터에 배경 화면을 각각 띄울 수 없다는 거로, gnome-shell은 왜인지 배경 화면을 하나로만 제공했다. 아마 Xinerama 같은 걸로 panning 옵션을 통해 모든 화면을 하나로 뭉쳐서 쓰기 위해 그런 것 같았다. 이리저리 뒤져보면 gnome-shell 안에서 panning을 풀어버리는 방법도 있을 거라고 생각은 했지만 시간도 오래 걸리고, 다른 모든 설정 프로그램이 단일한 배경만을 전제하는 상황에서 강제로 환경을 바꾸는 게 얼마나 효과가 있을지도 의문스러웠다.
그리고 이것도 아마 gnome-shell의 특성 때문에 생기는 문제인 듯한데, xrandr에서 여러 모니터 중에 하나를 제대로 사용하지 못하고 꺼버리거나 해상도를 엉뚱하게 맞추는 문제가 있었다. 인텔 내장 그래픽을 쓰기 때문에 어쩔 수 없는 건가(웃음) 싶기도 했다. 찾아보니 EDID나 mode 같은 용어가나오면서 직접 정하라는 얘기도 있었고, gnome-shell이 하드웨어 가속을 쓰려고 하기 때문에 생기는 증상이라는 의심도 들었다. Openbox를 쓰면서는 겪은 적이 없는 상황이었기 때문에 그냥 Openbox로 빨리 전환하는 걸 택했다.

Openbox를 기본으로 띄우고 뭔가 (아마도 XAtom 수준까지 내려가는) 영향을 주는 프로그램을 찾아서 똑같이 띄워주면 Firefox CSD를 그대로 쓸 수 있을까 싶어 ps 명령으로 각 환경마다 어떤 프로세스가떠 있는지도 확인해봤지만 이거다 싶은 게 없었다. 그래서 방법을 바꿨다.

lightdm에서 Openbox를 직접 선택하지 않고 다른 세션 안에서 openbox --replace 명령으로 창 관리자만 바꾸면 원하는 결과물을 만들어낼 수 있을 것 같았다. 실험해보니 파이어폭스는 여전히 CSD가 잘 동작했고, 그러면서도 Openbox의 기능을 쓸 수 있었다.

"apt-cache pkgnames | grep -- -session$" 명령으로 어떤 세션들이 있는지 찾아봤다. openbox-gnome-session 패키지는 혹해서 깔아봤지만 lightdm에서 진입하지 못하고 튕겼다. 찬찬히 보다가 선택한 게 xfce4-session이었다. 너무 요즘 거라서 gnome-shell의 영향을 강하게 받을만한 것도 아니고 적당히 독립적인 노선을 유지하기 때문에 Openbox랑 조합해서 쓸만할 것 같았다. 물론 파이어폭스 CSD도 잘 됐고, 탭 위로 여백도 없었다.

xfce4 환경은 만족스러웠다. lightdm에서 xfce4 세션을 선택하고 진입했을 때 처음 환경은 온통 xfce4 기본 프로그램들로 채워져 있었지만, 얼마든지 교체할 수 있었다. openbox --replace로 창 관리자를 바꾸고, ~/.config/openbox/autostart 명령을 세션 관리자에 등록해서 그동안 Openbox에서 쓰던 초기 실행 명령들을 그대로 살려 쓸 수도 있었다. 바탕화면에 아이콘을 보여주는 xfdesktop4는 삭제를 해도 다른 패키지 의존성에 전혀 영향을 주지 않을 정도였다. xfce4는 오직 세션 매니저만 제공하는 셈이었다.

이렇게 해서 Openbox 환경에 Firefox를 쓰면서 CSD 기능을 쓸 수 있게 되었다.

2018년 6월 2일 토요일

ZOTAC Nano CI327

윈도우 10 홈 라이센스가 동봉된, 32기가 저장장치가 내장된 모델을 굳이 샀었다. 꼭 윈도우를 써야 하는 경우가 어쩌다 있기도 하고, 저장장치가 하나라도 더 붙은 걸 고르면 쓸모가 있겠지 싶은 마음이었다.

그리고 9개월 여가 지난 지금, 32기가 디스크가 인식되지 않는 걸 발견했다. 32기가로는 단독으로 쓰기에 한계가 있어서 애초부터 SSD를 따로 붙여서 쓰고 있었다. 한동안 종종 윈도우로 부팅을 하다가 안 건드린지 한참 되긴 했는데 그래도 이렇게 속절없이 망가져 있으니 아까운 건 어쩔 수 없다. 아낀다고 뭐 많이 쓰지도 않았는데.

전화를 넣어본다 한들 수리를 할 수나 있을지 의문이다.