自宅サーバのDockerでDNSを運用する

自宅サーバを持っていると、外では自宅のIPアドレス、家ではローカルIPアドレスでアクセスなければならず、今まではhostsを直接書き換えるスクリプトを運用していた。しかし、それではiPadなどのモバイル端末では通用しないこともあって、DNSサーバを立てることにした。

Bind9のDockerイメージを作っている人もいたが、うまくいかなかったので、Debianのイメージから作ることにした。

FROM debian:8.1
RUN apt-get update
RUN apt-get install -y bind9
ADD * /etc/bind/
ENTRYPOINT service bind9 start;tail -f cat /var/log/faillog

いつものように、dockerコマンドはMakefileに記述して、直接入力しないようにしている。毎回buildし直すのはだるいので、トライアンドエラーをやっているときは、cpでファイルを入れてrestartで起動するようにしている。

build:
    docker build -t bind .
run:
    docker run -d --name bind --restart=always --publish 53:53/udp bind
bash:
    docker exec -it bind bash
rm:
    docker rm -f bind
pushconf:
    docker cp ./named.conf bind:/etc/bind/
    docker cp ./named.conf.default-zones bind:/etc/bind/
    docker cp ./named.conf.local bind:/etc/bind/
    docker cp ./named.conf.options bind:/etc/bind/
    docker cp ./db.house.j74th.com bind:/etc/bind/
    docker cp ./db.house bind:/etc/bind/
start: pushconf
    docker start bind
stop:
    docker stop bind
restart: pushconf
    docker restart bind
testyahoo:
    nslookup www.yahoo.co.jp 127.0.0.1
testhouse:
    nslookup house 127.0.0.1

まず、named.conf.localにzoneを定義する。

zone "house.j74th.com" {
    type master;
    file "/etc/bind/db.house.j74th.com";
};

db.house.j74th.comDNSレコードを記述する。

$TTL 604800
@   IN  SOA house.j74th.com. root.house.j74th.com. (
                  2     ; Serial
             604800     ; Refresh
              86400     ; Retry
            2419200     ; Expire
             604800 )   ; Negative Cache TTL
;
@   IN  NS  house.j74th.com.
@   IN  A   192.168.1.65

次に、named.cond.optionsにいかの設定をする。

  • 自宅サーバ以外のドメインでは、プロバイダのDNSを見に行くようにforwardersに記述する。
  • allow-queryにクエリを許可するアドレスとして、自宅内のアドレスを指定する。
options {
    directory "/var/cache/bind";

    allow-query {
        127.0.0.1;
        192.168.1.0/24;
    };

    forwarders {
        プロバイダのプライマリDNS;
        プロバイダのセカンダリDNS;
    };

    dnssec-validation auto;

    auth-nxdomain no;    # conform to RFC1035
        listen-on-v6 { any; };
};

これで、あとはdockerコマンドを叩く。

make build
make run

なぜか、一度リスタートしなければうまく動かなかった。

make bash
service bind9 restart

これで後は、ルータが見に行くDNSをこのDockerサーバのDNSに変更する。すると、家の中にある全ての機器で自宅サーバにアクセスできるようになった!

Public BetaになったLet's Encryptを使ってみた

Public BetaになったLet's Encryptを使ってみた。ほんとうに簡単に鍵が作れる。

まず、前提は以下のとおり。

  • 取得対象のドメインで443番で公開できること
  • もしくは、取得対象のドメインで80番webサーバを公開していること

本当に、443番ポートさえあれば良いみたい。ただし外部公開が必要。登録等は不要。

やり方については以下のサイトに書かれている。

letsencrypt.org

試しに、自宅サーバで取得してみた。

まず、目的のドメインのANAMEを、自宅のIPに変更した。次に、ルータの設定で、443番アクセスを自宅サーバに通した。

以下、作業コマンド。

$ docker run -it -p 443:443 ubuntu bash
# apt-get install -y git
# cd /root/
# git clone https://github.com/letsencrypt/letsencrypt
# cd letsencrypt
# ./letsencrypt-auto --help

これで、インストール作業は完了。

あとは以下のコマンドを叩く。途中、メールアドレスの入力と規約へのAgreeをさせられる。

# ./letsencrypt-auto certonly --standalone -d letsenctest.j74th.com
Updating letsencrypt and virtual environment dependencies.......
Running with virtualenv: /root/.local/share/letsencrypt/bin/letsencrypt certonly --standalone -d letsenctest.j74th.com
IMPORTANT NOTES:
 - If you lose your account credentials, you can recover through
   e-mails sent to site@j74th.com.
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/letsenctest.j74th.com/fullchain.pem. Your cert
   will expire on 2016-03-19. To obtain a new version of the
   certificate in the future, simply run Let's Encrypt again.
 - Your account credentials have been saved in your Let's Encrypt
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Let's
   Encrypt so making regular backups of this folder is ideal.
 - If you like Let's Encrypt, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

すると、それだけで、/etc/letsencrypt/live/以下に、秘密鍵と証明書ができている。

# ls /etc/letsencrypt/live/letsenctest.j74th.com/
cert.pem  chain.pem  fullchain.pem  privkey.pem

