Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
30
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

CoreOS クラスタ上で SkyDNS2 を使ってサービスディスカバリする

概要

CoreOS 上でのサービスディスカバリに SkyDNS2 を利用するという話。SkyDNS2 は Docker コンテナとして動かす。

SkyDNS2 とは

DNS サーバの一つ。データの保存先に etcd を使うことで分散 DNS サーバを実現してる。例えば、 5 台の CoreOS マシンからなるクラスタがあるとき、各マシンで SkyDNS2 を起動させておく。etcd にデータを置いているので、どのマシンの SkyDNS2 を利用しても同じ結果になる。

そして、後述する SRV レコードを返すことで単なる DNS サーバというよりはサービスディスカバリーを実現するためのサービスという位置づけになっている。

サービスディスカバリーに SRV レコードを使う

SRV レコードのポイントは

  • ポート情報まで持ってること
  • 負荷分散できること

ポート情報まで持っていること

DNS は通常名前 <---> IP の解決をするだけなので、あるサービス使いたい場合、「どの IP のどこのポートに繋げば良い?」みたいな場合に利用出来ない。が SRV レコード を使うと、IP+ポート情報まで持たせられるのでサービスディスカバリーに利用出来る。

# 例
$ dig SRV 1.rails.skydns.local

;; ANSWER SECTION:
1.rails.skydns.local. 3600  IN  SRV 10 100 8080 1.rails.skydns.local.

# ANSWER SECTION は以下の内容が書かれている
# service name, environment, TTL, priority, weight, service port, host name

さらに、 SRV レコードは負荷分散にも利用できる。

負荷分散できること

SRV レコードは、

  • Priority
  • Weight

という情報も持たせられる。 Priority の値の小さい方から優先的に通信される。 Weight は同じ優先順位のホスト郡での振り分け具合を決められる。

SkyDNS2 を使ったサービスディスカバリ

SkyDNS2 の Docker イメージ作成

# on CoreOS machine
core@core-01 ~ $ git clone https://github.com/skynetservices/skydns.git
core@core-01 ~ $ cd skydns

同梱されている Dockerfile は language stack を使っていない。なるだけ language stack ベースのイメージを使いたいので以下のように編集してビルドした。

# Dockerfile
FROM golang:1.3.3
MAINTAINER Miek Gieben <miek@miek.nl> (@miekg)

ADD . /go/src/github.com/skynetservices/skydns
RUN go get github.com/skynetservices/skydns

EXPOSE 53
ENTRYPOINT ["skydns"]
core@core-01 ~ $ docker build -t skydns2 .

SkyDNS のデフォルト設定を etcd にセット

core@core-01 ~ $ curl -L -XPUT http://172.17.8.101:4001/v2/keys/skydns/config -d value='{"nameservers": ["8.8.8.8:53","8.8.4.4:53"]}'

SkyDNS2 コンテナ起動

# SkyDNS2 の UDP 53 ポートをホストの Private IPの 53 ポートに bind 
core@core-01 ~/skydns $ docker run \
  -d \
  --name skydns2 \
  -p 172.17.8.101:53:53/udp \
  -e ETCD_MACHINES='172.17.8.101:4001,172.17.8.102:4001,172.17.8.103:4001' \
  skydns2:latest \
  -addr=0.0.0.0:53

core@core-01 ~ $ docker logs skydns2
[skydns] Oct 14 03:26:33.702 INFO      | ready for queries on skydns.local. for tcp://0.0.0.0:53 [rcache 0]
[skydns] Oct 14 03:26:33.702 INFO      | ready for queries on skydns.local. for udp://0.0.0.0:53 [rcache 0]
[skydns] Oct 14 03:27:51.679 INFO      | no nameservers defined or name too short, can not forward
[skydns] Oct 14 03:27:51.679 INFO      | no nameservers defined or name too short, can not forward

これで Core-01 の Private IP (172.17.8.101) を DNS nameserver として利用出来るになる

