请选择 进入手机版 | 继续访问电脑版

IT运维管理,ITIL,ITSS,ITSM,ISO20000-ITIL先锋论坛

 找回密码
 点击获取邀请码 - 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

搜索
查看: 311|回复: 0

基于容器编排的Dev/Ops流程方案

[复制链接]
来自- 广东广州

参加活动:0

组织活动:12

发表于 2017-8-17 15:40:51 | 显示全部楼层 |阅读模式 来自- 广东广州
随着 DevOps 和 SRE 概念的流行,越来越多的 developer 和 operater 们摒弃传统的开发部署流程,转向了如下图所示的无线循环模式:
在我理解 DevOps 包含三个大块:敏捷开发(Agile)、持续集成与交付(CI/CD)、自动运维(ITSM)。
8 d# ^9 K: A6 i9 H
在容器化的时代,我们是如何实现 DepOps 或者 SRE 的呢?下面我就来分享一下沪江学习产品线团队基于容器编排的 DevOps 流程。
敏捷开发
大道至简,所有血的教训告诉我们,不要把简单的事情复杂化。换句话说,不要用复杂的方法处理简单的事情。我对敏捷的理解是「快」和「微」。快指迭代快,开发快,上线快,性能快。微指微服务、微镜像。围绕这两点,在开发阶段我们需要做以下几件事:
应用微服务化
这是个比较大的概念,不在这里讨论,有兴趣可以参考我的其他文章。但只有应用小了,才有可能快起来。
给 Docker 镜像瘦身为了让 Docker 启动和运行得快,首先就是要对 Docker 瘦身。由于所有的应用全部会统一为 Java 语言开发,所以我们以 Java 为例,选用了 jre-alpine 作为我们的基础镜像,下面是 Dockerfile 的例子:FROM java:8-jre-alpine
7 v0 I4 K( k6 e" q7 v  9 v, t. S2 J, y5 |( p
#add timezone and default it to Shanghai
. p) U( E) P. L6 K6 O+ mRUN apk --update add --no-cache tzdata
: n) ~! e, A) w+ jENV TZ=Asia/Shanghai9 V  p0 N* g* t
  5 L. K& b8 s; m+ M, H
RUN mkdir -p /app/log
  M6 L/ r. u9 i- ^5 Z' YCOPY  ./target/xxx.jar  /app/xxx.jar1 i% C- p6 K) z
  4 S4 D% |2 x5 |
