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

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

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

扫描二维码登录本站

QQ登录

只需一步,快速开始

艾拓先锋
搜索
查看: 491|回复: 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)。 4 G1 V+ D( M$ W
在容器化的时代,我们是如何实现 DepOps 或者 SRE 的呢?下面我就来分享一下沪江学习产品线团队基于容器编排的 DevOps 流程。
敏捷开发
大道至简,所有血的教训告诉我们,不要把简单的事情复杂化。换句话说,不要用复杂的方法处理简单的事情。我对敏捷的理解是「快」和「微」。快指迭代快,开发快,上线快,性能快。微指微服务、微镜像。围绕这两点,在开发阶段我们需要做以下几件事:
应用微服务化
这是个比较大的概念,不在这里讨论,有兴趣可以参考我的其他文章。但只有应用小了,才有可能快起来。
给 Docker 镜像瘦身为了让 Docker 启动和运行得快,首先就是要对 Docker 瘦身。由于所有的应用全部会统一为 Java 语言开发,所以我们以 Java 为例,选用了 jre-alpine 作为我们的基础镜像,下面是 Dockerfile 的例子:FROM java:8-jre-alpine
: f1 f1 _  Q3 f1 B  / k9 m- W" ]8 `8 C
#add timezone and default it to Shanghai
5 x: J* j4 E; P. i, }/ G8 t, NRUN apk --update add --no-cache tzdata! H* @4 A$ n, w7 L9 q1 b
ENV TZ=Asia/Shanghai2 e0 o5 ]" `0 v) z' P3 P& _
  & }  J, Y- j) ?; _