etcd にサービス情報をセット

Core-01 上に起動している logspout を logspout.1 のように、3 台登録することにする

logspout.1.json

{
  "host":"172.17.8.101",
  "port":8080
}

logspout.2.json

{
  "host":"172.17.8.102",
  "port":8080
}

logspout.3.json

{
  "host":"172.17.8.103",
  "port":8080
}

etcd にセット

core@core-01 ~ $ curl -L -XPUT http://172.17.8.101:4001/v2/keys/skydns/local/skydns/logspout/1 --data-urlencode value@logspout.1.json
{"action":"set","node":{"key":"/skydns/local/skydns/logspout/1","value":"{\n  \"host\":\"172.17.8.101\",\n  \"port\":8000\n}\n","modifiedIndex":9000,"createdIndex":9000},"prevNode":{"key":"/skydns/local/skydns/logspout/1","value":"","modifiedIndex":8995,"createdIndex":8995}}

core@core-01 ~ $ curl -L -XPUT http://172.17.8.101:4001/v2/keys/skydns/local/skydns/logspout/2 --data-urlencode value@logspout.2.json
{"action":"set","node":{"key":"/skydns/local/skydns/logspout/2","value":"{\n  \"host\":\"172.17.8.102\",\n  \"port\":8000\n}\n","modifiedIndex":8887,"createdIndex":8887}}

core@core-01 ~ $ curl -L -XPUT http://172.17.8.101:4001/v2/keys/skydns/local/skydns/logspout/3 --data-urlencode value@logspout.3.json
{"action":"set","node":{"key":"/skydns/local/skydns/logspout/3","value":"{\n  \"host\":\"172.17.8.103\",\n  \"port\":8000\n}\n","modifiedIndex":9022,"createdIndex":9022}}

CoreOS マシン上のプライマリ DNS サーバを SkyDNS2 に変更する

SkyDNS2 での設定のとおり、ドメインの権威が無い問い合わせが届いた時は 8.8.8.8:53 と 8.8.4.4:53 に転送するので、SkyDNS2 プライマリ DNS サーバとして扱える。

core@core-01 ~ $ cat /etc/resolv.conf
# This file is managed by systemd-resolved(8). Do not edit.
#
# Third party programs must not access this file directly, but
# only through the symlink at /etc/resolv.conf. To manage
# resolv.conf(5) in a different way, replace the symlink by a
# static file or a different symlink.

#nameserver 10.0.2.3
nameserver 172.17.8.101 # -> 書き換え

(直に書き換えるのは良くはない)

CoreOS マシン(コンテナホスト)から ping してみる

ping できるか確認してみる
(CoreOS には、dig が入ってない。)

core@core-01 ~ $ ping 1.logspout.skydns.local
PING 1.logspout.skydns.local (172.17.8.101) 56(84) bytes of data.
64 bytes from 172.17.8.101: icmp_seq=1 ttl=64 time=0.113 ms
64 bytes from 172.17.8.101: icmp_seq=2 ttl=64 time=0.031 ms
64 bytes from 172.17.8.101: icmp_seq=3 ttl=64 time=0.039 ms
64 bytes from 172.17.8.101: icmp_seq=4 ttl=64 time=0.032 ms
64 bytes from 172.17.8.101: icmp_seq=5 ttl=64 time=0.048 ms
# Core-02 の logspout に振り分けされた
core@core-01 ~ $ ping logspout.skydns.local
PING logspout.skydns.local (172.17.8.102) 56(84) bytes of data.
64 bytes from 172.17.8.102: icmp_seq=1 ttl=64 time=0.369 ms
64 bytes from 172.17.8.102: icmp_seq=2 ttl=64 time=0.437 ms
64 bytes from 172.17.8.102: icmp_seq=3 ttl=64 time=0.409 ms
64 bytes from 172.17.8.102: icmp_seq=4 ttl=64 time=0.429 ms

