rixycf blog

書けたら書く

ラズパイとdockerでアドブロック用コンテナ(dnsmasq)を立てる

目的

LAN内に内向けDNSサーバ(dnsmasq)を立てて,アドブロックを行います. 今回はラズパイにdockerを入れてDNSサーバをコンテナとして運用します. そのための,dockerfileを書いていきます. アドブロックの仕組みは広告のドメインの名前解決の際に,0.0.0.0を返すようにするという単純なものです. これはDNSサーバの設定ファイルを書けば実現できます.

内向けDNSサーバによるアドブロックの長所,短所

長所

LAN内に接続する端末であれば,アドブロック用のアプリがなくてもアドブロックができる.

短所

DNSサーバの設定ファイルにない広告のドメインはブロックができない. LAN内のラズパイ死んだら,名前解決できなくなる.

用語のざっくりとした説明

DNS(Domain name system)サーバというのは,ドメイン名に対応するIPアドレスを返してくれるサーバです.その逆もできます. ブラウザ(chromeとか)にURLを入力し,相手のサーバとやりとりする前に,問い合わせるサーバです.

IIJのサイトがわかりやすいです.
DNSサーバとは

以下の動画がわかりやすいです.英語あまりわからなくても,なんとなく雰囲気で掴めるのではないでしょうか.
How a DNS Server (Domain Name System) works. - YouTube

今回はこのDNSサーバを利用します.
広告のドメインに対して,無関係のIPアドレス(0.0.0.0)をラズパイ上のDNSサーバが返すことによって,ブラウザで広告を表示させなくします.そのために,設定ファイルを書いていきます.

サーバ構築の手順

以下の手順でラズパイのOSの書き込みからDNSサーバのテストまで行いました.

  1. micro SD にraspbian-strech-lite jessieを書き込む
  2. ラズパイ初期設定(IPアドレスを固定)
  3. docker をインストール
  4. dnsmasqが入ったdocker image を作成する.
  5. ラズパイ上でコンテナを動かす.
  6. テスト

1 - 3については詳細は割愛します.

1 の参考サイト

https://hirazakura.hatenablog.com/entry/raspberrypi/setup/first

2 の参考サイト

https://qiita.com/MarieKawasuji/items/b088ffb252a92eee8f5d

3 の参考サイト

https://www.raspberrypi.org/blog/docker-comes-to-raspberry-pi/

上記のサイトを参考にして環境を構築しました.
環境は以下の通りです.
Raspberry Pi 3 Model B

raspberry pi version

$ uname -a
Linux raspberrypi 4.14.62-v7+ #1134 SMP Tue Aug 14 17:10:10 BST 2018 armv7l GNU/Linux

docker version

Docker version 18.06.1-ce, build e68fc7a
4. dnsmasqが入ったdocker image のビルド

今回は,DNSサーバにdnsmasqを選択しました.dnsmasqは小規模ネットワーク向けのDNSサーバです. DNSサーバを運用したことがなかったのでとりあえず,ざっと調べて良さげだったので選びました.

dnsmasqは,特定のドメインに対して,どのIPアドレスを返すのかをaddressオプションにて指定できます. 以下はdnsmasqのmanページのaddressオプションの引用です
Man page of DNSMASQ

-A, --address=/<domain>[/<domain>...]/[<ipaddr>]
Specify an IP address to return for any host in the given domains. Queries in the domains are never forwarded and always replied to with the specified IP address which may be IPv4 or IPv6. To give both IPv4 and IPv6 addresses for a domain, use repeated -A flags.

このオプションを使って,広告のドメインと0.0.0.0というIPアドレスを対応付けてやれば,アドブロックができます.

