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

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

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

扫描二维码登录本站

QQ登录

只需一步,快速开始

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

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

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

参加活动:0

组织活动:12

发表于 2017-8-17 15:40:51 | 显示全部楼层 |阅读模式 来自- 广东广州
随着 DevOps 和 SRE 概念的流行,越来越多的 developer 和 operater 们摒弃传统的开发部署流程,转向了如下图所示的无线循环模式:
在我理解 DevOps 包含三个大块:敏捷开发(Agile)、持续集成与交付(CI/CD)、自动运维(ITSM)。
/ U" v$ g# y9 ~1 Y$ P
在容器化的时代,我们是如何实现 DepOps 或者 SRE 的呢?下面我就来分享一下沪江学习产品线团队基于容器编排的 DevOps 流程。
敏捷开发
大道至简,所有血的教训告诉我们,不要把简单的事情复杂化。换句话说,不要用复杂的方法处理简单的事情。我对敏捷的理解是「快」和「微」。快指迭代快,开发快,上线快,性能快。微指微服务、微镜像。围绕这两点,在开发阶段我们需要做以下几件事:
应用微服务化
这是个比较大的概念,不在这里讨论,有兴趣可以参考我的其他文章。但只有应用小了,才有可能快起来。
给 Docker 镜像瘦身为了让 Docker 启动和运行得快,首先就是要对 Docker 瘦身。由于所有的应用全部会统一为 Java 语言开发,所以我们以 Java 为例,选用了 jre-alpine 作为我们的基础镜像,下面是 Dockerfile 的例子:FROM java:8-jre-alpine- m; |1 y9 _- }' y; Y4 J$ P
  $ k8 Y0 X0 q9 \$ O9 B2 @' w5 k9 l