# 今後は Core-03 に振り分けされた。
# 接続するごとに接続先ホストが変わる = 負荷分散されてることがわかる
core@core-01 ~ $ ping logspout.skydns.local
PING logspout.skydns.local (172.17.8.103) 56(84) bytes of data.
64 bytes from 172.17.8.103: icmp_seq=1 ttl=64 time=0.290 ms
64 bytes from 172.17.8.103: icmp_seq=2 ttl=64 time=0.417 ms
64 bytes from 172.17.8.103: icmp_seq=3 ttl=64 time=0.477 ms

ruby コンテナから SRV レコードを取得してみる

#!/usr/local/bin/ruby
# get_srv.rb

require 'resolv'
require 'pp'

resolver = Resolv::DNS.new(:nameserver => ['172.17.8.101'], :search => ['skydns.local'], :ndots => 1)
hosts = resolver.getresources('logspout.skydns.local', Resolv::DNS::Resource::IN::SRV)
pp hosts
puts ""
pp hosts.map{|h| (h.target.to_s + ":" + h.port.to_s) }
$ ruby get_srv.rb
[#<Resolv::DNS::Resource::IN::SRV:0x007f47882f6620
  @port=8000,
  @priority=10,
  @target=#<Resolv::DNS::Name: 1.logspout.skydns.local.>,
  @ttl=3600,
  @weight=33>,
 #<Resolv::DNS::Resource::IN::SRV:0x007f47882f5518
  @port=8080,
  @priority=10,
  @target=#<Resolv::DNS::Name: 2.logspout.skydns.local.>,
  @ttl=3600,
  @weight=33>,
 #<Resolv::DNS::Resource::IN::SRV:0x007f47882f45c8
  @port=8080,
  @priority=10,
  @target=#<Resolv::DNS::Name: 3.logspout.skydns.local.>,
  @ttl=3600,
  @weight=33>]

["1.logspout.skydns.local:8000",
 "2.logspout.skydns.local:8080",
 "3.logspout.skydns.local:8080"]

ubuntu:14.04 コンテナから ping してみる

# on CoreOS
core@core-01 ~ $ docker run -it --rm --dns=172.17.8.101 ubuntu:14.04 /bin/bash
# コンテナ内から ping してみる
root@91fcca071b27:/$ ping 1.logspout.skydns.local
PING 1.logspout.skydns.local (172.17.8.101) 56(84) bytes of data.
64 bytes from 172.17.8.101: icmp_seq=1 ttl=64 time=0.029 ms
64 bytes from 172.17.8.101: icmp_seq=2 ttl=64 time=0.038 ms
64 bytes from 172.17.8.101: icmp_seq=3 ttl=64 time=0.063 ms
64 bytes from 172.17.8.101: icmp_seq=4 ttl=64 time=0.053 ms

ubuntu:14.04 コンテナから dig してみる

image ubuntu:14.04 では dig が入ってないので入れる

# in ubuntu:14.04, install dig
root@952708774c41:/$ sudo apt-get update && sudp apt-get install dnsutils

skydns.local のドメイン情報取得

root@41ea3b47bc69:/$ dig skydns.local

; <<>> DiG 9.9.5-3-Ubuntu <<>> skydns.local
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29922
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;skydns.local.          IN  A

;; ANSWER SECTION:
skydns.local.       3600    IN  A   172.17.8.101

;; Query time: 17 msec
;; SERVER: 172.17.8.101#53(172.17.8.101)
;; WHEN: Tue Oct 14 09:44:11 UTC 2014
;; MSG SIZE  rcvd: 46

1.logspout.skydns.local の SRV 情報を取得。先ほど etcd にセットした /skydns/local/logspout/1 の情報が返ってくる。

root@41ea3b47bc69:/# dig SRV 1.logspout.skydns.local