広告のドメインは以下のサイトで公開されているものを引用しました.
参考(https://warui.intaa.net/adhosts/hosts.txt)
ドメインは現在およそ77000個ほどあるので,これだけのサイトをブロックすることができます. このファイルをdnsmasq用に加工したあと,設定ファイルに読み込ませるようにします. ちなみに,hosts.txtは以下のようなフォーマットなのでaddressオプションに使用できる形式にします

hotst.txtの形式

IPアドレス ドメイン名

addressオプションで使う形式

address=/ドメイン名/IPアドレス

自分はcurlで引っ張ってきたものをawkを使って整形しました. この出力結果を/etc/dnsmasq.confとは別のファイルに記述し,/etc/dnsmasq.confがそれを読み込むようにします.

試しにコマンドで確認します

curl -sL "https://warui.intaa.net/adhosts/hosts.txt" | head -n 4 | \
awk 'NR > 1 {print "address=/"$2"/"$1}'

出力結果

address=/___id___.c.mystat-in.net/0.0.0.0
address=/_thums.ero-advertising.com/0.0.0.0
address=/0.r.msn.com/0.0.0.0

以上を踏まえてDockerfileを書きました.

echo でdnsmasq.confに設定を追加していきます.
curlで引っ張ってきたものは/etc/dnsmasq.adblock.confに書いて,/etc/dnsmasq.confには,conf-fileの設定を記述し,/etc/dnsmasq.adblock.confを読み込むようにします.
設定の詳細については詳しくはmanのページにのってます. http://www.thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html

dockerfile

# @rixycf dnsmasq container for adblock

FROM arm32v6/alpine

LABEL maintainer="rixycf kasnake1013@gmail.com"

RUN apk add --no-cache dnsmasq curl && \
    curl -sL "https://warui.intaa.net/adhosts/hosts.txt" | \
    awk 'NR > 1 {print "address=/"$2"/"$1}' >> /etc/dnsmasq.adblock.conf && \
    echo "domain-needed" >> /etc/dnsmasq.conf && \
    echo "bogus-priv" >> /etc/dnsmasq.conf && \
    echo "no-resolv" >> /etc/dnsmasq.conf && \
    echo "no-poll" >> /etc/dnsmasq.conf && \
    echo "server=8.8.8.8" >> /etc/dnsmasq.conf && \
    echo "server=8.8.4.4" >> /etc/dnsmasq.conf && \
    echo "conf-file=/etc/dnsmasq.adblock.conf" >> /etc/dnsmasq.conf
    
CMD ["dnsmasq", "--no-daemon"]

このdockerfileをビルドします. イメージのビルドは手元のmacで行いました. イメージはビルドした後,自分のdocker hubにアップロードして,ラズパイから持ってこれるようにしました.
docker hubのリンク https://hub.docker.com/r/rixycf/dnsmasq_adblock_alpine/

5. ラズパイ上でコンテナを動かす.

以下のコマンドをラズパイ上で実行します.

docker container run --cap-add=NET_ADMIN -d -p 53:53/udp -p 53:53/tcp \
--name adblock_dns rixycf/dnsmasq_adblock_alpine:0.1

--cap-add=NET_ADMINオプションはコンテナ内でdnsmasqを動かすために必要です. これをつけないと,コンテナ内のdnsmasqがエラーを吐いてました.悲しい.

6. テスト

テストをする前に,LAN内に接続する端末が参照するDNSサーバをラズベリーパイのIPアドレスにしておきます.

テストは,digコマンドやnslookupなどでできます. ドメイン名に対するIPアドレスが0.0.0.0になっていれば正しく動作してます.

実行したコマンド

nslookup 0.r.msn.com

出力結果

Server:      192.168.1.250
Address:    192.168.1.250#53

Name:   0.r.msn.com
Address: 0.0.0.0

良さげですね. これで一通りの環境を構築できました.

まとめ

今回は,dnsmasqを使用して,DNSサーバをコンテナとして動かしてみました. とりあえず手元のiPhone 5sで試してみたんですが,上から降ってくるとかデカイ広告は一部を除いて見えなくなりました.ブラウザのレンダリングの結果がだいぶすっきりしました. 今回の手法ですと,広告のドメイン一覧が,更新されないので,何らかの方法で更新してやる必要があります.そこは次?の課題でしょうか.

ちなみにですが,dockerfileなどはgithubにあげときました.
GitHub - rixycf/raspi_adblock_DNS: ラズパイ上で動かすアドブロック用dnsmasqのコンテナ

その他参考

Raspberry Pi 3の WiFiを広告ブロック機能付きの無線LANアクセスポイント化 hostapd + dnsmasq編
http://www.neko.ne.jp/~freewing/raspberry_pi/raspberry_pi_3_wifi_wireless_access_point_dnsmasq/

Dnsmasq を広告ブロックツールとして使う https://scientre.hateblo.jp/entry/20150521/ad_block_with_dnsmasq

メルカリさんのスカラシップでgo conferenceに行った話.

f:id:rixycf:20180421160049j:plain

きっかけ

メルカリさんのエンジニアブログを見てたら,go conference 2018 Springのスカラシップ制度があった.

tech.mercari.com

 関東圏以外に在住しているgopherの学生をgo conferenceに招待してもらえるというもの. 1日目は, go conference へ参加し,2日目は六本木にあるメルカリ本社に行き,社員さんとのランチと,社内見学.交通費とか宿泊費などなど全額補助してもらえます.

応募したもん勝ちの精神で応募したら,通りました.作っててよかったプロダクト.

今回のスカラシップ制度に応募するため以下の条件がありました.

  1. golangで作ったプロダクトとその解説
  2. go conferenceに参加したい理由の記述

 自分はgolang製のtodoリスト製作ツールとスライドを作るツールを提出しました.

理由は以下に

  • そもそもこういう場所にいったことがなくて一度は行って見たいなぁと思ってた
  • 個人的にインフラ周りに興味があって,dockerとかkubernetesとかgolangで書かれているのでそれに関する発表を聞きたかった.
  • golang のメジャーな用途とは少し違った発表 が聞ける場所だった

最後のは,前回のgo conferenceでゲーム用のライブラリをgolangで書いた方がいらしたりして,conferenceに参加すれば,面白い発表が聞けるのでは?と考えてました.

 あとは,メルカリさんってgolangとインフラ周りで強いエンジニアさんが結構いるというイメージを僕が勝手にもってて会社自体にも興味があって応募したというのもあります.

会場

go conferenceは日本橋にあるサイボウズさんにて行われました. f:id:rixycf:20180421135336j:plain

以下セッション

資料一覧です.

gocon.connpass.com

一部取り上げて書きます. いろいろ振り返りつつ,自分への理解も含めて記述しているので少し長くなってます.

組み込みLinuxでのGolangのススメ

www.slideshare.net

組み込みの人さんのセッション
なんと2連続登壇です.凄まじい熱量.
 一つ目のセッションの内容は,golangを組み込みLinux(NanoPi Neo or ラズパイ)で動作させることを考えたときに,組み込み用途としてのgolangの容易さと気になったことをお話してくださいました.golangの主な用途って,CLIツールつくったり,サーバサイドで使用したりといったのは結構聞くんですが,組み込みで使ったというのは僕は初めてで,魅力的でした.

以下は容易な点と気になった点を軽くまとめました.

  • 組み込み用途としての容易な点

    • ロスコンパイルが簡単にできる
       クロスコンパイルとは,ソースを書いてるマシンから別のプラットフォーム向けにバイナリを生成することです.結局どういうことができるのかというと,手元のMacでコーディングして,ラズパイ用のバイナリを作れたりできます.golangの場合はbuildコマンドを叩く際にGOOSとGOARCHを指定してやればできます.簡単.クロスコンパイル自体は自分も一回だけ使ったことがあって,その時はラズパイ用にビルドしたバイナリをscpで送ってcrontabで定期実行させて遊んでました.

    • ビルドホストへのインストールが容易
       スライド(p 17)にも書いてあるとおり,4ステップでソースから最新版のビルドができるみたいです(apt-getでgolangのバイナリを入手 -> wget で最新のソースを持ってくる-> tarで展開-> make.bashでビルド).導入が楽なのは非常に良いですよね.

    • ランタイムの移植が不要
       golangは静的リンクなので,ビルドするとバイナリ一個だけできます.言語自体のランタイムとその他のライブラリとアプリケーションが一個のバイナリにまとめられます.なので,バイナリ一個渡せば,デプロイ完了というわけです.

  • 組み込み用途の視点から気になった点

    • メモリの解放がガベージコレクタ(以下,GC)
       golangGCは速度が結構はやいみたいで,組み込みの人さんはほとんどGC動作中の停止時間は気にならなかったみたいです.2016年の記事(https://postd.cc/golangs-real-time-gc-in-theory-and-practice/)で行われたGCの最長待ち時間についての検証だとOcamlに次いで早いです.記事ではサイズ制限のあるバッファに対してメッセージを送信し続けるというプログラムを各言語で実装して計測してます.

    • スレッドモデル
       golang の特徴に並行処理が楽にかけるという面があってgoroutineというものがあります.「go hoge()」とやればhoge関数がmainの関数とは別のgoroutineで動きます.各goroutine間のやりとりはメモリの共有ではなく,チャネルを介してやりとりします.

    • 実行ファイルのサイズ
       前述したとおり,golangは基本的には,静的リンクを使うので,バイナリのサイズが大きくなりがちです.組み込みだと容量はかなり制約があるみたいで,バイナリのサイズは結構問題みたいです.組み込みの人さんは,busybox方式によって,各バイナリを結合するという方法でサイズを減らす工夫をしています.

 golangの強みとか特徴って組み込みにおいても通用するんだなぁと素直に思った.この発表を聞けて一番の収穫は,実際の現場で20年以上も組み込みに関わってきた方の話を聞けたことです.低レイヤのお話って,歴史を勉強しても,あまり実感がわかなくて,経験をしてきた人ってやっぱり強い.その方のお話を聞けたというのは良い経験になりました.

starting docker with golang(LT)

speakerdeck.com

こちらはsakajunqualityさんのLTです.内容としては,ざっとこんな感じです.

  • dockerの概要
  • golangのバイナリを動作させるdockerイメージの軽量化

 このスライドで気になったのはdockerイメージの軽量化に使用したmulti stage buildという機能です.dockerのイメージの軽量化というと,alpine使ったり,ペアレントイメージに重ねるレイヤが多くなりすぎないように「&&」とかつけて1行にまとめるのとかは知ってたのですが,こちらは初めて.僕のdockerの情報はオライリーから出てるUsing Dockerが大半なので,やっぱ新しい情報を追うのは大事ですね. 

 dockerでバイナリ一個を動作させるイメージを作りたい時,コンパイラなどは不要なわけです.なので最終的にはバイナリが動作する環境さえあればよくて,従来では,以下のものが必要でした.

  • アプリケーションのビルド用dockerfile
  • アプリケーションの動作用dockerfile
  • 2つのdockerfileを橋渡しするシェルスクリプト

 シェルスクリプトのざっくりした内容は

  1. ビルド用dockerfileからイメージの作成(ここでバイナリができる)
  2. コンテナとして立ち上げる.
  3. コンテナからバイナリをホストマシンにコピー
  4. ビルド用コンテナの廃棄
  5. 動作用イメージの構築(ここで動作用イメージにバイナリがコピー)
  6. ホストのバイナリ削除

 この場合だと2つのdockerfileと1つのシェルスクリプトが必要だったわけで,管理とか大変だったり.

 multi stage buildはこの問題を解決するための機能で,一つのdockerfile内で上記の操作を行えるようにするものです.詳しくはdockerのドキュメントに書いてあります.

docs.docker.com

multi stageの名前通り,dockerイメージのビルドに複数の段階を設けられるようになります.段階は複数のFROMごとに分けられて,各FROMには異なるイメージを設定できます.公式のドキュメントだと,1段階目でgolangイメージ,2段階目でalpineを使ってます.multi stage buildを使うことで1段階目でコンパイラのある環境でバイナリを生成し,2段階目で最低限の綺麗な環境に前段階でつくったバイナリをコピーするということができます.このやり方だとコードの記述量も減ってかなり見通しがよくなります.

 発表だとバイナリ一つ動作させるイメージだと11MB です.公式のgolangイメージでバイナリをつくるだけという場合でも780MBほどなので,90%ほど削減できてます.

 multi stage build を知れたのは収穫で今後のdockerライフを良くできそう.

go conference 全体の感想

 現場でのgolangの用途を知れたので良かった.それでもやっぱ,企業に属して大きなシステムを触らないと話を聞いても実感がわかなかったり...という面も感じました.gRPCはそのうち手をつけようかなぁっておもってたのですが,カンファレンスの前にやっとくべきでしたね.今回のgo conferenceは午後から2つの部屋で並行にやってて,全部の発表を聞くというのは無理だったのですが,後から動画が公開されるみたいです.ありがたい.「GoらしいAPIを求める旅路」は気になるのでチェックしたいと思います.自分は未だにgolangらしい書き方がわかってないので.

メルカリさん訪問 

f:id:rixycf:20180421160030j:plain  メルカリの本社は六本木ヒルズにあります. そこの18Fまで上がってくと入り口があるわけですが,めっちゃオシャレ.ついでにデンドロビウムがおいてありました.つよい.デンドロビウムが置いてある会社ぜったい強い.実際,メルカリでは,ディスプレイなどの機材や技術書の無償提供を行なっていて,エンジニアさんがのびのび開発できる環境を提供しています.オフィスの中には,個室みたいな環境もあって,そこで英語を学ぶことも可能です.

メルカリ社員さんとのランチ

 オフィスから徒歩数分のオシャレなお店にいきました.社員さんとのランチって人事さんとかが来るのかなぁっと思ってたら(後から気づいたんですが,募集要項のとこにちゃんと”エンジニアとのランチ”って書いてありました),go conferenceで進行を勤めていたtenntennさんやスポンサーセッションにて登壇していたkazegusuriさん,そしてSREチームの方々と錚々たる方達がいらっしゃった.びっくり.緊張しました.研究室の某先輩にdeeeetさんにあったらSpinnakerのこと聞いてきてと頼まれてたんですが,全部忘れました.すんません.gRPCの話やドメインの話,OSSの呼び方の話とかしてました.メルカリには大規模プッシュ通知の基盤である,gaurunというOSSがあるんですが,どうにも”ガウラン”と呼ばれてしまうそうです.正しい読みは"ガウルン"です.僕は,kubernetes(k8s)の呼び方が一生わからないですが,bokkoさんが"ケーエイトエス" と読んでしまえば,だいたいいけますよと教えてくださったので,困ったら使いたいと思います. b4b4r07さんにzplugとenhancdのメッチャお世話になってますと伝えるのを忘れてたのが唯一の心のこり.zplugはプラグイン導入してる時のクルクル回る奴がスゴイかっこいいんですよね.

 ついでに,学食4日分のお魚料理はとても美味しかったです.

全体の感想

 メルカリのスカラシップに応募して,よかった.新しい体験が色々できたので2日間がとても濃かった.あとは,東京って技術系を含めてたくさんイベントがあって,羨ましい.そして,そのイベントにスカラシップとして招待してくださったメルカリさんにとても感謝.

最後に戦利品
 メルカリさんの本社にていただきました.研究室で泊まるときに使います. f:id:rixycf:20180421160418j:plain