DevOps 工具
DevOps 的目的是:“减少从系统更改到投入生产之间的时间,同时确保高质量”。
想要充分落地 DevOps,当然离不开软件工具和平台的支持。
当你考虑构建和运行系统时,实际上会有很多事情要做。以下是要考虑的:
- 获取计算机/服务器硬件
- 配置计算机/服务器硬件(操作系统,网络等)
- 监视计算机/服务器硬件
- 获取网络设备(负载均衡器,防火墙,路由器等)
- 配置网络设备
- 监控网络设备
- 构造软件
- 编译软件
- 测试软件
- 打包软件
- 部署/发布软件
- 监控软件
在 DevOps之前,我们曾经有四个不同的团队来完成这项工作:
- 开发人员:他们将执行#7,#8,有时甚至是#10
- QA团队:他们将执行#9,有时甚至执行#11
- 系统管理员:他们将执行#1,#2,#3,#12
- 网络管理员:他们将执行#4,#5,#6
随着 DevOps 的出现,关键是能够打破不同团队间障碍,使每个人成为一个团队的一部分,使所有系统的配置,部署和管理方式保持一致。
DevOps 生态圈有丰富的软件对其进行支持,DevOps 工程师可以选择合适的工具构建 DevOps 流程。
- 软件存储库:用于管理软件版本的工具– Git 是当今使用最广泛的工具。
- 构建工具:一些软件需要先进行编译,然后才能打包或使用,传统的构建工具包括 Make,Ant,Maven 和 MSBuild。
- 持续集成工具:每次你将代码提交存储库时,它都会构建,部署和测试软件。这通常可以提高代码质量和减少投产时间。这个市场上最受欢迎的工具是 Jenkins,Travis,TeamCity 和 Bamboo。
- 代码分析器/查看工具:这些工具可查找代码格式和质量以及测试覆盖范围中的错误。SonarQube 是该领域的流行工具。
- 配置管理:配置管理工具和数据库,通常会存储有关硬件和软件项目信息,并提供脚本或模板来自动化常见的任务。这个领域常见的工具有:Chef,Puppet,和 Salt。
- 部署工具:这些工具有助于软件的部署。许多 CI 工具也是 CD 工具,可帮助部署软件。传统上,在 Ruby中,Capistrano 工具已被广泛使用。在 Java 中,Maven 被许多人使用。所有编排工具也都支持这种部署。
- 编排工具:这些工具可配置,协调和管理计算机系统和软件。它们通常将自动化”和“工作流”作为其服务的一部分。Kubernetes 是一种非常流行的编排工具,专注于容器。Terraform 也是一种非常流行的编排工具,它的应用范围更加广泛,包括云编排。此外,每个云提供商都拥有自己的一套工具(CloudFormation,GCP Deployment Manager 和 ARM)。
- 监视工具:这些工具允许监视硬件和软件。通过监视程序和日志文件等,以确保系统的运行状况。Nagios 和 Prometheus 是一种流行的监视工具。
- 测试工具:测试工具用于管理测试以及测试自动化,包括性能和负载测试。
许多工具跨类别,并提供两个或多个类别的功能。
如你所见,Ansible,Terraform 和云工具(AWS,GCP 和 Azure)等正尝试将部署,配置管理和服务编排结合在一起。较旧的工具集:如 Puppet,Chef 和 SaltStack 专注于配置管理和自动化,但已扩展到编排和部署。还有一些工具,例如 GitLab 和 Azure DevOps,它们试图涵盖几乎所有类别的 DevOps。
基于 kubernetes 的 CI/CD
使用 Jenkins + Gitlab + Harbor + Helm + Kubernetes 来实现一个完整的 CI/CD 流水线作业,并且所有的组件都运行在 Kubernetes 中。
我们利用 Kubernetes 来动态运行 Jenkins 的 Slave 节点,可以很好的来解决传统的 Jenkins Slave 浪费大量资源的缺点。
当前 CI/CD 的流程图:
- 开发人员提交代码到 Gitlab 代码仓库
- 通过 Gitlab 配置的 Jenkins Webhook 触发 Pipeline 自动构建
- Jenkins 触发构建构建任务,根据 Pipeline 脚本定义分步骤构建
- 先进行代码静态分析,单元测试
- 然后进行 Maven 构建(Java 项目)
- 根据构建结果构建 Docker 镜像
- 推送 Docker 镜像到 Harbor 仓库
- 触发更新服务阶段,使用 Helm 安装/更新 Release
- 查看服务是否更新成功。
基于 Prometheus 的监控
整体流程比较简单,Prometheus 直接接收指标数据,在本地存储所有的获取的指标数据,并对这些数据进行一些规则整理,用来生成一些聚合数据或者报警信息,Grafana 用来可视化这些数据。
监控应用
应用只有提供一个 /metrics
接口暴露给 Prometheus,才能被采集到应用运行的指标数据。
- 一些应用本身内置了一个
/metrics
接口,比如 Kubernetes 的各个组件、istio 服务网格都直接提供了数据指标接口。 - 一些应用没有原生集成该接口,但是 Prometheus 官方或第三方可以提供一些
exporter
来获取到指标数据,比如mysqld_exporter
、node_exporter
,这些exporter
就有点类似于传统监控服务中的 agent,作为服务一直存在,用来收集目标服务的指标数据然后直接暴露给 Prometheus。 - 自己实现
/metrics
,像 Java 应用就可以添加 Prometheus jar 包来实现这个接口。
监控集群节点
我们这里通过 Prometheus 来采集节点的监控指标数据,可以通过 node_exporter 来获取,顾名思义,node_exporter
就是抓取用于采集服务器节点的各种运行指标,目前 node_exporter
支持几乎所有常见的监控点,比如 conntrack,cpu,diskstats,filesystem,loadavg,meminfo,netstat 等,详细的监控点列表可以参考其 Github 仓库。
我们可以通过 DaemonSet 控制器来部署该服务,这样每一个节点都会自动运行一个这样的 Pod,如果我们从集群中删除或者添加节点后,也会进行自动扩展。
目前只是监控了 k8s 部分组件,和所有节点。应用程序需要纳入监控的话,需要应用本身可以提供 /metric
接口可以采集监控数据。
报警方式现在是通过我个人的 QQ 邮箱发邮件到我的公司邮箱,同一类报警信息间隔5小时发送邮件通知。
基于 EFK 的日志收集
Kubernetes 中比较流行的日志收集解决方案是 Elasticsearch、Fluentd 和 Kibana(EFK)技术栈,也是官方现在比较推荐的一种方案。
Elasticsearch
是一个实时的、分布式的可扩展的搜索引擎,允许进行全文、结构化搜索,它通常用于索引和搜索大量日志数据,也可用于搜索许多不同类型的文档。
Elasticsearch 通常与 Kibana
一起部署,Kibana 是 Elasticsearch 的一个功能强大的数据可视化 Dashboard,Kibana 允许你通过 web 界面来浏览 Elasticsearch 日志数据。
Fluentd
是一个流行的开源数据收集器,我们将在 Kubernetes 集群节点上安装 Fluentd,通过获取容器日志文件、过滤和转换日志数据,然后将数据传递到 Elasticsearch 集群,在该集群中对其进行索引和存储。
DevOps 流程框架
业务系统迁移步骤
首先部署业务系统,要知道业务系统是怎样运行的,它是由哪些组件构成的;
- 例如,业务系统是由 Java 开发,并使用 PostgreSQL 数据库,那么系统要运行起来,就需要准备一个 Java 程序运行的环境(基础镜像:
openjdk:8-jre-alpine
),搞定服务运行的依赖包(Maven 构建),确定访问集群外数据库 PostgreSQL 的方式,确定是否对外提供服务及服务发现策略,是否高可用。
- 例如,业务系统是由 Java 开发,并使用 PostgreSQL 数据库,那么系统要运行起来,就需要准备一个 Java 程序运行的环境(基础镜像:
获取代码,本地运行测试是否正常
看一下 jar 中有什么文件
jar -tf springboot-web-demo-1.0-SNAPSHOT.jar
本地命令运行,测试是否成功,可以看到springboot启动日志
java -jar springboot-web-demo-1.0-SNAPSHOT.jar
- 编写 Dockerfile,构建镜像, 本地执行`docker run -it xxx:xxx` 运行容器,测试镜像是否可用
```bash
cd springboot-web-demo
vim Dockerfile
# Dockerfile文件内容:
FROM openjdk:8-jre-alpine
COPY target/springboot-web-demo-1.0-SNAPSHOT.jar /spring-web-demo.jar
ENTRYPOINT ["java","-jar","/springboot-web-demo.jar"]
# 制作镜像
docker build -t springboot-web:v1 .
# 测试镜像是否可用,run 一下
docker run -it springboot-web:v1
- 进入 Jenkins 创建和配置 Pipeline Job:devops-demo-springboot-web
- 配置
构建触发器
- 配置
流水线
,注意脚本路径
用来指定 Pipeline 执行文件 Jenkinsfile 的路径,这里放在项目的根目录了
- 配置
- 前往 Gitlab 中配置项目 devops-demo-java 的 Webhook,settings -> Webhooks,填写上面得到的 trigger
编写 Jenkinsfile 来实现具体的流水线
Clone代码 -> 单元测试 -> Maven编译打包 -> Docker镜像构建/推送 -> Helm部署服务 -> isRollBack
- 第一个阶段:单元测试。我们可以在这个阶段是运行一些单元测试或者静态代码分析的脚本,我们这里直接忽略。
第二个阶段:代码编译打包。我们可以看到我们是在一个
maven
的容器中来执行的,我们只需要在该容器中获取到代码,然后在代码目录下面执行打包命令即可,如下所示:stage('代码编译打包') {
try {
container('maven') {
echo "2.代码编译打包阶段"
sh """
cd springboot-web-demo
mvn clean package
"""
}
} catch (exc) {
println "构建失败 - ${currentBuild.fullDisplayName}"
throw(exc)
}
}
第三个阶段:构建 Docker 镜像。要构建 Docker 镜像,就需要提供镜像的名称和 tag,要推送到 Harbor 仓库,就需要提供登录的用户名和密码,所以我们这里使用到了
withCredentials
方法,在里面可以提供一个credentialsId
为 dockerhub 的认证信息,如下:stage('构建 Docker 镜像') {
withCredentials([[$class: 'UsernamePasswordMultiBinding',
credentialsId: 'docker-auth',
usernameVariable: 'DOCKER_USER',
passwordVariable: 'DOCKER_PASSWORD']]) {
container('docker') {
echo "3. 构建 Docker 镜像阶段"
sh """
docker login ${registryUrl} -u ${DOCKER_USER} -p ${DOCKER_PASSWORD}
docker build -t ${image} .
docker push ${image}
"""
}
}
}
第四个阶段:部署应用。现在镜像我们都已经推送到了 Harbor 仓库中去了,接下来就可以部署应用到 Kubernetes 集群中了,当然可以直接通过 kubectl 工具去操作 YAML 文件来部署,我们这里的示例,编写了一个 Helm Chart 模板,所以我们也可以直接通过 Helm 来进行部署,所以当然就需要一个具有 helm 命令的容器,这里我们使用
helm
这个镜像,这个镜像就是简单的将 helm 二进制文件下载下来放到 PATH 路径下面去即可。stage('运行 Helm') {
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
container('helm') {
sh "mkdir -p ~/.kube && cp ${KUBECONFIG} ~/.kube/config"
echo "4.开始 Helm 部署"
def userInput = input(
id: 'userInput',
message: '选择一个部署环境',
parameters: [
[
$class: 'ChoiceParameterDefinition',
choices: "Dev\nQA\nProd",
name: 'Env'
]
]
)
echo "部署应用到 ${userInput} 环境"
// 选择不同环境下面的 values 文件
if (userInput == "Dev") {
// 选择一个 Dev values 文件
} else if (userInput == "QA"){
// 选择一个 QA values 文件
} else {
// 选择一个 Pro values 文件
}
helmDeploy(
debug : false,
name : "${appName}",
chartDir : "./helm",
namespace : "${nameSpace}",
valuePath : "./helm/my-values.yaml",
imageTag : "${imageTag}"
)
echo "[INFO] Helm 部署应用成功..."
}
}
}
其中
helmDeploy
方法可以在全局中进行定义封装: ```groovy def helmLint(String chartDir) { println “校验 chart 模板” sh “helm lint ${chartDir}” }
def helmDeploy(Map args) { if (args.debug) { println “Debug 应用” sh “helm upgrade —dry-run —debug —install ${args.name} ${args.chartDir} -f ${args.valuePath} —set image.tag=${args.imageTag} —namespace ${args.namespace}” } else { println “部署应用” sh “helm upgrade —install ${args.name} ${args.chartDir} -f ${args.valuePath} —set image.tag=${args.imageTag} —namespace ${args.namespace}” echo “应用 ${args.name} 部署成功. 可以使用 helm status ${args.name} 查看应用状态” } }
然后由于每次我们构建的镜像 tag 都会变化,所以我们可以通过 `--set` 来动态设置。
然后去构建应用的时候,在 Helm 部署阶段就会看到 Stage View 界面出现了暂停的情况,需要我们选择一个环境来进行部署:![](https://cdn.nlark.com/yuque/0/2020/png/1471554/1599546329042-be73e268-b396-42ca-a3ac-bd3f23b9d043.png#height=527&id=RlVaO&margin=%5Bobject%20Object%5D&originHeight=702&originWidth=1590&originalType=binary&ratio=1&size=0&status=done&style=shadow&width=1193)
- **第五个阶段:**快速回滚。有时候我们部署的应用即使有很多测试,但是也难免会出现一些错误,这个时候如果我们是部署到线上的话,就需要要求能够立即进行回滚,这里我们同样可以使用 Helm 来非常方便的操作,添加如下一个回滚的阶段:
```groovy
stage('快速回滚?') {
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
container('helm') {
sh "mkdir -p ~/.kube && cp ${KUBECONFIG} ~/.kube/config"
def userInput = input(
id: 'userInput',
message: '是否需要快速回滚?',
parameters: [
[
$class: 'ChoiceParameterDefinition',
choices: "Y\nN",
name: '回滚?'
]
]
)
if (userInput == "Y") {
sh "helm rollback ${appName} --namespace kube-ops"
}
}
}
}
最后一条完整的流水线就完成了