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

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

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

QQ登录

只需一步,快速开始

扫一扫,访问微社区

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

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

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

参加活动:0

组织活动:12

发表于 2017-8-17 15:40:51 | 显示全部楼层 |阅读模式 来自- 广东广州
随着 DevOps 和 SRE 概念的流行,越来越多的 developer 和 operater 们摒弃传统的开发部署流程,转向了如下图所示的无线循环模式:
在我理解 DevOps 包含三个大块:敏捷开发(Agile)、持续集成与交付(CI/CD)、自动运维(ITSM)。
: z/ [& N1 k+ x1 f7 ^. V
在容器化的时代,我们是如何实现 DepOps 或者 SRE 的呢?下面我就来分享一下沪江学习产品线团队基于容器编排的 DevOps 流程。
敏捷开发
大道至简,所有血的教训告诉我们,不要把简单的事情复杂化。换句话说,不要用复杂的方法处理简单的事情。我对敏捷的理解是「快」和「微」。快指迭代快,开发快,上线快,性能快。微指微服务、微镜像。围绕这两点,在开发阶段我们需要做以下几件事:
应用微服务化
这是个比较大的概念,不在这里讨论,有兴趣可以参考我的其他文章。但只有应用小了,才有可能快起来。
给 Docker 镜像瘦身为了让 Docker 启动和运行得快,首先就是要对 Docker 瘦身。由于所有的应用全部会统一为 Java 语言开发,所以我们以 Java 为例,选用了 jre-alpine 作为我们的基础镜像,下面是 Dockerfile 的例子:FROM java:8-jre-alpine
! ?& ^# b  v# V0 x+ a' L  . N# _5 ?5 w1 J5 a: @5 U( _3 o
#add timezone and default it to Shanghai
8 R4 g3 k* i( [" zRUN apk --update add --no-cache tzdata# w  {8 L* s- t% n% f+ L) G  c
ENV TZ=Asia/Shanghai4 j/ S* _+ w+ o- L1 M
  
) ?! ^, }" G( b! X+ L5 B- dRUN mkdir -p /app/log
* p; G0 j* ], I( o' X! DCOPY  ./target/xxx.jar  /app/xxx.jar
1 f; F1 q. f5 W1 r- _  - E- I6 w7 ~$ u. v* D- j
EXPOSE 9999- |) l  f7 T9 L, q) D
VOLUME ["/app/log"]' C0 X7 ^# x' y: u% y+ [# p: l
WORKDIR /app/
: H9 _- J4 h  ?1 A, A  0 b% K+ {, N& L
ENTRYPOINT ["java","-Xms2048m", "-Xmx2048m", "-Xss512k", "-jar","xxx.jar"]5 e9 s& f7 V2 H+ ]6 [4 l
CMD []
使用上述 Dockerfile 生成的镜像平均只有 80 多 MB,启动时间几乎在 5 秒内。使用 alpine 镜像虽然减小了体积,但缺少一些工具命令,例如 curl 等,可以根据需要酌情安装。另外遇到的一个坑是时区问题:由于 Docker 镜像内的时区是 UTC 时间,和宿主机的东 8 区不一致,所以必须安装 timezone 工具并设置 TZ,才能使容器内时间和宿主机保持一致,对数据库的写入和日志的输出都是非常必要的一环。
把所有环境配置包含在镜像中
早在虚拟机时代,我们已经做到了使用包含依赖的虚拟机镜像来加速部署,那么为什么要止步于此呢?我们可以更进一步,把服务本身也包含在镜像中,Docker 用了更轻量的方式已经实现了这一点。
这里我们还要介绍一个概念,要让制作的镜像,能在所有安装了 Docker 的服务器上运行,而不在乎宿主机的操作系统及环境。借用 Java 的一句话来说:一次制作,多平台运行。所以,我们还会把所有环境的配置文件,以不同的文件名全部放入镜像中,通过参数来选择 Docker 启动时使用的环境配置文件。
值得注意的是,如果开发的应用是基于 spring 框架的话,这个功能很好实现。但如果是其他语言开发,会有一定的开发量。
本文以默认 Java 开发当所有的开发工作完成后,推荐程序目录结构是这样的:
0 G9 e5 H  r% ?" u) k+ O
├── src7 F) }* I6 X9 S
│   ├── main3 N0 c; W" o/ F7 Y
│   │   ├── java3 t: j0 S1 m- r7 ?( F
│   │   ├── resources
3 Q( E- R' x3 L1 H│   │   │   ├── application.yaml- c, ^  m* w1 g3 S; {+ F. @
│   │   │   ├── application-dev.yaml7 y! ?$ X/ m# k7 M4 |" u1 B- n7 d
│   │   │   ├── application-qa.yaml" L/ q. ]6 Y$ C" G% u9 H1 U' `
│   │   │   ├── application-yz.yaml; J$ S- ?6 x0 C- E
│   │   │   ├── application-prod.yaml  s' r& d* M5 r; L% _! Q
│   │   │   ├── logback.xml4 {8 J& i6 m) k. ~7 r1 Y, f
│   ├── test/ P1 \- Z4 s: ^
├── scripts% a0 I4 |5 K" B2 x( b
│   ├── Dockerfile
" l- ^$ b9 S" U6 {│   ├── InitDB.sql
2 |* S+ e5 r0 z1 b├── pom.xml
持续集成与交付
自动化的持续集成和交付在整个 DevOps 流中起了重要的角色,他是衔接开发和运维的桥梁。如果这一环做的不好,无法支撑大量微服务的快速的迭代和高效运维。在这一环节,我们需要灵活的运用工具,尽量减少人参与,当然仍然需要围绕「快」和「微」做文章。
如何减少人工参与到持续集成与持续交付呢?我们最希望的开发过程是:对着计算机说出我们的想要的功能,计算机按照套路,自动编码,自动发布到测试环境,自动运行测试脚本,自动上线。当然,目前时代要实现自动编码的过程还需要发明那只「猫」。
但只要对测试有足够信心,我们完全可以实现一种境界:在炎热的下午,轻松地提交自己编写的代码,去休息室喝杯咖啡,回来后看见自己的代码已经被应用在生产环境上了。在容器时代,我们可以很快速的实现这一梦想,其具体步骤如下图:
& e, ^' K  i9 w/ e% }

/ u' _. C% V# S  ^$ S3 a3 O: A

4 ^- g5 Y5 m! d0 C, O
Gitfolw 与 Anti-Gitflown
3 t1 Z3 E9 l9 w3 T9 z: H; g  j
持续集成的第一步是提交代码(Code Commit),VCS 也由 CVS,SVN 进化到如今的 Git,自然不得不说一下 Gitflow。谈起无人不晓的 Gitflow,大家一定会大谈其优点:支持多团队,设置多国家的开发人员并行开发,减小代码冲突或脏代码的上线概率。它的大致流程如下:

; O  Y) Z; N; Z: W7 f
Gitflow 给我们展示了复杂团队在处理不通代码版本的优雅解决方案,它需要feature、develop、release、hotfix、master 5 条分支来处理不同时段的并行开发。但这真的合适于一个不超过 20 人的本地合作团队开发吗?我们的开发团队不足 6 人,每个人负责 3 个以上的微服务,几乎不可能在同个项目上安排两个以上的同学并行开发。
) N9 d4 B. j: @3 @$ o  I  U
在初期我们准守规定并使用标准的 Gitflow 流程,开发人员立刻发现一个问题,他们需要在至少 3 条分支上来回的 merge 代码,且不会有任何代码冲突(因为就一个人开发),降低了开发的效率。这让我意识到,Gitflow 模式也许并不适合于小团队微服务的世界,一种反 Gitflow 模式的想法出现在脑海中。我决定对Gitflow 进行瘦身,化繁至简。

$ X. f! {- g! A! f: B4 k3 f

& F2 \- M8 W- |& c/ A
我们把 5 条分支简化为 3 条分支,其中 Master 分支的作用只是维护了最新的线上版本的作用,Dev 分支为开发的主要分支,所有的镜像是以此分支的代码为源头生成的。这时开发的过程变为:

! N+ Y0 a% L: I) W9 Z1 d
  • 开发人员从 Dev 分支中 checkout 新的 feature 分支,在 feature 分支上进行开发
  • 当开发完成后 merge 回 Dev 分支中,根据 Dev 分支的代码打成镜像,部署 QA 环境交给 QA 人员测试
  • 测试中如有 bug 便在新分支中修复问题循环步骤 2
  • 测试完成 merge 回 Master 分支
    8 H; p% ?- j, ~. @' g" C7 E3 u0 b8 Z
如此一来,只有从 Feature 把代码 merge 到 Dev 分支的一次 merge 动作,大大提升可开发效率。
使用Jenkins Pipeline
Jenkins 作为老牌 CI/CD 工具,能够帮我们自动化完成代码编译、上传静态代码分析、制作镜像、部署测试环境、冒烟测试、部署上线等步骤。尤其是Jenkins2.0 引入 Pipeline 概念后,以上步骤变的如此行云流水。它让我们从步骤 3 开始,完全可以无人值守完成整个集成和发布过程。
工欲善其事必先利其器,首先我们必须要在 Jenkins 上安装插件 :
& a: i1 d2 g/ m2 R- G
  • Pipeline Plugin(如果使用Jenkins2.0默认安装)
  • Git
  • Sonar Scaner
  • Docker Pipeline Plugin
  • Marathon

    , b( }4 p  F3 r$ Z% T. W/ K; \
如果你第一次接触 Jenkins Pipeline,可以从https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md找到帮助。
现在,我们开始编写 Groove 代码。基于容器编排的 Pipeline 分为如下几个步骤:
1.检出代码
这个步骤使用 Git 插件,把开发好的代码检出。
stage('Check out')! Y9 z: ^/ W8 z2 h2 s
  gitUrl = "git@gitlab.xxxx.com:xxx.git"
4 J7 q. T, ^( e' T  git branch: "dev", changelog: false, credentialsId: "deploy-key", url: gitUrl
% Z/ t7 `! F; N" ~
2.maven 构建 Java 代码
由于我们使用的是 spring boot 框架,生成物应该是一个可执行的 jar 包。
stage('Build')
( ~; ~9 N% F. t9 K5 \  sh "${mvnHome}/bin/mvn -U clean install"3. 静态代码分析
通过 Sonar Scaner 插件,通知 Sonar 对代码库进行静态扫描。
stage('SonarQube analysis')
4 c* i' p# B6 [8 w   // requires SonarQube Scanner 2.8+
+ L8 z: r+ Q. J3 {. ^   def scannerHome = tool 'SonarQube.Scanner-2.8';
4 y( u1 r: D% a  ]7 l& }/ k' O   withSonarQubeEnv('SonarQube-Prod') {1 B7 V% e; T; l! i
     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"* O4 \! O% K% m9 s7 L6 A0 T
   }
; r- Q% |% I, q) b6 S6 o4 K$ G% @
4.制作 Docker 镜像
. b. n" x9 Y, O" R/ J
此步骤会调用 Docker Pipeline 插件通过预先写好的 Dockerfile,把 jar 包和配置文件、三方依赖包一起打入 Docker 镜像中,并上传到私有 Docker 镜像仓库中。
stage('Build image')
% q: z* j. Q, b" b  docker.withRegistry('https://dockerhub.xxx.com', 'dockerhub-login') {
! a: O3 p! G- D, c" Z8 r    docker.build('dockerhub.xxx.com/xxxx').push('test') //test是tag名称
/ U' N) A0 m/ @3 O) I  R8 _  }5.部署测试环境
通过事先写好的部署文件,用 Marathon 插件通知 Marathon 集群,在测试环境中部署生成好的镜像。
stage('Deploy on Test')
) f0 p" w: b, h2 N# L  w    sh "mkdir -pv deploy") p: a; `0 o$ d5 Y! Q
    dir("./deploy") {
3 Z4 u1 B# E4 L1 Z7 Q        git branch: 'dev', changelog: false, credentialsId: 'deploy-key', url: 'git@gitlab.xxx.com:lms/xxx-deploy.git'
6 ?1 g9 T' U) J3 ~        //Get the right marathon url
0 Q& ~& j5 Q) @& Z# E5 u        marathon_url="http://marathon-qa"9 |- u/ ]7 j2 v$ |
        marathon docker: imageName, dockerForcePull: true, forceUpdate: true, url: marathon_url, filename: "qa-deploy.json"
0 q0 X8 _6 s, c" {    }
6 v8 b) A! H. }8 @) `0 ^, e; Y
6.自动化测试; |/ B6 W& \- Z5 K9 C
运行事先测试人员写好的自动化测试脚本来检验程序是否运行正常。
stage('Test')% }: E) f  m0 [/ h5 g; ^8 ~' E
   // 下载测试用例代码6 E6 t5 f$ k0 k" Z  a
   git branch: 'dev', changelog: false, credentialsId: 'deploy-key', url: 'git@gitlab.xxx.com:lms/xxx-test.git'
3 ?; k2 u& J; J' U   parallel(autoTests: {( h; ]6 @/ g/ U+ }3 H
        // 使用nosetests 运行测试用例% U2 ]$ y4 _# x1 }
        sh "docker run -it --rm -v $PWD:/code nosetests nosetests -s -v -c conf\run\api_test.cfg --attr safeControl=1"9 c+ e& ~: d) T* v4 z6 }
   },manualTests:{
5 _  Q3 c2 O* e9 G) [6 e2 H: d        sleep 30000+ g( g* F# z6 N' D3 H' o& J: g, v; v
   })
) p! @4 W4 N, N7 h2 O& Y2 r5 O
7. 人工测试
. P! I4 q( m4 F& B0 F' F/ T
如果对自动化测试不放心,此时可选择结束 Pipeline,进行人工测试。为了说明整个流程,我们这里选择跳过人工测试环节。
8. 部署生产环境
当所有测试通过后,Pipeline 自动发布生产环境。
stage('Deploy on Prod')- ^$ `6 M  B# O3 E2 [
    input "Do tests OK?"