RUN mkdir -p /app/log) c- l5 \2 p8 o) {1 s
COPY  ./target/xxx.jar  /app/xxx.jar
/ B/ I* ^$ Y! V& F/ U. t  
! M; R2 C# k" D5 {EXPOSE 99992 N. Q" L* S% v  _6 Z' r8 t
VOLUME ["/app/log"]& P; [9 x) `" _& C3 w# F
WORKDIR /app/
: B! C$ L- v1 {+ U: _  ( |+ ?: N, @3 t. C! g% Y
ENTRYPOINT ["java","-Xms2048m", "-Xmx2048m", "-Xss512k", "-jar","xxx.jar"]& v1 Y6 u5 m% E* t
CMD []
使用上述 Dockerfile 生成的镜像平均只有 80 多 MB,启动时间几乎在 5 秒内。使用 alpine 镜像虽然减小了体积,但缺少一些工具命令,例如 curl 等,可以根据需要酌情安装。另外遇到的一个坑是时区问题:由于 Docker 镜像内的时区是 UTC 时间,和宿主机的东 8 区不一致,所以必须安装 timezone 工具并设置 TZ,才能使容器内时间和宿主机保持一致,对数据库的写入和日志的输出都是非常必要的一环。
把所有环境配置包含在镜像中
早在虚拟机时代,我们已经做到了使用包含依赖的虚拟机镜像来加速部署,那么为什么要止步于此呢?我们可以更进一步,把服务本身也包含在镜像中,Docker 用了更轻量的方式已经实现了这一点。
这里我们还要介绍一个概念,要让制作的镜像,能在所有安装了 Docker 的服务器上运行,而不在乎宿主机的操作系统及环境。借用 Java 的一句话来说:一次制作,多平台运行。所以,我们还会把所有环境的配置文件,以不同的文件名全部放入镜像中,通过参数来选择 Docker 启动时使用的环境配置文件。
值得注意的是,如果开发的应用是基于 spring 框架的话,这个功能很好实现。但如果是其他语言开发,会有一定的开发量。
本文以默认 Java 开发当所有的开发工作完成后,推荐程序目录结构是这样的:
. y' ?) {9 ~7 F! b9 W
├── src
" ~/ q$ e' R; s" d1 _5 }│   ├── main
, y6 D# S- }) l- @│   │   ├── java
- w( n5 |  S1 S3 E$ z+ S- Y+ Y% Q│   │   ├── resources
' O/ t( E: }( t  q1 B│   │   │   ├── application.yaml" z& f. a" \+ R1 h! W# o. y0 c! p
│   │   │   ├── application-dev.yaml& ~. u. K! k- u! X, V3 ?8 \$ e
│   │   │   ├── application-qa.yaml
, F. L! {3 {  P% ^% Z- e; M│   │   │   ├── application-yz.yaml$ S5 [# ?$ y1 g& a
│   │   │   ├── application-prod.yaml
3 l6 o# Y7 B/ }& }+ y' S9 l│   │   │   ├── logback.xml
# S/ x% I) z+ b3 [: r. ^│   ├── test: I% C* x! o! F* }$ I
├── scripts
0 g$ @' L3 Z( ?1 R* N+ H│   ├── Dockerfile- G; j; W! }) f# N: y) S  F
│   ├── InitDB.sql
, {4 Q$ u) c* r$ X; s) |! n├── pom.xml
持续集成与交付
自动化的持续集成和交付在整个 DevOps 流中起了重要的角色,他是衔接开发和运维的桥梁。如果这一环做的不好,无法支撑大量微服务的快速的迭代和高效运维。在这一环节,我们需要灵活的运用工具,尽量减少人参与,当然仍然需要围绕「快」和「微」做文章。
如何减少人工参与到持续集成与持续交付呢?我们最希望的开发过程是:对着计算机说出我们的想要的功能,计算机按照套路,自动编码,自动发布到测试环境,自动运行测试脚本,自动上线。当然,目前时代要实现自动编码的过程还需要发明那只「猫」。
0?wx_fmt=png.jpg
但只要对测试有足够信心,我们完全可以实现一种境界:在炎热的下午,轻松地提交自己编写的代码,去休息室喝杯咖啡,回来后看见自己的代码已经被应用在生产环境上了。在容器时代,我们可以很快速的实现这一梦想,其具体步骤如下图:
# L1 y% d# i4 r8 _$ C* S& \
. b: D5 w, p- _
0?wx_fmt=png.jpg

0 G$ O& G" h! [4 c2 q9 K0 m# u
Gitfolw 与 Anti-Gitflown
# g) ^$ c1 {% q  r9 f" A8 G( w
持续集成的第一步是提交代码(Code Commit),VCS 也由 CVS,SVN 进化到如今的 Git,自然不得不说一下 Gitflow。谈起无人不晓的 Gitflow,大家一定会大谈其优点:支持多团队,设置多国家的开发人员并行开发,减小代码冲突或脏代码的上线概率。它的大致流程如下:

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

" F- Q1 G8 A4 {
0?wx_fmt=png.jpg

8 [- e; U% e. ^
我们把 5 条分支简化为 3 条分支,其中 Master 分支的作用只是维护了最新的线上版本的作用,Dev 分支为开发的主要分支,所有的镜像是以此分支的代码为源头生成的。这时开发的过程变为:
# X! I' {  ?8 k7 d, O5 P
  • 开发人员从 Dev 分支中 checkout 新的 feature 分支,在 feature 分支上进行开发
  • 当开发完成后 merge 回 Dev 分支中,根据 Dev 分支的代码打成镜像,部署 QA 环境交给 QA 人员测试
  • 测试中如有 bug 便在新分支中修复问题循环步骤 2
  • 测试完成 merge 回 Master 分支
    " _$ a+ G/ U" ~" K9 t: W- |
如此一来,只有从 Feature 把代码 merge 到 Dev 分支的一次 merge 动作,大大提升可开发效率。
使用Jenkins Pipeline
Jenkins 作为老牌 CI/CD 工具,能够帮我们自动化完成代码编译、上传静态代码分析、制作镜像、部署测试环境、冒烟测试、部署上线等步骤。尤其是Jenkins2.0 引入 Pipeline 概念后,以上步骤变的如此行云流水。它让我们从步骤 3 开始,完全可以无人值守完成整个集成和发布过程。
工欲善其事必先利其器,首先我们必须要在 Jenkins 上安装插件 :
9 M# [2 s* C& c4 k$ o% K# T
  • Pipeline Plugin(如果使用Jenkins2.0默认安装)
  • Git
  • Sonar Scaner
  • Docker Pipeline Plugin
  • Marathon
    - H" ?: R  k5 u9 ]- T7 o
如果你第一次接触 Jenkins Pipeline,可以从https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md找到帮助。
现在,我们开始编写 Groove 代码。基于容器编排的 Pipeline 分为如下几个步骤:
1.检出代码
这个步骤使用 Git 插件,把开发好的代码检出。
stage('Check out')2 f  P) H  r; Y. Q) X$ m6 F
  gitUrl = "git@gitlab.xxxx.com:xxx.git"
4 Z. b3 q0 T5 T8 R% l  git branch: "dev", changelog: false, credentialsId: "deploy-key", url: gitUrl
+ w' x# n9 R7 k5 n! c) q
2.maven 构建 Java 代码
由于我们使用的是 spring boot 框架,生成物应该是一个可执行的 jar 包。
stage('Build')
* v4 ]& x$ D% E, r0 b4 p% G  sh "${mvnHome}/bin/mvn -U clean install"3. 静态代码分析
通过 Sonar Scaner 插件,通知 Sonar 对代码库进行静态扫描。
stage('SonarQube analysis')
+ k% G+ @4 b; _8 C9 q4 Z2 W) [- l   // requires SonarQube Scanner 2.8+
6 e4 Q' h+ m1 J/ y   def scannerHome = tool 'SonarQube.Scanner-2.8';3 l( L2 V0 {/ k! `
   withSonarQubeEnv('SonarQube-Prod') {
- A# i( `8 L$ f0 x; Q: Q     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"0 D  X0 R: o/ M
   }# ?" d+ i# E1 z- o
4.制作 Docker 镜像' I7 ]( H/ t/ V) S2 g/ ]4 a: i
此步骤会调用 Docker Pipeline 插件通过预先写好的 Dockerfile,把 jar 包和配置文件、三方依赖包一起打入 Docker 镜像中,并上传到私有 Docker 镜像仓库中。
stage('Build image')! N( t! c6 K1 a  _; I/ M
  docker.withRegistry('https://dockerhub.xxx.com', 'dockerhub-login') {
: R+ F, c/ n  S) _  l    docker.build('dockerhub.xxx.com/xxxx').push('test') //test是tag名称
) H4 d. y9 [( I. |, \& j6 Z- i: t  }5.部署测试环境
通过事先写好的部署文件,用 Marathon 插件通知 Marathon 集群,在测试环境中部署生成好的镜像。
stage('Deploy on Test')5 G& b' }( f7 Z4 b( k5 Z" H' M1 S
    sh "mkdir -pv deploy"
, b& }" N! t' J' S6 W    dir("./deploy") {, z  M) J1 ?8 w# z, L7 \  i" j
        git branch: 'dev', changelog: false, credentialsId: 'deploy-key', url: 'git@gitlab.xxx.com:lms/xxx-deploy.git'
8 `7 Q9 I7 O. d        //Get the right marathon url
  j- V! c/ S9 ~2 `' z        marathon_url="http://marathon-qa"% t3 J6 p0 A) j
        marathon docker: imageName, dockerForcePull: true, forceUpdate: true, url: marathon_url, filename: "qa-deploy.json"
# F$ o# o5 A3 T" I* M    }& y) ?- w. g' k
6.自动化测试: x" Y2 e% Z) c9 r9 f% `% y, z) p
运行事先测试人员写好的自动化测试脚本来检验程序是否运行正常。
stage('Test')* s4 z' G' x4 E% F
   // 下载测试用例代码
5 a% l' `1 \7 W) e  _' c0 a   git branch: 'dev', changelog: false, credentialsId: 'deploy-key', url: 'git@gitlab.xxx.com:lms/xxx-test.git'
) o! W) \. [- D0 f5 s4 f   parallel(autoTests: {
$ U7 h! l  l. M  a- H        // 使用nosetests 运行测试用例3 u2 |5 o0 c1 J2 Z
        sh "docker run -it --rm -v $PWD:/code nosetests nosetests -s -v -c conf\run\api_test.cfg --attr safeControl=1"  Z, ?- `' C% a4 S. T6 X. B$ p
   },manualTests:{
/ u3 u' z  y! R5 q% T        sleep 30000
. a1 f3 [% I9 m- r3 b: Y# V   })
" {5 }; K7 P" I8 }8 K5 r
7. 人工测试( E/ F+ B) e4 c7 l* R
如果对自动化测试不放心,此时可选择结束 Pipeline,进行人工测试。为了说明整个流程,我们这里选择跳过人工测试环节。
8. 部署生产环境
当所有测试通过后,Pipeline 自动发布生产环境。
stage('Deploy on Prod'). P3 A5 f. p$ o5 n
    input "Do tests OK?"1 H+ ~+ A4 C9 ~8 ]7 `; C! H
    dir("./deploy") {
: ?& B  W& T- a9 p        //Get the right marathon url0 A# ~* i8 Z( E7 ?1 m8 b! y
        marathon_url="http://marathon-prod"
, o( I/ S' J& O* l$ }        marathon docker: imageName, dockerForcePull: true, forceUpdate: true, url: marathon_url, filename: "prod-deploy.json"
! u( p* m6 U4 ^8 f% g    }, t! j% H' d) ]+ m, @
( x$ M" G' f9 ]9 S5 h- p
最后我们来看看整个 Pipeline 的过程:
0?wx_fmt=png.jpg
容器编排配置文档化
在介绍敏捷开发时,曾介绍过根据不同环境的配置参数部署到不同的环境。如何告知部署程序用什么样的配置文件启动服务,每个环境又用多少 CPU,内存和 instance 呢?
/ O& [$ k8 H" }( D6 \6 r
下面我们就来介绍一下容器编排的配置文件。由于我们使用 Mesos+Marathon的容器编排方式,部署的重任从以前的写部署脚本变成了写一个 Marathon 的配置,其内容如下:
{
% U7 f/ p- `6 z8 G% P4 U- N; h  "id": "/appName",
  {% e- O/ ~" m# v$ a' W1 R  "cpus": 2,
$ Z; \- J; N( }/ s- U0 g/ w0 m  "mem": 2048.0,  x; q& C9 t( S/ o
  "instances": 2,
6 w7 K4 q1 h! r4 }0 d7 o8 J  "args": [6 v  _3 Z5 ]  j% U+ D2 Q" O
    "--spring.profiles.active=qa") [5 ?0 \9 J0 j9 q' A
  ],
' g! r: |9 l- F! ]& s; [  "labels": {
4 [* Z" B7 o& ^1 F7 B6 X# q    "HAPROXY_GROUP": "external",% x) X. r" v4 R2 @/ f- I
    "HAPROXY_0_VHOST": "xxx.hujiang.com"
$ G( F* ?# _+ V7 n  },
) O1 ~1 s0 r+ O8 e7 D- p( x5 j  "container": {# s9 x: y& O) A4 K1 z1 v) o- v7 ~
    "type": "DOCKER",+ X. |# |  I+ Z$ g- ~' L
    "docker": {
! |- P' R6 `& z' R      "image": "imageName",0 H0 V2 ?( L- K
      "network": "USER",' t4 H# q+ r- a& j# z5 [, X. |
      "forcePullImage": true,
' Z  L. d! r  m. Z5 t! f" {0 u      "portMappings": [
+ ?& D: p3 ^/ Q        {/ F; I  O; l; Q6 \- x' O9 p! ^
          "containerPort": 12345,
; x" G7 D, v. z4 Y1 p: t% ^          "hostPort": 0,. d: b$ N3 y( c
          "protocol": "tcp",# K# u# {8 c( W9 Z7 d/ l
          "servicePort": 12345
6 P: ~' S, G; |$ t- v5 U        }4 @1 K& e: h8 X4 H5 U
      ]0 w; x' r0 V0 K! s& t  W4 |
    },
# Y  b1 S% t9 z# `    "volumes": [
9 l6 w$ _# s5 G$ P* f, l7 u      {9 _, O: f7 @7 o" s
        "containerPath": "/app/log",
/ d1 n9 N, H# H        "hostPath": "/home/logs/appName",3 s( z( H4 V8 T& g7 s. Y5 S9 l
        "mode": "RW"
1 ]# _5 o  p) g- O9 c3 W      }" K0 x& L5 W2 C3 s, ?
    ]
  N% [% d! b% S% ^: I, [9 y) C. R  },% J( `4 t- ]6 F
  "ipAddress": {. \  d% A5 e6 X3 x/ @+ B
    "networkName": "calico-net"
" Y; Z- ~: U9 L: J1 A3 @) S) {5 i! Q  }," F, h7 |- ?3 z  r  J
  "healthChecks": [
, g& }* x6 K! r3 K$ {    {
- a6 F# @. w* s1 D0 `      "gracePeriodSeconds": 300,9 H# i1 y* w7 _/ R/ c5 Q+ _
      "ignoreHttp1xx": true,
7 Z$ l; N9 P0 {0 d7 G! w) i      "intervalSeconds": 20,1 C" N- W3 o7 N: H6 c. G
      "maxConsecutiveFailures": 3,
& R! v& T. d+ U$ L9 p      "path": "/health_check",! h  o$ e) f; a4 p9 |, d
      "portIndex": 0,0 q* d/ V7 p+ @" C+ S/ Q  p
      "protocol": "HTTP",$ i, u" L6 ], y( u2 A# \4 R
      "timeoutSeconds": 20* w9 b. {2 @7 Y+ w% R! E6 k
    }/ }* e# W* x0 ]; h1 |
  ],
& m+ H, F, `/ ]3 H8 c( h- l, T4 K    "uris": [4 J4 P+ k3 L' q; i% y) Z6 l
    "file:///etc/docker.tar.gz": c) T% A  M% a3 M7 A; s
  ]6 l- [- i1 a# W/ R4 D( n
}
我们把这个配置内容保存为不同的 json 文件,每个对应的环境都有一套配置文件。例如 Marathon-qa.json,Marathon-prod.json。当 Pipeline 部署时,可以通过Jenkins Marathon 插件,根据选择不同的环境,调用部署配置,从而达到自动部署的目的。
自动化流程和部署上线分离与管理
开发部署如此的简单快捷,是不是每个人都能方便的使用呢?答案是否定的,并不是因为技术上有难度,而是在于权限。在理想的情况下,通过这套流程的确可以做到在提交代码后,喝杯咖啡的时间就能看见自己的代码已经被千万用户使用了。
但风险过大,我们并不是每个人都能像 Rambo 一样 bug 的存在,大多数的情况还需要使用规范和流程来约束。就像自动化测试取代不了人工黑盒测试一样,部署测试后也不能直接上生产环境,在测试通过后还是需要有个人工确认和部署生产的过程。
所以我们需要把自动化流程和最后的部署上线工作分开来,分别变成两个 Job,并给后者单独分配权限,让有权限的人来做最后的部署工作。这个人可以是 Team leader、开发经理,也可以是运维伙伴,取决于公司的组织结构。
那这个部署的 Job 具体干什么呢?在容器编排时代,结合镜像既构建物的思想,部署 Job 不会从代码编译开始工作,而是把一个充分测试且通过的镜像版本,通过 Marathon Plugin 部署到产线环境中去。这里是 Deploy_only 的例子:
node('docker-qa'){. E+ A( l0 g+ l' [! A
    if (ReleaseVersion ==""){
# \, F/ c% I/ K0 |5 j. H( r        echo "发布版本不能为空"
' C' c' N% ?4 L# ^6 ]) k* m        return) t! h" N7 |8 B2 b& h
    }8 ^9 d' u' |. y- s
    stage "repare image"
; `+ E! @' \' U' e* }* P        def moduleName = "${ApplicationModule}".toLowerCase()
2 v6 i9 d! P* F8 g4 T& W1 b# _        def resDockerImage = imageName + ":latest". {5 w; G+ x. V) E- Y" o
        def desDockerImage = imageName + "{ReleaseVersion}"/ m8 R1 ~$ I8 E; G) H; u! _
        if (GenDockerVersion =="true"){2 S2 g0 W9 p3 K" V8 Q
            sh "docker pull ${resDockerImage}"
' _& _, W- V6 z0 o9 h  ?* A            sh "docker tag ${resDockerImage} ${desDockerImage}"2 t* y* [9 J5 \+ i. L" S8 X
            sh "docker push ${desDockerImage}"
2 H) F& K7 s0 E, W. E1 @            sh "docker rmi -f ${resDockerImage} ${desDockerImage}"
8 H  ?; P: F" Y7 d        }
3 c) K+ k. N. t& f     5 W' s1 k6 c' t  q% r2 A- N
    stage "Deploy on Mesos"
