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

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

 找回密码
 微信、QQ、手机号一键注册

扫描二维码登录本站

QQ登录

只需一步,快速开始

艾拓先锋
搜索
查看: 435|回复: 0

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

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

参加活动:0

组织活动:12

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

' w- j7 M# f; b* q* _' b
├── src
3 b7 @, F( P9 n$ [& |' p│   ├── main
' l6 [, |8 [5 ^- Y% R1 U# J* x% p│   │   ├── java% x! P" B8 d, }  Y
│   │   ├── resources8 c% R9 @) C+ o$ x7 l$ L
│   │   │   ├── application.yaml
! t# c7 z1 u# m& d│   │   │   ├── application-dev.yaml
1 Q0 B+ k+ a! W; e! {$ q│   │   │   ├── application-qa.yaml0 v, l1 H6 u, }7 B
│   │   │   ├── application-yz.yaml
; W, G' A( L! a5 h│   │   │   ├── application-prod.yaml. n9 L) V  o% P9 ~3 i% z
│   │   │   ├── logback.xml
2 r* f+ s* _3 l" s7 @│   ├── test) [  w5 s# j" g7 V
├── scripts# o! U9 M4 x+ ~
│   ├── Dockerfile+ e; E' Y& C5 I  i
│   ├── InitDB.sql) z7 i" Q* k0 g5 t7 ]/ [+ K
├── pom.xml
持续集成与交付
自动化的持续集成和交付在整个 DevOps 流中起了重要的角色,他是衔接开发和运维的桥梁。如果这一环做的不好,无法支撑大量微服务的快速的迭代和高效运维。在这一环节,我们需要灵活的运用工具,尽量减少人参与,当然仍然需要围绕「快」和「微」做文章。
如何减少人工参与到持续集成与持续交付呢?我们最希望的开发过程是:对着计算机说出我们的想要的功能,计算机按照套路,自动编码,自动发布到测试环境,自动运行测试脚本,自动上线。当然,目前时代要实现自动编码的过程还需要发明那只「猫」。
0?wx_fmt=png.jpg
但只要对测试有足够信心,我们完全可以实现一种境界:在炎热的下午,轻松地提交自己编写的代码,去休息室喝杯咖啡,回来后看见自己的代码已经被应用在生产环境上了。在容器时代,我们可以很快速的实现这一梦想,其具体步骤如下图:
3 x. g2 {8 p. q: J" k+ H

  v. M% o6 m4 v8 t; |0 m3 D
0?wx_fmt=png.jpg

4 ?! d, X: C3 n8 P: M
Gitfolw 与 Anti-Gitflown0 D% S$ D6 G( O8 X2 P8 ^( j
持续集成的第一步是提交代码(Code Commit),VCS 也由 CVS,SVN 进化到如今的 Git,自然不得不说一下 Gitflow。谈起无人不晓的 Gitflow,大家一定会大谈其优点:支持多团队,设置多国家的开发人员并行开发,减小代码冲突或脏代码的上线概率。它的大致流程如下:
1 ^# l* T5 w, u+ Q
0?wx_fmt=png.jpg
Gitflow 给我们展示了复杂团队在处理不通代码版本的优雅解决方案,它需要feature、develop、release、hotfix、master 5 条分支来处理不同时段的并行开发。但这真的合适于一个不超过 20 人的本地合作团队开发吗?我们的开发团队不足 6 人,每个人负责 3 个以上的微服务,几乎不可能在同个项目上安排两个以上的同学并行开发。
- h3 Y) p* e- _3 E
在初期我们准守规定并使用标准的 Gitflow 流程,开发人员立刻发现一个问题,他们需要在至少 3 条分支上来回的 merge 代码,且不会有任何代码冲突(因为就一个人开发),降低了开发的效率。这让我意识到,Gitflow 模式也许并不适合于小团队微服务的世界,一种反 Gitflow 模式的想法出现在脑海中。我决定对Gitflow 进行瘦身,化繁至简。
; i0 G" V( B' q0 J
0?wx_fmt=png.jpg
: G% O2 K+ h* L1 q: b7 p) G
我们把 5 条分支简化为 3 条分支,其中 Master 分支的作用只是维护了最新的线上版本的作用,Dev 分支为开发的主要分支,所有的镜像是以此分支的代码为源头生成的。这时开发的过程变为:

1 h- @; X' a, `0 q' B" T  a4 v
  • 开发人员从 Dev 分支中 checkout 新的 feature 分支,在 feature 分支上进行开发
  • 当开发完成后 merge 回 Dev 分支中,根据 Dev 分支的代码打成镜像,部署 QA 环境交给 QA 人员测试
  • 测试中如有 bug 便在新分支中修复问题循环步骤 2
  • 测试完成 merge 回 Master 分支

    : C( @2 X* q  d
如此一来,只有从 Feature 把代码 merge 到 Dev 分支的一次 merge 动作,大大提升可开发效率。
使用Jenkins Pipeline
Jenkins 作为老牌 CI/CD 工具,能够帮我们自动化完成代码编译、上传静态代码分析、制作镜像、部署测试环境、冒烟测试、部署上线等步骤。尤其是Jenkins2.0 引入 Pipeline 概念后,以上步骤变的如此行云流水。它让我们从步骤 3 开始,完全可以无人值守完成整个集成和发布过程。
工欲善其事必先利其器,首先我们必须要在 Jenkins 上安装插件 :
& X' |( q; s' \3 L" s* B* k$ ~' K* E
  • Pipeline Plugin(如果使用Jenkins2.0默认安装)
  • Git
  • Sonar Scaner
  • Docker Pipeline Plugin
  • Marathon
    ( q7 o+ u9 L5 ?( x+ S4 E
如果你第一次接触 Jenkins Pipeline,可以从https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md找到帮助。
现在,我们开始编写 Groove 代码。基于容器编排的 Pipeline 分为如下几个步骤:
1.检出代码
这个步骤使用 Git 插件,把开发好的代码检出。
stage('Check out')
8 {1 c2 }/ c& [" P  gitUrl = "git@gitlab.xxxx.com:xxx.git"
  n( H2 S0 Q' G  git branch: "dev", changelog: false, credentialsId: "deploy-key", url: gitUrl2 @( p, w# n" M& `5 m
2.maven 构建 Java 代码
由于我们使用的是 spring boot 框架,生成物应该是一个可执行的 jar 包。
stage('Build')
' I* k6 _  e& |( P9 @  sh "${mvnHome}/bin/mvn -U clean install"3. 静态代码分析
通过 Sonar Scaner 插件,通知 Sonar 对代码库进行静态扫描。
stage('SonarQube analysis')0 U. ~! L0 w. [5 z- p8 \
   // requires SonarQube Scanner 2.8+. u! ^8 g- z, R# C
   def scannerHome = tool 'SonarQube.Scanner-2.8';+ x/ c5 R3 M( ^4 _
   withSonarQubeEnv('SonarQube-Prod') {/ H8 l. h+ ~8 z' T" {- w
     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"; q; B/ n( U* r9 _0 G
   }
+ X0 x! e$ D5 u% \/ v8 ?
4.制作 Docker 镜像1 k- D$ q, h4 a0 r- ?% q6 B
此步骤会调用 Docker Pipeline 插件通过预先写好的 Dockerfile,把 jar 包和配置文件、三方依赖包一起打入 Docker 镜像中,并上传到私有 Docker 镜像仓库中。
stage('Build image')
4 _9 p2 H0 ]6 Q( i  docker.withRegistry('https://dockerhub.xxx.com', 'dockerhub-login') {7 l7 ^7 P3 T" C5 C! X
    docker.build('dockerhub.xxx.com/xxxx').push('test') //test是tag名称7 L, d8 Y* I% ]$ h* p
  }5.部署测试环境
通过事先写好的部署文件,用 Marathon 插件通知 Marathon 集群,在测试环境中部署生成好的镜像。
stage('Deploy on Test'), y; t: i& }8 v" B/ [
    sh "mkdir -pv deploy"
  R" `: ^% v7 A    dir("./deploy") {! [' B9 y! o& a1 N: a5 g, r
        git branch: 'dev', changelog: false, credentialsId: 'deploy-key', url: 'git@gitlab.xxx.com:lms/xxx-deploy.git'; j0 p, x" J: k: d0 s
        //Get the right marathon url
( n, i8 ~( r, ^; P, z5 o2 L        marathon_url="http://marathon-qa"
  k8 T4 J1 o, O+ X& d        marathon docker: imageName, dockerForcePull: true, forceUpdate: true, url: marathon_url, filename: "qa-deploy.json"
+ ?* n) ^  [- s$ z    }: D* u9 L+ K* |% S2 y1 N$ f  U
6.自动化测试
! d. N3 M; p2 [
运行事先测试人员写好的自动化测试脚本来检验程序是否运行正常。
stage('Test')
; m4 x4 ~! j: U1 @   // 下载测试用例代码
  R8 p% u/ H. E9 U% ~6 e2 |   git branch: 'dev', changelog: false, credentialsId: 'deploy-key', url: 'git@gitlab.xxx.com:lms/xxx-test.git'
* g  C0 O3 F- z2 C+ u3 e   parallel(autoTests: {7 f% \/ r: y. \( P  e$ G
        // 使用nosetests 运行测试用例7 Q( B2 N& f0 ?
        sh "docker run -it --rm -v $PWD:/code nosetests nosetests -s -v -c conf\run\api_test.cfg --attr safeControl=1"# r& B3 ~/ y5 R  e
   },manualTests:{. X3 r4 A( a* X, p& l
        sleep 300002 q4 x' G: [5 U6 q9 L* }
   })
& m/ ]' I$ `7 W! G' x& v8 G
7. 人工测试
9 C! B) `/ ^' N- I/ w2 }- x- h
如果对自动化测试不放心,此时可选择结束 Pipeline,进行人工测试。为了说明整个流程,我们这里选择跳过人工测试环节。
8. 部署生产环境
当所有测试通过后,Pipeline 自动发布生产环境。
stage('Deploy on Prod')) A" e% B! v5 ]# O
    input "Do tests OK?"
. ^1 N/ b0 F7 c) L  E7 O3 i+ i    dir("./deploy") {% e2 G8 N1 @2 u
        //Get the right marathon url
1 O; E# v: p8 C        marathon_url="http://marathon-prod"
# m4 ?2 V) m* ^3 B0 w7 M        marathon docker: imageName, dockerForcePull: true, forceUpdate: true, url: marathon_url, filename: "prod-deploy.json"4 }* D; Z. e* z1 A5 B; Q) \) V
    }& C- C+ Z+ j) f, u
0 ~6 H- r# I% f: F- A3 F
最后我们来看看整个 Pipeline 的过程:
0?wx_fmt=png.jpg
容器编排配置文档化
在介绍敏捷开发时,曾介绍过根据不同环境的配置参数部署到不同的环境。如何告知部署程序用什么样的配置文件启动服务,每个环境又用多少 CPU,内存和 instance 呢?) G8 b( E7 y- y1 j
下面我们就来介绍一下容器编排的配置文件。由于我们使用 Mesos+Marathon的容器编排方式,部署的重任从以前的写部署脚本变成了写一个 Marathon 的配置,其内容如下:
{* b- G* A9 b3 H
  "id": "/appName",
2 D" k1 y- u9 [7 C  "cpus": 2,
  M" k6 \$ Y& h, W5 I8 v  k  "mem": 2048.0,  j; d  e. c+ y- ?, [( C$ F
  "instances": 2,
$ n- V- E' e" ~' E" O  Z  "args": [, j* u' ~4 \( t% I& \% ^
    "--spring.profiles.active=qa"
4 A# c  M; l* B$ ]  ],
' R7 `5 {: ?9 V  z  "labels": {0 X3 N: {$ j# [1 W8 V" f
    "HAPROXY_GROUP": "external",
: h* |/ Z  S# m) L    "HAPROXY_0_VHOST": "xxx.hujiang.com"- S& A1 H4 {7 v( U; ?. P* X4 V
  },
, h9 K; m/ G9 N8 B- I; r. `, o  "container": {) X/ A9 P: I* a
    "type": "DOCKER",
8 H, {/ ~# ~/ R$ T5 Y' d  M    "docker": {& D' M! `& S! g" m, M8 ^! D- n- D
      "image": "imageName",
! ~" ]$ M8 s- j9 r7 R5 D      "network": "USER",
. B+ i, ]* `% V5 D) A      "forcePullImage": true,& g; U7 k8 r4 U7 @: N( x# S+ _  Y
      "portMappings": [3 W( L, N+ w( P5 e6 k6 y
        {
# i; R" `; u# L/ [          "containerPort": 12345,
" ?( u) p! s4 m7 j# Q/ P          "hostPort": 0,- }; s; V( w- W# d6 O$ U5 `
          "protocol": "tcp",+ V/ K; T/ Z1 r" v7 G3 q1 T
          "servicePort": 12345
: {, Q1 `) ^' f, ]        }
3 s/ A( j6 K) X  S' ?* m      ]
; c- p- u/ r% u- `/ H: j    },
2 \* J8 j$ o3 _5 G" |& X! P    "volumes": [/ `  U0 k. e+ a% T! }6 R2 s
      {
' P/ l% H) H* o: v% j: k        "containerPath": "/app/log",
( m! C" M; Q0 Z8 O. ]6 O* l' H        "hostPath": "/home/logs/appName",
6 E3 \# ]* w9 f& ^* x4 b# U: w, G# N/ n5 H        "mode": "RW"
" z$ B6 Y0 g. ]5 P4 S      }
5 K, K6 _8 ?4 {& A    ]/ Q# y& x& C3 r
  },/ Z- B3 y! u, x' Y) P8 K7 Y9 \
  "ipAddress": {; h$ b  D7 d8 H: F
    "networkName": "calico-net"/ J. b8 w8 d) C1 H" t8 C( M
  },; u9 N6 L; n3 ^7 m+ X9 \
  "healthChecks": [6 D1 r6 E- J- b! ?3 z% y1 s3 v
    {
2 T7 D) M1 f" n% V1 J      "gracePeriodSeconds": 300,
1 }% `4 y) x+ ~* {: K& h& i( u      "ignoreHttp1xx": true,
3 s4 h" q6 S/ ?3 H6 T% D0 k      "intervalSeconds": 20,& P8 s# N, ]1 D7 Z* W9 C9 I
      "maxConsecutiveFailures": 3,& X( F% ~* H; p" B  N$ E# j5 b
      "path": "/health_check",7 \1 ?0 y# P( p& W+ Z: c
      "portIndex": 0,; u. T  Z, |, w( C' \6 t
      "protocol": "HTTP",
5 c& A3 X# H% |7 I( g5 F% `) H# K      "timeoutSeconds": 20; V- A& P( G: `5 h
    }, `& S- G+ H6 O& e% T1 u
  ],; ~6 d- ^+ O4 O; C; Q) ?$ u
    "uris": [- X' J. ~  h' U4 i  J
    "file:///etc/docker.tar.gz"
# z7 @. x) d  J8 |8 K  ]
4 R1 N# j- x3 z) Q7 h4 U8 Y+ C( u}
我们把这个配置内容保存为不同的 json 文件,每个对应的环境都有一套配置文件。例如 Marathon-qa.json,Marathon-prod.json。当 Pipeline 部署时,可以通过Jenkins Marathon 插件,根据选择不同的环境,调用部署配置,从而达到自动部署的目的。
自动化流程和部署上线分离与管理
开发部署如此的简单快捷,是不是每个人都能方便的使用呢?答案是否定的,并不是因为技术上有难度,而是在于权限。在理想的情况下,通过这套流程的确可以做到在提交代码后,喝杯咖啡的时间就能看见自己的代码已经被千万用户使用了。
但风险过大,我们并不是每个人都能像 Rambo 一样 bug 的存在,大多数的情况还需要使用规范和流程来约束。就像自动化测试取代不了人工黑盒测试一样,部署测试后也不能直接上生产环境,在测试通过后还是需要有个人工确认和部署生产的过程。
所以我们需要把自动化流程和最后的部署上线工作分开来,分别变成两个 Job,并给后者单独分配权限,让有权限的人来做最后的部署工作。这个人可以是 Team leader、开发经理,也可以是运维伙伴,取决于公司的组织结构。
那这个部署的 Job 具体干什么呢?在容器编排时代,结合镜像既构建物的思想,部署 Job 不会从代码编译开始工作,而是把一个充分测试且通过的镜像版本,通过 Marathon Plugin 部署到产线环境中去。这里是 Deploy_only 的例子:
node('docker-qa'){0 T& \  I- m. ~& b7 t! ]
    if (ReleaseVersion ==""){
$ D" f' M; M8 ?1 o        echo "发布版本不能为空"' Z. U. x% k/ V! r. p# E
        return
/ |8 V' D! H5 L, q1 l4 O+ W3 {    }8 _& t0 j& y0 }: o2 j" l
    stage "repare image"
8 S8 o# }3 ]; K4 x6 Y        def moduleName = "${ApplicationModule}".toLowerCase()! u6 E* p3 Y  g6 u' O4 _: y
        def resDockerImage = imageName + ":latest"
4 |5 S! j( Y6 ~, E0 V/ g1 w6 Y        def desDockerImage = imageName + "{ReleaseVersion}"; @- G/ }( F8 {. f; B. I8 k
        if (GenDockerVersion =="true"){
3 J& e. k5 T0 O& u            sh "docker pull ${resDockerImage}"% |8 k. A0 a6 a. m
            sh "docker tag ${resDockerImage} ${desDockerImage}"
% |7 K' B" D6 u, U            sh "docker push ${desDockerImage}"' H8 N$ |; I( C- k7 k) D% U; }
            sh "docker rmi -f ${resDockerImage} ${desDockerImage}"
1 Z# \8 L- V' @; }' Z( X0 d        }3 Q) Z: G0 D) v, [; P3 K
     
  h( C7 @* M" f# x# G% i2 m4 c% V    stage "Deploy on Mesos"
4 g; T0 i3 c* F; B        git branch: 'dev', changelog: false, credentialsId: 'deploy-key', url: 'git@gitlab.xxx.com:lms/xxx-test.git'  
5 O; K/ k6 @3 [% P        //Get the right marathon url
2 h  Y5 V4 p* s( g1 N1 [        echo "DeployDC: " + DeployDC
% N" t* g. k0 F0 u        marathon_url = ""
* B5 z& D6 a$ ?& g8 `        if (DeployDC=="AA") {& |+ m. I. L/ `7 l
            if (DeployEnv == "prod"){
2 E. Z6 m' T# a* U  A) i. j/ E& Z+ S              input "Are you sure to deploy to production?"
1 R- [. }4 X! f% J              marathon_url = "${marathon_AA_prod}"/ ~  O, e8 t% n8 E/ B
            }else if (DeployEnv == "yz") {
- c, {7 }2 _  w3 _1 ]( I              marathon_url = "${marathon_AA_yz}", @" u$ c: k  a
            }+ [! u  A$ \7 S
        }else if ("${DeployDC}"=="BB"){
& n* ~8 L. {6 `: r# e          if ("${DeployEnv}" == "prod"){( _1 d' ?' Q6 S- ~) p# y
            input "Are you sure to deploy to production?"
/ c. S- [5 m( D* g! o            marathon_url = "${marathon_BB_prod}"
2 M; r+ _' A' v6 A8 }, \3 o          }else if ("${DeployEnv}" == "yz") {- U4 G; G2 }0 P: y
            marathon_url = "${marathon_BB_yz}"
) X) r5 k# t+ a          }
( E, Z; c) w, s% d) C( K        }
$ p. E9 q* Z+ h) O" Z2 h- ~* s        marathon docker: imageName, dockerForcePull: true, forceUpdate: true, url: marathon_url, filename: "${DeployEnv}-deploy.json"; q3 u) J5 S2 u8 M0 J$ N8 D2 {
}  I" N( Z3 W& `" K- f, ]) H& b
为什么不把这个文件跟随应用项目一起放到 scripts 下呢?因为把部署和应用分开后,可以由两拨人进行维护,兼顾公司的组织架构。. e0 V- d8 f# t' d
自动化运维在 DevOps 的最后阶段是运维阶段。在容器时代,如何对庞大的镜像制品进行运维呢?我们的目标是尽量实现自动化运维,这里主要讲述两点:容器的监控
容器的监控大致有两种方式:物理机上安装其他服务监控本机上的所有容器;通过 Mesos 或 kubernates 自带 API 监控容器状态。两种方式其实都需要在物理机上安装相应的监控软件或 Agent。
在我们团队目前使用 cAdvisor+influxDB+Grafana 的组合套件实现对容器的监控。
首先需要在 Mesos 集群中所有的 Agent 安装 cAdvisor 。他负责把宿主机上所有运行中的容器数据以数据点(data point)形式发送给时序数据库(influxDB),下面是 cAdvisor 监控的一些数据点:
$ H6 }6 f  D. _- w7 D6 {
0?wx_fmt=png.jpg
这些数据点经过 Grafana 整理,展示在界面上,这样我们就能掌握具体容器的性能指标了。下面是一个 Grafana 的截图:

6 ^2 i( K5 J; v( A
0?wx_fmt=png.jpg

5 }# X& D# A! B: u$ q 除了对容器本身的监控,宿主机的监控也是必不可少的。由于监控的点有很多,这里不一一例举。
自动伸缩有了监控指标只是实现了自动化运维的第一步,当业务请求发生大量增加或减少,通过人工监测是不能及时的进行相应的,况且还不一定有那么多的人,7×24 小时的监控。一定需要有一套根据监控数据自行伸缩容的机制。在学习产品线,我们针对容器编排的 Mesos+Marathon 框架,开发了一套针对应用本身的自动扩容微服务。其原理如下:
: F3 H, I8 `0 |& {; f
0?wx_fmt=png.jpg
  • 通过 Restful 的接口通知 AutoScaler 程序需要监控的应用服务。
  • AutoScaler 程序开始读取每台 Agent 上部署相关应用的 Metrics 数据,其中包括 CPU,内存的使用状况。
  • 当发现有应用过于繁忙(其表现形式大多是 CPU 占用过高或内存占用过大)时调用 Marathon API 将其扩容
  • Marathon 收到消息后,立刻通知 Mesos 集群发布新的应用,从而缓解当前的繁忙状况。
      G) E7 d" a) E3 x% e
结束语
DevOps 和 SRE 并不是一个渴望而不可及的概念,它们需要在不同的环境中落地。我们整个 DevOps 流程是建立在容器编排的基础上的,目的是简化流程和实现自动化 CI/CD 和自动化运维。当中会有很多没有想到的地方,可能也不太适用于复杂场景。其次,本文中的例子也做了相应的隐私处理,可能无法直接使用。希望大家能通过我们在实践中产生的成功和遇到的问题,提炼出适合自己的 DevOps 流程。

7 v2 w4 G/ W( {: R" u
原创:黄凯

& w- n( H: A, j7 g

本版积分规则

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

QQ|小黑屋|手机版|Archiver|艾拓先锋网 ( 粤ICP备11099876号-1|网站地图

Baidu

GMT+8, 2018-12-13 01:29 , Processed in 0.267709 second(s), 33 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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