fullchain.pemとprivkey.pemをサーバに設定すれば使えるようになる。

試しに、apache2に設定してみた。

# apt-get install -y apache2 openssl
# a2enmod ssl
# vi /etc/apache2/sites-available/default-ssl.conf
-- 以下を編集 --
SSLCertificateFile      /etc/letsencrypt/live/letsenctest.j74th.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/letsenctest.j74th.com/privkey.pem
# a2ensite default-ssl
# service apache2 start

以下の様な証明書だった。

  • RSA 2048bit
  • 有効期限は3ヶ月
  • iPhoneSafariからは「信頼されていません」と表示
  • iPhoneChromeからは緑色にはならないが、エラーはなし

そうかー、信頼されていないになってしまうのか。 なお、上記コマンドではCUIでメールアドレスの入力が求められるが、試していないが--email address@emil.com--agree-tos`でスキップもできるようだ。

更新の際には、元のコマンドを呼ぶだけでいいらしい。

./letsencrypt-auto

やってみたところ、TUIでいろいろ聞かれたので、まだ早かったのかもしれない。

とりあえず、今後サイト作るときは、とりあえずLet's Encryptで暗号化しようと思います。

dockerのデータボリュームとそのバックアップ方法

この記事はqiitaにも投稿しています→http://qiita.com/74th/items/41393f506d223850f2c3

データの永続化はdockerでよく課題になると思います。 docker docsには、Manage data in containersの節に、いくつかの方法が示されています。

https://docs.docker.com/engine/userguide/dockervolumes/

  • データボリュームを利用する
  • ホストのディレクトリにマウントする。

しばらく前まではホストのディレクトリに逃がしていたのですが、ホストのディレクトリとコンテナの中ではユーザの番号や書き込み権限の管理が違ったりして、うまくいかないことも多かったので、最近はまじめにデータボリュームを使うようにしています。

MySQLを例に、データボリュームとそのバックアップ方法をまとめてみます。

データボリュームを作成してマウントする

データボリュームは、dockerfileのVOLUMEで指定したディレクトリ、またはdocker runにて-vで指定したディレクトリに、自動で作られます。そしてそれは、コンテナとは別に管理され、docker commitdocker exportしてもデータボリュームの内容は含まれません。コンテナ間のデータ共有は、データボリュームによってのみ可能です。

イメージ f:id:j74th:20151207081144p:plain

自動で作られるだけではなく、コマンドで作ることもできます。MySQLのデータを管理するデータボリューム作ってみます。 このデータボリュームの名前をmysql_dataとします。

docker volume create --name mysql_data

データボリュームのリストは、コマンドで確認できます。

docker volume ls
DRIVER              VOLUME NAME
local               mysql_data

では、MySQLのコンテナにこのデータボリュームをマウントさせます。

docker run -d --name mysql -p 3306:3306 -v mysql_data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=password mysql

確かに、マウントされていることが、docker inspectで確認できます。

docker inspect mysql

    ...

    "Mounts": [
        {
            "Name": "mysql_data",
            "Source": "/mnt/sda1/var/lib/docker/volumes/mysql_data/_data",
            "Destination": "/var/lib/mysql",
            "Driver": "local",
            "Mode": "z",
            "RW": true
        }
    ],

    ...

なお、データボリュームはcreateすることができますが、標準のlocalの場合、一度コンテナに紐付けられると、そのコンテナが破棄された時にデータボリュームも一緒に破棄されます。よって、データボリュームを作成するときは、busyboxなどのコンテナにわかりやすい名前で紐つけておいたほうが良いと思われます。

docker create --name mysql_data -v mysql_data:/var/lib/mysql busybox

データボリュームのバックアップ

コンテナやイメージと違い、データボリュームは単体でバックアップする方法は提供されていないようでした。このデータボリュームはプラグイン化されており、docker volume create -d [plugin]で指定できます。きっとバックアップは各プラグインで考えることなのだろうと思います。

ちなみに、上記のdocker inspectの結果localと書かれていますが、実はSourceのディレクトリがマウントされているだけです。バックアップには、このディレクトリを直接処理しても良いと思います。

よく登場するのは、他のコンテナにこのデータボリュームをマウントし、そこでバックアップをする方法です。なんだかなーとおもって、データバックアップ専用のコンテナ74th/volumebackupを作成しました。

https://hub.docker.com/r/74th/volumebackup/ https://hub.docker.com/r/74th/volumerestore/

以下のコマンドを実行すると、mysql_data-YYYYMMDDHHmmss.tar.gzというファイルにバックアップします。

docker run -v mysql_data:/target -v `pwd`:/export -e NAME=mysql_data 74th/volumebackup

復元するには、復元用コンテナを使います

docker volume create --name mysql_data2
docker run -v mysql_data2:/target -v `pwd`:/import -e TARGETFILE=mysql_data-20151206124353.tar.gz 74th/volumerestore

最後に、このバックアップが使えることを確認します。

docker run -d --name mysql2 -p 3306:3306 -v mysql_data2:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=password mysql

おわり

dockerは正義!なツールを発表しようと思っていましたが、まだ未熟なツールなので、ちゃんと理解していなかったデータボリュームについてまとめました。

https://github.com/74th/flyingwhale