在這篇文章中,咱們將討論如何用Rancher實現consul的服務發現。java
若是你尚未準備好,推薦你閱讀本系列中先前的文章: 第一篇:CI /CD和Docker入門 第二篇:使部署邏輯向使用Docker Compose更進一步 第三篇:借力Rancher完成容器編排nginx
在這構建部署流水線系列的最後一篇文章中,咱們將探討在轉換到Rancher進行集羣調度時面臨的一些挑戰。在以前的文章中,咱們經過使用Rancher執行調度,讓運維人員無須再負責選擇每一次容器運行的位置。要使用這個新方案,咱們必須讓環境的其餘部分知道調度程序放置這些服務的位置,以及如何訪問它們。咱們還將討論如何使用標籤來操做調度程序,以調整容器放置位置,並避免端口綁定衝突。最後,咱們將經過利用Rancher的回滾功能優化咱們的升級過程。docker
在引入Rancher以前,咱們的環境是一個至關靜態的環境。咱們老是將容器部署到相同的主機上,而部署到不一樣的主機則意味着咱們須要更新一些配置文件以反映新位置。例如,若是咱們要添加'java-service-1'應用程序的一個附加實例,咱們還須要更新load balancer以指向附加實例的IP。使用調度器讓咱們沒法預測容器部署的位置,而且咱們須要動態配置環境,使其能自動適應變化。爲此,咱們須要使用服務註冊和服務發現。編程
服務註冊表爲咱們提供了應用程序在環境中的位置的單一來源。和硬編碼服務位置不一樣,咱們的應用程序能夠經過API查詢服務註冊表,並在咱們的環境發生變化時自動從新配置。Rancher使用Rancher的DNS和元數據服務提供了開箱即用的服務發現。然而,混合使用Docker和非Docker應用程序時,咱們不能徹底依賴Rancher來處理服務發現。咱們須要一個獨立的工具來跟蹤咱們全部服務的位置,consul就符合這個要求。後端
咱們不會詳細說明如何在您的環境中設置Consul,可是,咱們將簡要描述咱們在ABC公司使用Consul的方式。在每一個環境中,咱們都有一個部署爲容器的Consul集羣。咱們在環境中的每一個主機上都部署一個Consul代理,若是主機正在運行Docker,咱們還會部署一個註冊器容器。註冊器監視每一個守護進程的Docker事件API,並在生命週期事件期間自動更新Consul。例如,在新容器被部署後,註冊器會自動在Consul中註冊該服務。當容器被刪除時,註冊器撤銷它的註冊。api
在Consul中註冊全部服務後,咱們能夠在負載均衡器中運行consul-template,根據Consul中存儲的服務數據動態填充上游列表。對於咱們的NGINX負載均衡器,咱們能夠建立一個模板來填充’java-service-1’應用程序的後端:微信
# upstreams.conf upstream java-service-1 { {{range _, $element := service "java-service-1"}} server {{.Address}}:{{.Port}}; {{else}} server 127.0.0.1:65535; # force a 502{{end}} }
此模板在Consul中查找註冊爲「java-service-1」的服務的列表。而後它將循環該列表,添加具備該特定應用程序實例的IP地址和端口的服務線。若是在Consul中沒有註冊任何「java-service-1」應用程序,咱們默認拋出502以免NGINX中的錯誤。負載均衡
咱們能夠在守護進程模式下運行consul-template,使其監控Consul的更改,在發生更改時從新渲染模板,而後從新加載NGINX以應用新配置。less
TEMPLATE_FILE=/etc/nginx/upstreams.conf.tmpl RELOAD_CMD=/usr/sbin/nginx -s reload consul-template -consul consul.stage.abc.net:8500 \ -template "${TEMPLATE_FILE}:${TEMPLATE_FILE//.tmpl/}:${RELOAD_CMD}"
經過使用咱們的負載均衡器設置來動態地改變其他的環境變化,咱們能夠徹底依賴Rancher調度器來作出咱們的服務應該在哪裏運行的複雜的決定。可是,咱們的「java-service-1」應用程序在Docker主機上綁定TCP端口8080,若是在同一主機上調度了多個應用程序容器,則會致使端口綁定衝突並最終失敗。爲了不這種狀況,咱們能夠經過調度規則來操做調度器。運維
經過在docker-compose.yml文件中使用容器標籤來提出條件,是Rancher給咱們的一種操做調度器的方法。條件能夠包括親和規則、否認、至「軟」強制(意味着儘量地避免)。在咱們使用'java-service-1'應用程序的狀況下,咱們知道在給定時間只有一個容器能夠在主機上運行,所以咱們能夠基於容器名稱設置反關聯性規則。這將使調度程序查找一個未運行名稱爲「java-service-1」的容器的Docker主機。咱們的docker-compose.yml文件看起來像下面這樣:
java-service-1: image: registry.abc.net/java-service-1:${VERSION} container_name: java-service-1 ports: - 8080:8080 labels: io.rancher.scheduler.affinity:container_label_ne: io.rancher.stack_service.name=java-service-1
注意「標籤」鍵的引入。全部調度規則都做爲標籤被添加。標籤能夠被添加到Docker主機和容器。當咱們在Rancher註冊咱們的主機時,咱們能夠將它們與標籤關聯,之後就能夠切斷調度部署。例如,若是咱們有一組使用SSD驅動器進行存儲優化的Docker主機,咱們能夠添加主機標籤storage=ssd。
須要利用優化存儲主機的容器能夠添加標籤來強制調度程序僅在匹配的主機上部署它們。咱們將更新咱們的「java-service-1」應用程序,以便只部署在存儲優化的主機上:
java-service-1: image: registry.abc.net/java-service-1:${VERSION} container_name: java-service-1 ports: - 8080:8080 labels: io.rancher.scheduler.affinity:container_label_ne: io.rancher.stack_service.name=java-service-1 io.rancher.scheduler.affinity:host_label: storage=ssd
經過使用標籤,咱們能夠根據所需的容量,而不是個別主機運行特定的容器集,來精細地調整咱們的應用程序部署。切換到Rancher進行集羣調度,即便您仍然有必須在特定主機上運行的應用程序。
最後,咱們能夠利用Rancher的回滾功能優化咱們的服務升級。在咱們的部署工做流中,經過調用rancher-compose來指示Rancher在該服務堆棧上執行升級以部署服務。升級過程大體以下:
當給定服務的部署很是少時,此工做流就行了。可是,當某個服務處於「升級」狀態(在部署者選擇「完成升級」以前)時,在執行「完成升級」或是「回滾」操做以前,你都不能對它進行任何新的升級」。rancher-compose實用程序讓咱們能夠選擇以編程方式選擇要執行的操做,以部署程序者的身份執行操做。例如,若是您對服務進行自動測試,則能夠在rancher-compose升級返回後調用此類測試。根據這些測試的狀態,rancher-compose能夠被再次調用,此次咱們告訴堆棧「完成升級」或「回滾」。咱們部署Jenkins做業的一個原始示例可能以下:
# for the full job, see part 3 of this series /usr/local/bin/rancher-compose --verbose \ -f ${docker_dir}/docker-compose.yml \ -r ${docker_dir}/rancher-compose.yml \ up -d --upgrade JAVA_SERVICE_1_URL=http://java-service-1.stage.abc.net:8080/api/v1/status if curl -s ${JAVA_SERVICE_1_URL} | grep -q "OK"; then # looks good, confirm or "finish" the upgrade /usr/local/bin/rancher-compose --verbose \ -f ${docker_dir}/docker-compose.yml \ -r ${docker_dir}/rancher-compose.yml \ up --confirm-upgrade else # looks like there's an error, rollback the containers # to the previously deployed version /usr/local/bin/rancher-compose --verbose \ -f ${docker_dir}/docker-compose.yml \ -r ${docker_dir}/rancher-compose.yml \ up --rollback fi
這個邏輯將調用咱們的應用程序端點來執行簡單的狀態檢查。若是輸出顯示的是‘OK’,那麼咱們完成升級,不然咱們須要回滾到之前部署的版本。若是您沒有自動測試,另外一個選擇是簡單地老是完成或「確認」升級。
# for the full job, see part 3 of this series /usr/local/bin/rancher-compose --verbose \ -f ${docker_dir}/docker-compose.yml \ -r ${docker_dir}/rancher-compose.yml \ up -d --upgrade --confirm-upgrade
若是不久之後,您肯定須要回滾,就使用相同的部署做業簡單地從新部署之前的版本。這確實不像Rancher的升級和回滾功能那麼友好,但它經過使堆棧不處於「升級」的狀態來解鎖未來的升級。
當服務在Rancher中回滾時,容器將被從新部署到之前的版本。當使用通用標記如「latest」或「master」部署服務時,可能會出現意外的後果。例如,讓咱們假設'java-service-1'應用程序之前被部署了標籤'latest'。對圖像進行更改,推送到註冊表,Docker標籤「latest」被更新爲指向此新映像咱們使用標籤「latest」繼續升級,在測試後決定應用程序須要回滾。使用Rancher滾動堆棧仍然會從新部署最新的映像,由於標籤「latest」還沒有被更新爲指向上一個映像。回滾能夠在純技術術語中實現,可是部署最近的工做副本的預期效果徹底沒法實現。在ABC公司,咱們經過始終使用與應用程序版本相關的特定標記來避免這種狀況。所以,不要使用標記latest」部署咱們的「java-service-1」應用程序,咱們可使用版本標籤「1.0.1-22-7e56158」。這保證回滾將始終指向咱們的應用程序在環境中的最新工做部署。
咱們但願咱們分享的經驗對大家有所幫助。這有助於咱們有條不紊地採用Docker,穩步改進咱們的流程,並讓咱們的團隊能熟悉這些概念。對更自動化的部署工做流進行增量更改,使組織可以更快地實現自動化的優點,部署團隊能夠更加務實地決定他們在流水線中須要什麼。咱們的經歷證實Rancher在可行性、自動化、甚至團隊協做方面都是成功的。咱們但願分享這些咱們在Docker應用過程當中得到的經驗教訓將有助於您本身的應用過程。
歡迎關注Rancher官方微信公衆號(RancherLabs),獲取第一手技術乾貨推送;歡迎添加客服微信(RancherLabsChina)爲好友,加入Rancher官方技術交流羣,獲取免費技術支持,與數千Docker/Rancher使用者互動。
9月27日,北京海航萬豪酒店,容器技術大會Container Day 2017即將舉行。
CloudStack之父、海航科技技術總監、華爲PaaS部門部長、恆豐銀行科技部總經理、阿里雲PaaS工程總監、民生保險CIO······均已加入豪華講師套餐!
11家已容器落地企業,15位真·雲計算大咖,13場純·技術演講,結合實戰場景,聚焦落地經驗。免費參會+超高規格,詳細議程及註冊連接請戳