: V, ~* K5 n1 U& Q! ~+ L5 X  `! k9 p        git branch: 'dev', changelog: false, credentialsId: 'deploy-key', url: 'git@gitlab.xxx.com:lms/xxx-test.git'    O/ `0 f7 F1 g$ ~
        //Get the right marathon url
, _' s4 E  X! e, @' l$ d        echo "DeployDC: " + DeployDC( h; R$ V" A+ m9 u9 `
        marathon_url = ""
2 F) \3 L) o# h" {        if (DeployDC=="AA") {
$ j8 i, V% F% E1 A$ Z3 b            if (DeployEnv == "prod"){
" ]! b  E% v; r; W5 {7 r' {! {              input "Are you sure to deploy to production?"
7 f9 W" e4 ~8 J. [, O' ?0 a7 A              marathon_url = "${marathon_AA_prod}"
: W% g$ K) U9 P) g% n3 K3 F            }else if (DeployEnv == "yz") {
# k* g) I  f: W% c              marathon_url = "${marathon_AA_yz}"
9 s' Z0 o5 ~5 d2 n9 Y( o8 o( G            }, ^; K: s, j5 u# p$ ?
        }else if ("${DeployDC}"=="BB"){
3 l) r. \2 N3 X, G) e  K          if ("${DeployEnv}" == "prod"){
. W# D% J7 l  k) Z            input "Are you sure to deploy to production?"/ t  Q0 M9 ^8 m* y+ u+ Z
            marathon_url = "${marathon_BB_prod}"/ n5 k, c- ^# y/ f7 j
          }else if ("${DeployEnv}" == "yz") {9 _+ R  I! x: a
            marathon_url = "${marathon_BB_yz}"9 L+ C% g7 b9 J: k; v* F3 \
          }% ?  |1 N; i; F, ?9 N  [
        }
