摘要:是一個鍵值存儲,用于共享配置以及服務發現。對于我們而言,意味著注冊進程必須考慮到端口映射。這個方法被用于管理服務發現。如果未指定,將被從的端口映射找到意味著,你必須在運行的命令中指定它,比如。為了測試取消登記,停止一個容器將立即從中移除。
注:該文由 adetante 編寫,該文的原文地址為 Service discovery with Docker - 2
該文緊接著上篇文章 Docker 與服務發現 - 1
在上一篇文章中,我們看到了一個簡單的方法,通過使用 Synapse 來做基于同一臺 Docker 主機上的多個容器的服務發現。
現在,我們想在多臺 Docker 主機上部署相同的應用,來擴展不同的服務以及確保容錯性。
這次,在架構中我們需要一個新的組件: etcd 。
etcdetcd 是一個鍵值存儲,用于共享配置以及服務發現。它使用 GO 編寫,并且是 CoreOS 發行版的一部分。etcd 集群提供了高可用的機制:基于 Raft,它允許一組 etcd 實例組成一個集群。
etcd 提供了 REST API,允許客戶端創建,更新和刪除鍵。客戶端還可以監聽發生在特定鍵上的變化(客戶端將被通知在該鍵上或者是鍵的目錄的每次變化)。當創建一個鍵,客戶端可以定義一個 TTL (存活時間),當客戶端不再更新這個鍵的時候,它將會被自動清除,這個對于服務注冊是非常有用的。
概述原理就是 Docker 容器注冊進 etcd 集群:當一個應用的實例作為一個 Docker 容器啟動的時候,該容器自己注冊進 etcd 集群 ,當一個容器停止或者是應用掛掉的時候,對應的鍵將被移除出 etcd 集群。
Haproxy 只需要簡單的查找 etcd 來獲取可用的后端來提供 HTTP 服務,Haproxy 監聽 etcd 的變化并且相應的更新配置。
在這篇文章中,我將描述服務注冊部分的解決方案,關于 Haproxy 的發現部分將在下一篇文章中描述。
Docker 的動態端口映射Docker 是一個非常偉大的工具,它提供了很多的功能來簡化應用程序的部署。但它有一個新的方式管理以及部署這些應用。
其中的一個方式就是對外公開的端口關聯應用的能力。
當你啟動一個 Docker 容器,你可以使用以下命令:
docker run -p 8000 myApplication
-p 8000 參數意味著你可以暴露 8000 端口運行這個容器,并且在 Docker 主機上是一個隨機的端口。我們的應用在 Docker 容器中是監聽的 8000 端口,但是這個端口將被映射到 Docker 主機上的一個動態端口。為了查看映射的端口,當容器正在運行的時候,你可以使用 docker ps 命令:
ONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6275ea4e2ebd coreos/etcd:latest /opt/etcd/bin/etcd 2 weeks ago Up 1 seconds 0.0.0.0:49153->4001/tcp, 0.0.0.0:49154->7001/tcp pensive_leakey
在以上的輸出中,你可以看到 PORTS 列的在容器中的 4001 端口被映射成了 在 Docker 主機上的 O.O.O.O:49153。
對于我們而言,意味著注冊進程必須考慮到端口映射。我們必須注冊映射端口,而不是應用監聽的端口。同樣的,我們必須使用 Docker 主機的 IP 代替容器的 IP 來注冊。
服務注冊為了把服務注冊進 etcd ,我們有以下不同的解決方案:
應用它自己能建立一個連接到 etcd,并且創建一個 key 來通知其他的服務它正在運行。當停止的時候,應用必須移除該 key 。它可能在服務終止的時候會變得更加復雜,但是使用 TTL ,我們可以使損失降到最小(key 不會被立即移除,僅僅在 TTl 后才被移除)。但是這意味著應用必須感知到注冊進程:必須知道 etcd 實例的清單列表,必須保持一個循環定期的刷新 etcd 中的 key 。。。我更喜歡應用能與注冊進程完全獨立。
在容器啟動的時候,執行一個啟動腳本來創建 etcd 中的 key ,然后在停止的時候移除它。它可能在通知應用停止的時候會變得更加復雜。而且,這還有一個風險,就是在應用完全啟動之前, key 已經在 etcd 中被創建了,然后 Haproxy 可能轉發 HTTP 請求到容器中,盡管應用還未啟動。
一個 ‘sidekick’ 進程,運行在同樣的容器中,能處理應用的注冊和健康檢查。這個方法被 CoreOS 用于管理服務發現。這就是我將在示例中使用的解決方案。
Sidekick 進程用于注冊負責注冊的進程執行以下任務:
調用 Docker API 來檢索應用在容器中的對外i端口映射到本地主機的端口
執行應用的健康檢查:當應用可用,使用 Docker 主機的 IP 和端口 創建或是更新 etcd 中的 key
當應用沒有正確響應,或者容器停止了:從 etcd 中移除 key
為了執行這些任務,我使用 GO 寫了一些程序,可用的版本在我的 GitHub 倉庫中:github.com/adetante/dockreg。
這個程序接收以下參數:
--etcd:必須的,用于注冊的 etcd 的服務列表,使用以下格式:
--etcd http://host1:port1,http://host2:port2
--key:可選的,程序在 etcd 中為 keys 創建的父目錄的名字,默認的值是 service 。
--port:必須的,應用用于注冊的本地端口
--docker:可選的,用于訪問 Docker API 的 Docker UNIX socket,默認的值是 /var/run/docker.sock。(看 Docker Introspection)
--ip:可選的,放進 etcd 的 Docker 主機的 IP 地址。如果未指定,IP 將被從 Docker API 的端口映射找到(意味著,你必須在 docker 運行的命令中指定它,比如 docker run -p 8000::192.168.1.54)。
這個進程將每 5 秒請求應用監聽的 --port,如果它在 3 秒內沒有得到響應,key 將被從 etcd 中移除,否則,一個 key 將被創建在 etcd 服務器的以下路徑:/keys/{service}/{ip}:{mapped_port}。
Docker 回顧正如你以上所見,dockreg 進程通過一個 Unix Domain socket(/var/run/docker.sock)訪問 Docker API。這是必須的,因為 Docker 沒有提供其他的方式來獲取容器的信息。這個需求在 Docker repository 中被討論(see issues 7421 and 3778 for example),這個在未來的版本可能會實現。目前,唯一的方法就是通過共享容器的 docker.sock 來實現這個需求。它并不理想,因為安全原因(使用這個接口,在安全認證之外,容器能訪問和修改很多信息)。
為了分享 Docker socket,意味著容器必須以 -v 選項啟動:
docker run -p 8000 -v /var/run/docker.sock:/var/run/docker.sock myApplication
如果一個端口映射已經在容器中定義,JSON 響應內容包含的一些東西如下:
"NetworkSettings": { "Bridge": "docker0", "Gateway": "172.17.42.1", "IPAddress": "172.17.0.4", "IPPrefixLen": 16, "PortMapping": null, "Ports": { "8000/tcp": [ { "HostIp": "0.0.0.0", "HostPort": "49155" } ] } }
dockreg 將使用響應中的 ports 數據來找回對外服務的端口(和 IP 地址)。
現在開始作為一個概念驗證,我在基于 Vagrant 構建的 2 個主機上創建了一個 demo,首先,克隆 vagrant 倉庫:
git clone git@github.com:adetante/dockreg-vagrant.git
這個倉庫包含:
用于創建 2 個主機的 Vagrantfile。基礎的 Vagrant box 是一個 Ubuntu 14.04 以及 放進 VM 的 2 個 Docker 鏡像:ubuntu 和 etcd,這個僅僅是用于完成主機加速。
NodeJS 示例程序,我們想部署進 Docker 容器中的。
一個 dockreg 的構建工具
一個 Dockerfile 用于構建一個鏡像,包含 NodeJS app 和 dockreg sidekick 進程。
當開始的時候,vagrant 腳本(build.sh) 將啟動一個 etcd 容器,作為一個 host-1 和 host-2 的集群配置。下一步,它將構建一個包含 NodeJS app 和 dockreg sidekick 進程的鏡像,Dockerfile 如下:
FROM ubuntu:trusty RUN apt-get update && apt-get install -y python python-setuptools nodejs && easy_install supervisor && mkdir /var/log/dockreg EXPOSE 8000 CMD [] ENTRYPOINT ["/usr/local/bin/supervisord","-c","/etc/supervisord.conf"] ADD supervisord.conf /etc/supervisord.conf ADD dockreg /usr/bin/dockreg ADD node-app/server.js /root/server.js RUN chmod a+x /usr/bin/dockreg
在這個構建鏡像中,一個 supervisord 進程將啟動 NodeJS 應用和 dockreg 進程。
Supervisord 配置如下:
[supervisord] nodaemon=true logfile=/var/log/dockreg/supervisord.log logfile_maxbytes=50MB logfile_backups=4 loglevel=info pidfile=/var/run/supervisord.pid [program:nodejs-server] command=nodejs /root/server.js autorestart=unexpected stdout_logfile=/var/log/dockreg/http.stdout stdout_logfile_maxbytes=1MB stdout_logfile_backups=10 stderr_logfile=/var/log/dockreg/http.stderr stderr_logfile_maxbytes=1MB stderr_logfile_backups=10 [program:dockreg] command=/usr/bin/dockreg --port 8000 --etcd http://%(ENV_ETCD_PORT_4001_TCP_ADDR)s:%(ENV_ETCD_PORT_4001_TCP_PORT)s --ip %(ENV_IP)s autorestart=unexpected stdout_logfile=/var/log/dockreg/dockreg.stdout stdout_logfile_maxbytes=1MB stdout_logfile_backups=10 stderr_logfile=/var/log/dockreg/dockreg.stderr stderr_logfile_maxbytes=1MB stderr_logfile_backups=10
是時間開始了,啟動一個主機:
vagrant up host-1
在 boot 日志中,你將看到 Docker 容器的構建進程。在最后:
Successfully built a98722a9f44b
下一步,登陸進 VM:
vagrant ssh host-1
檢查 etcd 容器是否在運行:
docker ps
你可以使用以下的地址訪問 etcd :http://10.1.0.101:4001/v2/machines
下一步,啟動一個新的容器,運行 NodeJS app:
docker run -d -p 8000 -v /var/run/docker.sock:/var/run/docker.sock -e IP=10.1.0.101 --link etcd:etcd local/dockreg
當容器啟動的時候,可以在 etcd 中看到注冊:
curl http://10.1.0.101:4001/v2/keys/service { "action": "get", "node": { "key": "/service", "dir": true, "nodes": [ { "key": "/service/10.1.0.101:49155", "value": "running", "expiration": "2014-08-26T21:17:28.431730841Z", "ttl": 19, "modifiedIndex": 23, "createdIndex": 23 } ], "modifiedIndex": 3, "createdIndex": 3 } }
在這個示例中,暴露的端口是 49155。
訪問應用:
curl http://10.1.0.101:49155 Hello from 2d151d56f838
成功,下一步,啟動第二個主機:
vagrant up host-2
一旦運行,檢查已經加入到集群中的新的 etcd 的實例:
curl http://10.1.0.102:4001/v2/machines http://10.1.0.101:4001, http://10.1.0.102:4001
檢查已經復制的插入進 host-1 的 key:
curl http://10.1.0.102:4001/v2/keys/service { "action": "get", "node": { "key": "/service", "dir": true, "nodes": [ { "key": "/service/10.1.0.101:49155", "value": "running", "expiration": "2014-08-26T21:39:07.415916256Z", "ttl": 17, "modifiedIndex": 73, "createdIndex": 73 } ], "modifiedIndex": 3, "createdIndex": 3 }
現在,登陸 host-2 (vagrant ssh host-2),然后啟動一個新的應用容器:
docker run -d -p 8000 -v /var/run/docker.sock:/var/run/docker.sock -e IP=10.1.0.102 --link etcd:etcd local/dockreg
http://10.1.0.101:4001/v2/keys/service 和 http://10.1.0.102:4001/v2/keys/service 現在可以顯示運行在 host-2 上的新的實例(或許需要花一點時間用于應用啟動)。
還需要一個新的?僅僅需要再一次運行前面的 docker run 命令。現在 etcd 包含 3 個實例。
為了測試取消登記,停止一個容器:
docker stop fdd27afacbbb
key 將立即從 etcd 中移除。
總結在這個例子中,我們看到了一種把 Docker 容器注冊進一個外部配置存儲的方法。通過使用一個 sidekick 進程,服務注冊完全獨立于應用,并且它提供了更精確的監控。
達到這個目標的其他可選方案,The CoreOS project 提議了一份工具列表來簡化注冊和服務發現。
在下一篇文章中,我將描述基于 HAProxy 和 etcd 的服務發現。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/26340.html
摘要:為了動態配置管理,當我們啟動和停止一個新容器的時候,我們想后端能自動注冊進負載均衡器。這是基本需求,叫做服務發現我們想負載均衡器能自動發現提供服務的容器。一個團隊開發的簡單的服務發現的工具。服務發現目標是減少或消除組件之間的手動的連接。 注:該文由 adetante 編寫,原文地址為 Service discovery with Docker 這篇博客的第一篇文章,我將寫一篇...
摘要:運行在上的微服務服務發現與注冊在上一節中,我們學習了如何在上構建一個風格的微服務。接下來,我們將學習如何把運行在上的微服務暴露在服務中心上,以便客戶端的調用。資源服務在關閉時需要將服務實例在服務中心進行注銷操作。響應用戶的終止。 運行在 Docker 上的微服務 - 服務發現與注冊 tags: Docker Microservice RESTful etcd Author: And...
摘要:后續將其他節點加入集群都會用到這個值將節點加入集群查看節點信息相關命令創建服務更新服務刪除服務減少服務實例增加服務實例查看所有服務查看服務的容器狀態查看服務的詳細信息。前言本篇是Docker第十三篇,Docker的使用至此就介紹完成,接下來繼續Kubernetes。Docker系列文章:為什么要學習DockerDocker基本概念Docker鏡像基本原理Docker容器數據卷Dockerfi...
摘要:之前提到的文件即可利用以下模板生成請注意,其中的與就是占位符。如將某一特定部署至生產環境并運行個實例。而另一種方式則是使用等負載均衡器即服務器端發現。可重配置且能夠在變更發生后立即將請求路由至新實例。 如今與Mesos相關的文章可謂層出不窮,不過展示能夠直接用于生產的完整基礎設施的資料卻相當少見。在今天的文章中,我將介紹各組件的配置與使用方式,旨在幫助大家利用Mesos構建起持續交付且...
摘要:服務發現服務發現被容器處理。主機首先,我們啟動注冊我們的地址是。首先,啟動然后,啟動一個簡單的客戶端容器并傳給它。這時,構造一些請求給服務端口來看他們的負載。同樣地,的事件和容器減輕了服務注冊和使用注冊服務發現比如的困難。 使用 Etcd 和 Haproxy 做 Docker 服務發現 標簽(空格分隔): Etcd Haproxy Docker 服務發現 architecture ...
閱讀 2423·2019-08-29 13:53
閱讀 2507·2019-08-29 11:32
閱讀 3047·2019-08-28 17:51
閱讀 3776·2019-08-26 10:45
閱讀 3492·2019-08-23 17:51
閱讀 2983·2019-08-23 16:56
閱讀 3337·2019-08-23 16:25
閱讀 3085·2019-08-23 14:15