成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

技術(shù)實(shí)踐 | Mesos 全方位“烹飪”指南

archieyang / 2503人閱讀

摘要:之前提到的文件即可利用以下模板生成請(qǐng)注意,其中的與就是占位符。如將某一特定部署至生產(chǎn)環(huán)境并運(yùn)行個(gè)實(shí)例。而另一種方式則是使用等負(fù)載均衡器即服務(wù)器端發(fā)現(xiàn)??芍嘏渲们夷軌蛟谧兏l(fā)生后立即將請(qǐng)求路由至新實(shí)例。

如今與Mesos相關(guān)的文章可謂層出不窮,不過(guò)展示能夠直接用于生產(chǎn)的完整基礎(chǔ)設(shè)施的資料卻相當(dāng)少見(jiàn)。在今天的文章中,我將介紹各組件的配置與使用方式,旨在幫助大家利用Mesos構(gòu)建起持續(xù)交付且擁有容錯(cuò)能力的運(yùn)行時(shí)平臺(tái)。不過(guò)設(shè)備配置腳本屬于基礎(chǔ)設(shè)施當(dāng)中的主體部分,因此在文章中無(wú)法完全公布——但值得大家了解的內(nèi)容已經(jīng)全部到位。

概述

我們不會(huì)具體探討設(shè)備的實(shí)際安裝與配置,不過(guò)大家可以通過(guò)下圖了解我們已經(jīng)安裝的軟件:

目前,我們運(yùn)行有3臺(tái)主節(jié)點(diǎn)與3臺(tái)從節(jié)點(diǎn),并利用Saltstack進(jìn)行配置。

下面讓我們從宏觀角度審視代碼構(gòu)建與配置及執(zhí)行的完整部署流程。


在以下章節(jié)中,我們將探討各組件是如何交互及運(yùn)作的。

準(zhǔn)備Docker鏡像

雖然Mesos能夠利用自身默認(rèn)容器完美處理各類(lèi)可執(zhí)行文件,但我們?nèi)匀煌扑]運(yùn)行Docker化應(yīng)用。我們需要向每套Docker鏡像中添加一點(diǎn)內(nèi)容,從而保證其能夠輕松同這套運(yùn)行時(shí)平臺(tái)相集成。

首先,我們需要了解Docker宿主主機(jī)的實(shí)際IP地址。雖然人們一直要求支持特殊的Docker標(biāo)記,可以很容易的通過(guò)定制化腳本輕松實(shí)現(xiàn):

#!/bin/sh

set -e

DOCKERHOST=$(ip route show 0.0.0.0/0 | grep -Eo "via S+" | awk "{ print $2 }")
echo "$DOCKERHOST dockerhost" >> /etc/hosts

exec "$@"

現(xiàn)在容器化中的應(yīng)用程序已經(jīng)能夠可靠地引用“dockerhost”主機(jī)名稱(chēng),在必要時(shí)接入該Docker宿主主機(jī)。

接下來(lái)是服務(wù)配置管理(我們將在后文中詳盡討論),我們需要向Docker鏡像中添加一套名為service-wrapper的腳本。另外,我們還需要安裝其關(guān)聯(lián)性元素——jq。如果大家使用精簡(jiǎn)化Linux鏡像(例如Alpine),請(qǐng)確保其中包含curl命令工具。這一切匯總起來(lái),我們就擁有了以下面向Node.js應(yīng)用程序的Docker鏡像:

FROM node:4

