Docker 로 Linux 없이 Linux 개발하기

지난 달 말 — 이미 10월 말인 것 같지만 다 기분탓 — 발표에 썼던 슬라이드.

Windows + VisualStudio / macOS + Nuclide 환경에서 내부에 같이 띄운 docker container에 접근해서 C++ 프로그래밍을 디버깅 하는 내용을 다뤘다. 기록 차원에서 블로그 글로도 남긴다.

Docker + C++ IDE 개발환경 꾸려보기

Windows / macOS 용 docker를 이용하면 VM을 따로 띄우지 않아도 로컬 환경을 리눅스 개발 환경처럼 쓸 수 있다.
전에도 한 얘기지만, 툴은 가능하면 해당 OS 용의 GUI 도구를 활용하고 싶은게 내 심정.

그래서 (?) 요즘 나오는 좋을 툴들을 써서 Windows / macOS를 쓰는 기기에서 docker + linux 개발환경을 해당 OS 용 IDE 로 개발하게 꾸려보았다. (컴파일은 linux 컨테이너, 디버거 UI는 호스트 OS의 IDE를 쓴단 소리)

Windows

Widows 의 VisualStudio 확장 기능으로 linux  개발을 지원하는 Visual C++ Tools for Linux 라는게 있다. 지난 2016-09-06 에 업데이트.

이걸 써서 같은 컴퓨터에 띄운 docker 컨테이너에 접근하면, 디버거까지 붙여서 돌려볼 수 있다.
하재승 군의 crow 예제 하나를 디버거 붙여보면 잘 돈다.

vs-debugging

다만 고칠게 좀 많다:

  • Docker for Windows 의 volume 설정이 좀 이상한 것
  • 권한을 추가로 주지 않으면 잘 안 도는 것 (디버깅)
  • 빌드/디버깅/빌드 결과물을 한땀한땀 입력해야하는 것 (…)

macOS

macOS 용으론 Facebook 의 Nuclide 가 있다. 여기서도 crow 예제를 돌려보았다.mac-nuclide-io

macOS 에 띄운 docker 컨테이너에서 프로세스를 띄우고, lldb (GDB가 아니라…) 를 띄워 디버깅하는게 가능하다. 다만 의존성 걸린게 많아서 내가 만들어본 역대 최대 크기 (1.1 GiB) 짜리 docker 이미지가 나오더라; 용량은 차치하고, Docker for macOS 쪽이 volume 지원같은게 낫긴하지만 이쪽도 문제는 한 바가지긴 하다.

  • 설정을 한땀한땀 넣어야한다. (VS 쪽보다 아주 약간 편함)
  • 깔아야하는게 한 가득 (atom, nuclide, npm, clang, llvm, lldb, … 그리고 clang, llvm, lldb 에 대한 python 래퍼)
  • 테스트 한다고 썼던 ubuntu 16.04 에선 라이브러리 내의 경로가 잘못 박힌게 많아서 고쳐써야할 부분도 많다 (ubuntu 14.04 쪽도 크게 다르지 않으리라 생각)

이런 내용을 포함해서 이번 주 수요일 (2016-09-28) 에 넥슨 코리아 지하에서 기술 세미나를 합니다. 궁금하신 분은 와서 보시길.

Interop Madness

클라이언트 서버간 암호화  관련해서 개념 증명 + 몇 가지 성능 측정을 해야해서 몇 가지 언어 + 플랫폼에서 libsodium 1 을 호출해봤다. 그 와중에 겪은 일 정리.

C++

이쪽은 평범한 C/C++ 인터페이스니 문제 없이 끝.

Python

위에서 구현한 부분을 클라이언트 쪽 구현을 (빨리) 만들어서 테스트하는 작업을 했다.

여기서부터 문제가 생기기 시작. Ubuntu 16.04 (xenial) 이 제공하는 libsodium 래퍼가 python-nacl 2 인데, 써보니 내가 쓰려는 함수가 여럿 없다. 특히 crypto_stream* 류 함수가 없더라. 그래서 다른 래퍼가 있나하고 PyPI 에서 몇 가지 써보고는 빠른 포기.

이제 cffi 를 쓸 타이밍. C 코드로 정의한 함수를 변환해서 만든  .py 파일로 동적 라이브러리 (.so, .dll, .dylib) 에서 가져오는 방식을 썼다. 3 예~전에 ctypes 로 로딩할 때 괴로웠던 부분이 확실히 줄어들었다. ABI 대신 API 수준에서 접근하는 차이는 정말 컸다. cdata의 buffer 인터페이스도 쓸만했다.