1 S6 ^/ f. Z7 `! g9 Z2 j- O# r        marathon docker: imageName, dockerForcePull: true, forceUpdate: true, url: marathon_url, filename: "${DeployEnv}-deploy.json") w  ~6 b  p/ E8 m9 c
}$ R& m2 F* h6 t$ g9 F4 L+ [
为什么不把这个文件跟随应用项目一起放到 scripts 下呢?因为把部署和应用分开后,可以由两拨人进行维护,兼顾公司的组织架构。
4 t. W6 u# u0 f
自动化运维在 DevOps 的最后阶段是运维阶段。在容器时代,如何对庞大的镜像制品进行运维呢?我们的目标是尽量实现自动化运维,这里主要讲述两点:容器的监控
容器的监控大致有两种方式:物理机上安装其他服务监控本机上的所有容器;通过 Mesos 或 kubernates 自带 API 监控容器状态。两种方式其实都需要在物理机上安装相应的监控软件或 Agent。
在我们团队目前使用 cAdvisor+influxDB+Grafana 的组合套件实现对容器的监控。
首先需要在 Mesos 集群中所有的 Agent 安装 cAdvisor 。他负责把宿主机上所有运行中的容器数据以数据点(data point)形式发送给时序数据库(influxDB),下面是 cAdvisor 监控的一些数据点:
" p$ X9 U% M% ?# N; Y3 u" \1 [8 A
0?wx_fmt=png.jpg
这些数据点经过 Grafana 整理,展示在界面上,这样我们就能掌握具体容器的性能指标了。下面是一个 Grafana 的截图:

- P, O9 t; _" T
0?wx_fmt=png.jpg

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

3 M' Z. M0 j2 L0 X4 V. C

本版积分规则

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

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

Baidu

GMT+8, 2019-2-24 05:53 , Processed in 0.210192 second(s), 29 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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