EXPOSE 99998 p( J' W) A# m( I9 m
VOLUME ["/app/log"]. ~9 ?  @8 v9 e) C9 {
WORKDIR /app/
4 ?/ R) R" x- q* n3 g$ Z  6 o) R6 ]4 w- ]6 H( }
ENTRYPOINT ["java","-Xms2048m", "-Xmx2048m", "-Xss512k", "-jar","xxx.jar"]) Q: {+ {" w& [; }; u9 Y
CMD []
使用上述 Dockerfile 生成的镜像平均只有 80 多 MB,启动时间几乎在 5 秒内。使用 alpine 镜像虽然减小了体积,但缺少一些工具命令,例如 curl 等,可以根据需要酌情安装。另外遇到的一个坑是时区问题:由于 Docker 镜像内的时区是 UTC 时间,和宿主机的东 8 区不一致,所以必须安装 timezone 工具并设置 TZ,才能使容器内时间和宿主机保持一致,对数据库的写入和日志的输出都是非常必要的一环。
把所有环境配置包含在镜像中
早在虚拟机时代,我们已经做到了使用包含依赖的虚拟机镜像来加速部署,那么为什么要止步于此呢?我们可以更进一步,把服务本身也包含在镜像中,Docker 用了更轻量的方式已经实现了这一点。
这里我们还要介绍一个概念,要让制作的镜像,能在所有安装了 Docker 的服务器上运行,而不在乎宿主机的操作系统及环境。借用 Java 的一句话来说:一次制作,多平台运行。所以,我们还会把所有环境的配置文件,以不同的文件名全部放入镜像中,通过参数来选择 Docker 启动时使用的环境配置文件。
值得注意的是,如果开发的应用是基于 spring 框架的话,这个功能很好实现。但如果是其他语言开发,会有一定的开发量。
本文以默认 Java 开发当所有的开发工作完成后,推荐程序目录结构是这样的:

* _4 N; P& {  d, P
├── src
1 k" J* L) u! D+ `% D% d8 B│   ├── main0 n+ E# s! b7 W5 |8 x  k
│   │   ├── java/ `! k! e! c; B: g; c/ I7 g
│   │   ├── resources
4 n( s* P  e! A$ f. w│   │   │   ├── application.yaml+ k; F3 Y. K- d. O
│   │   │   ├── application-dev.yaml
5 O8 I+ R  c& u! n% {│   │   │   ├── application-qa.yaml
7 U8 K  U  f6 n/ N; e6 I& v: s+ ^│   │   │   ├── application-yz.yaml
: i/ E7 g7 R% k+ ?8 S│   │   │   ├── application-prod.yaml# f* Y/ A6 b# ^- e9 N% |/ ?) D$ p$ N
│   │   │   ├── logback.xml
/ y- E: W: `9 q7 t- \5 b2 f& A│   ├── test
3 @4 e. S7 U1 l├── scripts
& ]- Q8 s3 h+ v* a* R5 C│   ├── Dockerfile
# N2 X/ y2 ~+ ~( H" P& d( `│   ├── InitDB.sql
% Q$ T/ F6 \2 N% H├── pom.xml
持续集成与交付
自动化的持续集成和交付在整个 DevOps 流中起了重要的角色,他是衔接开发和运维的桥梁。如果这一环做的不好,无法支撑大量微服务的快速的迭代和高效运维。在这一环节,我们需要灵活的运用工具,尽量减少人参与,当然仍然需要围绕「快」和「微」做文章。
如何减少人工参与到持续集成与持续交付呢?我们最希望的开发过程是:对着计算机说出我们的想要的功能,计算机按照套路,自动编码,自动发布到测试环境,自动运行测试脚本,自动上线。当然,目前时代要实现自动编码的过程还需要发明那只「猫」。
但只要对测试有足够信心,我们完全可以实现一种境界:在炎热的下午,轻松地提交自己编写的代码,去休息室喝杯咖啡,回来后看见自己的代码已经被应用在生产环境上了。在容器时代,我们可以很快速的实现这一梦想,其具体步骤如下图:5 |2 J: i( x5 q# X- M' j$ z
& i6 Q( F( }% {( x- p2 G4 ~
; _, X& ?( s9 [" K' T* R9 v2 y
Gitfolw 与 Anti-Gitflown
- y+ q# D( U9 d& y, Q0 n4 R2 }
持续集成的第一步是提交代码(Code Commit),VCS 也由 CVS,SVN 进化到如今的 Git,自然不得不说一下 Gitflow。谈起无人不晓的 Gitflow,大家一定会大谈其优点:支持多团队,设置多国家的开发人员并行开发,减小代码冲突或脏代码的上线概率。它的大致流程如下:
: G4 Z  l( K0 e7 K2 C+ K( o' X
Gitflow 给我们展示了复杂团队在处理不通代码版本的优雅解决方案,它需要feature、develop、release、hotfix、master 5 条分支来处理不同时段的并行开发。但这真的合适于一个不超过 20 人的本地合作团队开发吗?我们的开发团队不足 6 人,每个人负责 3 个以上的微服务,几乎不可能在同个项目上安排两个以上的同学并行开发。
0 |/ ?, t8 T6 [: X
在初期我们准守规定并使用标准的 Gitflow 流程,开发人员立刻发现一个问题,他们需要在至少 3 条分支上来回的 merge 代码,且不会有任何代码冲突(因为就一个人开发),降低了开发的效率。这让我意识到,Gitflow 模式也许并不适合于小团队微服务的世界,一种反 Gitflow 模式的想法出现在脑海中。我决定对Gitflow 进行瘦身,化繁至简。
/ y) v: e/ O7 K+ b% ]& \/ D( q
* r% P# G6 R" c9 ~# f8 H$ u: c3 L/ A
我们把 5 条分支简化为 3 条分支,其中 Master 分支的作用只是维护了最新的线上版本的作用,Dev 分支为开发的主要分支,所有的镜像是以此分支的代码为源头生成的。这时开发的过程变为:

& w: O  s9 H7 d- V2 D* C! A
  • 开发人员从 Dev 分支中 checkout 新的 feature 分支,在 feature 分支上进行开发
  • 当开发完成后 merge 回 Dev 分支中,根据 Dev 分支的代码打成镜像,部署 QA 环境交给 QA 人员测试
  • 测试中如有 bug 便在新分支中修复问题循环步骤 2
  • 测试完成 merge 回 Master 分支

    % p% E$ e* ~# p( |  C: P* E
如此一来,只有从 Feature 把代码 merge 到 Dev 分支的一次 merge 动作,大大提升可开发效率。
使用Jenkins Pipeline
Jenkins 作为老牌 CI/CD 工具,能够帮我们自动化完成代码编译、上传静态代码分析、制作镜像、部署测试环境、冒烟测试、部署上线等步骤。尤其是Jenkins2.0 引入 Pipeline 概念后,以上步骤变的如此行云流水。它让我们从步骤 3 开始,完全可以无人值守完成整个集成和发布过程。
工欲善其事必先利其器,首先我们必须要在 Jenkins 上安装插件 :

9 S/ d2 v5 {, s* p
  • Pipeline Plugin(如果使用Jenkins2.0默认安装)
  • Git
  • Sonar Scaner
  • Docker Pipeline Plugin
  • Marathon
    . V9 A4 H! M& d- Q+ w
如果你第一次接触 Jenkins Pipeline,可以从https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md找到帮助。
现在,我们开始编写 Groove 代码。基于容器编排的 Pipeline 分为如下几个步骤:
1.检出代码
这个步骤使用 Git 插件,把开发好的代码检出。
stage('Check out')" F* J+ M+ C9 i
  gitUrl = "git@gitlab.xxxx.com:xxx.git"9 N# l- _1 ^- g7 i3 e
  git branch: "dev", changelog: false, credentialsId: "deploy-key", url: gitUrl8 `+ p* ?* Q! s% \$ j
2.maven 构建 Java 代码
由于我们使用的是 spring boot 框架,生成物应该是一个可执行的 jar 包。
stage('Build')
) S* e: l  R; G' B9 _  sh "${mvnHome}/bin/mvn -U clean install"3. 静态代码分析
通过 Sonar Scaner 插件,通知 Sonar 对代码库进行静态扫描。
stage('SonarQube analysis'); u: I  m- W& O1 A8 H/ i1 Y: q& ]
   // requires SonarQube Scanner 2.8+
! e. g# k" k; `$ @1 B   def scannerHome = tool 'SonarQube.Scanner-2.8';" h7 X  ^2 h3 u6 s8 O
   withSonarQubeEnv('SonarQube-Prod') {5 ]* B( p" j4 _6 w" h1 f9 t
     sh "${scannerHome}/bin/sonar-scanner -e -Dsonar.links.scm=${gitUrl} -Dsonar.sources=. -Dsonar.test.exclusions=file:**/src/test/java/** -Dsonar.exclusions=file:**/src/test/java/** -Dsonar.language=java -Dsonar.projectVersion=1.${BUILD_NUMBER} -Dsonar.projectKey=lms-barrages -Dsonar.projectDescription=0000000-00000 -Dsonar.java.source=8 -Dsonar.projectName=xxx"
; A1 @6 A, @' `7 R4 \# q   }
4 x# l) r9 p6 e* Q
4.制作 Docker 镜像
' y; L4 C  V1 F0 q& {1 N
此步骤会调用 Docker Pipeline 插件通过预先写好的 Dockerfile,把 jar 包和配置文件、三方依赖包一起打入 Docker 镜像中,并上传到私有 Docker 镜像仓库中。
stage('Build image')
) g1 ?5 h2 E+ M$ H6 s  g  docker.withRegistry('https://dockerhub.xxx.com', 'dockerhub-login') {. H. b( i/ b9 p# i: J. W- u
    docker.build('dockerhub.xxx.com/xxxx').push('test') //test是tag名称
! J  d7 }) w- j  }5.部署测试环境
通过事先写好的部署文件,用 Marathon 插件通知 Marathon 集群,在测试环境中部署生成好的镜像。
stage('Deploy on Test')
' P$ a' o7 B- Z+ w    sh "mkdir -pv deploy"
1 [0 O( f4 e  R7 T( G: f9 u    dir("./deploy") {
1 ]# R9 l) f' ]' d        git branch: 'dev', changelog: false, credentialsId: 'deploy-key', url: 'git@gitlab.xxx.com:lms/xxx-deploy.git'# t) v. T9 d, e; }1 H4 e9 m
        //Get the right marathon url
3 I4 ~5 e) c" t        marathon_url="http://marathon-qa", [" W: U- F  w" w, n( R1 z
        marathon docker: imageName, dockerForcePull: true, forceUpdate: true, url: marathon_url, filename: "qa-deploy.json") h$ j1 j9 K6 h: J
    }
) |" |& R% t. b1 c. \% M
6.自动化测试
9 ?8 ?- ]0 F+ b- G) n
运行事先测试人员写好的自动化测试脚本来检验程序是否运行正常。
stage('Test')% q1 n0 @( f: ^  X# r
   // 下载测试用例代码
4 l, `( _# H, B( r6 J7 Y   git branch: 'dev', changelog: false, credentialsId: 'deploy-key', url: 'git@gitlab.xxx.com:lms/xxx-test.git'
. Z3 ?- B, @4 E' `3 t   parallel(autoTests: {4 c. n9 H, x/ c1 o7 G
        // 使用nosetests 运行测试用例
8 q3 o6 ^1 y: `        sh "docker run -it --rm -v $PWD:/code nosetests nosetests -s -v -c conf\run\api_test.cfg --attr safeControl=1"
7 h+ }  v+ ?& Q' ~3 ]   },manualTests:{
% C, l7 B8 ?2 {9 ~2 N- J% L" w, {$ u' \        sleep 30000
* N( Y* B- G( m   })4 [9 a; C8 p4 I) |
7. 人工测试4 \* W# C) `& n- w  S+ @
如果对自动化测试不放心,此时可选择结束 Pipeline,进行人工测试。为了说明整个流程,我们这里选择跳过人工测试环节。
8. 部署生产环境
当所有测试通过后,Pipeline 自动发布生产环境。
stage('Deploy on Prod')7 w' c7 X- z3 K: e/ j
    input "Do tests OK?"
$ ~" C. R: A6 p% ~. _/ W+ j    dir("./deploy") {+ b2 O" u0 [* J/ J, F, [& J+ {/ f
        //Get the right marathon url
6 o  O' T! W% g3 [5 h* \# g        marathon_url="http://marathon-prod"
2 M- ~6 e- z7 U8 L% V6 ~        marathon docker: imageName, dockerForcePull: true, forceUpdate: true, url: marathon_url, filename: "prod-deploy.json"
  Z. x5 ~5 v% E9 ?  F* n7 ]- a: j    }
$ @& L- k, s& _" f) b! l+ ~3 `
. w+ x& ^2 M5 I" {) x, }
最后我们来看看整个 Pipeline 的过程:
容器编排配置文档化
在介绍敏捷开发时,曾介绍过根据不同环境的配置参数部署到不同的环境。如何告知部署程序用什么样的配置文件启动服务,每个环境又用多少 CPU,内存和 instance 呢?
4 P9 A& ~1 v: R6 s% p; i3 Y
下面我们就来介绍一下容器编排的配置文件。由于我们使用 Mesos+Marathon的容器编排方式,部署的重任从以前的写部署脚本变成了写一个 Marathon 的配置,其内容如下:
{. Y: a: d& C3 K4 t) N( `1 q2 L
  "id": "/appName",
) e4 }# B/ Z# n4 _7 m6 a+ J7 J  "cpus": 2,
' m& _* z( M2 U: E# A5 x' J( @  "mem": 2048.0,: ^1 `/ p; |7 [; n" p
  "instances": 2,2 l0 M- P+ ]& |* G1 K5 p
  "args": [
1 X8 V. t( g7 j9 s4 k) s& v& I    "--spring.profiles.active=qa"6 S! r, T5 P& \9 G4 c. q. x- w
  ],2 P$ g$ F3 v& o" q* s; ~* l% w4 V  o
  "labels": {
+ x6 m' h8 r- a. W' s: z! b' J    "HAPROXY_GROUP": "external",9 A, L) e6 \' I% A
    "HAPROXY_0_VHOST": "xxx.hujiang.com"
; r9 c8 L) W+ g- u# X  },& }5 L( C& u* ?: R8 ^+ x. k
  "container": {( E' d" V7 `: N' V9 v
    "type": "DOCKER",
8 I5 {1 s$ ~9 F' `% K    "docker": {3 a: p! G3 r) e8 c5 G/ T/ Y
      "image": "imageName",9 z, w& a7 X2 W! v8 \6 m
      "network": "USER",) P! `! r& r5 p/ |- y) E
      "forcePullImage": true,5 @$ s/ [( |7 i
      "portMappings": [: H2 O5 J) g/ f& Y. O/ `0 K
        {
- L5 T; _5 A+ x7 y          "containerPort": 12345,
& k5 }% M+ F+ F8 q* k+ M          "hostPort": 0,4 K# S1 y3 j; X! |* Q
          "protocol": "tcp",
9 ~3 N# f0 ^* t          "servicePort": 12345) Q5 \, v6 S/ T# n8 e9 h
        }* R& R# t9 e, X
      ]
! v+ U! k3 z" H8 ?$ B9 W    },- J# b$ S( @' Q7 C
    "volumes": [+ L# Z  q1 R. G9 U0 l& Y$ _% l
      {
; [" W" o9 S, y: N3 d% J( Q  F        "containerPath": "/app/log"," F) q8 C- I$ O4 y
        "hostPath": "/home/logs/appName",8 A+ z$ g  O, s9 q0 M' Q
        "mode": "RW"  z' a3 ~- j9 h' w3 n; o1 B) ~
      }$ V$ C$ y1 c. y$ W
    ]
' t! S3 _8 [2 w6 h' U  },& {7 Y$ W4 O% W) l
  "ipAddress": {
' G; B& ]( F- t: }) b, c    "networkName": "calico-net"3 k9 U$ W3 K; b, G) Y
  },
5 I' n6 w! r" M2 b  "healthChecks": [/ D5 t' `/ H7 m* y  n8 f
    {! ], N: u3 _# f$ s& i6 R+ K9 c0 U
      "gracePeriodSeconds": 300,$ d9 g$ Q4 g( i
      "ignoreHttp1xx": true,0 c2 C8 \3 p* j
      "intervalSeconds": 20,
- A( y: r6 w$ C      "maxConsecutiveFailures": 3,  Q. T  m! v  \  R5 B
      "path": "/health_check",
7 L& I7 N: L7 p+ x      "portIndex": 0,* h0 g$ a, h! U0 U: o1 ~- ^
      "protocol": "HTTP",! `3 [9 q1 p$ {# l2 l* h) X
      "timeoutSeconds": 20
' a9 b0 d7 b! Q: J1 [' d    }0 D; z0 F# ^5 }2 d- V
  ],* K, g3 W' e; ^# i+ j7 L- ?
    "uris": [
- {! x; E% T! H# b! ]    "file:///etc/docker.tar.gz"3 i9 O* q) z  f4 |4 \6 u1 L" y  I
  ]" q& t0 v) b) W- s6 b1 g
}
我们把这个配置内容保存为不同的 json 文件,每个对应的环境都有一套配置文件。例如 Marathon-qa.json,Marathon-prod.json。当 Pipeline 部署时,可以通过Jenkins Marathon 插件,根据选择不同的环境,调用部署配置,从而达到自动部署的目的。
自动化流程和部署上线分离与管理
开发部署如此的简单快捷,是不是每个人都能方便的使用呢?答案是否定的,并不是因为技术上有难度,而是在于权限。在理想的情况下,通过这套流程的确可以做到在提交代码后,喝杯咖啡的时间就能看见自己的代码已经被千万用户使用了。
但风险过大,我们并不是每个人都能像 Rambo 一样 bug 的存在,大多数的情况还需要使用规范和流程来约束。就像自动化测试取代不了人工黑盒测试一样,部署测试后也不能直接上生产环境,在测试通过后还是需要有个人工确认和部署生产的过程。
所以我们需要把自动化流程和最后的部署上线工作分开来,分别变成两个 Job,并给后者单独分配权限,让有权限的人来做最后的部署工作。这个人可以是 Team leader、开发经理,也可以是运维伙伴,取决于公司的组织结构。
那这个部署的 Job 具体干什么呢?在容器编排时代,结合镜像既构建物的思想,部署 Job 不会从代码编译开始工作,而是把一个充分测试且通过的镜像版本,通过 Marathon Plugin 部署到产线环境中去。这里是 Deploy_only 的例子:
node('docker-qa'){
' d8 c( l8 L/ \# C9 ~$ F1 W    if (ReleaseVersion ==""){8 D+ T, K' V2 |, z, D3 N- Q( g
        echo "发布版本不能为空"# p8 I7 ^1 v, h$ W2 Z8 j! I/ F
        return* n4 |* ^% }9 s% n. G/ j1 y
    }( p, y) L* K& u# z2 v
    stage "repare image"
4 n( r! A/ |3 K        def moduleName = "${ApplicationModule}".toLowerCase()! L8 \# m  Q* E
        def resDockerImage = imageName + ":latest"
5 p( O1 d) F( y        def desDockerImage = imageName + "{ReleaseVersion}"7 K4 W5 M; z' Y2 w$ s- P
        if (GenDockerVersion =="true"){
( \3 l- L# Y5 |            sh "docker pull ${resDockerImage}"
9 x0 _  W. a# a. N            sh "docker tag ${resDockerImage} ${desDockerImage}"
$ w9 g6 D* M2 \            sh "docker push ${desDockerImage}"5 x  T2 e/ v* t! G1 y5 c
            sh "docker rmi -f ${resDockerImage} ${desDockerImage}"
: p, r: L) K' P7 ~0 c' F3 n+ T        }
! N" M# e% X/ i) k$ E+ Z/ H; \     + k8 ]. a/ G7 H4 f2 Z6 t1 I: I
    stage "Deploy on Mesos"
) k' O& ~9 I2 [8 i+ ^        git branch: 'dev', changelog: false, credentialsId: 'deploy-key', url: 'git@gitlab.xxx.com:lms/xxx-test.git'  . [, a7 ~6 V& T) b/ u
        //Get the right marathon url- v; m9 c6 P4 e# s  `( C/ ^" o
        echo "DeployDC: " + DeployDC6 i1 J0 ?; X* W
        marathon_url = ""
1 ~: D" W5 f3 e/ ~' F$ |        if (DeployDC=="AA") {
* ^  q7 O; c6 a- P3 S1 E            if (DeployEnv == "prod"){
1 F: ]! p: _$ m; }$ O( ?/ |! T              input "Are you sure to deploy to production?"' Y; s& N8 P: \% y0 _! S
              marathon_url = "${marathon_AA_prod}"7 y# k: c% I6 d% W1 [7 A; \0 I
            }else if (DeployEnv == "yz") {8 g8 l' k+ G% L6 x" l
              marathon_url = "${marathon_AA_yz}"
4 D7 x4 o' W' j6 Y            }- Q, j( N- ]) d" _! i, E
        }else if ("${DeployDC}"=="BB"){7 |. W  L$ k9 u9 [# S
          if ("${DeployEnv}" == "prod"){( C0 R3 d0 d+ r
            input "Are you sure to deploy to production?"
" S- Y. {8 N. [            marathon_url = "${marathon_BB_prod}"  ^& W- S4 W  z" D; J) n  s, G2 F
          }else if ("${DeployEnv}" == "yz") {
% b) J4 c, }/ v5 Y; n# t            marathon_url = "${marathon_BB_yz}"7 l- q: d2 X2 d9 c
          }
  ~: m3 l# d: J% _  E        }
; j3 ~. h/ L; J& z. p        marathon docker: imageName, dockerForcePull: true, forceUpdate: true, url: marathon_url, filename: "${DeployEnv}-deploy.json"5 Y) S5 `$ q6 A8 E; h  n
}
6 j+ ~! ]9 D& H! Q, u
为什么不把这个文件跟随应用项目一起放到 scripts 下呢?因为把部署和应用分开后,可以由两拨人进行维护,兼顾公司的组织架构。1 ~. @- O$ ], d0 k9 U( D
自动化运维在 DevOps 的最后阶段是运维阶段。在容器时代,如何对庞大的镜像制品进行运维呢?我们的目标是尽量实现自动化运维,这里主要讲述两点:容器的监控
容器的监控大致有两种方式:物理机上安装其他服务监控本机上的所有容器;通过 Mesos 或 kubernates 自带 API 监控容器状态。两种方式其实都需要在物理机上安装相应的监控软件或 Agent。
在我们团队目前使用 cAdvisor+influxDB+Grafana 的组合套件实现对容器的监控。
首先需要在 Mesos 集群中所有的 Agent 安装 cAdvisor 。他负责把宿主机上所有运行中的容器数据以数据点(data point)形式发送给时序数据库(influxDB),下面是 cAdvisor 监控的一些数据点:
, z, S  `. G% h  b. U8 a! x
这些数据点经过 Grafana 整理,展示在界面上,这样我们就能掌握具体容器的性能指标了。下面是一个 Grafana 的截图:

7 |- w, {1 F7 W$ k
$ P- L3 Q1 {2 B; R
除了对容器本身的监控,宿主机的监控也是必不可少的。由于监控的点有很多,这里不一一例举。
自动伸缩有了监控指标只是实现了自动化运维的第一步,当业务请求发生大量增加或减少,通过人工监测是不能及时的进行相应的,况且还不一定有那么多的人,7×24 小时的监控。一定需要有一套根据监控数据自行伸缩容的机制。在学习产品线,我们针对容器编排的 Mesos+Marathon 框架,开发了一套针对应用本身的自动扩容微服务。其原理如下:4 d" Y$ D! @+ h' R/ j
  • 通过 Restful 的接口通知 AutoScaler 程序需要监控的应用服务。
  • AutoScaler 程序开始读取每台 Agent 上部署相关应用的 Metrics 数据,其中包括 CPU,内存的使用状况。
  • 当发现有应用过于繁忙(其表现形式大多是 CPU 占用过高或内存占用过大)时调用 Marathon API 将其扩容
  • Marathon 收到消息后,立刻通知 Mesos 集群发布新的应用,从而缓解当前的繁忙状况。

    & |5 z6 o( D& e& x6 I5 A0 i( O
结束语
DevOps 和 SRE 并不是一个渴望而不可及的概念,它们需要在不同的环境中落地。我们整个 DevOps 流程是建立在容器编排的基础上的,目的是简化流程和实现自动化 CI/CD 和自动化运维。当中会有很多没有想到的地方,可能也不太适用于复杂场景。其次,本文中的例子也做了相应的隐私处理,可能无法直接使用。希望大家能通过我们在实践中产生的成功和遇到的问题,提炼出适合自己的 DevOps 流程。
0 O, z* v" [( ~& x% P& }) F# S  j
原创:黄凯

* e' C% w  s( ]' F2 x( p7 `8 d

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?点击获取邀请码 - 立即注册

x

本版积分规则

选择云运维时代的王牌讲师-长河老师,助你轻松入门ITIL Foundation培训课程

QQ|小黑屋|手机版|Archiver|ITIL先锋论坛五万运维人社区 ( 粤ICP备17056641号|网站地图

Baidu

GMT+8, 2018-6-20 06:18 , Processed in 0.158300 second(s), 35 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表