; <<>> DiG 9.9.5-3-Ubuntu <<>> SRV 1.logspout.skydns.local
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51547
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; QUESTION SECTION:
;1.logspout.skydns.local.   IN  SRV

;; ANSWER SECTION:
1.logspout.skydns.local. 3600   IN  SRV 10 100 8000 1.logspout.skydns.local.

;; ADDITIONAL SECTION:
1.logspout.skydns.local. 3600   IN  A   172.17.8.101

;; Query time: 13 msec
;; SERVER: 172.17.8.101#53(172.17.8.101)
;; WHEN: Tue Oct 14 10:33:28 UTC 2014
;; MSG SIZE  rcvd: 100

wildcard も利用できる。
*.logspout.skydns.local の SRV 情報を取得。先ほど etcd にセットした /skydns/local/logspout/* の情報が返ってくる。

root@41ea3b47bc69:/$ dig SRV *.logspout.skydns.local

; <<>> DiG 9.9.5-3-Ubuntu <<>> SRV *.logspout.skydns.local
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2579
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 3

;; QUESTION SECTION:
;*.logspout.skydns.local.   IN  SRV

;; ANSWER SECTION:
*.logspout.skydns.local. 3600   IN  SRV 10 33 8000 1.logspout.skydns.local.
*.logspout.skydns.local. 3600   IN  SRV 10 33 8080 2.logspout.skydns.local.
*.logspout.skydns.local. 3600   IN  SRV 10 33 8080 3.logspout.skydns.local.

;; ADDITIONAL SECTION:
1.logspout.skydns.local. 3600   IN  A   172.17.8.101
2.logspout.skydns.local. 3600   IN  A   172.17.8.102
3.logspout.skydns.local. 3600   IN  A   172.17.8.103

;; Query time: 12 msec
;; SERVER: 172.17.8.101#53(172.17.8.101)
;; WHEN: Tue Oct 14 10:28:25 UTC 2014
;; MSG SIZE  rcvd: 224
root@41ea3b47bc69:/$ dig SRV logspout.skydns.local

; <<>> DiG 9.9.5-3-Ubuntu <<>> SRV logspout.skydns.local
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 44941
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 3

;; QUESTION SECTION:
;logspout.skydns.local.     IN  SRV

;; ANSWER SECTION:
logspout.skydns.local.  3600    IN  SRV 10 33 8000 1.logspout.skydns.local.
logspout.skydns.local.  3600    IN  SRV 10 33 8080 2.logspout.skydns.local.
logspout.skydns.local.  3600    IN  SRV 10 33 8080 3.logspout.skydns.local.

;; ADDITIONAL SECTION:
1.logspout.skydns.local. 3600   IN  A   172.17.8.101
2.logspout.skydns.local. 3600   IN  A   172.17.8.102
3.logspout.skydns.local. 3600   IN  A   172.17.8.103

;; Query time: 13 msec
;; SERVER: 172.17.8.101#53(172.17.8.101)
;; WHEN: Tue Oct 14 10:28:59 UTC 2014
;; MSG SIZE  rcvd: 222

サービス情報の自動登録

CoreOS 上の Docker コンテナのサービス情報を registrator を使って SkyDNS2 に自動登録する を参照

メモ

クライアント側で SRV レコードを使うようにしないといけない

SkyDNS2 で「あるサービスが、このホスト郡のこのポートで起動してるよ」というのは取得できるようになったが、クライアント側で、 SRV レコードを利用して接続するようにしないといけない。

負荷分散できるの便利

最初は、1.rails.skydns.local でサービス情報がとれても、実際には、rails コンテナはその時その時で何台あるかわからない状態。番号まで指定して情報を取得するのは大変だなと思っていたが、*.rails.skydns.local という感じでサービス情報郡を取得でき、さらに負荷分散までできる。クライアント側で SRV レコードを使うようにしさえすれば非常に便利だと思った。

REF

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
30
Help us understand the problem. What are the problem?