0 k, M8 j! F9 w% T8 i' ~7 c2 E  V    dir("./deploy") {
) U/ i3 ]4 Q& E8 u* ], U        //Get the right marathon url5 W& ~3 L8 Y. ^' ]" W- }
        marathon_url="http://marathon-prod"
2 w1 |0 P1 c5 c, d5 A( u        marathon docker: imageName, dockerForcePull: true, forceUpdate: true, url: marathon_url, filename: "prod-deploy.json"
8 c' }1 R4 q8 J( R( h- L1 I    }
8 X7 Q. P! r, ~. _5 V
: m: b& }1 Z& e8 l
最后我们来看看整个 Pipeline 的过程:
容器编排配置文档化
在介绍敏捷开发时,曾介绍过根据不同环境的配置参数部署到不同的环境。如何告知部署程序用什么样的配置文件启动服务,每个环境又用多少 CPU,内存和 instance 呢?8 B5 P# S% b# m' x/ g) D
下面我们就来介绍一下容器编排的配置文件。由于我们使用 Mesos+Marathon的容器编排方式,部署的重任从以前的写部署脚本变成了写一个 Marathon 的配置,其内容如下:
{# t& e% `8 v1 {/ D4 h. w2 g8 }9 j
  "id": "/appName",8 k4 _, J3 m4 E' j
  "cpus": 2,- s2 v% i/ a: j  Q6 X; m
  "mem": 2048.0,8 A% @3 l8 g5 H$ h$ f. k6 V
  "instances": 2,( b; y  l9 U5 ]& o
  "args": [
4 e) p. ]3 x: r1 D) J" b    "--spring.profiles.active=qa"
' E: M! ^. W- T3 I4 o: p  ],
. l1 L8 s2 h$ g+ s- p- b2 i6 ^  "labels": {' T' F" p7 r8 c( C2 _
    "HAPROXY_GROUP": "external",2 u% j% M; m; V" T2 `- e
    "HAPROXY_0_VHOST": "xxx.hujiang.com"
' Z! t2 W4 v9 _# {9 }  },
, K' `3 g" Q& y4 A2 K. Q  o  "container": {% C! W3 M% p1 T
    "type": "DOCKER",' I: f0 @  I; C& h( [, b
    "docker": {, S% E+ }2 m, E
      "image": "imageName",7 g/ N( A  C1 H2 g- p) G' x
      "network": "USER",  s' m, O' w. `5 I( C
      "forcePullImage": true,
+ k) X7 r/ `6 V      "portMappings": [# z) S1 l& R2 h$ c! F4 S3 Z" N/ B
        {- K/ R0 B5 L1 I' ?5 ?! s8 ~. Q! M2 {
          "containerPort": 12345,+ ]/ f& Z* V$ V& J
          "hostPort": 0,! u& _' w! y3 F; C' b8 J/ p
          "protocol": "tcp",
* [! U; I& G" d( x$ V          "servicePort": 12345
% U; u) y# Y5 d: f) J        }
( U1 r) e0 v9 l/ y0 u" ]2 f2 U4 f      ]
6 P- V- y; O8 C6 R2 M6 T    },
" K4 k$ v' z! k) {    "volumes": [
0 A  o# {9 `3 r9 Z* Y: U      {- ?, ^% `  q9 c5 r, c
        "containerPath": "/app/log",
7 j  w8 M6 S( ^4 e2 q        "hostPath": "/home/logs/appName",
; }/ k7 h  ?8 L        "mode": "RW"3 V* p: G9 e- e9 v9 ]
      }