cffi 로 libsodium 에서 필요한 함수들을 가져다 쓰기 시작한 이후로는 금방 일이 정리.

…하지만 이 시점에선 어떤 비참한 미래가 기다리는지 모르고 있었다. (?)

C#

(나로써는) 슬프게도, 클라이언트 쪽 구현 중 하나는 C#으로 해야한다. (Unity3d + mono) 게다가 이건 여러 플랫폼을 지원해야 한다:

  • Unity Editor: Windows, MacOS
  • Android: 다행히도 ARMv7만. Unity가 ARMv6는 지원하지 않는다 (?)
  • iOS: 기기 + 시뮬레이터에서 모두 돌아야 한다.

Windows는 (내가) 당장 쓸 머신이 없어서 일단 미뤄두고, 나머지에 대해서 잘 도는지 시험하기 시작. 꼬박 2일 걸린 것 같다 — 생각해보니 절반은 C++ 기반인 cocos2d 랑 같이 처리하는 것 때문이었던 것 같기도?

우선 각 플랫폼 별로 크로스 빌드를 시도…해야하나 했는데, libsoidum 저장소에 플랫폼 별 빌드 스크립트가 있다. 4 iOS/Android 쪽에 내가 쓰려던 함수 중 몇 개가 빠져서 컴파일 플래그를 조금 고친 것 말고는 별 일 없이 진행. 그리고 Unity 에서 (native) 동적 라이브러리를 어떻게 가져가나 고민했는데 경험 많은 동료분이 설명해주셔서 매우 간단한게 통과.

대략,

  • DllImport 로  C에 있는 함수들을 CLR 쪽에 노출하고
  • C# 코드로 이 함수들을 래핑하고
  • 다시 이 함수들을 써서 실제 개발자가 쓸 고수준 API로 바꾸자

라는 방향으로 진행했다. 에디터(=랩탑 위)에서 잘 도는걸 보고 android  기기에 올리기 시작. 왠걸, 초기화 (=sodium_init()) 은 성공했고 몇몇 초기화도 했는데, 그 이후에 호출하는 함수에서 크래시 (SIGSEGV).  (당연하게도) 콜 스택은 native code에서 죽는 것.

원인을 추측하기 시작:

  • C 함수 원형을 잘못보고 옮겼는지 확인 시작. C는 타입 무시하고 심볼 이름만 보니 내가 잘못 옮겼다면 크래시할 수도 있으니 우선 여길 의심하고 C 함수 원형과 하나씩 대조. 별 이상 없어 보였다 (불행의 단초)
  • 크로스 컴파일을 잘못했는가 확인: 생각해보니 C/C++ 로 올렸을 때는 잘 돌았다 (…)

…대략 정신이 멍해져오는데 다시 함수 원형을 보다가 불현듯 깨달은 사실:

C 쪽의 size_t 를 C#의 ulong 으로 지정했는데 Unity + ARMv7 은 32bit ABI를 쓰니 uint 여야하는 것. Orz.

그래서 이걸 iOS / Android 플래그로 ulong / uint 처리하게 했다가, iOS도 아직 32bit인게 남아있는 걸 보고는 (iPhone 5 및 그 이전 + iPhone 5C) UIntPtr 로 처리하고 강제 캐스팅하게 수정해서 마무리했다. 그러고나니 잘 돌더라.

 

3줄 요약

  • ABI 맞추기는 삽질이다. 어떻게든 API 수준으로 해결할 수 있는 법을 찾자 — python의 cffi 처럼. 아니면 기계적으로 처리할 방법을 찾아야?
  • (부득이하게) ABI를 맞춰야 한다면 가능한 arch 목록을 잘 확인하자. C/C++에서 편했던 platform dependent type들이 대재앙
  • 여러 플랫폼 지원하는 라이브러리는 정말 인생에 도움이 된다. 잘 쓰고나면 널리 알려줍시다 (?)

 


  1. libsodium 페이지. 현 시점에 적합한 대칭키 암호화 + AEAD, ECC 함수들, system random source 를 래핑한 함수, side channel 공격을 피하는 비교, 해시, … 등등을 제공하는 잘 만든 라이브러리. 인터페이스도 보고 바로 쓰는게 그다지 어렵지 않다. 
  2. GitHub 저장소. libsodium 이 fork(?)한 NaCl 을 래핑한 것 같은 이름이지만 libsodium 을 래핑한다. 
  3. API 수준에서, 소스 코드 밖에서 정의 부분을 참고해서 작성했다. 
  4. 저장소의 dist-build 디렉터리 의 스크립트들이 이에 해당한다. 