RUN apt-get update && apt-get install -y jq && 
  rm -rf /var/lib/apt/lists/*

ADD service-wrapper.sh /usr/bin/
ADD entrypoint.sh /usr/bin/

此鏡像應(yīng)被推送至Docker 倉(cāng)庫(kù)并由CI服務(wù)器進(jìn)行訪問(wèn)。在我們的示例中,將是可用的私有Docker倉(cāng)庫(kù)在registry.local這臺(tái)宿主主機(jī)上。

構(gòu)建與部署

我們利用Drone實(shí)現(xiàn)持續(xù)集成,其使用方式非常簡(jiǎn)單但卻能夠在Docker容器當(dāng)中很好地執(zhí)行構(gòu)建任務(wù)。另外,其全部插件也都是普通的Docker容器,其能夠獲取build信息載荷并能夠以獨(dú)特的插件方式加以處理。而且沒(méi)錯(cuò),甚至是克隆代碼庫(kù)也能夠通過(guò)多帶帶的Docker容器實(shí)現(xiàn)。

由于我們使用的技術(shù)相當(dāng)多元化,因此需要利用Drone簡(jiǎn)化很多我們的服務(wù)器構(gòu)件設(shè)置——我們只需要為每種不同技術(shù)堆棧準(zhǔn)備多帶帶的Docker鏡像,并要求其利用此鏡像進(jìn)行構(gòu)建。舉例來(lái)說(shuō),這些鏡像分別用于運(yùn)行Node.js、Java以及Mono的構(gòu)建。當(dāng)然,它們同樣由Drone負(fù)責(zé)構(gòu)建。

為了便于理解,我創(chuàng)建一款名為test-server的Node.js Web應(yīng)用,其只負(fù)責(zé)顯示各項(xiàng)環(huán)境變量——大家可以 點(diǎn)擊此處在GitHub上查看源代碼。我們?cè)诤笪闹羞€將多次提到這款示例應(yīng)用,了解如何利用test-server創(chuàng)建一套Docker鏡像并將其部署至Marathon。需要強(qiáng)調(diào)的是,該服務(wù)應(yīng)當(dāng)盡可能遵循十二因素應(yīng)用原則,從而更好地與這套運(yùn)行時(shí)平臺(tái)相集成。

在進(jìn)行構(gòu)建之前,需要注意的是,我們會(huì)利用Marathon調(diào)度自己的長(zhǎng)期運(yùn)行服務(wù)。它正是整套運(yùn)行時(shí)平臺(tái)的基石,其負(fù)責(zé)控制服務(wù)可用性并用于實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)。其擁有非常直觀的“可curl”API,我們可以利用它實(shí)現(xiàn)自動(dòng)部署。為了利用Marathon部署服務(wù),大家需要調(diào)用其API并發(fā)送JSON文件以進(jìn)行服務(wù)描述,具體如下所示:

{
  "id": "/app/production/test-server",
  "labels": {
    "version": "master-ef5a154e25b268c611006d08a78a3ec0a451e7ed-56",
"environment": "production"
  },
  "env": {
"SERVICE_TAGS": "production,internal-listen-http-3000",
"SERVICE_NAME": "test-server"
  },
  "cpus": 0.05,
  "mem": 64.0,
  "instances": 4,
  "args": [
    "service-wrapper.sh", "dockerhost:18080", "dockerhost:18500", "app/production/test-server",
"node", "/app/server.js"
  ],
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "registry.local/test-server:master-ef5a154e25b268c611006d08a78a3ec0a451e7ed-56",
      "forcePullImage": true,
      "network": "BRIDGE",
      "portMappings": [{
        "containerPort": 3000
      }]
    }
      },
  "healthChecks": [{
    "protocol": "HTTP",
    "path": "/healthcheck",
    "gracePeriodSeconds": 2,
    "intervalSeconds": 10,
    "maxConsecutiveFailures": 3
  }],
  "upgradeStrategy": {
    "minimumHealthCapacity": 0.5,
    "maximumOverCapacity": 0.5
  }
}

它會(huì)指示Marathon調(diào)用4個(gè)Docker服務(wù)實(shí)例,來(lái)源則為來(lái)自registry.local/test-server且擁有master-ef5a154e25b268c611006d08a78a3ec0a451e7ed-56標(biāo)簽的鏡像。我們將其稱(chēng)為服務(wù)定義。我們不會(huì)對(duì)其規(guī)范進(jìn)行具體討論,感興趣的朋友可以點(diǎn)擊此處查閱Marathon API參考。更重要的是,此文件能夠在構(gòu)建過(guò)程中自動(dòng)生成。對(duì)于每一項(xiàng)可部署服務(wù),其服務(wù)定義模板中都包含一個(gè)以“$”開(kāi)頭的占位符。之前提到的文件即可利用以下模板生成:

{
  "id": "/app/$environment/test-server",
  "labels": {
    "version": "$tag",
    "environment": "$environment"
  },
  "env": {
    "SERVICE_TAGS": "$environment,internal-listen-http-3000",
    "SERVICE_NAME": "test-server"
  },
  "cpus": 0.05,
  "mem": 64.0,
  "instances": $instances,
  "args": [
    "service-wrapper.sh", "dockerhost:18080",     "dockerhost:18500", "app/$environment/test-server",
    "node", "/app/server.js"
  ],
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "registry.local/test-server:$tag",
      "forcePullImage": true,
      "network": "BRIDGE",
      "portMappings": [{
        "containerPort": 3000
      }]
    }
  },
  "healthChecks": [{
    "protocol": "HTTP",
    "path": "/healthcheck",
    "gracePeriodSeconds": 2,
    "intervalSeconds": 10,
    "maxConsecutiveFailures": 3
  }],
  "upgradeStrategy": {
    "minimumHealthCapacity": 0.5,
    "maximumOverCapacity": 0.5
  }
}

請(qǐng)注意,其中的$tag、$environment與$instances就是占位符。$tag值會(huì)在構(gòu)建過(guò)程中生成并被以下簡(jiǎn)單腳本添加至service.json當(dāng)中:

#!/bin/bash

set -e

VERSION="$CI_BRANCH-$CI_COMMIT-$CI_BUILD_NUMBER"
declare -A TARGETS=(
    [test-server]="."
)

# Set version in service.json
for i in "${!TARGETS[@]}"
do
    SERVICE=${TARGETS[$i]}/service.json
    TARGET=service-defs/${TARGETS[$i]}
    mkdir -p $TARGET
    echo "Setting version $VERSION for $SERVICE"
    sed "s/$tag/$VERSION/g" $SERVICE > $TARGET/service-$CI_BRANCH.json
    cp $TARGET/service-$CI_BRANCH.json $TARGET/service-$VERSION.json
done

它創(chuàng)建兩條服務(wù)定義:其一以完整版本命名,其二以分支版本命名,即service-master-ef5a154e25b268c611006d08a78a3ec0a451e7ed-56.json與service-master.json。在這兩個(gè)文件當(dāng)中,$tag會(huì)被替換為master-ef5a154e25b268c611006d08a78a3ec0a451e7ed-56,但$environment與$instances則仍然保持不變,我們隨后還需要在部署階段使用它們。下面來(lái)看看Drone的build配置(其完整語(yǔ)法可點(diǎn)擊此處查看):

build:
  image: registry.local/buildimage-nodejs:latest
  commands:

tools/gen-service-defs.sh

publish:

 docker:
   image: plugins/drone-docker
   repo: registry.local/test-server
   tag:

latest

$$BRANCH

$$BRANCH-$$COMMIT-$$BUILD_NUMBER

 s3:
   image: plugins/drone-s3
   acl: public-read
   region: eu-west-1
   bucket: build-artifacts
   access_key: $$S3_ACCESS_KEY
   secret_key: $$S3_SECRET_KEY
   source: service-defs/
   target: test-server/
   recursive: true

而后,CI根據(jù)指令發(fā)布build構(gòu)件:

創(chuàng)建一套Docker鏡像并將其推送至Docker倉(cāng)庫(kù)

將生成的服務(wù)定義發(fā)送至S3

我們完全可以將一部分最新發(fā)布的Docker鏡像標(biāo)簽存儲(chǔ)在Docker 倉(cāng)庫(kù)當(dāng)中,甚至可以在磁盤(pán)空間比較充裕時(shí)全部加以存儲(chǔ)。通過(guò)這種方式,我們就能在新近部署的版本出現(xiàn)問(wèn)題時(shí)利用Marathon輕松回滾至原有版本。

現(xiàn)在我們已經(jīng)可以部署自己的全新服務(wù)版本了。為了完成這項(xiàng)任務(wù),我們需要將服務(wù)定義JSON發(fā)送至Marathon的/v2/apps API。不過(guò)首先,我們需要替換現(xiàn)有占位符,即$environment與$instances。盡管相關(guān)操作非常簡(jiǎn)單,但我們?nèi)匀灰胢arathon-deploy工具實(shí)現(xiàn)自動(dòng)化處理。其能夠自動(dòng)下載服務(wù)定義模板,利用對(duì)應(yīng)值替換點(diǎn)位符并創(chuàng)建/更新Marathon中的應(yīng)用。具體方式如下:

`marathon-deploy.sh   [instances-count]`

其中service-template-url為被發(fā)布至S3的服務(wù)定義構(gòu)件的URL,而environment則可為任意其它運(yùn)行時(shí)環(huán)境(例如分段、生產(chǎn)、A/B分組測(cè)試等),instances-count則允許指定需要啟動(dòng)的服務(wù)實(shí)例數(shù)量,默認(rèn)情況下為1。例如:

`marathon-deploy.sh https://build-artifacts.s3.amazonaws.com/test-server/service-master.json staging`

其將主分支的最新build部署至分段環(huán)境并運(yùn)行單一實(shí)例。如:

`marathon-deploy.sh https://build-artifacts.s3.amazonaws.com/test-server/service-master-ef5a154e25b268c611006d08a78a3ec0a451e7ed-56.json production 4`

將某一特定build部署至生產(chǎn)環(huán)境并運(yùn)行4個(gè)實(shí)例。

在本示例中,我們將marathon-deploy腳本復(fù)制到全部Mesos-slave 的宿主機(jī)當(dāng)中,并通過(guò)Chronos進(jìn)行配置與部署。因?yàn)槲覀円呀?jīng)將各關(guān)鍵服務(wù)預(yù)部署到了不同環(huán)境當(dāng)中,因此這一部署流程只需要一次點(diǎn)擊即可完成。Chronos的最大優(yōu)勢(shì)在于,它能夠?qū)⒋罅咳蝿?wù)串聯(lián)起來(lái),意味著大家能夠通過(guò)配置在實(shí)際部署前、后執(zhí)行一次性任務(wù)以準(zhǔn)備運(yùn)行時(shí)環(huán)境。

服務(wù)發(fā)現(xiàn)與負(fù)載均衡

分布式系統(tǒng)中的服務(wù)總是出于種種原因而不斷上線、下線,例如服務(wù)啟動(dòng)/停止,規(guī)模伸縮或者服務(wù)故障。與利用已知IP地址及主機(jī)名稱(chēng)同服務(wù)器協(xié)作的靜態(tài)負(fù)載均衡器不同,Marathon中的負(fù)載均衡機(jī)制的實(shí)時(shí)性使得其需要以更為復(fù)雜的方式進(jìn)行服務(wù)注冊(cè)與注銷(xiāo)。有鑒于此,我們需要利用某種服務(wù)注冊(cè)表以容納已注冊(cè)服務(wù)信息并將此信息提供給客戶(hù)端。這一概念也就是服務(wù)發(fā)現(xiàn),且成為大多數(shù)分布式系統(tǒng)中的核心組件。

這里就要用到Consul了。正如其官方網(wǎng)站上所言,“Consul能夠輕松幫助服務(wù)進(jìn)行自我注冊(cè),同時(shí)通過(guò)DNS或者HTTP接口發(fā)現(xiàn)其它服務(wù)”。除此之外,它還擁有其它一些非常實(shí)用的功能,我們將在后文提到?,F(xiàn)在我們已經(jīng)擁有了服務(wù)注冊(cè)表,接下來(lái)要做的就是告知其哪些服務(wù)需要啟動(dòng)、這些服務(wù)的具體位置(主機(jī)名稱(chēng)與端口)并可選擇提供其它相關(guān)元信息。實(shí)現(xiàn)這一目標(biāo)的方法之一在于讓服務(wù)本身直接使用Consul API,但這種作法會(huì)導(dǎo)致各項(xiàng)服務(wù)必須擁有內(nèi)置通信邏輯。如果服務(wù)數(shù)量不多還好,面對(duì)大規(guī)模服務(wù)集時(shí)這將成為一場(chǎng)災(zāi)難,特別是當(dāng)它們由不同編程語(yǔ)言編寫(xiě)而成時(shí)。另一種方式在于利用某些第三方工具對(duì)服務(wù)進(jìn)行監(jiān)控,并將服務(wù)報(bào)告給Consul。我們使用的程序名為marathon-registrator,它能夠與Marathon緊密集成并注冊(cè)Marathon所運(yùn)行的任何服務(wù)類(lèi)型。另一種選項(xiàng)則是使用Gliderlabs registrator,當(dāng)然前提是大家的服務(wù)全部存在于Docker容器當(dāng)中。選擇一種工具,將其實(shí)例運(yùn)行在Mesos-slave宿主機(jī)上即可。

服務(wù)注冊(cè)完成之后,其它服務(wù)就能夠?qū)ζ溥M(jìn)行定位了。如此一來(lái),它們就能夠利用Consul API或者DNS進(jìn)行直接通信并獲取此類(lèi)元信息(即客戶(hù)端發(fā)現(xiàn))。而另一種方式則是使用HAProxy等負(fù)載均衡器(即服務(wù)器端發(fā)現(xiàn))。

HAProxy服務(wù)發(fā)現(xiàn)較客戶(hù)端發(fā)現(xiàn)擁有多種優(yōu)勢(shì):

免費(fèi)負(fù)載均衡機(jī)制。

能夠?qū)⒎?wù)注冊(cè)表中的變更即時(shí)傳播至消費(fèi)方。HAProxy可重配置且能夠在變更發(fā)生后立即將請(qǐng)求路由至新實(shí)例。

配置更為靈活,例如:負(fù)載均衡策略、運(yùn)行狀態(tài)檢查、ACL、A/B測(cè)試、日志記錄以及統(tǒng)計(jì)等等。

不需要由服務(wù)實(shí)現(xiàn)額外的發(fā)現(xiàn)邏輯。

不過(guò)HAProxy是如何在Consul中追蹤已注冊(cè)服務(wù)的?一般來(lái)講,其配置會(huì)利用全部已知后端以靜態(tài)方式完成。不過(guò)我們也可以例如consul-template等外部工具對(duì)其進(jìn)行動(dòng)態(tài)構(gòu)建。這款工具能夠監(jiān)控Consul中的變更并生成任意文本文件,因此其并不只限于配置HAProxy,亦可用于其它能夠利用文本文件實(shí)現(xiàn)配置的工具(例如nginx、varnish以及apache等等)。該模板語(yǔ)言的說(shuō)明文檔非常全面,感興趣的朋友可以點(diǎn)擊此處查看。

大家可能已經(jīng)注意到,我們?cè)诟庞[圖中運(yùn)行有兩套不同的HAProxy配置:一套用于內(nèi)部負(fù)載均衡,另一套用于外部負(fù)載均衡。內(nèi)部實(shí)例跨越各后端服務(wù)提供實(shí)際服務(wù)發(fā)現(xiàn)與負(fù)載流量。外部實(shí)例則額外將服務(wù)發(fā)現(xiàn)聲明至TCP 80端口并接收來(lái)自外部的請(qǐng)求,以此實(shí)現(xiàn)前端服務(wù)負(fù)載均衡。

在這些不同的HAProxy實(shí)例中,我們需要管理兩套獨(dú)立的consul-template模板文件——這兩個(gè)文件本身則由另一套模板引擎(即Jinja2)在Saltstack進(jìn)行設(shè)備配置時(shí)構(gòu)建完成。這種作法主要是為了保證流程清晰,同時(shí)將來(lái)自設(shè)備配置軟件的數(shù)據(jù)填充至其中的特定部分。讓我們首先來(lái)看外部負(fù)載均衡器配置模板。請(qǐng)注意,raw/endraw標(biāo)記負(fù)責(zé)讓Jinja引擎忽略Go模板的大括號(hào)并按原樣使用初始內(nèi)容:

global
  log /dev/log  local0
  log /dev/log  local1 notice
  chroot /var/lib/haproxy
  user haproxy
  group haproxy
  daemon
  maxconn {% raw %}{{key "service/haproxy/maxconn"}}{% endraw %}

  # Default SSL material locations
  ca-base /etc/ssl/certs
  crt-base /etc/ssl/private

  ssl-default-bind-options no-sslv3 no-tls-tickets
  ssl-default-bind-ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH

  tune.ssl.default-dh-param 2048

{% include "mesos/files/haproxy-defaults.ctmpl.jinja" %}
{% include "mesos/files/haproxy-internal-frontend.ctmpl.jinja" %}
{% include "mesos/files/haproxy-external-frontend.ctmpl.jinja" %}
{% include "mesos/files/haproxy-wellknown-services.ctmpl.jinja" %}
{% include "mesos/files/haproxy-backends.ctmpl.jinja" %}

其中還包含其它一些關(guān)聯(lián)性。haproxy-defaults.ctmpl.jinja屬于常見(jiàn)于各類(lèi)HAProxy配置示例中的靜態(tài)部分,而haproxy-internal-frontend.ctmpl.jinja則比較有趣——它負(fù)責(zé)指定內(nèi)部服務(wù)發(fā)現(xiàn)配置的實(shí)現(xiàn)位置。

其基本思路在于為每一項(xiàng)可發(fā)現(xiàn)服務(wù)匹配一條已知端口編號(hào),同時(shí)創(chuàng)建一套HAProxy前端以監(jiān)聽(tīng)該端口。我們將使用與每項(xiàng)已注冊(cè)服務(wù)一同存儲(chǔ)的元信息。Consul允許用戶(hù)為服務(wù)指定一套關(guān)聯(lián)標(biāo)簽列表,而marathon-registrator會(huì)通過(guò)名為SERVICE_TAGS的服務(wù)環(huán)境變量讀取這些標(biāo)簽。查看test-server的service.json模板,其中包含兩個(gè)以逗號(hào)隔開(kāi)的標(biāo)簽,即$environment與internal-listen-http-3000。后者在consul-template模板中用于標(biāo)記已聲明端口以實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)的服務(wù)(在本示例中為3000)。以下代碼片段會(huì)自動(dòng)生成必要的HTTP前端:

{% raw %}

{{range $service := services}}{{range $tag := $service.Tags}}
{{$servicePort := $service.Name | regexReplaceAll "^[w-]+?(d*)$" "$1"}}{{$tagPort := $tag | regexReplaceAll "^[w-]+?(d*)$" "$1"}}
{{if or (not $servicePort) (eq $servicePort $tagPort)}}
{{if $tag | regexMatch "internal-listen-http-d+"}}
##
# Production internal http frontend for {{$service.Name}}
##

frontend internal_http_in_production:{{$service.Name}}
  bind :{{$tag | replaceAll "internal-listen-http-" ""}}
  use_backend cluster_production:{{$service.Name}}

##
# Staging internal http frontend for {{$service.Name}}
##

frontend internal_http_in_staging:{{$service.Name}}
  bind :1{{$tag | replaceAll "internal-listen-http-" ""}}
  use_backend cluster_staging:{{$service.Name}}
{{end}}
{{end}}
{{end}}{{end}}

{% endraw %}

它的外環(huán)會(huì)列出全部Consul服務(wù),內(nèi)環(huán)則列出每項(xiàng)服務(wù)的標(biāo)簽并嘗試找到與internal-listen-http-匹配的條目。每一次匹配成功,其都會(huì)創(chuàng)建對(duì)應(yīng)的HTTP前端。這里的每項(xiàng)服務(wù)都擁有兩種硬編碼環(huán)境:production與staging,用于進(jìn)行區(qū)分。其中分段環(huán)境的端口編號(hào)會(huì)以“1”開(kāi)頭,因此如果生產(chǎn)前端監(jiān)聽(tīng)端口3000,那么分段則監(jiān)聽(tīng)端口13000。

另外,if語(yǔ)句允許我們?yōu)閱我环?wù)指定多個(gè)可發(fā)現(xiàn)端口。要實(shí)現(xiàn)這一效果,我們只需要在標(biāo)簽列表當(dāng)中額外添加internal-listen-http-標(biāo)記,例如:

`$environment,internal-listen-http-3000,internal-listen-http-3010`

現(xiàn)在我們需要添加一個(gè)指向container.docker.portMappings服務(wù)定義文件組的聲明端口,從而保證Marathon能夠正確配置我們的容器網(wǎng)絡(luò)。請(qǐng)注意,本示例中的marathon-registrator將分別注冊(cè)兩項(xiàng)服務(wù):test-server-3000與test-server-3010,對(duì)二者進(jìn)行分別解析并避免名稱(chēng)混淆。

大家也可以利用其它預(yù)定義標(biāo)記在模板中實(shí)現(xiàn)其它邏輯類(lèi)型,例如引入internal-listen-tcp-以生成TCP前端,或者利用balance-roundrobin或balance-leastconn控制均衡策略。

這套模板允許我們配置HAProxy,從而指定每臺(tái)設(shè)備通過(guò)接入localhost:以訪問(wèn)每項(xiàng)Consul已知服務(wù),最終解決服務(wù)發(fā)現(xiàn)問(wèn)題。
在haproxy-wellknown-services.ctmpl.jinja當(dāng)中,我們可以指定多種靜態(tài)管理服務(wù),例如Marathon、Consul以及Chronos,這是因?yàn)樗鼈冚^易于發(fā)現(xiàn)。它們會(huì)在設(shè)備配置過(guò)程中由systemd/upstart/etc啟動(dòng)。舉例來(lái)說(shuō),以下代碼片段允許來(lái)自集群內(nèi)任意設(shè)備的請(qǐng)求通過(guò)聯(lián)系localhost:18080 輕松訪問(wèn)Marathon實(shí)例,而localhost:14400 與localhost:18500 則分別對(duì)應(yīng)Chronos與Consul(在本示例中,集來(lái)自配置管理軟件):

frontend internal_http_in:marathon
  bind :18080
  use_backend cluster:marathon

frontend internal_http_in:chronos
  bind :14400
  use_backend cluster:chronos

listen internal_http_in:consul
  bind :18500
  timeout client 600000
  timeout server 600000
  server local 127.0.0.1:8500

backend cluster:marathon
  option forwardfor
  option httpchk GET /ping
  balance roundrobin
{%- for host, ip in master_nodes.iteritems() %}
  server {{ host }} {{ ip }}:8080 check inter 10s
{% endfor -%}

backend cluster:chronos
  option forwardfor
  option httpchk GET /ping
  balance roundrobin
{%- for host, ip in master_nodes.iteritems() %}
  server {{ host }} {{ ip }}:4400 check inter 10s
{% endfor -%}

haproxy-external-frontend.ctmpl.jinja用于描述HTTP與HTTPS前端。其中包含多套Jinja宏,用于為域名匹配定義ACL規(guī)則并將后端與這些規(guī)則相綁定:

{% macro hosts(environment, domain_prefix="") -%}
  # {{ environment }} hosts
  acl host_{{ environment }}:test-server  hdr_dom(host) -i -m str {{ domain_prefix }}mesos-test.domain.com
{%- endmacro %}

{% macro bind(service, environment) -%}
  use_backend cluster_{{ environment }}:{{ service }} if host_{{ environment }}:{{ service }}
{%- endmacro %}

frontend external_https_in
  bind :443 ssl crt domain_com.pem

  http-response set-header Strict-Transport-Security max-age=31536000; preload
  http-response set-header X-Frame-Options DENY
  http-response set-header X-Content-Type-Options nosniff

  {{ hosts("staging", "staging-") }}
  {{ hosts("production") }}

  # Staging bindings
  {{ bind("test-server", "staging") }}

  # Production bindings
  {{ bind("test-server", "production") }}

frontend external_http_in
  bind :80

  {{ hosts("staging", "staging-") }}
  {{ hosts("production") }}

  # Staging bindings
  {{ bind("test-server", "staging") }}

  # Production bindings
  {{ bind("test-server", "production") }}

最后,還有haproxy-backends.ctmpl.jinja文件。它會(huì)列出之前章節(jié)中提到的全部可用服務(wù)。所有后端都可以進(jìn)行手動(dòng)調(diào)整,因?yàn)橛脩?hù)可能需要滿(mǎn)足運(yùn)行狀態(tài)檢查或者負(fù)載均衡方面的特殊要求:

{% macro backends(environment) -%}

##
# {{ environment }} backends
##
{{ "{{" }}$environment := "{{ environment }}"{{ "}}" }}
backend cluster_{{ environment }}:test-server
  option forwardfor
  option httpchk GET /healthcheck
  balance roundrobin{% raw %}{{range $i, $s := service (print $environment ".test-server")}}
  server {{$s.Node}}-{{$i}} {{$s.Address}}:{{$s.Port}} check inter 10s fall 1 rise 1{{end}}{% endraw %}

{%- endmacro %}

{{ backends("production") }}
{{ backends("staging") }}

內(nèi)部負(fù)載均衡配置文件要稍稍簡(jiǎn)單一點(diǎn),其只需要將連接路由至內(nèi)部可訪問(wèn)服務(wù):

global
  log /dev/log  local0
  log /dev/log  local1 notice
  chroot /var/lib/haproxy
  user haproxy
  group haproxy
  daemon
  maxconn {% raw %}{{key "service/haproxy/maxconn"}}{% endraw %}

{% include "mesos/files/haproxy-defaults.ctmpl.jinja" %}
{% include "mesos/files/haproxy-internal-frontend.ctmpl.jinja" %}
{% include "mesos/files/haproxy-wellknown-services.ctmpl.jinja" %}
{% include "mesos/files/haproxy-backends.ctmpl.jinja" %}
零停機(jī)時(shí)間部署

動(dòng)態(tài)運(yùn)行時(shí)系統(tǒng)的一大共通優(yōu)勢(shì)在于,其能夠以零停機(jī)時(shí)間為前提的實(shí)現(xiàn)服務(wù)部署。在實(shí)際部署過(guò)程中,我們往往希望確保服務(wù)的可用性不受影響。下面來(lái)看如何在自己的系統(tǒng)中實(shí)現(xiàn)這一效果。

其基本思路在于運(yùn)行多個(gè)服務(wù)實(shí)例以支撐輸入請(qǐng)求,并在部署期間一一替換這些實(shí)例:只有新實(shí)例頂替上之后,我們才會(huì)關(guān)停舊實(shí)例。Marathon能夠完全搞定這樣的滾動(dòng)重啟方式,但為了保證恒定的正常運(yùn)行時(shí)間,我們還需要確保負(fù)載均衡器停止向已經(jīng)被關(guān)停的實(shí)例路由流量。

下面要討論Mesos如何停止基于Docker的服務(wù)實(shí)例。與其它Unix進(jìn)程控制系統(tǒng)一樣,它會(huì)嘗試以正常方式停止服務(wù)。首先,SIGTERM會(huì)被發(fā)送至目標(biāo)進(jìn)程,而后該進(jìn)程預(yù)計(jì)將在掛起請(qǐng)求并清空后自行退出。如果其在指定時(shí)間內(nèi)仍未退出,SIGKILL會(huì)強(qiáng)制將其關(guān)閉。Mesos的具體執(zhí)行方式如下:

`docker stop -t= `

(詳見(jiàn):https://docs.docker.com/engine/reference...

現(xiàn)在,我們的服務(wù)應(yīng)該能夠正確處理終止信號(hào)了(其同樣也是十二因子應(yīng)用原則之一)。在接收到SIGTERM后,其應(yīng)該告知負(fù)載均衡器不再向其路由流量。要實(shí)現(xiàn)這一效果,最簡(jiǎn)單的方式就是拒絕全部后續(xù)運(yùn)行狀態(tài)檢查,但仍然正常處理其它潛在請(qǐng)求。一旦負(fù)載均衡器發(fā)現(xiàn)該實(shí)例運(yùn)行狀態(tài)不正常,它將停止將流量路由至該處。為了確保這一流程正常實(shí)現(xiàn),我們需要確保關(guān)停超時(shí)足夠長(zhǎng),使得負(fù)載均衡器能夠自行發(fā)現(xiàn)運(yùn)行狀態(tài)變化并停止對(duì)掛起請(qǐng)求的處理。默認(rèn)情況下,Mesos的配置超時(shí)為5秒,不過(guò)大家也可以利用以下命令行參數(shù)變更該值:

`--executor_shutdown_grace_period=60secs --docker_stop_timeout=30secs`

感興趣的朋友也可以參閱https://github.com/x-cray/test-server/bl... 示例以了解如何處理SIGTERM。

需要強(qiáng)調(diào)的是,docker化服務(wù)的處理方式有所不同。為了允許信號(hào)傳入Docker容器進(jìn)程,我們應(yīng)當(dāng)在Dockerfile中使用ENTRYPOINT而非CMD以指定執(zhí)行權(quán)限。在運(yùn)行時(shí),CMD執(zhí)行會(huì)被打包至shell進(jìn)程當(dāng)中,而其不會(huì)轉(zhuǎn)發(fā)任何信號(hào)(詳見(jiàn)Docker說(shuō)明文檔)。

基本上,到這里我們已經(jīng)實(shí)現(xiàn)了零停機(jī)時(shí)間部署。不過(guò)對(duì)于HAProxy而言,這樣的配置只適用于BSD系統(tǒng)。在Linux系統(tǒng)當(dāng)中還存在一個(gè)小問(wèn)題:當(dāng)其進(jìn)行配置重載時(shí),服務(wù)器會(huì)在一小段時(shí)間內(nèi)(約20到50毫秒)無(wú)法監(jiān)聽(tīng)輸入連接。此時(shí)段內(nèi)的全部輸入請(qǐng)求自然也將失敗。其根本原因在于Linux內(nèi)核處理SO_REUSEPORT套接選項(xiàng)的方式身上(詳情可參閱http://lwn.net/Articles/542629/ )。要解決這個(gè)問(wèn)題,大家不妨閱讀由Yelp發(fā)布的一篇文章。我們最終選擇了簡(jiǎn)單的SYN數(shù)據(jù)包丟棄方案。這種作法對(duì)于我們目前的使用場(chǎng)景來(lái)講已經(jīng)足夠了。以下為我們的consul-template如何重載HAProxy實(shí)例:

#!/bin/bash

iptables -I INPUT -p tcp --dport 80 --syn -j DROP
sleep 0.2
systemctl reload haproxy
iptables -D INPUT -p tcp --dport 80 --syn -j DROP
服務(wù)配置管理

我們運(yùn)行的每項(xiàng)服務(wù)都需要擁有自己的配置,包括連接字符串以及API密鑰等等。一般來(lái)講,這些信息不應(yīng)被硬編碼,也應(yīng)該從構(gòu)建來(lái)提供(調(diào)試/發(fā)布/其它),因?yàn)榇蠹铱赡芟M诓煌h(huán)境(生產(chǎn)/分段/分組測(cè)試)下通過(guò)不同的配置實(shí)現(xiàn)同樣的執(zhí)行效果。

服務(wù)配置通常有著不同的來(lái)源(各來(lái)源亦擁有自己的優(yōu)先級(jí)排序):默認(rèn)、文件、環(huán)境變量、argv等。如果該服務(wù)可通過(guò)環(huán)境變更進(jìn)行配置,那么我們就能通過(guò)多種途徑以集中方式對(duì)其進(jìn)行管理——我們要做的就是在服務(wù)正式啟動(dòng)前為其準(zhǔn)備正確的環(huán)境。好消息是,現(xiàn)在我們已經(jīng)擁有了免費(fèi)的集中化配置存儲(chǔ)方案。Consul提供內(nèi)置鍵-值存儲(chǔ)(Consul KV)機(jī)制,可用于保存配置值——但我們還需要另一種手段將這些值轉(zhuǎn)發(fā)至服務(wù)環(huán)境。

專(zhuān)門(mén)用于解決這類(lèi)需求的工具為envconsul,它會(huì)讀取Consul KV數(shù)據(jù)并將其傳遞至服務(wù)環(huán)境。而在KV數(shù)據(jù)更新時(shí),它會(huì)重啟對(duì)應(yīng)服務(wù)實(shí)例。不過(guò),它在服務(wù)滾動(dòng)重啟以實(shí)現(xiàn)服務(wù)可用性方面的表現(xiàn)并不好——它會(huì)一次性重啟全部實(shí)例,并因此造成請(qǐng)求失敗。作為后備選項(xiàng),我們可以要求Marathon在KV數(shù)據(jù)更新時(shí),確保一切已經(jīng)部署到位并由調(diào)度器完成相關(guān)重啟工作。正因?yàn)槿绱耍覀冞x擇了一套小型Shell腳本service-wrapper來(lái)代替envconsul,其能夠從Consul KV處讀取數(shù)據(jù),設(shè)置服務(wù)環(huán)境并在KV變更發(fā)生時(shí)通過(guò)Marathon進(jìn)行重啟。另外,它還能夠?qū)⒔邮盏降腟IGTERM轉(zhuǎn)發(fā)至底層進(jìn)程以實(shí)現(xiàn)正常關(guān)閉。大家應(yīng)該將這套腳本內(nèi)置于Docker鏡像當(dāng)中。它需要使用curl與jq,因此請(qǐng)確保二者同樣存在于Docker鏡像內(nèi)。以下為具體使用方法:

`service-wrapper.sh    `

其中marathon-host:port 與consul-host:port 擁有自描述特性,prefix值按照慣例應(yīng)為Marathon應(yīng)用ID,而command則為包含相關(guān)參數(shù)的實(shí)際服務(wù)可執(zhí)行文件。為了設(shè)定各服務(wù)環(huán)境變量,我們需要將值添加至Consul KV存儲(chǔ)內(nèi)的prefix路徑下。以下為service-wrapper運(yùn)行示例:

`service-wrapper.sh dockerhost:18080 dockerhost:18500 app/staging/test-server node /app/server.js`

請(qǐng)注意dockerhost:18080 與dockerhost:18500 ——二者為之前提到的服務(wù)器端內(nèi)部服務(wù)發(fā)現(xiàn)示例。

現(xiàn)在如果我們添加/移除/修改prefix之下的任意值,該服務(wù)都將根據(jù)新配置進(jìn)行正常重啟。

總結(jié)

基于Mesos的架構(gòu)能夠幫助我們將多種不同組件加以混合與匹配,從而擁有一套符合實(shí)際需要的完整工作系統(tǒng)。舉例來(lái)說(shuō),要實(shí)現(xiàn)負(fù)載均衡,我們可以使用HAProxy或者Nginx并配合由consul-template生成的動(dòng)態(tài)配置,甚至可以利用其它一些既能夠與Consul通信、又能夠配置IPVS負(fù)載均衡的其它方案替代consul-template。我們還可以利用Netflix Eureka替換整個(gè)服務(wù)發(fā)現(xiàn)/負(fù)載均衡層,或者基于Etcd乃至ZooKeeper編寫(xiě)自己的定制化解決方案。構(gòu)建這樣一套系統(tǒng)能夠幫助大家更好地了解分布式運(yùn)行時(shí)平臺(tái)背后的各個(gè)進(jìn)程及其核心組件。

這套平臺(tái)還具備良好的可移植性,其不僅可被托管至特定云/IaaS之上,也可以通過(guò)內(nèi)部甚至是混合(云加內(nèi)部)環(huán)境實(shí)現(xiàn)。目前甚至有一些項(xiàng)目能夠?qū)esos移植至Windows平臺(tái)。

原文鏈接:
https://medium.com/@x_cray/how-we-cook-m...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/26575.html

相關(guān)文章

  • Container容器技術(shù)大會(huì)PPT分享

    摘要:大會(huì)是由國(guó)內(nèi)容器社區(qū)組織的專(zhuān)為一線開(kāi)發(fā)者和運(yùn)維工程師設(shè)計(jì)的頂級(jí)容器技術(shù)會(huì)議,會(huì)議強(qiáng)調(diào)實(shí)踐和交流,話(huà)題設(shè)置圍繞容器運(yùn)維云計(jì)算等技術(shù)領(lǐng)域,力求全方位多角度為參會(huì)者解讀容器技術(shù)。 @Container大會(huì)是由國(guó)內(nèi)容器社區(qū) DockOne 組織的專(zhuān)為一線開(kāi)發(fā)者和運(yùn)維工程師設(shè)計(jì)的頂級(jí)容器技術(shù)會(huì)議,會(huì)議強(qiáng)調(diào)實(shí)踐和交流,話(huà)題設(shè)置圍繞容器、運(yùn)維、云計(jì)算等技術(shù)領(lǐng)域,力求全方位、多角度為參會(huì)者解讀容器技術(shù)...

    Zachary 評(píng)論0 收藏0
  • GIAC 2017全球互聯(lián)網(wǎng)架構(gòu)大會(huì)最新日程

    摘要:月日至日,高可用架構(gòu)和聯(lián)合主辦的全球互聯(lián)網(wǎng)架構(gòu)大會(huì)將于上海光大會(huì)展中心舉行。全球互聯(lián)網(wǎng)架構(gòu)大會(huì)是高可用架構(gòu)技術(shù)社區(qū)推廣的面向架構(gòu)師技術(shù)負(fù)責(zé)人及高端技術(shù)從業(yè)人員的技術(shù)架構(gòu)大會(huì)。本次大會(huì)共有大板塊方向,場(chǎng)技術(shù)專(zhuān)題,個(gè)互聯(lián)網(wǎng)架構(gòu)案例。 showImg(https://segmentfault.com/img/bVZ3Vh?w=600&h=375);12月22日至23日,高可用架構(gòu)和msup聯(lián)...

    617035918 評(píng)論0 收藏0
  • GIAC 2017全球互聯(lián)網(wǎng)架構(gòu)大會(huì)最新日程

    摘要:月日至日,高可用架構(gòu)和聯(lián)合主辦的全球互聯(lián)網(wǎng)架構(gòu)大會(huì)將于上海光大會(huì)展中心舉行。全球互聯(lián)網(wǎng)架構(gòu)大會(huì)是高可用架構(gòu)技術(shù)社區(qū)推廣的面向架構(gòu)師技術(shù)負(fù)責(zé)人及高端技術(shù)從業(yè)人員的技術(shù)架構(gòu)大會(huì)。本次大會(huì)共有大板塊方向,場(chǎng)技術(shù)專(zhuān)題,個(gè)互聯(lián)網(wǎng)架構(gòu)案例。 showImg(https://segmentfault.com/img/bVZ3Vh?w=600&h=375);12月22日至23日,高可用架構(gòu)和msup聯(lián)...

    Imfan 評(píng)論0 收藏0
  • 周末“干活”之 Mesos Meetup

    摘要:愛(ài)奇藝歷程采用的軟件棧服務(wù)現(xiàn)狀集群建設(shè)自動(dòng)化部署經(jīng)驗(yàn)沒(méi)有采用嵌入式管理服務(wù)降低風(fēng)險(xiǎn),對(duì)紅帽有一點(diǎn)擔(dān)憂(yōu)。再次感謝和數(shù)人科技共同組織的,非常期待下一次的周末相聚。 周末兩天都是大霧霾天,作為運(yùn)營(yíng)也不能在家宅,告別了技術(shù)就得腿兒勤點(diǎn)兒。 非常感謝 Linker 的 Sam Chen 和 數(shù)人科技 的 CTO 共同組織的Mesos Meetup,OneAPM 最帥的 Docker 工程獅~陳亮...

    warmcheng 評(píng)論0 收藏0
  • 從小白程序員一路晉升為大廠高級(jí)技術(shù)專(zhuān)家我看過(guò)哪些書(shū)籍?(建議收藏)

    摘要:大家好,我是冰河有句話(huà)叫做投資啥都不如投資自己的回報(bào)率高。馬上就十一國(guó)慶假期了,給小伙伴們分享下,從小白程序員到大廠高級(jí)技術(shù)專(zhuān)家我看過(guò)哪些技術(shù)類(lèi)書(shū)籍。 大家好,我是...

    sf_wangchong 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<