天天看點

如何使用Docker、Docker-Compose和Rancher搭建部署Pipeline(三)

使用Docker-Compose時面臨的挑戰

首先,運維人員必須手動地調整所有服務的執行計劃。部署人員需要決定将哪一個應用部署至哪一台主機,這意味着部署人員需要時刻對每一台主機的剩餘可用資源都有了解,如果某一台主機或者容器崩潰了,部署的操作人員将需要對應用進行重新部署。實際生産中,這意味着主機常常處于負載失衡的狀态,并且服務在崩潰之後需要很長時間才能得到恢複。

其次,使用Docker-Compose時,想要獲得你的服務的目前狀态是十分困難的。舉個例子來說,我們經常會從運維人員、項目經理以及開發者口中聽到這樣的問題:“現在部署環境中運作的到底是XX應用程式的哪個版本?”如果我們采用的是手動調整服務的執行計劃的方式,想要得到這個問題的答案通常需要詢問指定的進行操作的工程師,工程師們需要登陸伺服器并運作docker中的ps指令來檢視容器的資訊。然而面對這些問題,Rancher将會給我們提供極大的便利:每個人都可以非常容易地擷取已經部署的服務的資訊,而不需要臨時請求運維人員的幫助。

使用Rancher之前,我們試着了解過不少其他能夠管理Docker主機或叢集的解決方案。然而這些解決方案都沒有注意到這是對Docker主機或叢集在多種環境(multi-environment)下的管理,這将成為最大的麻煩與負擔之一。如果有服務以不同的負載運作在8種不同的環境下,我們需要的是一個統一的方式來管理叢集,而不會想要通路8個不同的服務。并且,我們希望讓重新建構環境對于我們而言,變成分分鐘就能完成的任務,這樣開發者就可以随意地更改開發環境。然而,對于生産環境而言,我們希望提供給他們的隻是有限的隻讀通路權限。面對這樣的需求,一個采用基于角色的通路控制(RBAC)模型的集中管理方案就顯得十分必要了。我們最初決定嘗試Rancher就是因為它在部署上非常簡單。

當Rancher面臨這些挑戰

在短短半天的時間裡,使用AWS ELB、Elasticache、RDS和現有的Docker主機,我們已經将Rancher部署好并成功運作。能夠友善地配置認證資訊也是Rancher的優點之一。

我們就從建立不同的環境開始吧,為了使得這個過程盡量簡單些,我們将對開發環境(dev)、部署環境(stage)以及生産環境(prod)分别進行設定。每個環境都已有運作在Ubuntu之上的Docker主機,且這些Docker主機是由内部的Ansible配置的,Ansible安裝了Docker、我們的監控代理、并進行了一些組織特定的更改。在Rancher上,你隻需要運作一條指令,将Docker主機在Rancher server内部進行注冊,就可以将已有的Docker主機添加至每個環境中。

添加一台Rancher主機

<code>name: install dependencies </code><code>for</code> <code>uri module</code>

<code>  </code><code>apt: name=python-httplib2 update_cache=yes</code>

<code>name: check </code><code>if</code> <code>the rancher-agent is running</code>

<code>  </code><code>command: docker ps –filter ‘name=rancher-agent’</code>

<code>  </code><code>register: containers</code>

<code>name: get registration command from rancher</code>

<code>  </code><code>uri:</code>

<code>    </code><code>method: GET</code>

<code>    </code><code>user: “{{ RANCHER_API_KEY }}”</code>

<code>    </code><code>password: “{{ RANCHER_SECRET_KEY }}”</code>

<code>    </code><code>force_basic_auth: yes</code>

<code>    </code><code>status_code: </code><code>200</code>

<code>    </code><code>url: “https:</code><code>//rancher.abc.net/v1/projects/{{ RANCHER_PROJECT_ID }}/registrationtokens”</code>

<code>    </code><code>return_content: yes</code>

<code>    </code><code>validate_certs: yes</code>

<code>  </code><code>register: rancher_token_url</code>

<code>  </code><code>when: “‘rancher-agent’ not in containers.stdout”</code>

<code>name: register the host machine with rancher</code>

<code>  </code><code>shell: &gt;</code>

<code>    </code><code>docker run -d –privileged</code>

<code>    </code><code>-v /var/run/docker.sock:/var/run/docker.sock</code>

<code>    </code><code>{{ rancher_token_url.json[‘data’][</code><code>0</code><code>][‘image’] }}</code>

<code>    </code><code>{{ rancher_token_url.json[‘data’][</code><code>0</code><code>][‘command’].split() | last}}</code>

随着工作的一步步進行,我們已經完成了環境的建立并已經将主機在Rancher server中注冊,現在就讓我們來了解一下,如何将我們的部署工作流整合至Rancher中。我們知道,對于每一台Docker來說,其中都有着一些正在運作的容器,這些系統的部署是通過Ansible工具借助Jenkins完成的。Rancher提供了以下開箱即用的功能:

