Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.

GitHub 인수를 보며 드는 생각

2주 정도 전에 Microsoft가 GitHub을 75억 달러(약 8조 원)에 인수했다. Facebook이 Instagram을 10억 달러에 인수하고(지금 와서 보면 정말 싸게 샀다고 생각하지만...) Facebook이 WhatsApp을 190억 달러 인수한 걸 생각하면 아주 많지도 적지도 않은 금액이다.

인수 결과가 발표되기 전에 온라인에서 소문이 들렸지만 별로 신경 쓰지 않았다.

위 트윗을 올리고 이틀 만에 바로 인수 뉴스를 접했다.

처음에는 거부감이 많이 들었는데 "왜 거부감이 들지"라고 생각해 보니 위의 이유였다. 인수되고 2주 정도가 흘렀고 지금 오픈소스, 그리고 개발의 중심에 있는 것이나 마찬가지인 GitHub이 인수되었는데 생각을 좀 정리해볼 필요가 있어서 개인적 느낌이나 적어보려고 한다. GitHub이 인수되었는데 아무런 글도 안 남기기도 그렇고 해서...

Microsoft

Microsoft를 좋아하는 편은 아니지만 Satya Nadella가 CEO가 된 이후로는 정말 잘하고 있다.(개인적으로 스티브 발머는 정말 싫었다.) 한때(라기에는 너무 오래되었나.) 오픈소스의 완전히 반대쪽 입장으로 대변되던 MS가 "Microsoft ♥ Linux"나 "Microsoft ♥ OpenSource"라고 말하는 걸 보면 격세지감을 느끼긴 한다. 어느 순간부터 MS의 기술들은 나하고는 많이 멀어져서 접할 일이 많지 않지만 최근 Microsoft의 행보는 긍정적으로 보고 있다.

그리고 사람들 말대로 Microsoft를 살만한 회사인 Google, Facebook, Oracle, Amazon과 비교한다면 Microsoft는 괜찮은 선택이라고 생각한다. 물론 Satya Nadella 시대가 끝나고 다른 CEO가 온다면 또 어떻게 될지 모르지만 그건 GitHub의 CEO가 바뀌었을 때도 마찬가지일 테니...

추측이지만 Xamarin의 창업자인 Nat Friedman을 새 GitHub CEO로 선정한 것도 GitHub을 Microsoft으로 채우지 않고 기존처럼 유지해서 개발자들의 반발(?)을 줄이려는 의도가 아닐까 싶다. 이는 Nat의 글과 레딧에서 진행한 AMA를 봐도 개발자들의 반응을 Microsoft가 신경 쓰고 있다는 걸 알 수 있다. Xamarin을 잘 모르고 Microsoft의 다른 인물들도 잘 모르지만, 개발문화를 잘 이해하고 있는 사람일 거라는 생각에 이번 인선은 나쁘지 않아 보인다. 1년 정도 전에 GitHub의 CEO였던 Chris Wanstrath가 CEO를 대신할 사람을 찾으면 자신은 제품에만 집중하고 싶다고 했는데 Microsoft에 인수되는 형식으로 그 사람을 찾았다고 보인다. Chris에 대한 신뢰가 있어서 Nat을 새로운 CEO로 결정한 것에도 어느 정도 조율이 있었을 거로 생각한다.

GitHub

이렇게 생각하면 Microsoft는 잘하고 있고 GitHub이 인수된 것에 아무런 문제가 없다. 하지만 내가 느끼는 싫은 감정은 그대로였다.

개발자 중에 GitHub을 안 좋아할 사람이 얼마나 있겠냐마는 나는 GitHub을 무척 좋아한다. GitHub 굿즈도 웬만한 건 다 가지고 있다.

GitHub 굿즈

오픈소스의 중심이 된 주요플랫폼이기도 하지만 GitHub이 서비스를 만드는 것 보면 항상 너무 적절해서 감탄만 나올 뿐이다. 어차피 모든 사람이 원하는 기능을 다 만들 수는 없는 데 GitHub을 이용해서 개발하는 데 중요한 기능을 항상 잘 만들고 있다고 생각하고 있다.(비슷하게 서비스를 너무 잘 만든다고 생각하는 또 하나의 회사는 Instagram이다.) 그래서 수년간 입사하고 싶은 회사 1위였다.