Docker for Mac 베타 사용기

연휴 내내 하루 빼고 일하다가 드디어 짬이 났다. 그래서 한 달 반쯤 전에 공개된 Docker for Mac 을 써보기 시작. 베타용 토큰도 지난 주에 받아서 사실 그 전엔 시간 났어도 못 써봤겠지만.

일단 내 희망 사항인 linux 툴들과 Mac 용 GUI 툴을 같이 쓰는 걸 시도해봤다. 대략 docker volume 으로 로컬 디렉터리를 컨테이너에 마운트해서,

  • MacOSX 환경에서 GUI 툴을 가져다 쓸 수 있을 것: 예를 들어 git mergetoolp4merge 를 쓴다거나
  • linux 몇 가지 distro. — 특히 ubuntu 14.04/16.04, CentOS 6/7 — 에 대해서 빌드 환경을 쉽게 불러내서 사용할 수 있을 것: 예를 들어 ubuntu 14.04 gcc4 에서 빌드 + 테스트해보고 + centos 6 (w/ devtoolset) 에서 빌드 + 테스트해보기 등.

이었다.

VirtualBOX 를 중간에 껴 넣는 대신, xhyve 를 써서 상대적으로 더 빠를 것 + volume 이 제대로 동작할 걸 기대했다. 대략 기대한대로 돌았는데 …

CentOS 7 컨테이너에서 빌드를 시작했더니 끝나질 않아서 activity monitor 를 열어보니 상태가 심각하다:

something-wrong

Docker volume 을 위한 구현체인 com.docker.osxfs 가 CPU 를 다 잡아먹고 있다. Docker volume 아닌 곳에서 빌드해보면 그 차이가 더 뚜렷함. (com.docker.xhyve 가 CPU를 다 쓴다)

something-acceptable

VMware Fusion 도 그러던데, Docker for Mac 도 CPU core 수 최대 값을 4개로 잡는다 — 12″ 맥북에서 무슨 만행을… 이것도 2개로 설정. (기본 값이 2개였는데, 메모리 늘리면서 생각없이 늘려서 Orz)

docker-setting-cpu-cores

설정 자체는 원하는 방향으로 가능해졌지만, docker volume (=osxfs) 관련은 앞으로 더 패치된 후에 성능이 나아지길 기대해야. 아니면 지금처럼 build 디렉터리를 docker volume 외부에 두는 식으로 해야할 것 같다;;;

요약

  • GUI 는 Mac에서, 개발툴은 linux 에서 이용하는 (내가 생각하는) 이상적인 휴대 작업 환경이 가능해 짐
  • boot2docker 등과 달리 정식으로 docker volume 을 지원하고, OSX 에서 직접 hypervisor 를 제어하는건 좋음 (메모리, 디스크, …)
  • osxfs 를 이용한 docker volume 의 성능 문제는 개선되지 않으면 못 쓸 정도

프로그래머의 일상: 험난한 python 패키징

제목처럼 거창한 건 아니지만.

웹 페이지에서 JSON web token (jwt) 를 쓸 일이 있어서 pyjwt 를 가져다 쓰기 시작했다. 근데 이걸 서비스 중인 vm들에 배포하려면 .deb 패키지로 묶어야 한다. Python 라이브러리를 .deb (간단하게) 패키징 할 때는 python-stdeb 패키지를 이용해서 간단히 묶어 버리고 있다 – 이건 기회가 되면 나중에 설명할 일이 있었으면 한다.

하지만 문제 발생:

$ python setup.py  --command-packages=stdeb.command bdist_deb
...
Traceback (most recent call last):
  File "setup.py", line 77, in 
    'jwt = jwt.__main__:main'
  File "/usr/lib/python2.7/distutils/core.py", line 151, in setup
    dist.run_commands()
  File "/usr/lib/python2.7/distutils/dist.py", line 953, in run_commands
    self.run_command(cmd)
  File "/usr/lib/python2.7/distutils/dist.py", line 972, in run_command
    cmd_obj.run()
  File "/usr/lib/python2.7/dist-packages/stdeb/command/bdist_deb.py", line 23, in run
    self.run_command('sdist_dsc')
  File "/usr/lib/python2.7/distutils/cmd.py", line 326, in run_command
    self.distribution.run_command(command)
  File "/usr/lib/python2.7/distutils/dist.py", line 972, in run_command
    cmd_obj.run()
  File "/usr/lib/python2.7/dist-packages/stdeb/command/sdist_dsc.py", line 139, in run
    remove_expanded_source_dir=self.remove_expanded_source_dir,
  File "/usr/lib/python2.7/dist-packages/stdeb/util.py", line 1061, in build_dsc
    -- %(maintainer)s  %(date822)s\n"""%debinfo.__dict__)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 3: ordinal not in range(128)

문제의 원인이 좀 어이 없었는데 – 달력을 확인한다면 데미지 두 배,

  • 저자 이름에 non-ascii 문자가 포함되어 있고 (저자의 이름이 José)
  • stdeb 에서 문자열 치환할 때 이 처리를 하지 않고 있는 것

해당 버그는 아직 처리 중인듯.

그래서 문제를 우회할 방법이 두 가진데,

  1. stdeb 버그를 수정한다; 이 경우엔 저 위의 오류난 곳의 __dict__ 의 unicode 타입인 걸 하나 하나 찾아서 encode('utf-8') 하는 것
  2. 문제를 부정한다 (?): …이러면 안될 것 같지만 저자 이름을 수정

일단 2로 우회했는데 – stdeb 도 우분투 패키지라 이걸 덮어쓰게 배포하기가 찜찜해서 – 외부에 배포할 일이 생기거나 하면 결국 1안으로 가야할 듯 하다. 혹은 더 복잡한 다른 패키지 .deb로 만들 때 처럼 debian 파일들을 다 만들거나.

요약 (?)

  • Python 모듈을 .deb 로 변환하는 python-stdeb 패키지가 있다.
  • 근데 이 패키지가 unicode 를 제대로 못 다루는 부분이 있다.
  • 엄한 우회책은 있지만 매우 괴롭다. 지금 2016년인데…

2015 년, 내 프로그래밍 언어는 …

2014 년, 내 프로그래밍 언어는 … 에 이어서.

작년 한 해 동안 주로 사용한 언어는,

  • C++ (제한적인 C++1x,y,z)
  • Python
  • …과 거의 비등한 양의 shell script (거의 bash 지만)

회사에서 만들고 있는 게임 서버 엔진 (+ 이걸로 만드는 게임 서버 혹은 게임 서버 개발 지원) 으로 거의 C++ 만 쓰고 지낸 듯 하다. 그래도 엔진 자체만 빼고는 C++11 이후를 써도 되서 꽤 편하게 짠 듯.

Python은 대략 이전에도 썼던 log 분석, 웹 서비스 stub 등에서 많이 썼고, bash 는 패키징 (.deb, .rpm …) 할 때 주로 썼으니..

올해도 아마 C++을 제일 많이 쓰는 한 해가 될 것 같구만.

Python 으로 JSON 빨리 처리하기

지난 며칠 동안 모 모바일 게임의 알파테스트가 있었다. 그리고 갑이 뽑아달라는 ad-hoc 통계를 뽑느라 로그 처리를 왕창 할 일이 있었다.

대략,

  • 로그 데이터는 하나의 JSON 문서로, 각 파일에 한 줄씩 차지하고 있다
  • 파일은 날짜 별로 쪼개져서 서버 로그 디렉터리에 남아있다

내부 테스트나 첫날 정도까지는 로그 처리가 순식간에 끝날 수준이라 (k초 수준; k < 10) 별로 신경 안 썼는데, 막상 데이터가 커지기 시작하니 오래 걸리기 시작.
(오래 걸린다 == 실행하고 결과 나올 때까지 걸리는 시간이 내 집중력이 유지되는 시간보다 길다)
그리고 ad-hoc 통계를 뽑으려다 보니 내가 실행하는 횟수가 계속 늘어서 걸리는 시간 줄이려고 삽질한 기록이 아래와 같다.

진행

대략 로그가 1 GiB 정도 쌓인 시점에서, 로그 처리를 완료하고 통계 데이터가 나올 때까지 55초 정도 걸리더라. (i7-2600 / 메모리 16 GiB / 샘숭 840pro)
일단 아래 두 가지로 급한 불은 껐고, 알파테스트가 끝나갈 때야 왜 빨라졌는지 알게 되었다.

일단 PyPy 를 끼얹어 본다.

메모리야 남아돌고, CPU가 100%로 튀는 상황이니 일단 PyPy 를 가져다가 써봤다.
Ubuntu 14.04 에는 PyPy 2.2.1 이 있다. 이걸 설치하고 동작하니 대략 33초까지 줄더라. (40% 향상)

최신 버전 릴리즈되는 PPA가 없나 검색해보니, 있더라: https://launchpad.net/~pypy.
여기서 PyPy 4.0.1을 가져다 쓰면 28초까지 실행 시간이 줄어들더라. (49% 향상)

mmap 도 끼얹어 봅니다.

이전에 하재승 군이 mmap 언급했던 게 생각나서 적용해보았다.
조금 더 빨라진다. 이젠 23초 수준.

여하튼 이 상태로 알파테스트 종료까지 갔더니 대략 로그 2GiB 처리하는데 53~55초 수준. 아마 처음 상태로 끝까지 갔으면 (끝나는 날 오후에도 갑이 통계 추가해달랬으니..) 내 멘탈은 더욱더 남아나지 않았을 듯 (…).

왜 빨라졌는가

왜 빨라졌는지 파악 하지 못하고 있었으니 측정해보자.
vmprof 프로파일러 를 붙여서 돌려봤다. (2:20 소요)

Python 2.7 실행 결과

loads 밑 그 하위 함수들 (decode, raw_decode) 들에서 잔뜩 시간을 쓰고 있다. 즉, 대부분의 시간을 JSON 디코딩하는데 쓰고 있다는 소리 (json.loads 함수라서)

PyPy 로 구동한건 다음과 같다. 0:55 소요.

PyPy 4.0.1 실행 결과

작은 루프를 계속해서 돌기 때문인지 대부분의 구간이 JIT 번역된 코드를 실행하고 있다. 여기서도 json.loads 호출의 비율이 크지만 Python 2.7 보다는 그 비율이 낮다.
왜 JSON 성능이 PyPy 쪽이 좋은지 확인해보니 PyPy 2.2.0 릴리즈 노트에 그런 내용이 있더란.

JSON decoding is now very fast (JSON encoding was already very fast)

근데 JSON 성능은 (보통은?) 외부 C library 에 의존해서 성능을 올린 경우가 많다. 그래서 전통의(?) simplejson 과 ujson 을 붙여서 테스트해봤다.
simplejson 으론 성능 향상이 없더라. (PyPy 의 경우 오히려 느려졌다)
C기반 JSON 구현체의 python 바인딩인 ujson 을 시도해봤다.

Python 2.7 + ujson 실행 결과

… ujson C 코드 디버깅 심볼이 없어서인지 제대로 프로파일링 안된 것 같긴한데, 같은 Python 2.7이면서도 시간은 대폭 줄었다. 1:19. (거의 절반)
그래도 통계 데이터를 실제로 해석하는 작은 루프들 성능이 JIT 쪽이 나은지 전체 시간은 여전히 PyPy 쪽이 더 좋다.

요약

  • vmprof 좋아요 씁시다.
  • Python 표준 라이브러리의 JSON은 너무 느리다. CPython을 써야한다면 ujson, 그게 아니면 PyPy 쓰자.

nginx + ngx_pagespeed

꽤나 예전에 동아리 서버에는 적용해봤는데 — 동아리 서버는 apache 웹서버를 써서 구글에서 바이너리로 배포하는 mod_pagespeed 를 썼지만 — 이 블로그가 쓰는 웹 서버는 nginx를 써서 적용 못하고 있었다.
Nginx 는 다 좋은데 동적으로 로드 가능한 모듈을 지원하질 않아서 소스에 넣고 빌드해줘야하는 것. 개인 웹 서버라 개발툴 없이 돌리는 상태를 유지하고 싶어서 회사 개발머신을 빌려 데비안 패키지만 만들고 옮겨서 설치하는 것으로. 아래는 그 기록.

빌드 기록

빌드 과정은 소스에서 ngx_pagespeed 빌드하기 를 따라하되 nginx 소스코드와 빌드 자체는 ubuntu 14.04의 debian 빌드 스크립트를 이용했다.

소스 코드 얻기

nginx 소스 패키지와 ngx_pagespeed 소스 타르볼, 그리고 PSOL 타르볼을 얻는다:

# nginx (1.4.6) 소스코드 + 빌드스크립트
$ apt-get source nginx

# ngx_pagespeed 릴리즈 아카이브
$ wget https://github.com/pagespeed/ngx_pagespeed/archive/release-1.9.32.10-beta.zip

# PSOL
$ wget https://dl.google.com/dl/page-speed/psol/1.9.32.10.tar.gz

# 압축 해제 및 필요한 구조로 변경
$ tar -zxf 1.9.32.10.tar.gz
$ unzip release-1.9.32.10-beta.zip

# PSOL 을 ngx_pagespeed 밑으로
$ mv psol/ ngx_pagespeed-release-1.9.32.10-beta/

# ngx_pagespeed 를 모듈 디렉터리로 이전
$ mv ngx_pagespeed-release-1.9.32.10-beta/ nginx-1.4.6/debian/modules/

nginx 빌드룰 수정

데비안 패키지의 빌드룰은 “{패키지-버전}/debian/rules” 에 있다. 여기선 nginx-1.4.6/debian/rules 를 열어 nginx-full 에 해당하는 config.status.full 항의 맨 뒤에 “--add-module=$(MODULESDIR)/ngx_pagespeed-release-1.9.32.10-beta \” 를 추가해서 아래와 같이 수정하다:

config.status.full: config.env.full
  cd $(BUILDDIR_full) && ./configure  \
      $(common_configure_flags) \
      --with-http_addition_module \
      --with-http_dav_module \
      --with-http_geoip_module \
      --with-http_gzip_static_module \
      --with-http_image_filter_module \
      --with-http_spdy_module \
      --with-http_sub_module \
      --with-http_xslt_module \
      --with-mail \
      --with-mail_ssl_module \
      --add-module=$(MODULESDIR)/nginx-auth-pam \
      --add-module=$(MODULESDIR)/nginx-dav-ext-module \
      --add-module=$(MODULESDIR)/nginx-echo \
      --add-module=$(MODULESDIR)/nginx-upstream-fair \
      --add-module=$(MODULESDIR)/ngx_http_substitutions_filter_module \
      --add-module=$(MODULESDIR)/ngx_pagespeed-release-1.9.32.10-beta \
            >$@

데비안 패키지 생성

$ cd nginx-1.4.6/
$ debuild -uc -us -rfakeroot -b
$ ls -1 ../*.deb
../nginx_1.4.6-1ubuntu3.3_all.deb
../nginx-common_1.4.6-1ubuntu3.3_all.deb
../nginx-core_1.4.6-1ubuntu3.3_amd64.deb
../nginx-core-dbg_1.4.6-1ubuntu3.3_amd64.deb
../nginx-doc_1.4.6-1ubuntu3.3_all.deb
../nginx-extras_1.4.6-1ubuntu3.3_amd64.deb
../nginx-extras-dbg_1.4.6-1ubuntu3.3_amd64.deb
../nginx-full_1.4.6-1ubuntu3.3_amd64.deb
../nginx-full-dbg_1.4.6-1ubuntu3.3_amd64.deb
../nginx-light_1.4.6-1ubuntu3.3_amd64.deb
../nginx-light-dbg_1.4.6-1ubuntu3.3_amd64.deb
../nginx-naxsi_1.4.6-1ubuntu3.3_amd64.deb
../nginx-naxsi-dbg_1.4.6-1ubuntu3.3_amd64.deb
../nginx-naxsi-ui_1.4.6-1ubuntu3.3_all.deb

…적당히 기다리고 나면 탑 디렉터리에 .deb 파일 수 개가 생긴다. 위에서 빌드 룰 수정한 nginx-full 패키지를 가져가서 서버에 설치.[1] 빌드 시간을 줄이고 싶다면 debian/control 을 수정하는 것도 (다음 번엔) 고려해야겠다.

설정하기

ngx_pagespeed : Nginx의 PageSpeed 모듈 :: Outsider’s Dev Story 를 참조해서 설정했다. 기본 값 + JavaScript 비동기 로딩 정도 설정함.

총평

Google PageSpeed Insight 점수가 15점 쯤 올랐다 (…). 행복하군 (야)
대신 앞으론 ubuntu 쪽 패키지 업데이트 / Google 쪽 릴리즈 마다 새로 빌드해야한다 (이쪽은 전혀 달갑지 않다…)

PS. (아마도) GPL인 debian/rules 파일을 일부 인용했는데, 이 글 라이센스를 CC-BY 대신 GFDL로 해야하나? 아니면 공정 사용이니 그냥 CC-BY 해도되나?(…)

  1. 빌드할 때 좀 괴롭더라. -j8 주니 빌드 실패한다. 빌드 스크립트에 무슨 삽질을 해놓은걸까? []