#add timezone and default it to Shanghai1 s3 U5 Y6 o( t3 z
RUN apk --update add --no-cache tzdata- _. I( L! @2 m' m6 {& s
ENV TZ=Asia/Shanghai
" W) V& K* f3 w/ m2 A1 |% @  + m7 p/ u9 \* I3 t
RUN mkdir -p /app/log
5 ~- Z, k3 L% Z4 u, s. H" ]COPY  ./target/xxx.jar  /app/xxx.jar, O. s# B5 ]: S: {; \! U8 s
  
1 y, T! F% r: {EXPOSE 9999
4 u% Q+ E, v- gVOLUME ["/app/log"]
/ y& j& P9 D2 Y- m! N2 c8 bWORKDIR /app/* F/ W+ l  |& Z
  / r7 g! Y& v$ h1 I$ ^/ Z) e. h3 W; d
ENTRYPOINT ["java","-Xms2048m", "-Xmx2048m", "-Xss512k", "-jar","xxx.jar"]. }) d# L- O. P5 S
CMD []
使用上述 Dockerfile 生成的镜像平均只有 80 多 MB,启动时间几乎在 5 秒内。使用 alpine 镜像虽然减小了体积,但缺少一些工具命令,例如 curl 等,可以根据需要酌情安装。另外遇到的一个坑是时区问题:由于 Docker 镜像内的时区是 UTC 时间,和宿主机的东 8 区不一致,所以必须安装 timezone 工具并设置 TZ,才能使容器内时间和宿主机保持一致,对数据库的写入和日志的输出都是非常必要的一环。
把所有环境配置包含在镜像中
早在虚拟机时代,我们已经做到了使用包含依赖的虚拟机镜像来加速部署,那么为什么要止步于此呢?我们可以更进一步,把服务本身也包含在镜像中,Docker 用了更轻量的方式已经实现了这一点。
这里我们还要介绍一个概念,要让制作的镜像,能在所有安装了 Docker 的服务器上运行,而不在乎宿主机的操作系统及环境。借用 Java 的一句话来说:一次制作,多平台运行。所以,我们还会把所有环境的配置文件,以不同的文件名全部放入镜像中,通过参数来选择 Docker 启动时使用的环境配置文件。
值得注意的是,如果开发的应用是基于 spring 框架的话,这个功能很好实现。但如果是其他语言开发,会有一定的开发量。
本文以默认 Java 开发当所有的开发工作完成后,推荐程序目录结构是这样的:
! l, |$ t# k4 L0 E
├── src
% l* A1 j, P4 J$ C; d  f│   ├── main9 O. V7 u2 T! ^% b1 Q
│   │   ├── java; P/ y7 @6 g; b# J
│   │   ├── resources# Q9 i6 I! O- V( J& g3 ]
│   │   │   ├── application.yaml
+ A3 t9 u: @5 }$ R│   │   │   ├── application-dev.yaml$ @8 q7 F: ]. B7 t3 }# D
│   │   │   ├── application-qa.yaml( T5 @/ x3 U% h/ A' s# {
│   │   │   ├── application-yz.yaml' Y' M% g3 E  b8 i) @; P
│   │   │   ├── application-prod.yaml4 C" a0 c1 ?- y0 Y) V) b
│   │   │   ├── logback.xml
/ c( z# x, l8 _" Y3 z  t% g│   ├── test' \$ A, H1 o% t; Q# P
├── scripts
& B/ q: c2 ^; {! h  o. R( J│   ├── Dockerfile+ c% f9 a3 B! Z0 \0 Y' `
│   ├── InitDB.sql
  @# h+ t1 R' b$ m. u├── pom.xml
持续集成与交付
自动化的持续集成和交付在整个 DevOps 流中起了重要的角色,他是衔接开发和运维的桥梁。如果这一环做的不好,无法支撑大量微服务的快速的迭代和高效运维。在这一环节,我们需要灵活的运用工具,尽量减少人参与,当然仍然需要围绕「快」和「微」做文章。
如何减少人工参与到持续集成与持续交付呢?我们最希望的开发过程是:对着计算机说出我们的想要的功能,计算机按照套路,自动编码,自动发布到测试环境,自动运行测试脚本,自动上线。当然,目前时代要实现自动编码的过程还需要发明那只「猫」。
但只要对测试有足够信心,我们完全可以实现一种境界:在炎热的下午,轻松地提交自己编写的代码,去休息室喝杯咖啡,回来后看见自己的代码已经被应用在生产环境上了。在容器时代,我们可以很快速的实现这一梦想,其具体步骤如下图:
: f1 \5 e2 W4 A: r$ c& b
5 H( }5 H6 k0 ^( V! u

3 N5 Z7 P) @  [) s! e
Gitfolw 与 Anti-Gitflown
+ O( g$ S7 R0 b2 u; V# L
持续集成的第一步是提交代码(Code Commit),VCS 也由 CVS,SVN 进化到如今的 Git,自然不得不说一下 Gitflow。谈起无人不晓的 Gitflow,大家一定会大谈其优点:支持多团队,设置多国家的开发人员并行开发,减小代码冲突或脏代码的上线概率。它的大致流程如下:

! t6 f8 l6 ~" @) \1 r- S4 v0 d. U9 F6 z
Gitflow 给我们展示了复杂团队在处理不通代码版本的优雅解决方案,它需要feature、develop、release、hotfix、master 5 条分支来处理不同时段的并行开发。但这真的合适于一个不超过 20 人的本地合作团队开发吗?我们的开发团队不足 6 人,每个人负责 3 个以上的微服务,几乎不可能在同个项目上安排两个以上的同学并行开发。
) f$ H0 F) P9 x( r
在初期我们准守规定并使用标准的 Gitflow 流程,开发人员立刻发现一个问题,他们需要在至少 3 条分支上来回的 merge 代码,且不会有任何代码冲突(因为就一个人开发),降低了开发的效率。这让我意识到,Gitflow 模式也许并不适合于小团队微服务的世界,一种反 Gitflow 模式的想法出现在脑海中。我决定对Gitflow 进行瘦身,化繁至简。
- B9 n. y4 E+ _6 J
8 |! D7 J! [9 A0 ]5 R% K
我们把 5 条分支简化为 3 条分支,其中 Master 分支的作用只是维护了最新的线上版本的作用,Dev 分支为开发的主要分支,所有的镜像是以此分支的代码为源头生成的。这时开发的过程变为:
. O: b2 K- }" |, ?
  • 开发人员从 Dev 分支中 checkout 新的 feature 分支,在 feature 分支上进行开发
  • 当开发完成后 merge 回 Dev 分支中,根据 Dev 分支的代码打成镜像,部署 QA 环境交给 QA 人员测试
  • 测试中如有 bug 便在新分支中修复问题循环步骤 2
  • 测试完成 merge 回 Master 分支

    , Y* k; B% y% m% S  e9 x  Z: n
如此一来,只有从 Feature 把代码 merge 到 Dev 分支的一次 merge 动作,大大提升可开发效率。
使用Jenkins Pipeline
Jenkins 作为老牌 CI/CD 工具,能够帮我们自动化完成代码编译、上传静态代码分析、制作镜像、部署测试环境、冒烟测试、部署上线等步骤。尤其是Jenkins2.0 引入 Pipeline 概念后,以上步骤变的如此行云流水。它让我们从步骤 3 开始,完全可以无人值守完成整个集成和发布过程。
工欲善其事必先利其器,首先我们必须要在 Jenkins 上安装插件 :
0 G+ K! {3 D  ^9 p1 c$ Q0 h
  • Pipeline Plugin(如果使用Jenkins2.0默认安装)
  • Git
  • Sonar Scaner
  • Docker Pipeline Plugin
  • Marathon

    4 A$ R$ v" [7 J2 a
如果你第一次接触 Jenkins Pipeline,可以从https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md找到帮助。
现在,我们开始编写 Groove 代码。基于容器编排的 Pipeline 分为如下几个步骤:
1.检出代码
这个步骤使用 Git 插件,把开发好的代码检出。
stage('Check out')
5 h: Z2 M4 }2 X% A& Z  gitUrl = "git@gitlab.xxxx.com:xxx.git"; L1 X8 M" I+ M: T3 T4 q6 M
  git branch: "dev", changelog: false, credentialsId: "deploy-key", url: gitUrl
" F& D/ O/ r$ S% A
2.maven 构建 Java 代码
由于我们使用的是 spring boot 框架,生成物应该是一个可执行的 jar 包。
stage('Build')
* _- ^0 }6 A: t1 g, l1 }2 [% [  A  sh "${mvnHome}/bin/mvn -U clean install"3. 静态代码分析
通过 Sonar Scaner 插件,通知 Sonar 对代码库进行静态扫描。
stage('SonarQube analysis')! l+ ^/ [- Y& b; ~+ ?+ }/ E* `
   // requires SonarQube Scanner 2.8+- W. r! s* b! O4 m. @9 N7 L
   def scannerHome = tool 'SonarQube.Scanner-2.8';" [$ L6 F5 S4 H6 V
   withSonarQubeEnv('SonarQube-Prod') {
! |6 \0 Z9 i/ k$ P% [* j. 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"! _. ~, I# N. n3 H, {/ l, E
   }
, l' @& F3 r7 N, a. x
4.制作 Docker 镜像
+ L0 ~: ]9 l+ D5 K8 R5 N' j& K
此步骤会调用 Docker Pipeline 插件通过预先写好的 Dockerfile,把 jar 包和配置文件、三方依赖包一起打入 Docker 镜像中,并上传到私有 Docker 镜像仓库中。
stage('Build image')
8 Z$ b1 Y% o- p8 Y+ s& ~  docker.withRegistry('https://dockerhub.xxx.com', 'dockerhub-login') {4 G6 S5 M0 E/ ]) |
    docker.build('dockerhub.xxx.com/xxxx').push('test') //test是tag名称
/ N6 D$ r' t& n/ K7 Q% y! G  }5.部署测试环境
通过事先写好的部署文件,用 Marathon 插件通知 Marathon 集群,在测试环境中部署生成好的镜像。
stage('Deploy on Test')
. M& `; m* n! B- K7 U; t$ [+ L    sh "mkdir -pv deploy") d! p$ f8 C' l
    dir("./deploy") {
/ A6 s3 C6 u4 u" U        git branch: 'dev', changelog: false, credentialsId: 'deploy-key', url: 'git@gitlab.xxx.com:lms/xxx-deploy.git'
$ g7 w+ j, J" r9 b  o. a) U# {6 E        //Get the right marathon url4 ]% s4 n9 c* h' ]/ s. E
        marathon_url="http://marathon-qa"
8 n: M/ w8 \0 x5 w        marathon docker: imageName, dockerForcePull: true, forceUpdate: true, url: marathon_url, filename: "qa-deploy.json"! u9 [, z" i! Z; i0 }; e0 @+ z
    }, B# M& R% h0 i9 r* h% S
6.自动化测试" R' q( L4 P  k0 W
运行事先测试人员写好的自动化测试脚本来检验程序是否运行正常。
stage('Test'): Y; }" X: W& h7 M- k8 H
   // 下载测试用例代码0 t. G2 H+ d. v+ `* B: U, k, C" d5 ^$ s
   git branch: 'dev', changelog: false, credentialsId: 'deploy-key', url: 'git@gitlab.xxx.com:lms/xxx-test.git'/ U7 C, G$ i( [; |$ D
   parallel(autoTests: {
7 M' |: }1 p( D& [0 g6 q, U( y9 s        // 使用nosetests 运行测试用例7 `, H) O: v4 X# \+ x2 r
        sh "docker run -it --rm -v $PWD:/code nosetests nosetests -s -v -c conf\run\api_test.cfg --attr safeControl=1"% r3 @$ z/ P7 T2 i. i( U/ @
   },manualTests:{/ ?/ s6 z9 A9 P' }' g
        sleep 300009 m! N. D4 R# z( o# ^+ F; c8 ]# R
   })8 O1 ]; ?5 v+ [. a+ S5 w: R/ W
7. 人工测试$ _) f7 T2 N  G7 d, P2 L
如果对自动化测试不放心,此时可选择结束 Pipeline,进行人工测试。为了说明整个流程,我们这里选择跳过人工测试环节。
8. 部署生产环境
当所有测试通过后,Pipeline 自动发布生产环境。
stage('Deploy on Prod')0 I* l7 Y. C* w' t! j: |) h
    input "Do tests OK?"
$ }; I5 j. F7 C8 n1 [3 t' G5 u+ I8 Y    dir("./deploy") {) q+ L5 p9 w2 I/ M$ T- G
        //Get the right marathon url
/ Q+ X* v* p* Z, J2 j5 h5 X        marathon_url="http://marathon-prod"
, Z0 A: B% e7 ?& ?* B        marathon docker: imageName, dockerForcePull: true, forceUpdate: true, url: marathon_url, filename: "prod-deploy.json"& O8 ~; V* S# Q8 P8 A4 j' k6 i
    }
6 z4 t. u( U6 K) W/ z# o0 j( r0 e! b( Q& I1 q( S% d1 X" `
最后我们来看看整个 Pipeline 的过程:
容器编排配置文档化
在介绍敏捷开发时,曾介绍过根据不同环境的配置参数部署到不同的环境。如何告知部署程序用什么样的配置文件启动服务,每个环境又用多少 CPU,内存和 instance 呢?2 q4 s- c% _' {7 r* X0 i
下面我们就来介绍一下容器编排的配置文件。由于我们使用 Mesos+Marathon的容器编排方式,部署的重任从以前的写部署脚本变成了写一个 Marathon 的配置,其内容如下:
{6 z, N& X  `/ M# ^$ e" v
  "id": "/appName",2 O* _8 [* n) a3 a
  "cpus": 2,9 d8 s: e+ G7 D$ k) V& G+ n3 l0 `$ @
  "mem": 2048.0,
$ V0 n! D8 z/ V! _  "instances": 2,
7 ~4 d+ Q7 F, L2 R$ d, O5 |  "args": [
8 W0 _4 w, O- O0 o) B- o8 m    "--spring.profiles.active=qa"
: E2 Z$ x; V3 s; ~7 E2 L9 H+ X  ],
2 ]5 ]' u$ O: P: \% j  "labels": {
0 ?: o. H- F: j( }# Y    "HAPROXY_GROUP": "external",2 N& p2 ?8 P8 P: M& s
    "HAPROXY_0_VHOST": "xxx.hujiang.com"- b% R1 R4 l: A$ u( g
  },1 i0 }: p7 M8 T! n8 l" C# u# d
  "container": {' N! {0 v" t6 F$ q$ f5 C
    "type": "DOCKER",
- A7 i5 \2 {5 e; N4 R6 x1 A    "docker": {! B: S" t9 X1 Q
      "image": "imageName",4 V  i0 [0 @" }7 F- O, c
      "network": "USER",
( n+ T2 k( X4 i2 P% ~9 N      "forcePullImage": true,
& r! U9 W5 R" l% A/ {8 s/ P1 A" E      "portMappings": [# q0 `8 Z6 V4 t( v4 e8 H
        {. C: }* y: n+ |2 I$ x8 C
          "containerPort": 12345,
" u! n9 D) c0 @1 I          "hostPort": 0,# ^3 w( y0 Z! ^: r
          "protocol": "tcp",  G, c2 b- j2 e2 T5 k
          "servicePort": 12345
6 [* P$ R% `0 z' d        }) q9 C5 r4 e/ U- Y/ L
      ]
/ ]1 `5 K" [6 D' |  k$ b    },
& Q1 |; [" C/ q; U/ b7 N- s4 [    "volumes": [/ _' w! v, \$ J# D9 k% F
      {4 R9 d4 B+ \0 E+ Y
        "containerPath": "/app/log",% Z; W6 B' \0 Q' c- @% i
        "hostPath": "/home/logs/appName",' p1 x& o0 O: i3 J+ A
        "mode": "RW"$ a& e' A6 n1 j% F7 O; ~/ H8 S
      }
! K& X6 y9 `) ~0 p/ y+ q    ]2 b! X" J- a# r5 K% ?
  },
4 d, \4 O: a: K$ Q6 ]4 n+ N+ w+ a, H  "ipAddress": {' O" m' Z. \( a: W8 @5 G* l( B
    "networkName": "calico-net"
! {$ J4 ]6 L$ G, u% l  },4 n5 p+ d) \7 d* J3 ^, u; b
  "healthChecks": [
4 F: w1 y: N4 Q8 w1 }    {- t' l" g# r/ x
      "gracePeriodSeconds": 300,
3 E4 q+ \# n* i% {      "ignoreHttp1xx": true,. o: J8 Y3 E  g0 a: |
      "intervalSeconds": 20,0 K: n: a* q. @2 L0 d' J9 n
      "maxConsecutiveFailures": 3,
' M" e! v! x$ G: n& x. O      "path": "/health_check",* M3 m- W; [5 @
      "portIndex": 0,$ _: y% x' N, {( H; O: g) k
      "protocol": "HTTP",. M# M2 b- Q4 m& P2 h) B3 ]% o
      "timeoutSeconds": 20
2 O7 o: d) c' w% a3 N    }( L9 C, h1 P$ A) ?
  ],. B& K) q+ _" Y. i
    "uris": [
' g1 M2 _1 \; ]    "file:///etc/docker.tar.gz"
& H% I( i# A3 v1 q4 t: S  ]
+ c. {5 c2 {" e1 |; Z}
我们把这个配置内容保存为不同的 json 文件,每个对应的环境都有一套配置文件。例如 Marathon-qa.json,Marathon-prod.json。当 Pipeline 部署时,可以通过Jenkins Marathon 插件,根据选择不同的环境,调用部署配置,从而达到自动部署的目的。
自动化流程和部署上线分离与管理
开发部署如此的简单快捷,是不是每个人都能方便的使用呢?答案是否定的,并不是因为技术上有难度,而是在于权限。在理想的情况下,通过这套流程的确可以做到在提交代码后,喝杯咖啡的时间就能看见自己的代码已经被千万用户使用了。
但风险过大,我们并不是每个人都能像 Rambo 一样 bug 的存在,大多数的情况还需要使用规范和流程来约束。就像自动化测试取代不了人工黑盒测试一样,部署测试后也不能直接上生产环境,在测试通过后还是需要有个人工确认和部署生产的过程。
所以我们需要把自动化流程和最后的部署上线工作分开来,分别变成两个 Job,并给后者单独分配权限,让有权限的人来做最后的部署工作。这个人可以是 Team leader、开发经理,也可以是运维伙伴,取决于公司的组织结构。
那这个部署的 Job 具体干什么呢?在容器编排时代,结合镜像既构建物的思想,部署 Job 不会从代码编译开始工作,而是把一个充分测试且通过的镜像版本,通过 Marathon Plugin 部署到产线环境中去。这里是 Deploy_only 的例子:
node('docker-qa'){
& O2 F. j# g% O% Y  R    if (ReleaseVersion ==""){% G- t, t" m, n  W4 w$ k$ q7 x3 u* R4 C
        echo "发布版本不能为空"
6 c0 K1 F! ]8 R        return
' W$ y/ J) ?2 w2 z- b/ F$ F& ~1 y    }
1 j* a" M$ q( Y8 A+ @) G/ r    stage "repare image"
! T3 H0 k) M# h% }4 {2 g        def moduleName = "${ApplicationModule}".toLowerCase()
4 H, Y3 X2 Z+ |8 O3 m7 |1 E        def resDockerImage = imageName + ":latest"2 _2 p4 @4 Q, V
        def desDockerImage = imageName + "{ReleaseVersion}"
$ `: y2 E" ?3 t1 g        if (GenDockerVersion =="true"){& C7 ~: I3 q3 W
            sh "docker pull ${resDockerImage}"
, v. X* s, I& x* }7 q% W            sh "docker tag ${resDockerImage} ${desDockerImage}"
5 \% r: I3 z7 R4 V. n            sh "docker push ${desDockerImage}"
7 h4 `' |% I7 P7 k) T            sh "docker rmi -f ${resDockerImage} ${desDockerImage}"
; M* U( |  N( U3 q7 [        }
& x+ ?& F/ S0 m: w     
$ R+ h- H0 j' u- S7 C    stage "Deploy on Mesos"
8 l2 S0 c! ~; w# @        git branch: 'dev', changelog: false, credentialsId: 'deploy-key', url: 'git@gitlab.xxx.com:lms/xxx-test.git'  ' H6 C0 G; X+ a
        //Get the right marathon url9 U9 o& ]. A5 U% t3 W: [% D& E+ _* [
        echo "DeployDC: " + DeployDC
! k5 l  H3 R) B3 u7 @! b        marathon_url = ""
7 q% A7 ?: @9 {% E        if (DeployDC=="AA") {
8 K/ i6 N0 n7 d7 n7 ~( Z. T& ]6 I            if (DeployEnv == "prod"){
" Y' w$ c$ l, E2 H& V( F              input "Are you sure to deploy to production?"
' f' z. W7 _5 V* V2 l              marathon_url = "${marathon_AA_prod}"
# I% g4 B2 [+ h$ v" A            }else if (DeployEnv == "yz") {# `" R& C; V( _5 W
              marathon_url = "${marathon_AA_yz}"
  w# Y! X: u6 [" F' X/ D0 ]            }8 h' O# C* F& @/ X! N3 P
        }else if ("${DeployDC}"=="BB"){' m! I: N! w% I" G8 @+ H
          if ("${DeployEnv}" == "prod"){* J" O* o* k8 d0 o
            input "Are you sure to deploy to production?"8 ^0 S5 x- K7 S$ A, H
            marathon_url = "${marathon_BB_prod}") n# U  J  u0 \  t1 k
          }else if ("${DeployEnv}" == "yz") {# H  |* b" n3 I0 N+ o1 h3 l* [" ^8 M
            marathon_url = "${marathon_BB_yz}"9 [7 h+ U) o% |$ B2 F
          }. C, W: e4 ]5 ~  [
        }4 {+ E7 `: b$ P: \
        marathon docker: imageName, dockerForcePull: true, forceUpdate: true, url: marathon_url, filename: "${DeployEnv}-deploy.json"
9 w/ l9 X2 E9 c1 H# N* b% y}
1 Q4 b4 a7 y$ q: o
为什么不把这个文件跟随应用项目一起放到 scripts 下呢?因为把部署和应用分开后,可以由两拨人进行维护,兼顾公司的组织架构。
6 X5 Q+ D( S9 u+ i8 C* T4 p
自动化运维在 DevOps 的最后阶段是运维阶段。在容器时代,如何对庞大的镜像制品进行运维呢?我们的目标是尽量实现自动化运维,这里主要讲述两点:容器的监控
容器的监控大致有两种方式:物理机上安装其他服务监控本机上的所有容器;通过 Mesos 或 kubernates 自带 API 监控容器状态。两种方式其实都需要在物理机上安装相应的监控软件或 Agent。
在我们团队目前使用 cAdvisor+influxDB+Grafana 的组合套件实现对容器的监控。
首先需要在 Mesos 集群中所有的 Agent 安装 cAdvisor 。他负责把宿主机上所有运行中的容器数据以数据点(data point)形式发送给时序数据库(influxDB),下面是 cAdvisor 监控的一些数据点:

' R( C. U/ {1 |
这些数据点经过 Grafana 整理,展示在界面上,这样我们就能掌握具体容器的性能指标了。下面是一个 Grafana 的截图:

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

/ k! L1 f8 l3 A2 S8 K" \
原创:黄凯

/ u7 X+ H  D1 D

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?微信、QQ、手机号一键注册

x

本版积分规则

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

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

Baidu

GMT+8, 2018-10-16 01:59 , Processed in 0.278156 second(s), 29 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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