인수되고 충격을 받은 이유 중 하나는 인수당하지 않을 거라고 생각했기 때문이다. GitHub이 회사 규모로 엄청나게 큰 회사도 아니고 Private repository와 GitHub Enterprise로 충분한(?) 수익을 벌고 있다고 생각하고 있었다. GitHub CEO Chris Wanstrath To Step Down After Finding His Own Replacement를 보면 연간 매출(revenue면 수익인가)이 2억 달러를 돌파했다는 얘기가 나오는데 평소 생각하면 GitHub의 규모를 생각하면 충분히 큰 매출이라고 생각했다.

이번 인수가 새로운 CEO를 물색하는 과정이었는지 아니면 GitHub이 수익이 충분치 않아서였는지는 나온 얘기가 없어서 잘 모르겠다. 한편으로 생각해보면 대부분의 오픈소스가 무료로 GitHub을 이용하고 있어서 서버 대수도 엄청날 테고 요즘은 패키지 매니저들이 GitHub에서 바로 끌어오거나 GitHub과 통합된 서비스들도 많으므로 CDN이나 트래픽 비용을 생각하면 저 매출은 많지 않을 수도 있겠다.

그래도 나는 GitHub이 자생해서 성공하거나 상장을 하는 모습을 은연중에 꿈꿨던 것 같다. 기술 중심 회사가 상장하는 것을 봐도 고무적인데 개발자 중심의 오픈소스를 사업의 핵심에 놓고 있는 회사가 상장하는 멋진 모습을 기대하고 있었던 것 같다. Microsoft에 인수되었다고 GitHub이 달라질 것 같진 않지만 결국 자립하지 못했다는 게 내가 슬픈 느낌이 드는 이유인 것 같다. 물론 스타트업 세계에서 인수도 성공적인 Exit의 한 방법이지만 내가 좋아하는 GitHub은 훨씬 멋진 모습으로 남아있길 개인적으로 기대했달까...

2018/06/18 03:53 2018/06/18 03:53

사이드 프로젝트로 만든 Private Terraform 모듈 레지스트리: citizen

작년 HashiConf에 참석했을 때 Terraform Module Registry가 공개되었다. 모듈 같은 개념에서는 지극히 자연스러운 흐름인데 npm이나 PyPI와 마찬가지로 공개 레지스트리를 이용하게 되면 회사 내에서는 비공개 레지스트리가 필요하게 된다.

비공개 레지스트리가 필요한 이유는 오픈소스가 아니라서 외부에 공개하기 어려운 것도 있고, 공개되어도 상관없는 내용이더라도 외부에 공개하려면 정리도 해야 하고 관리에도 더 리소스가 들어가기 마련이다. Terraform의 모듈 레지스트리는 엔터프라이즈 버전에서만 비공개 모듈을 사용할 수 있다. 모듈 레지스트리는 오픈 소스가 아니므로 회사 내부에 설치해서 사용할 수가 없지만, 다행히도 API는 문서로 공개되어 있다.

개발 과정

그래서 API를 보고 Private Terraform Module Registry를 만들면 써먹을 수 있겠다 싶어서 citizen이라고 이름 짓고 작년 말부터 만들기 시작했고 손에 익은 Node.jsExpress를 선택했다.(다른 언어로도 자꾸 해봐야 하는데...)

컨트리뷰션 그래프

API 문서는 정리가 잘 되어 있는 편이었다. Terrafrom CLI가 있으므로 만들고 있는 서버에 직접 찔러 보면서 어떻게 요청이 들어오는지 확인하면서 작업을 했다. 작업하다 보니 API 문서에서 잘못된 부분과 내부에서 URL 처리가 잘못되는 부분이 있어서 PR을 3개나 올리게 되었다.

HTTPS

처음 겪은 문제는 Terraform Module Registry가 HTTPS로만 동작한다는 점이다. Terraform CLI에서 레지스트리를 지정하면 서비스 디스커버리 API를 요청해서 JSON을 받아가고 이를 기반으로 다른 API를 요청하게 되는데 여기서 HTTPS로만 동작하게 된다. API 구현 작업 자체는 어차피 테스트코드를 작성할 것이므로 HTTP를 사용해도 되지만 문서만 보고 만들어서 동작한다고 보장할 수 없으므로 Terraform CLI와 통합테스트를 작성해야 했다. 다른 사람들이 얼마나 사용할지는 모르지만, 나중에 버그를 잡거나 Terraform의 기능이 변경되더라도 따라가기 위해서는 통합테스트가 필요했다.

로컬에서 셀프사인 인증서로 동작 여부를 테스트했지만, 통합테스트를 HTTPS로 작성하려고 여러 가지 방법을 고민하다가 ngrok를 이용해서 HTTPS로 통합 테스트를 할 수 있도록 구현했다. 통합테스트는 특정 버전의 Terraform CLI를 다운로드 받아서 서버를 띄우고 ngrok으로 HTTPS 프락시를 만든 다음에 CLI와 동작이 잘하는지를 확인했다.

