快速入門
這個簡短的教程幫你快速開始使用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":{}}