管理已有的容器(比如:啟動、修改、檢視日志、啟動一個互動式的shell)

獲得關于運作中的和停止運作的容器的資訊(比如:鏡像資訊、初始化指令資訊、指令資訊,端口映射資訊以及環境變量資訊)

檢視主機和容器層級上的資源使用情況(比如:CPU使用率、記憶體占用率、以及磁盤和網絡的使用情況)

獨立的容器

很快,我們就已經将Docker主機注冊至Rancher Server中,現在我們可以檢視容器在各種環境下的運作狀态資訊了。不僅如此,如果想要将這些資訊分享給其他團隊,我們僅僅需要針對某個環境給予他們一些有限的權限。通過以上的方式,在想要獲得狀态資訊時我們就完全沒有必要請求操作人員登入Docker主機,再通過人工的方式去查詢,同時這樣也減少了申請獲得環境資訊的請求的數目,因為我們已經将某些通路權限配置設定至各個團隊了。舉個例子來說,如果為開發團隊配置設定環境資訊的隻讀權限,那麼将會在開發團隊與部署操作團隊之間架起一座溝通的橋梁,這樣兩個團隊都會對這個環境的狀态比以往更加的關心。在這個基礎上,故障的排除也變成了一種小組間互相合作的過程,而不是以往的那種單向的、依賴同步資訊流的解決方式,互相合作的方式也會減少解決突發事件的總時間。

應用與服務:Rancher将每個獨立的容器(指的是部署在Rancher之外的容器,或者是通過Rancher UI生成的一次性功能的容器)、應用和服務彼此分離開。簡單地說,應用是一組服務,而所有容器都需要利用服務(關于應用和服務的内容之後将會由更加詳細的介紹)以建構一個應用。獨立的容器需要手動地進行排程。

排程:在之前的部署技術中,運維人員需要決定容器應當在哪一台主機上運作。如果使用的是部署腳本,那麼意味着運維人員需要決定部署腳本在哪一台或哪幾台主機上運作;如果使用Ansible,這将意味着運維人員需要決定哪些主機或組需要到Jenkins中工作。不論是哪一種方式,都需要運維人員去做一些決定,但是在大多數情況下,他們做出的決定都缺乏一些可靠的依據,這對我們的部署工作很是不利(比如說某一台主機的CPU使用率高達100%)。很多解決方案,比如像Docker Swarm、Kubernetes、Mesos和Rancher都采用了排程器來解決這類問題。對于需要執行的某個操作,排程器将會請求獲得一組主機的資訊,并判斷出哪幾台是适合執行這個操作的。排程器會根據預設的需求設定或者使用者定義的特定需求,比如CPU使用率高低、親和性或反親和性規則(比如:禁止在同一台主機上部署兩個相同容器)等類似的需求,以逐漸縮小主機選擇的範圍。如果我是一個負責部署的運維人員,排程器将會極大的減少我的工作負擔(尤其是我在深夜加班忙于部署時),因為排程器對以上資訊的計算比我快的多,也準的多。Rancher在我們通過應用部署服務的時候能夠提供一個開箱即用排程器。

Docker compose:Rancher使用Docker compose來建立應用并定義服務。由于我們已經将服務轉化為Docker compose的檔案,我們在此基礎上建立應用就變得容易了許多。應用可以手動的從UI界面中建立,也可以通過Rancher compose在指令行(CLI)下快速的建立。

Rancher compose:Rancher compose是一種通過指令行(CLI)讓我們得以對Rancher中的每一種環境的應用和服務進行友善的管理的工具。同時,通過rancher-compse.yml檔案,Rancher compose還能允許對Rancher工具進行一些其他通路。這是一個純粹的附加的檔案,将不會取代原有的docker-compose.yml檔案。在rancher-compose.yml檔案中,你可以定義以下内容,比如說:

每種服務的更新政策資訊

每種服務的健康檢查資訊

每種服務的需求規模資訊

通過将已有的部署工作交給Rancher Compose來替代之前的Ansible工具,我們能夠很輕松的将服務遷移并部署為Rancher應用的形式。之後,我們就能夠去除DESTINATION參數了,但我們依然保留VERSION參數,因為我們在插入docker-compose.uml檔案的時候還要使用它。以下是使用Jenkins部署時,部署邏輯的shell片段:

<code>export RANCHER_URL=http:</code><code>//rancher.abc.net/</code>

<code>export RANCHER_ACCESS_KEY=…</code>

<code>export RANCHER_SECRET_KEY=…</code>

<code>if</code> <code>[ -f docker/docker-compose.yml ]; then</code>

<code>  </code><code>docker_dir=docker</code>

<code>elif [ -f /opt/abc/dockerfiles/java-service-</code><code>1</code><code>/docker-compose.yml ]; then</code>