파일 스토리지

사이드 프로젝트이지만 내가 사용할 가능성을 생각하고 만들고 있으므로 파일 스토리지로 처음에는 S3를 사용했다. 개인 사이드 프로젝트이므로 초기 버전에서는 당연히 범용성보다는 내가 사용할 형태를 먼저 생각하다 보니 디스크 관리를 하지 않으려고 처음에는 S3를 파일 스토리지로 선택했다. 내가 프로덕션에서 이 프로젝트를 사용한다면 디스크 관리를 고민하기보다는 그냥 S3를 쓸 것 같았기 때문이다.

프로젝트 초기에 너무 범용성을 고민하기보다는 적당히 내가 원하는 기능에 맞추는 것은 나쁘지 않은 선택이라고 생각하지만, 결과적으로는 좋지 않은 선택이 되었다. Terraform 모듈을 업로드하면 압축된 모듈 파일을 스토리지에 저장해야 하므로 이 선택은 스토리지에 의존성이 있는 로직의 테스트를 어렵게 만드는 결과가 되었다. 로컬이나 CI에서 테스트할 때마다 S3를 이용하는 건 비용도 비용이고 시간이 오래 걸리기 때문에 nock으로 외부 요청을 모킹해서 테스트를 작성했지만, 테스트 시나리오가 많아질수록 관리가 무척 어려워졌다.

최종적으로는 S3만 지원하는 것은 사용자 편의성에 좋지 않다는 생각에 로컬 디스크를 사용하는 옵션을 추가해서 스토리지 타입을 선택해서 사용할 수 있도록 했다. 이후로는 테스트는 로컬 디스크를 사용하도록 작성하고 S3는 S3의 기능만 따로 테스트하면 되므로 모킹을 대부분 제거하고 테스트가 더 깔끔해졌다. 처음부터 로컬 디스크로 만들었으면 편했을 텐데....

클라이언트

쉽게 생각하면 Terrafor Module Registry의 클라이언트는 Terraform이지만 공식 Terraform Module Registry는 GitHub와 통합되어 있다. 그래서 모듈을 배포하려면 GitHub에 올린 뒤에 이 저장소를 Terraform Module Registry에서 연동시켜서 사용하게 된다.

이런 상황이다 보니 citizen에서는 어떻게 모듈을 업로드하게 할 것인가 하는 문제가 생겼다. 공식 레지스트리처럼 GitHub 등과 통합시킬 수도 있지만 Private이라는 특성 때문에 비공개 저장소에 접근하기 위한 권한 관리 등도 해야 하고 비공개이므로 사용자가 GitHub을 사용한다는 보장도 없었고 개인 프로젝트에서 여러 VCS를 지원할 여력도 없었다.

결국, 모듈을 업로드하는 CLI 클라이언트를 만들기로 했다. VCS와 통합하는 것보다야 불편하겠지만 구현하는 입장에서는 환경에 상관없이 사용할 수 있다는 장점이 있어서 Commander.js를 이용해서 CLI를 만들었다. CLI를 만들다 보니 결국 서버와 CLI 클라이언트를 2개 배포해야 하는 상황이 되었는데 HashiCorp의 대부분 도구처럼 하나의 바이너리에서 서버와 클라이언트를 모두 제공하는 게 낫겠다 싶었고 Go 언어에서 하듯이 하나의 바이너리로 배포하니까 파일 하나만 받아놓고 서버, 클라이언트를 모두 사용할 수 있으니까 꽤 편했다.

Commander.js를 이용해서 하나의 CLI로 서버와 클라이언트를 모두 가동할 수 있게 작성하고 전부터 사용해보고 싶었던 Pkg를 이용해서 하나의 바이너리 파일로 만들었다. Pkg는 require()를 추적해서 사용하는 코드만 모아서 하나의 바이너리로 만들어 준다. 기존에는 pouchdb를 사용하고 있었는데 pouchdb가 LevelDB를 사용하기 때문에 네이티브 애드온이 포함되어 있다. pkg가 아직 네이티브 애드온을 번들링 하지 못하는 문제때문에 결국 NeDB로 갈아탔다. Private 모듈 레지스트리의 디비가 엄청나게 클 것 같지는 않으므로 큰 문제는 안될 거라고 생각한다. 처음 pkg를 적용할 때는 Spread Operator를 지원하지 않아서 Spread Operator의 사용을 모두 제거했지만 이후 다시 지원하게 되어 Spread Operator를 다시 적용했다.

