WatchTower, Observe API Calls in browser

도입

adibfara/WatchTower(https://github.com/adibfara/WatchTower)는 브라우저 내 에서 OKHttp으로 인한 통신에 대한 요청 / 결과 데이터 및 헤더 등을 볼 수 있는 라이브러리로, 2019년 5월 24일에 첫 버전이 릴리즈된 라이브러리이다.

지금까지 OKHttp으로 인한 통신을 앱에서 검출하려면 주로 facebook/stetho(https://facebook.github.io/stetho/) 를 사용했으나, stetho의 기반은 Chrome developer tools에 작동한다는 점에서 이 WatchTower는 그러한 제약을 가지지 않고, 앱 내에서 NanoHTTPd를 사용하여 웹 서버를 열고 자료를 볼 수 있게 하는 것에 큰 차이점을 가진다.

또한 차후 확장하여 액티비티 내에서 볼 수 있게 하는 점도 가능하니, 기능은 Stetho에 비해 매우 빈약하지만 (Stetho가 네트워크 인터셉터 외에도 뷰 구조나 덤프 등을 제공하기 때문에) 네트워크 인터셉트 기능으로 한정하면 WatchTower가 더 이점을 가진다고 볼 수 있다.

당연하게도 Retrofit 또한 OKHttp가 기반이므로 Retrofit를 사용해도 위 기능을 전부 활용할 수 있다.

따라서 이 글에서는 기본적인 WatchTower의 사용법을 소개한다.

사용법

모듈의 gradle에 아래 종속성을 추가한다.

implementation 'com.snakyapps.watchtower:core:1.0.0'
debugImplementation 'com.snakyapps.watchtower:interceptor-okhttp:1.0.0'
releaseImplementation 'com.snakyapps.watchtower:interceptor-okhttp-no-op:1.0.0'

debugImplementation, releaseImplementation으로 나눠지는데 이는 디버그 빌드에서만 해당 행동을 할 수 있게 종속성 분야에서 강제하는 것이다. 따라서 별도로 BuildConfig.DEBUG로 판단할 필요가 없어진다.

1.0.0 문서에 따르면, 안드로이드 환경에서는 Service에서 WatchTower를 시작하는 것이 권장된다고 되어있어, Service 객체를 생성한다.

class WatchTowerService : Service() {

   override fun onBind(intent: Intent?): IBinder? {
       return null
  }

   override fun onCreate() {
       super.onCreate()
       val port = Config.confg.watchTowerPort
       WatchTower.start(WebWatchTowerObserver(port = port))

       Timber.d("WatchTower is started. URL: http://localhost:$port")
  }

   override fun onDestroy() {
       super.onDestroy()
       WatchTower.shutDown()
  }
}
<service
           android:name=".module.watch.WatchTowerService"
           android:enabled="true" />

위와 같이 작성하고 Manifest에 작성하였으면, 그 다음에는 OKHttp를 설정할 때에 Interceptor를 추가하면 된다.

현재 구축된 기반의 경우 Dagger의 Multibinding 기능을 이용하여 Set<Interceptor>LoggingInterceptor 순서로 추가하게 되어 있으므로, LoggingInterceptor 뒤에 WatchTower 자체의 Interceptor를 추가한다.

@Provides
fun provideClient(interceptors: Set<@JvmSuppressWildcards Interceptor>,
                     @Named("loginterceptor") logsInterceptor: Interceptor): OkHttpClient {
   val builder = OkHttpClient().newBuilder()
   builder.readTimeout(Config.config.timeout.toLong(), TimeUnit.MILLISECONDS)
   builder.connectTimeout(Config.config.connectTimeout.toLong(), TimeUnit.MILLISECONDS)
   builder.retryOnConnectionFailure(Config.config.retryOnConnectionFailure)
   if (interceptors.isNotEmpty()) {
       interceptors.forEach {
           builder.addInterceptor(it)
      }
  }

   if (!Config.config.notUseLogInterceptor) {
       builder.addInterceptor(logsInterceptor)
  }

   if (Config.config.useWatchTower) {
       builder.addInterceptor(WatchTowerInterceptor())
  }

       return builder.build()
}

마지막으로 Activity 에서 서비스를 시작하거나 중지하면 작동하게 된다.

이제, 앱을 빌드하게 되면 기기의 브라우저에서는 http://localhost:8085 를, PC에서는 http://기기의 로컬 주소:8085 를 입력하면 접속이 되고, OKHttp로 통해 통신이 진행될 경우 맨 위의 사진처럼 로그가 나오게 된다. 기기의 로컬 주소는 기기에서 https://www.whatismybrowser.com/detect/what-is-my-local-ip-address 에 접속하면 나온다.

마무리

간단한 사용법을 가지면서도, 편리한 사용법을 가져서 누구나 쉽게 적용할 수 있다는 포인트가 제일 강점이다. 구현하는 데에도 큰 시간이 들어가지 않으므로 적용해서 사용하면 큰 편리함을 얻을 수 있을 것 같다.

UzukiLive 서버 현황

Vultr VC2가 같은 가격에 SSD 용량을 추가로 제공한다는 사실을 이제 깨달은 나머지(…) 전체적으로 UzukiLive 서버를 유지보수 하면서 작업을 진행했는데, 차후 서버를 옮길 필요가 있을 때 참고를 해야 할 경우가 있어서 업데이트 겸에 정리를 진행했습니다.

UzukiLive 서버란?

UzukiLive 서버는 소유중인 도메인인 ‘uzuki.live’ 라는 도메인 이름에서 파생된 서버 이름이고, Uzuki 라는 이름의 모티브는 ‘アイドルマスターシンデレラガールズ’ 의 메인 캐릭터인 ‘島村卯月'(Uzuki Shimamura) 에서 가져왔습니다.

이 서버는 2018. 12. 22 ~ 2018. 12. 25 일에 진행된 ‘UzukiLive 새 인스턴스 확장 이전'(https://pyxispub.uzuki.live/?p=1463) 으로 생성된 서버로, 기존 Vultr VC2 1Core 2GB , Vultr VC2 2Core 4GB 인스턴스를 합치고 새로 생성한 서버입니다. 리전은 Tokyo로 등록되어 있습니다.

이 서버의 목적은 개인 운용 목적의 서버로 블로그 서버 + 메일 서버 + 클라우드 서버 기능을 포함하며, 기타 안드로이드 개발에 필요한 Jenkins CI + JFrog Artifactory를 포함합니다.

그 외, 서버를 원할하게 관리하기 위한 Monitoring 스택 (cAdvisor + NodeExporter + Prometheus + Grafana) 을 구현하여 실제 프로덕션 환경에서 최소한으로 관리할 수 있는 능력에 대한 연습 서버이기도 합니다.

도메인은 NameCheap, Inc에서 등록되었고, DNS 네임서버는 dnsever에서 관리되고 있습니다.

서버 구조 개요

UzukiLive는 Vultr Cloud Compute (VC2) 의 4 CPU 8 GB 160GB SSD 기반의 클라우드에 Ubuntu 18.04.2 LTS + Docker 18.09.5 버전으로 실행중인 서버로, 현재 약 21개의 도커 인스턴스가 실행되고 있습니다.

  • Nginx – Proxy-pass, SSL (Let’s Encrypt) 연결을 위한 서비스
  • Service Layer
    • WordPress – PyxisPub 발행을 위한 워드프레스 서비스
    • Jenkins – Android 및 Docker CI/CD 작업을 위한 Jenkins 서비스
    • Artifcatory – 비공개 그레들 아키펙트 배포 및 기존 아키펙트 레포지토리에 대한 캐시 서비스
    • OwnCloud – 개인 저장용 클라우드 서비스
    • Rainloop – 메일 서버를 위한 프론트엔드 UI
  • Internal Layer
    • Docker-mailserver – 개인 이메일 ([email protected]) 및 부가 이메일 서비스를 위한 메일 서버 (IMTP(POP3)/SMTP 구현 포함)
    • Shadowbox – Jigsaw 가 개발하는 Outline 의 기반 컨테이너
    • Redis – Redis 데이터베이스, OwnCloud 전용
    • MariaDB – MariaDB 데이터베이스, WordPress 전용
    • pure-ftpd – (S)FTP 제공
    • Adminer – MariaDB에 대한 web admin
  • Monitor Layer
    • cAdvisor – 도커 엔진, 컨테이너, 이미지 등에 대한 데이터를 수집하는 모니터링 도구
    • NodeExporter – 호스트 서버를 모니터링 하는 도구
    • Prometheus – 컨테이너로부터의 데이터를 받기 위한 중간 매개체 도구
    • Grafana – 여러 데이터 제공자로부터 데이터를 받아 그래프로 보여주는 도구
    • AlertManager – Prometheus로부터 데이터를 전달받아 이벤트가 발생되었을 때 정해놓은 알림 룰을 통해 전송하는 도구
    • PushGateway – Prometheus 에 일회성/배치 작업에 대한 통계를 전송하도록 하는 도구

모든 레이어는 단일 uzukilive-network 네트워크로 엮여져있으며, 각 레이어마다 내부 통신을 위한 네트워크가 별도로 구성되어 있습니다.

외부에 포트 노출이 필요한 Nginx, MailServer, ShadowBox, pure-ftpd 을 제외하고는 내부 포트를 통해 통신하게 되며, 내부간 통신이 필요할 경우 uzukilive-network 네트워크와 각 레이어마다 할당된 네트워크를 통해 구현하게 됩니다.

Service Layer와 Grafana는 실제 외부에서 접근 가능한 서비스들이지만 이 포트들은 외부에 노출되지 않고 Nginx를 통해 Proxy-pass하게 됩니다. 즉, Nginx가 각 서비스에 접근하기 위한 게이트웨이로 작용하게 되어 서브도메인으로 구분하게 됩니다.

이 때, http로 접속하였을 경우 https로 리다이렉트하는데, 이 https에 대한 인증서는 Let’s Encrypt를 통해 발급되었습니다.

서버 업데이트 내역

2019.04.28 이후 내역을 정리합니다.

  • 2019.04.28
    • 사양 업그레이드 – VC2 4core 8GB 100GB SSD -> VC2 4core 8GB 160GB SSD
    • 아키펙트 레포지토리 캐시 서버 cron 개선 – 매 정각 12시마다 336시간 동안 사용되지 않은 아키펙트 삭제 -> 매 정각 12시마다 168시간 동안 사용되지 않은 아키펙트 삭제
    • 사용하지 않는 Expose된 포트 제거
    • cAdvisor, Prometheus, AlertManager, PushGateway 등이 어떠한 경로를 통하여 외부에서 접근이 가능한 우회 방법 방지
    • 사용하지 않는 A 레코드 정보 제거