てきとうにサクッとDNSサーバを立てる using Docker

macOSでやった。Docker (docker-compose) を使う。

この前作ったコレを使うと何も考えずにできる。

github.com


使い方。
当該リポジトリをcloneしてくる

$ git clone https://github.com/S64/dockerfile-dns.git
$ cd dockerfile-dns

同梱のdocker-compose.example.ymlを元に、docker-compose.ymlをつくる。

$ cp docker-compose.example.yml docker-compose.yml # .gitignoreで無視してるので安心して

以下のようにして立ち上げられる。

$ ./up_daemon.sh

または、これでそのまま立ち上げられる。

$ docker-compose up # --force-recreate --build -d
# docker-machineを使ってる場合は `docker-compose $(docker-machine config yourmachinename) up`

以下で停止できる。

$ ./down_daemon.sh

または、これでそのまま停止できる。

$ docker-compose down # --rmi local
# docker-machineを使ってる場合は `docker-compose $(docker-machine config yourmachinename) down`

解決したいドメインの追加はdocker-compose.ymlを編集すればできる。/services/dns/extra_hosts/*の位置にFQDNを書く。たとえば以下のように。

...
      - 8.8.4.4
    extra_hosts:
      - "example.dev:93.184.216.34"
      - "yourawesomedomain.local:192.168.0.1"
    cap_add:
...

上流のDNSサーバは/services/dns/dns/*で追加できる。

...
    restart: always
    dns:
      - 8.8.8.8
      - 8.8.4.4
      - 192.168.0.1
...
    extra_hosts:

標準ではdockerデーモンと同時に自動起動するので、手動で立ち上げるようにしたければ/services/dns/restart"no"変える。

...
      - "53:53/tcp"
    restart: "no"
    dns:
...

疎通 / 解決チェック。ローカルマシンで見る場合は

$ nslookup example.dev 127.0.0.1
# docker-machineなら nslookup example.dev $(docker-machine ip yourmachinename)

LAN内の他マシンから見る場合は、まずこちらの記事を参考に自分のIPアドレスを取る。

blog.s64.jp

いちおうこんな感じ。

# on macOS
$ ipconfig getifaddr en0 # 使ってるネットワークif

んで、他のマシンからnslookupする。

$ nslookup example.dev 192.168.0.xxx # さっき取ったIPへ試す

DNSサーバは53番ポートを使うので、もし上手く行かない場合はこちらをチェック。

blog.s64.jp

特定のGitリポジトリだけ名義を変える

仕事で生徒の演習やる時に使った。
会社は実名+会社メールアドレス、プライベートはハンドルネーム+個人メールアドレス、みたいに使い分けたい時に便利。

git init済みのディレクトリで

git config --local user.name 'リポジトリ限定ユーザ名'
git config --local user.email 'mylocalusername@example.com'

という風にやればいい。

リポジトリローカルな設定を消して元に戻したい (globalのを使いたい) 場合は

git config --local --unset user.name
git config --local --unset user.email

すればいい。

ユーザをsudo使えるようにしたり特定ユーザのみsudoのパスワード確認を省略する

Macでやった。他にもLinux系ディストリビューションとかUnix系なら大体同じだと思う。
危険なことが多いので、やらなくていいならやらないに越したことはない。


特定ユーザをsudo使えるようにする。
特権ユーザとして (≒ sudoを付けて) 以下を実行。

# on macOS
dscl . -append /Groups/wheel GroupMembership yourawesomeusername # ユーザ名

CentOSとかの多くのunixライクOSならこう

# on generic unix-like os and distributions
usermod --append --groups wheel yourawesomeusername # ユーザ名

DebianやUbuntuなどの場合はこう

# on debian-based distributions
usermod --append --groups sudo yourawesomeusername # ユーザ名

これでyourawesomeusernameさんはsudoが使えるようになった。


ユーザを例外的にパスワード無しでsudo通過できるようにする。
sudo可能なユーザでvisudoコマンドを実行すると、sudoersファイルを編集できる。以下のように行を追加する。

yourawesomeusername         ALL = (ALL) NOPASSWD:ALL

これでyourawesomeusernameさんはパスワードを省略しsudoできるようになった。

macOSで起動時にDockerデーモンを立ち上げる

Docker for Mac (Docker.app) を使えばHyperKitによるMacネイティブな仮想化の恩恵を受けられる。
開発用としてGUIログインする場合にはこれで十分。 f:id:S64:20170609013514p:plain


が、macOS Serverとして利用する場合はGUIログインしたくない。
現時点 (2017-06-09 01:36, Docker.app stable 17.03.1-ce-mac12) ではDocker.appはGUIログイン時にしか自動起動できず、またdocker, docker-composeなどの関連コマンドもDocker.appが自動的に配置するため、ブートタイムにこれを利用するのは難しい。

一応psすると/Applications/Docker.app/Contents/MacOS/com.docker.hyperkitあたりが実体のように見えるが、それなりに複雑なパラメータが渡されているため安易に直叩きするのは危険。


仕方ないので、Docker Toolboxに同梱されているdocker-machineを使う。すなわち、VirtualBox上のdockerマシンを見ることにする。

  • Docker Toolbox
  • VirtualBox
  • Oracle VM VirtualBox Extension Pack

をインストール。

docker-machineは各実行ユーザの~/.docker/machine配下で管理するようなので、デーモン用のユーザを作成。 今回は_myawesomeuser、ホームディレクトリを/Users/_myawesomeuserとした。(Macにおいてデーモン等のシステムユーザは先頭がアンダースコア)

システムユーザなのでログインさせないようにしておく。

sudo dscl . create /Users/_myawesomeuser IsHidden 1

以下のようにしてデーモン用ユーザになり、仮想マシンを作成。

sudo su -l _myawesomeuser
docker-machine create myawesomemachine
exit # 元のユーザに戻る

/Library/LaunchDaemons配下に、以下のような起動スクリプトを作成。

<!-- /Library/LaunchDaemons/your.awesome.domain.myawesomemachine.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
      
        <key>EnvironmentVariables</key>
        <dict>
            <key>PATH</key>
            <string>/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin</string>
        </dict>
        
        <key>Label</key>
        <string>your.awesome.domain.myawesomemachine</string>
        
        <key>UserName</key>
        <string>_myawesomeuser</string>
        
        <key>ProgramArguments</key>
        <array>
            <string>/usr/local/bin/docker-machine</string>
            <string>start</string>
            <string>myawesomemachine</string>
        </array>
        
        <key>RunAtLoad</key>
        <true/>
        
    </dict>
</plist>

以下のようにして起動に組み入れる。

sudo launchctl load /Library/LaunchDaemons/your.awesome.domain.myawesomemachine.plist

注意点として、Docker.appの場合と違いポートがexposeされる先がVirtualBoxの仮想マシンになる。以下のようにして仮想マシンのIPを取得し叩く必要がある。

sudo -u clean -- bash -l -c 'docker-machine ip myawesomemachine'

よってリバースプロキシなんかを挟む場合には一筋縄では行かない。これはまたこんど記事を書く。

macOSで80番ポートを開ける

macOS 10.12.4、加えてmacOS Server (Server.app) 5.3.1を想定。


まず、普通に開けようとすると以下のようにエラーになる。

$ ruby -rwebrick -e 'WEBrick::HTTPServer.new(:DocumentRoot => "./", :Port => 80).start'
[2017-06-09 01:03:38] INFO  WEBrick 1.3.1
[2017-06-09 01:03:38] INFO  ruby 2.3.0 (2015-12-25) [x86_64-darwin15]
/Users/shuma/.anyenv/envs/rbenv/versions/2.3.0/lib/ruby/2.3.0/socket.rb:205:in `bind': Permission denied - bind(2) for 0.0.0.0:80 (Errno::EACCES)
  from /Users/shuma/.anyenv/envs/rbenv/versions/2.3.0/lib/ruby/2.3.0/socket.rb:205:in `listen'
   from /Users/shuma/.anyenv/envs/rbenv/versions/2.3.0/lib/ruby/2.3.0/socket.rb:759:in `block in tcp_server_sockets'
...

使ってるサーバは違えど、bind時にPermission denied系統が投げられる。
これはMacのセキュリティ仕様として、1000番ポート以下を一般ユーザが開けられないため。昇格すればいける。

$ sudo ruby -rwebrick -e 'WEBrick::HTTPServer.new(:DocumentRoot => "./", :Port => 80).start'
Password:
[2017-06-09 01:06:25] INFO  WEBrick 1.3.1
[2017-06-09 01:06:25] INFO  ruby 2.3.0 (2015-12-25) [x86_64-darwin15]
[2017-06-09 01:06:25] INFO  WEBrick::HTTPServer#start: pid=35327 port=80

環境によっては、以下のようになる。

$ sudo ruby -rwebrick -e 'WEBrick::HTTPServer.new(:DocumentRoot => "./", :Port => 80).start'
Password:
[2017-06-09 01:08:05] INFO  WEBrick 1.3.1
[2017-06-09 01:08:05] INFO  ruby 2.3.0 (2015-12-25) [x86_64-darwin15]
/Users/shuma/.anyenv/envs/rbenv/versions/2.3.0/lib/ruby/2.3.0/socket.rb:205:in `bind': Address already in use - bind(2) for 0.0.0.0:80 (Errno::EADDRINUSE)
  from /Users/shuma/.anyenv/envs/rbenv/versions/2.3.0/lib/ruby/2.3.0/socket.rb:205:in `listen'
   from /Users/shuma/.anyenv/envs/rbenv/versions/2.3.0/lib/ruby/2.3.0/socket.rb:759:in `block in tcp_server_sockets'
...

Address already in use、つまり80番ポートが使用されている。
Macにはapacheがビルトインされているので、ほとんどの場合こいつのせい。以下で自動起動を辞めさせられる。

$ sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist

ただし、macOS Server (Server.app) の場合は

$ sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist
/System/Library/LaunchDaemons/org.apache.httpd.plist: Could not find specified service

なんて風になって止められない。80番ポートを自由に使いたいという前提で進めているので、apacheの80番ポートlistenを辞めさせればいい。
/Library/Server/Web/Config/apache2/httpd_server_app.confにある設定ファイルで、以下のようにコメントアウト。

#Listen 80
#Listen 443

内部では80番ポートが見えるが、外からは永遠に待たされるなど見えない場合がある。
nmapなんかで確認すると

$ nmap 127.0.0.1

Starting Nmap 7.12 ( https://nmap.org ) at 2017-06-09 01:23 JST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00074s latency).
Not shown: 722 closed ports, 268 filtered ports
PORT     STATE SERVICE
80/tcp   filtered  http
...

なんて風になっているかもしれない。これはMacのファイアウォールで許可していないため。
環境設定からファイアウォールのオプションを開き、接続許可をすれば良い。

f:id:S64:20170609012734p:plain