快速入門
這個簡短的教程幫你快速開始使用Registrator。完整參看,查看運行參考
概述
Registrator監控新建的Docker容器,並且檢查判定這些容器提供的服務。從我們的目的出發,任何監聽在某個端口的程序都是服務。Registrator發現在容器內發現的任務服務,都將被添加到一個服務注冊端,比如Consul或etcd。
在這個教程中,我們將使用Registrator和Consul,運行一個Redis容器並自動添加到Consul。
准備
我們需要一個運行Docker的主機,可以是一個本地的boot2doker虛擬機和一個安裝了docker client可以連接到虛擬機的shell。
我們在容器里運行一個Server模式的consul實例
$ docker run -d --name=consul --net=host gliderlabs/consul-server -bootstrap
Consul在產品模式下的不是這樣運行的,我們這里使用這種方式完成教程。現在我們可以訪問通過Docker主機的IP訪問Consul的HTTP API。
$ curl $(boot2doker ip):8500/v1/catalog/services
{"consul":[]}
現在我們可以啟動Registrator了。
運行Registrator
Registrator運行在每台主機上,我們這里只有一台主機,就運行一次就行。啟動Registrator需要配置如何連接到注冊機,即這里的Consul。
除了標志選項,唯一需要的參數就是注冊機URI。注冊機URI編碼了注冊機類型,如何連接等選項。
$ docker run -d \
--name=registrator
--net=host \
gliderlabs/registrator:latest \
consul://localhost:8500
先說一下Docker運行參數。首先,我們獨立的運行容器和命名。我們也采用主機網絡模式。這確保Registrator擁有實際主機的主機名和IP,也使Registrator更容易連接到Consul。我們也必須掛載Docker socket。
最后一行是Registrator運行參數,只有注冊機URI。我們使用consul//localhost:8500,因為Registrator和Consul 運行在同一個網口。
$ docker logs registrator
我們應該可以看到Registrator運行起來並在“監聽Docker事件"。Registrator正常運行了。
運行Redis
現在當你啟動的容器如果提供任何服務,他們將被添加到Consul。我們現在運行標准鏡像庫的Redis:
$ docker run -d -P --name=redis redis
我們使用-P
發布所有端口,除了Registrator我們不經常這樣使用。這樣不僅發布了容器的所有端口,而且隨機分配了一個主機端口。從Registrator和Consul提供服務發現的角度看,端口並不重要。盡管還有一些情況,你仍然想手動指定端口。
我們再來看看Consul的服務端:
$ curl $(boot2docker ip):8500/v1/catalog/services
{"consul":[],"redis":[]}
現在Consul已經有了一個redis服務。我們可以通過Consul的服端API查看更多諸如服務發布端口等信息:
$ curl $(boot2docker ip):8500/v1/catalog/service/redis
[{"Node":"boot2docker","Address":"10.0.2.15","ServiceID":"boot2docker:redis:6379","ServiceName":"redis","ServiceTags":null,"ServiceAddress":"","ServicePort":32768}]
如果我們移除redis容器,我們能夠看到服務也從consul移除了。
$ docker rm -f redis
redis
$ curl $(boot2docker ip):8500/v1/catalog/service/redis
[]
就到這了。我知道單獨來看這並沒什么意義,但是當服務注冊到Consul后你可以做很多事情。當然,這超出了Registrator的范圍,它做的就是把容器中的服務放進Consul。
下一步
這還有很多方法配置Registrator,並且有很多方法運行容器,自定義服務。想了解這些,去看看運行參考和服務模型
運行參考
Registrator設計是在每個主機上運行一次。你可以在一個集群中運行單個Registrator,但是在每個主機上運行可以使你或得更好的擴展屬性和更簡單的配置。從一定程度的自動化來說,每個主機都運行比在某個地方運行一次更簡單。
運行Registrator
docker run [docker options] gliderlabs/registrator[:tag] [options] <registry uri>
Registrator要求和推薦一些Docker選項,也有它自己的選項集,然后需要個注冊機URI。下面是一個運行Registrator的經典方式:
$ docker run -d \
--name=registrator \
--net=host \
--volume=/var/run/docker.sock:/tmp/docker.sock \
gliderlabs/registrator:latest \
consul://localhost:8500
Docker選項
Option | Required | Description |
---|---|---|
--volume=/var/run/docker.sock:/tmp/docker.sock | yes | 允許Registrator訪問Docker API |
--net=host | recommended | 幫助Registrator獲取主機級的IP和主機名 |
與設置主機網絡模式相比,另一個可選的方案是設置容器名字為宿主主機名(-h $HOSTNAME
),並且使用下面Registrator的-ip選項。
Registrator選項
Option | Since | Description |
---|---|---|
-cleanup | v7 | 清理懸掛服務 |
-deregister
|
v6 | 取消注冊退出的服務 "always"或"on-success".缺省值:always |
-internal | 使用暴露端口代替發布端口 | |
-ip
|
v6 | 強制設置注冊服務使用的IP地址 |
-resync
|
v6 | 服務再同步頻率。缺省值:0,never |
-retry-attempts
|
v7 | 與注冊機后台建立連接的最大重試次數 |
-retry-interval
|
v7 | 重試間隔(以毫秒為單位) |
-tags
|
v5 | 強制設置所有注冊服務的都好分割的tags |
-ttl
|
服務TTL。缺省值0,no expiry(注冊機后台唯一支持) | |
-ttl-refresh
|
服務TTL刷新頻率(注冊機后台唯一支持) | |
-useIdFromLabel | 使用存儲在給定label的IP地址,這個label在容器中設置,用以注冊Consul。 |
如果設置了-internal
選項,Registrator會注冊docker內部IP和端口,而不是映射到主機的端口。
默認情況下,注冊服務時,Registrator會嘗試解析當前主機名來設置服務地址。如果你想強制指定服務地址為某個特定地址,你可以指定-ip
參數。
對於支持TTL超期的注冊機后端,Registrator支持設置和刷新服務的TTLs,使用-ttl
和-ttl-refresh
。
如果你想無限制的重連嘗試,可以使用-retry-attempts -1
。
-resync
選項控制Registrator查詢Docker中所有容器並且注冊所有服務的頻率。這個選項允許Registrator和服務注冊機重新找到掉出同步的服務。要謹慎使用這個選項,它會通知已經注冊到你服務上的所有觀察者,可能會迅速淹沒你的系統(比如consul-template就大量使用監測)。
Consul ACL令牌
如果consul配置要求提供ACL令牌,Registrator需要知道,或者你會在consul的docker容器中看到警告。
[WARN] consul.catalog: Register of service 'redis' on 'hostname' denied due to ACLs
ACL令牌通過一個環境變量傳入docker:CONSUL_HTTP_TOKEN
。
$ docker run -d \
--name=registrator \
--net=host \
--volume=/var/run/docker.sock:/tmp/docker.sock \
-e CONSUL_HTTP_TOKEN=<your acl token> \
gliderlabs/registrator:latest \
consul://localhost:8500
注冊URI
<backend>://<address>[/<path>]
注冊機后台使用URI來定義。架構是支持的注冊機名字。地址是用來連接注冊機的一個主機或者主機和端口。一些注冊機支持一個定義的路徑,比如作為前綴在服務定義中供基於注冊機的key-value使用。
所以支持的后端參考,查看注冊機后端
服務模型
Registrator主要關注的那些要被添加到服務發現注冊機的服務。對我們而言,所有監聽在某個端口的程序都是服務。如果一個容器監聽了多個端口,它就又多個服務。
服務,包括來自容器的信息和用戶在容器上定義的元數據被創建成一個服務對象。這個服務對象隨后被傳遞給注冊機后端,嘗試放置到一個特定的注冊項。
type Service struc {
ID string //unique service instance ID
Name string //service name
IP string //IP address service is located at
Port int //Port service is listening on
Tags []string //extra tags to classify service
Attrs map[string]string //extra attribute metadata
}
容器覆蓋
Name,Tags,Attrs,ID
字段可以被用戶自定義的容器元數據覆蓋。你可以使用前綴SERVICE_
或者SERVICE_x_
,其中x
是內部暴露端口的環境變量或者標簽設置這些值。例如,SERVICE_NAME=customerdb
和SERVICE_80_NAME=api
你在這些環境變量中使用的端口指的是在這個端口上的特定服務。名字中沒有使用端口的元數據變量用作所有服務的缺省值,或者便捷的指向暴露的單個服務。
Attrs
字段集合所有使用其他字段名的關鍵字,例如,SERVICE_REGION=us-east
。
因為元數據被存儲為環境變量或者標簽,因此容器作者可以在Dockerfile中包含他們自己的元數據定義。操作者仍然能夠覆蓋這些作者定義的缺省值。
發現服務
缺省情況下,你可以期望Registrator從那些已經顯式發布端口(例如使用'-p'或者-P
)的容器中獲取服務。這對於那些以主機網絡模式運行的容器也是正確的,因此你必須發布端口,即使它沒什么做任何網絡智慧的事情。
$ docker run --net=host -p 8080:8080 -p 8443:8443 ...
如果使用-internal
選項運行,相反它將尋找暴露的端口。這些可以在Dockerfile中隱式設置或者使用docker run --expose=8080...
顯式設定。
你也可以通過設置一個叫SERVICE_IGNORE
的標簽或者環境變量告訴Registrator忽略一個容器。
如果你需要在某些容器中忽略幾個服務,你可以使用SERVICE_<port>_IGNORE=true
。
服務名稱
服務名是你在服務發現查找中使用的。缺省情況下,服務名按下面的格式確定:
<base(container-image)>[-<exposed-port> if >1 ports]
使用容器鏡像的基礎,如果鏡像是gliderlabs/footbar
,服務名就是footbar
。如果鏡像是redis
,服務名就是簡單的redis
。
而且如果一個容器有多個暴露端口,它將各自追加內部暴露端口以區別。例如,一個鏡像nginx
有兩個暴露端口,80和443,將產生兩個服務,分別命名nginx-80
和nginx-443
。
你可以使用標簽或者環境變量,SERVICE_NAME
或者'SERVICE_x_NAME',其中x
是內部暴露端口,覆蓋這些缺省名字。注意如果一個容器有多個暴露端口,設置SERVICE_NAME
會導致多個服務命名為SERVICE_NAME-<exposed port>
。
IP和端口
IP和端口組成了服務名解析的地址。這有許多方法Registrator能夠依賴你的設置判斷IP地址和端口。缺省情況下,端口就是發布的公共端口,IP將是你的主機IP。
由於自動判定正確的IP是困難的,推薦使用-ip
選項顯式告訴Registrator使用什么IP。
如果你使用-internal
選項,Regisrator會使用暴露端口和docker分配的內部容器IP。
Tags和Attributes
Tags和attributes是服務額外的元數據字段。並不是所有的后端都支持他們。事實上,目前consul支持tags,並且最近的v1.0.7以KV元數據的形式添加了對attributes的支持,但是沒有其他的后端支持attributes。
Attributes也能被后端用來注冊特定的特性,不僅僅是元數據。例如,consul使用他們指定specifying HTTP health checks
。
Unique ID
ID是服務示例在集群內的唯一標識。大部分情況下,它是一個實現細節,通常用戶使用服務名而不是ID。Registrator使用一個人機友好的字符串,基於下面的格式編碼了有用的信息在ID中:
<hostname>:<container-name>:<exposed-port>[:udp if udp]
ID包括了主機名,幫助你識別服務運行的主機。這也是Registrator運行在主機網絡模式下或者設置Registrator的主機名為寄宿主機的主機名重要的原因。否則它將是Registrator容器的ID,那沒有什么用處。
這個服務的容器名稱也包含進來了。它使用容器名稱代替容器ID,因為它更人性化,並且用戶可配置。
為了識別出容器中這個服務,它使用內部暴露端口。這代表這個服務在容器內在這個端口上監聽。我們使用這個是因為它比公共的發布端口更好的表達了這個服務。一個公共的端口可能是一個任意的54292,然而暴露的端口可能是80,表示它是一個HTTP服務。
最后,如果服務定義為UDP,這會被包括到ID中與監聽在相同端口的TCP服務區別開。
盡管這可以使用容器的SERVICE_ID
或者SERVICE_x_ID
覆蓋,但是不推薦這樣做。
示例
缺省的單個服務
$ docker run -d --name redis.0 -p 10000:6379 progrium/redis
Service
結果是:
{
"ID": "hostname:redis.0:6379",
"Name": "redis",
"Port": 10000,
"IP": "192.168.1.102",
"Tags": [],
"Attrs": {}
}
指定元數據的單個服務
$ docker run -d --name redis.0 -p 10000:6379 \
-e "SERVICE_NAME=db" \
-e "SERVICE_TAGS=master,backups" \
-e "SERVICE_REGION=us2" progrium/redis
Service
結果是:
{
"ID": "hostname:redis.0:6379",
"Name": "db",
"Port": 10000,
"IP": "192.168.1.102",
"Tags": ["master", "backups"],
"Attrs": {"region": "us2"}
}
記住並不是所有的Service
對象都會被注冊后端使用。例如,目前不支持注冊任意attributes。這個字段留作將來使用。
逗號可能可以通過反斜杠轉義,像下面的例子:
$ docker run -d --name redis.0 -p 10000:6379 \
-e "SERVICE_NAME=db" \
-e "SERVICE_TAGS=/(;\\,:-_)/" \
-e "SERVICE_REGION=us2" progrium/redis
缺省的多個服務
$ docker run -d --name nginx.0 -p 4443:443 -p 8000:80 progrium/nginx
兩個Service
對象的結果:
[
{
"ID": "hostname:nginx.0:443",
"Name": "nginx-443",
"Port": 4443,
"IP": "192.168.1.102",
"Tags": [],
"Attrs": {},
},
{
"ID": "hostname:nginx.0:80",
"Name": "nginx-80",
"Port": 8000,
"IP": "192.168.1.102",
"Tags": [],
"Attrs": {}
}
]
指定元數據的多個服務
$ docker run -d --name nginx.0 -p 4443:443 -p 8000:80 \
-e "SERVICE_443_NAME=https" \
-e "SERVICE_443_ID=https.12345" \
-e "SERVICE_443_SNI=enabled" \
-e "SERVICE_80_NAME=http" \
-e "SERVICE_TAGS=www" progrium/nginx
兩個Service
對象的結果:
[
{
"ID": "https.12345",
"Name": "https",
"Port": 4443,
"IP": "192.168.1.102",
"Tags": ["www"],
"Attrs": {"sni": "enabled"},
},
{
"ID": "hostname:nginx.0:80",
"Name": "http",
"Port": 8000,
"IP": "192.168.1.102",
"Tags": ["www"],
"Attrs": {}
}
]
使用labels定義元數據
$ docker run -d --name redis.0 -p 10000:6379 \
-l "SERVICE_NAME=db" \
-l "SERVICE_TAGS=master,backups" \
-l "SERVICE_REGION=us2" dockerfile/redis
Service
結果:
{
"ID": "hostname:redis.0:6379",
"Name": "db",
"Port": 10000,
"IP": "192.168.1.102",
"Tags": ["master", "backups"],
"Attrs": {"region": "us2"}
}
注冊后端
Registrator支持很多后端注冊機。為了發揮Registrator的用途,你需要運行其中一個。下面是被支持后端使用的注冊URI和它們的特性文檔。
Consul
consul://<address>:<port>
consul-unix://<filepath>
consul-tls://<address>:<port>
Consul是推薦的注冊機,因為它專門為服務發現提供了健康檢查服務。
如果沒有指定地址和端口,默認將使用127.0.0.1:8500。
consul支持tags,但不是任意服務attributes。
當使用consul-tls
架構,Registrator通過TLS與Consul通信。你必須設置下面的環境變量:*CONSUL_CAERT
:CA 文件位置, *CONSUL_TLSKEY
:Key位置
了解更多關於Consul檢查參數信息,查看API documentation。
Consul HTTP Check
這個特性只能在Consul 0.5及更新版本中使用。容器通過環境變量或者標簽指定的這些額外的元數據用來在服務中注冊一個HTTP健康檢查。
SERVICE_80_CHECK_HTTP=/health/endpoint/path
SERVICE_80_CHECK_INTERVAL=15s
SERVICE_80_CHECK_TIMEOUT=1s # optional, Consul default used otherwise
它適用於任何端口的服務,不僅僅是80端口。如果它是唯一的服務,你也可以使用
SERVICE_CHECK_HTTP
Consul HTTPS Check
這個特性只能在Consul 0.5及更新版本中使用。容器通過環境變量或者標簽指定的這些額外的元數據用來在服務中注冊一個HTTPS健康檢查。
SERVICE_443_CHECK_HTTPS=/health/endpoint/path
SERVICE_443_CHECK_INTERVAL=15s
SERVICE_443_CHECK_TIMEOUT=1s # optional, Consul default used otherwise
Consul TCP Check
這個特性只能在Consul 0.6及更新版本中使用。容器通過環境變量或者標簽指定的這些額外的元數據用來在服務中注冊一個TCP健康檢查。
SERVICE_443_CHECK_TCP=true
SERVICE_443_CHECK_INTERVAL=15s
SERVICE_443_CHECK_TIMEOUT=3s # optional, Consul default used otherwise
Consul Script Check
這個特性很難用,因為它讓你指定一個腳本檢查從Consul運行。如果在容器中運行Consul,你就被限制只能在那個容器中運行。例如,curl必須按照以使用這個特性:
SERVICE_CHECK_SCRIPT=curl --silent --fail example.com
任務no-TTL檢查的缺省間隔是10秒,但是你可以使用_CHECK_INTERVAL
設置。檢查命令可以使用$SERVICE_IP
和$SERVICE_PORT
占位符插值:
SERVICE_CHECK_SCRIPT=nc $SERVICE_IP $SERVICE_PORT | grep OK
Consul TTL Check
你也可以向consul注冊一個TTL Check。記住這意味着Consul將期待一個常規的心跳ping到他的API,用以保持服務標志健康。
SERVICE_CHECK_TTL=30s
Consul Initial Health Check Status
缺省的當一個服務在Consul注冊時,狀態被設置為"critical"。你可以指定初始的健康檢查狀態:
SERVICE_CHECK_INITIAL_STATUS=passing
Consul Critical Service Deregistration
Consul可能撤銷注冊一個服務,如果檢查在critical
狀態超過設定的時間值。如果啟用,這應該比可期待的恢復故障更長。
SERVICE_CHECK_DEREGISTER_AFTER=10m
Consul KV
consulkv://<address>:<port>/<prefix>
consulkv-unix://<filepath>:/<prefix>
這是一個分離后端,使用Consul的key-value存儲代替它的本地服務目錄。這種表現更像etcd,因為它有相似的語義,但是目前不支持TTLs。
如果沒有指定地址和端口,默認是127.0.0.1:8500
。
使用Registry URI前綴,服務定義存儲為下面的格式:
<prefix>/<service-name>/<service-id> = <ip>:<port>
Etcd
etcd://<address>:<port>/<prefix>
Etcd工作方式與Consul KV相似,而且支持服務TTLs。它目前也不支持服務attributes和tags。
如果沒有指定地址和端口,它將使用默認值127.0.0.1:2379
。
使用Registry URI作為前綴,服務定義被儲存為下面的格式:
<prefix>/<service-name>/<service-id> = <ip>:<port>
SkyDNS 2
skydns2://<address>:<port>/<domain>
SkyDNS2 使用etcd,因此這個后端寫服務定義的格式兼容SkyDNS2。path不能被省略,必須是一個對SkyDNS有效的DNS域名。
如果沒有指定地址和端口,它將是默認值:127.0.0.1:2379
。
使用Registry URI和域名cluster.local
,服務定義存儲為下面的格式:
/skydns/local/cluster/<service-name>/<service-id> = {"host":"<ip>","port":<port>}
SkyDNS要求服務ID是一個有效的DNS主機名,因此這個后端要求容器用一個有效的DNS名字覆蓋服務ID。例如:
$ docker run -d --name redis-1 -e SERVICE_ID=redis-1 -p 6379:6379 redis
Zookeeper Store
Zookeeper后端讓你發布臨時的znodes到zookeeper。這個模式在指定zookeeper路徑后可以使用。zookeeper后端支持發布一個json格式的znode body,完成定義服務attributes/tags,也包括服務名和容器id。URI示例:
$ registrator zookeeper://zookeeper.host/basepath
$ registrator zookeeper://192.168.1.100:9999/basepath
在zookeeper URI指定的base path中,registrator將為服務創建下面的包括一個JSON入口路徑樹:
<service-name>/<service-port> = <JSON>
JSON將包括發布容器服務的所有信息。例如下面的容器啟動:
docker run -i -p 80 -e 'SERVICE_80_NAME=www' -t ubuntu:14.04 /bin/bash
將產生的zookeeper path和JSON znode body:
/basepath/www/80 = {"Name":"www","IP":"192.168.1.123","PublicPort":49153,"PrivatePort":80,"ContainerID":"9124853ff0d1","Tags":[],"Attrs":{}}