통합 테스트

유닛테스트도 작성하고 API 레벨에서도 테스트코드를 작성하면서 작성했지만 결국 Terraform CLI를 이용해서 사용하게 되므로 동작여부를 제대로 확인하려면 Terraform CLI를 이용해서 통합테스트를 작성해야 한다고 생각했다. 만들면서 Terraform으로 동작을 확인하기는 했지만 릴리스를 하고 나서 버그를 확인하거나 동작을 확인하려면 통합테스트가 있는 편이 관리하기 쉽다고 생각했다. 일단 레지스트리를 문서를 보고 만든 것이라서 잘못 이해하고 구현했거나 Terraform에 버그가 있을수도 있으므로...

통합테스트 실행 결과

버전을 지정해놓고 Terraform CLI를 다운로드 받아오는 스크립트를 작성하고 테스트에서 레지스트리 서버를 띄우고(이때 HTTPS가 필요해서 앞에서 얘기한 ngrok이 필요했다) Child Process로 Terraform CLI로 레지스트리에 접속하고 등록된 모듈을 가져오는 기본 통합 테스트를 추가했다. 앞으로 이슈가 생기면 테스트를 추가하면서 확인해 보면 될 것 같다.

릴리스 준비

내가 사용할 목적으로 만든 사이드 프로젝트이지만 아직 사용하고 있지는 않다. 실제로 사용하면서 발견되는 문제가 꽤 있겠지만 일단 기능 구현이 마무리되어 릴리스를 준비했다. 나중에 배포 등을 관리하는 건 귀찮으므로 작업 마무리 할 때 아예 태그를 푸시하면 자동으로 GitHub 릴리스까지 생성하도록 했다. 단순히 소스코드만 배포하면 되는 것이 아니라 pkg로 만든 바이너리를 플랫폼별로 배포해야 했기에 TravisCI에서 바이너리를 생성한 뒤에 GitHub 릴리스에 배포하도록 했다.

GitHub 릴리스 페이지

요즘은 서버를 Docker로 배포하는 게 일반적이므로 당연히 릴리스할 때마다 Docker 이미지로 만들어서 배포하도록 했다. 처음에는 CI에서 직접 만들어서 Docker Hub에 푸시하다가 Docker Hub에 Automated Build가 있다는 걸 최근에 깨닫고 Docker Hub를 이용해서 배포했다. 최근에는 README를 Markdown 대신 AsciiDoc으로 작성하고 있는데 GitHub에서는 괜찮지만, Docker Hub는 AsciiDoc을 파싱하지 못해서 안타까울 뿐이다.

라이센스는 Terraform과 같은 Mozilla Public License 2.0를 사용했다. 보통은 그냥 MIT 라이센스를 쓰는 편이지만 그냥 다른 걸 한번 써보고 싶었다. 라이센스 해석은 항상 어렵지만, MIT와 다른 점은 특허 관련해서 사용할 수 있고 배포할 때 소스코드를 항상 공개해야 하고 수정해도 같은 라이센스로 배포해야 한다는 제약 정도가 있어 보인다. 라이센스는 그냥 LICENSE 파일만 넣어도 무방하지만 오픈소스 라이센스를 검사해 주는 FOSSA를 연동했다.

FOSSA 뱃지

프로젝트 라이센스 뿐만 아니라 의존성의 라이센스검사까지 해준다.

릴리스

개발하면서 버전을 올릴 일은 없지만, 릴리스를 준비하면서 0.2로 작업하다가 0.3으로 릴리스를 했다. 버전에 큰 의미는 없고 어차피 열어 넣고 개발하고 있었으므로 릴리스해도 아무런 일은 일어나지 않는다. 그냥 릴리스하고 프로젝트를 마무리했다는 개인적인 만족감이랄까? ㅎㅎㅎ HashiCorp에서 리트윗이라도 하나 해주지 않을까 기대했지만 역시 그런 일은 일어나지 않았다. ㅎㅎㅎ

citizen을 포크한 사용자

그래도 Terraform 사용자 중에 Private Module Registry를 찾는 사람들이 있는지 다 만들기도 전에 몇 명이 포크 해서 약간 수정도 하고 그랬다. 나만 필요하다고 생각한 건 아니라는 거에 위안하고 있다

작년 말에 시작하면서는 2월 내지 3월 정도까지 마무리하는 게 목표였지만 6개월이나 걸렸다. 그래도 중간에 그만두지 않고 완성해서 릴리스까지 한 것에 만족한다.

2018/06/17 15:13 2018/06/17 15:13