<code>  </code><code>docker_dir=/opt/abc/dockerfiles/java-service-</code><code>1</code>

<code>else</code>

<code>  </code><code>echo “No docker-compose.yml found. Can’t </code><code>continue</code><code>!”</code>

<code>  </code><code>exit </code><code>1</code>

<code>fi</code>

<code>if</code> <code>! [ -f ${docker_dir}/rancher-compose.yml ]; then</code>

<code>  </code><code>echo “No rancher-compose.yml found. Can’t </code><code>continue</code><code>!”</code>

<code>/usr/local/bin/rancher-compose –verbose \</code>

<code>  </code><code>-f ${docker_dir}/docker-compose.yml \</code>

<code>  </code><code>-r ${docker_dir}/rancher-compose.yml \</code>

<code>  </code><code>up -d –upgrade</code>

閱讀完代碼段,我們可以發現其主要包括以下内容:

我們定義了以環境變量的方式如何通路我們的Rancher server。

需要找到docker-compose.yml檔案,否則将會任務将會報錯退出。

需要找到rancher-compose.yml檔案,否則任務将會報錯退出。

運作Rancher-compose,并告訴它不要block并且使用-d指令輸出日志,使用-upgrade指令更新一個已經存在的服務。

也許你已經發現了,在絕大部分,代碼的邏輯都是相同的,而最大的差別就是使用rancher-compose代替使用Ansible工具完成部署,并對每一個服務添加了rancher-compose.yml檔案。具體到我們的java-service-1應用,docker-compose檔案和rancher-compose檔案現在是這樣的:

<code>docker-compose.yml</code>

<code>java-service-</code><code>1</code><code>:</code>

<code>image: registry.abc.net/java-service-</code><code>1</code><code>:${VERSION}</code>

<code>container_name: java-service-</code><code>1</code>

<code>expose:</code>

<code>– </code><code>8080</code>

<code>ports:</code>

<code>– </code><code>8080</code><code>:</code><code>8080</code>

<code>rancher-compose.yml</code>

<code>scale: </code><code>3</code>

在開始部署工作之前,我們先回顧一下部署工作的流程:

開發人員将代碼的修改推送至git上

使用Jenkins對代碼進行單元測試,在測試工作結束之後觸發下遊工作

下遊工作采用新的代碼建構一個docker鏡像,并将其推送至我們自己的Docker鏡像倉庫中

建立包含應用名、版本号、部署環境的deployment ticket

<code>DEPLOY-</code><code>111</code><code>:</code>

<code>  </code><code>App: JavaService1, branch “release/</code><code>1.0</code><code>.</code><code>1</code><code>”</code>

<code>  </code><code>Environment: Production</code>

部署工程師針對應用運作Jenkins的部署工作,運作時需要将版本号作為參數。

Rancher compose開始運作,對于某個環境建立或更新應用,并且當達到所需規模的時候,結束這個工作

部署工程師以及開發工程師分别手動地對服務進行校驗

部署工程師在Rancher UI中确認完成更新

關鍵點

使用Rancher進行我們的服務部署時,我們從Rancher内建的排程、彈性伸縮、還原、更新、和復原等工具中獲得極大的便利,使得我們在部署過程中沒有花太大的力氣。同時我們發現,在将部署工作從Ansible工具中遷移至Rancher的工作量也是很小的,僅僅需要在原有的基礎上增加rancher-compose.yml檔案。然而,使用Rancher來處理我們容器的排程意味着我們将難以确認我們的應用到底是在哪台主機上運作的。比方說,之前我們并沒有決定java-service-1應用在哪裡運作,對于後端,在進行負載均衡相關操作時,該應用就沒有一個靜态的IP。我們需要找到一種辦法,使得我們的各種應用之間能夠互相察覺到對方。最終,對于我們的java-service-1應用,我們将明确地将應用容器所在的docker主機的8080端口與應用綁定,不過,如果有其他服務與應用綁定為相同的端口,它将會啟動失敗。通常負責排程決策的工程師将會對以上的事務進行處理。然而,我們最好将這些資訊通知排程器以避免這樣的事情發生。

在本教程的最後一個部分,我們将繼續探索一些方案來解決在使用親和性規則、主機标簽、服務探索以及智能更新和復原等特性時出現的問題。

9月27日,北京海航萬豪酒店,容器技術大會Container Day 2017即将舉行。

CloudStack之父、海航科技技術總監、華為PaaS部門部長、恒豐銀行科技部總經理、阿裡雲PaaS工程總監、民生保險CIO······均已加入豪華講師套餐!

<a href="https://s2.51cto.com/wyfs02/M02/06/E6/wKiom1nAdXaSpz_BAAgMYxVaxjM446.png" target="_blank"></a>

本文轉自 RancherLabs 51CTO部落格,原文連結:http://blog.51cto.com/12462495/1958622