# P" G8 F% s* H( x  s8 l    ]. i6 X9 ~3 C# A) V. p
  },6 m: r( G+ F: \+ X- u
  "ipAddress": {
* _  s5 P: @' \+ j    "networkName": "calico-net"5 Z* k3 m. n7 y! p& ]& k& I
  },
& l# p( i% d  {# z3 R" ~. _4 R  "healthChecks": [; d" H' I# Z8 l
    {' M8 ?7 F: y, Z( w0 T
      "gracePeriodSeconds": 300,
# J4 _$ e( ~: q6 q* I- N      "ignoreHttp1xx": true,
' q& S4 V& V# j2 @# d5 g% K, Q      "intervalSeconds": 20,
1 d! C/ W  k/ H- h6 j1 T: y      "maxConsecutiveFailures": 3,- P* z# ^9 y$ ^& f& D+ D! `( ^( P/ a
      "path": "/health_check",, J' q5 A8 C5 a' _
      "portIndex": 0,2 @/ s7 W5 _( a# f$ x7 g& V  i
      "protocol": "HTTP",
# f* x4 Z  R3 C& E' H+ e      "timeoutSeconds": 20. |8 I- K- C4 ]+ C
    }
, z" t6 a+ D; w9 W! r9 n9 S( ?  ]," @9 ~1 i' h$ ^1 }0 i
    "uris": [
. L; a9 g3 y8 J9 M" M* t" \    "file:///etc/docker.tar.gz"& X& u# }4 e/ \5 `9 L+ T6 Y2 D
  ]' X/ q4 W( I" e: |2 P) n' P& ?
}
我们把这个配置内容保存为不同的 json 文件,每个对应的环境都有一套配置文件。例如 Marathon-qa.json,Marathon-prod.json。当 Pipeline 部署时,可以通过Jenkins Marathon 插件,根据选择不同的环境,调用部署配置,从而达到自动部署的目的。
自动化流程和部署上线分离与管理
开发部署如此的简单快捷,是不是每个人都能方便的使用呢?答案是否定的,并不是因为技术上有难度,而是在于权限。在理想的情况下,通过这套流程的确可以做到在提交代码后,喝杯咖啡的时间就能看见自己的代码已经被千万用户使用了。
但风险过大,我们并不是每个人都能像 Rambo 一样 bug 的存在,大多数的情况还需要使用规范和流程来约束。就像自动化测试取代不了人工黑盒测试一样,部署测试后也不能直接上生产环境,在测试通过后还是需要有个人工确认和部署生产的过程。
所以我们需要把自动化流程和最后的部署上线工作分开来,分别变成两个 Job,并给后者单独分配权限,让有权限的人来做最后的部署工作。这个人可以是 Team leader、开发经理,也可以是运维伙伴,取决于公司的组织结构。
那这个部署的 Job 具体干什么呢?在容器编排时代,结合镜像既构建物的思想,部署 Job 不会从代码编译开始工作,而是把一个充分测试且通过的镜像版本,通过 Marathon Plugin 部署到产线环境中去。这里是 Deploy_only 的例子:
node('docker-qa'){
& J: y  c- \# ?: I$ |2 X& y7 R+ ^    if (ReleaseVersion ==""){& J8 {4 v, i, j5 w% Q& d2 L7 a
        echo "发布版本不能为空"
1 K" I+ V1 W. @+ n" q        return
* Q% G9 _8 ^2 R4 E' ^  \) e    }0 I0 Y' \; {/ i# r
    stage "repare image"
1 X1 F5 d1 Q( T        def moduleName = "${ApplicationModule}".toLowerCase()0 B( J; @! h, K3 Q, X
        def resDockerImage = imageName + ":latest"- }7 M1 E3 d3 r, F& @$ O' I
        def desDockerImage = imageName + "{ReleaseVersion}"
2 d5 \+ O! R: D        if (GenDockerVersion =="true"){
, g! T  b# c  O- m8 ~            sh "docker pull ${resDockerImage}"" N$ h0 c7 z7 P( q5 v/ W' _6 X
            sh "docker tag ${resDockerImage} ${desDockerImage}"" @7 M+ ^; k  o6 k. q5 |% B" J$ G
            sh "docker push ${desDockerImage}"3 ?$ A9 @, s" f0 o4 |
            sh "docker rmi -f ${resDockerImage} ${desDockerImage}"# _& `  e2 [' A' _
        }
5 R+ e' _! r5 T     
6 _" z+ w  l4 Y    stage "Deploy on Mesos"
* W1 B- L( o: |  T( d! D. e, n        git branch: 'dev', changelog: false, credentialsId: 'deploy-key', url: 'git@gitlab.xxx.com:lms/xxx-test.git'  
9 B7 I+ ^( p5 C' F( F  f8 }/ k# t        //Get the right marathon url
% M5 [0 a/ Z& p& z+ ]5 G5 v        echo "DeployDC: " + DeployDC
6 r7 \8 J" X7 P! U$ M* Z        marathon_url = ""
! s$ j3 G& ]2 Z5 U" R; B        if (DeployDC=="AA") {" i* V: [- u& [
            if (DeployEnv == "prod"){
7 |+ g! F6 N9 E& ~$ J3 B- e0 d              input "Are you sure to deploy to production?"
* T! r) `  L. {$ J9 l              marathon_url = "${marathon_AA_prod}". g. ]- Y0 `8 U1 W5 o0 W
            }else if (DeployEnv == "yz") {& d' h3 }; H4 n
              marathon_url = "${marathon_AA_yz}"
2 `& O* Y7 K9 a% d5 @' g* h- ]& U0 N# e            }. R3 y- b$ X6 P$ s& s7 m+ M
        }else if ("${DeployDC}"=="BB"){: h( D3 n5 ]0 r: u
          if ("${DeployEnv}" == "prod"){8 x) P8 C1 ^( ?* I. l+ X  S3 q
            input "Are you sure to deploy to production?"! Z3 j* ]- d7 h- T
            marathon_url = "${marathon_BB_prod}"
! J; R5 O5 T  F& r          }else if ("${DeployEnv}" == "yz") {4 Z" Z7 {& x6 {
            marathon_url = "${marathon_BB_yz}". s( o6 A, C$ p& e& h( f7 f
          }1 O) @( }, X" g+ d) W
        }( H- u4 l0 G8 d. |# ?) V) ?
        marathon docker: imageName, dockerForcePull: true, forceUpdate: true, url: marathon_url, filename: "${DeployEnv}-deploy.json"! f: \* w" r& V1 n; w5 I  I+ D
}
5 A. U7 M! e/ o4 V" g
为什么不把这个文件跟随应用项目一起放到 scripts 下呢?因为把部署和应用分开后,可以由两拨人进行维护,兼顾公司的组织架构。5 v( q+ I9 {' W+ Q7 X: w, D6 H
自动化运维在 DevOps 的最后阶段是运维阶段。在容器时代,如何对庞大的镜像制品进行运维呢?我们的目标是尽量实现自动化运维,这里主要讲述两点:容器的监控
容器的监控大致有两种方式:物理机上安装其他服务监控本机上的所有容器;通过 Mesos 或 kubernates 自带 API 监控容器状态。两种方式其实都需要在物理机上安装相应的监控软件或 Agent。
在我们团队目前使用 cAdvisor+influxDB+Grafana 的组合套件实现对容器的监控。
首先需要在 Mesos 集群中所有的 Agent 安装 cAdvisor 。他负责把宿主机上所有运行中的容器数据以数据点(data point)形式发送给时序数据库(influxDB),下面是 cAdvisor 监控的一些数据点:
- H0 y; h2 O! z% v. q: B8 n3 F# }
这些数据点经过 Grafana 整理,展示在界面上,这样我们就能掌握具体容器的性能指标了。下面是一个 Grafana 的截图:
/ }% z7 g5 i' T8 f$ S3 {6 @) l

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

    5 n& D% f7 T$ v6 K
结束语
DevOps 和 SRE 并不是一个渴望而不可及的概念,它们需要在不同的环境中落地。我们整个 DevOps 流程是建立在容器编排的基础上的,目的是简化流程和实现自动化 CI/CD 和自动化运维。当中会有很多没有想到的地方,可能也不太适用于复杂场景。其次,本文中的例子也做了相应的隐私处理,可能无法直接使用。希望大家能通过我们在实践中产生的成功和遇到的问题,提炼出适合自己的 DevOps 流程。
  {0 f' z# m- Q5 e8 r/ S1 A' t  p
原创:黄凯
1 f8 Q* j' x& b0 [( i& r

本帖子中包含更多资源

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

x

本版积分规则

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

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

Baidu

GMT+8, 2018-8-21 23:36 , Processed in 0.253283 second(s), 35 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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