1. 概述
本文是对CI/CD具体流程的一种实践,仅代表个人观点。在阅读本文前掌握以下内容,更方便理解。
1. 对K8S有基本了解,部署过具体应用;
2. 使用过Helm部署K8S应用,了解Helm基本原理;
3. 熟练使用Jenkins,理解流水线任务和Jenkins公共库的概念;
4. 熟悉Harbor、GitLab和sonarQube相关工具;
本文目标如下:
- 实现微服务应用从提交代码到部署应用到K8S的全自动化流程,其中包括:代码下载、静态分析、单元测试、编译发布、环境切换和安装部署等工作,整个过程不需要人工干预;
- 借助Jenkins Library公共库,对部署过程的步骤进行抽象,不需要每个项目都写Jenkinsfile文件(如果特殊情况也可以定义自己的);
- 借助Kubectl Config工具,对K8S集群环境访问进行动态切换,实现不同集群环境部署。
- 借助Helm Chart自定义Chart功能,制定标准的K8S发布所需资源模板Chart,开发人员无需关注部署的K8S YAML全部语法,直接指定values.yaml文件中需要的资源即可;
另外,除了在部署流程的标准化、自动化之外,还需要考虑面向微服务应用开发人员和运维人员的配置人性化问题。例如:让一个开发人员去了解复杂的K8S配置,理论上不太实际,同样的运维人员对部署应用所需的条件(例如:CPU和内存)等也不能同等对待,需要开发人员配合给出。实现将运维和研发的关注点分离。
CI/CD具体流程如下:
如上图,为CI/CD整个发布流程,该方案特点:
1. CI/CD发起支持手工构建和GitLab的WebHook构建两种启动方式;
2. 支持Maven结构的单模块和多模块微服务应用的发布;
具体流程说明如下:
1. 由开发人员PUSH代码或手工在Jenkins平台触发构建;
2. 开发人员提交代码后,GitLab会向Jenkins发起WebHook调用;
3. Jenkins平台通过指定的"流水线"配置的GitLab上的Jenkins Library地址,下载Jenkinsfile文件;
4. JenkinsFile文件中通过"@Library"命令加载在Jenkins配置的公共库,并调用公共库里面的"build"方法;
5. 从GitLab上下载项目源文件;
6. 通过maven插件sonarqube对源代码进行静态分析,并将结果上传到SonarQube服务器上;
7. 开始单元测试;
8. 通过Maven插件jib打包镜像并PUSH到Harbor仓库;
9. 通过Kubectl Config工具切换要部署到的K8S平台;
10. 通过Helm install向指定的K8S发起创建POD请求;
11. 最后,K8S接收到Helm的安装请求后,从Harbor中下载Docker镜像和Helm Chart部署系统。
2. 微服务应用
微服务应用以容器的方式运行在K8S Pod上,在Kubernetes集群中,Pod是所有业务类型的基础,也是K8S管理的最小单位级,它是一个或多个容器的组合。这些容器共享存储、网络和命名空间,以及如何运行的规范。在Pod中,所有容器都被同一安排和调度,并运行在共享的上下文中。对于具体应用而言,Pod是它们的逻辑主机,Pod包含业务相关的多个应用容器。
微服务应用部署结构如下:
如上图所示,微服务应用部署包括以下三个容器:
1. Skywalking-Agent-Sidecar容器:initContainers容器,该容器在POD启动前执行,执行完成后立即停止,主要目的是将Skywalking Agent所需要的
文件拷贝进容器组中,其中连接Skywalking服务器的配置文件是通过ConfigMap方式注入进容器;
2. 微服务应用容器:该容器为主容器,运行了程序员定义的微服务程序(采用java -cp方式运行,运行目录为/app,包括classes、libs和resources
三部分)。启动时采用了-javaagent代理Skywalking运行,用于收集链路日志记录,同时内置Consul服务发现和服务配置,通过访问
Consul-Agent-SideCar与Consul Server进行通信;
3. Consul-Agent-SideCar容器:该容器伴随微服务主容器一起运行,生命周期与主容器一样,主要目的是在Consul Server服务器上建立一个Consul
Client,用于在微服务应用与Consul Server之间转发请求,主容器微服务只需要通过127.0.0.1:8500进行通信,而不用关心Consul Server的部署IP
和端口;Consul Agent连接服务器的配置信息是通过ConfiMap注入进来的;
2.1 Skywalking-Agent-Sidecar镜像
skywalking-agent-sidecar镜像包括skywalking agent所需的文件,如下:
在微服务应用容器运行时,作为initContainers容器,项目Pod启动时负责拷贝文件到指定位置,供项目启动时调用,运行完成后会停止该容器。
2.2 Consul-Agent-Sidecar镜像
consul-agent-sidecar镜像是一个边车模式的镜像,与微服务应用容器生命周期保持一致,主要负责与远端的Consul Server通信,这样项目容器通过127.0.0.1:8500访问即可,不用关心Consul Server的IP地址和端口。
2.3 微服务应用镜像
微服务应用镜像是将开发代码打包成镜像,能够运行在K8S上。需要部署的项目都是采用Maven的文件结构,具体如下:
2.3.1 集成jib插件
微服务应用项目需要集成jib插件,jib无需Docker守护程序即可为Java应用程序构建优化的Docker和OCI映像-无需深入掌握Docker最佳实践。它可以作为Maven和Gradle的插件以及Java库使用。
1. 快速-快速部署您的更改。Jib将您的应用程序分成多个层,将依赖项与类分开。现在,您不必等待Docker重建整个Java应用程序-只需部署已更改的层。
2. 可重现-用相同的内容重建容器映像始终会生成相同的映像。永远不要再次触发不必要的更新。
3. 无守护程序-减少CLI依赖性。从Maven或Gradle内部构建Docker映像,然后推送到您选择的任何仓库(例如:Harbor)。无需再编写Dockerfile
并调用docker build / push。
平台已经提供,只需要在pom.xml中加入如下配置即可:
<properties>
<!-- 去掉发布后镜像的环境前缀 -->
<docker.image.project.version.prefix></docker.image.project.version.prefix>
<!-- 自定义镜像启动主类,默认为com.egrand.EgrandCloudApplication -->
<docker.image.project.main.class>com.egrand.EgrandCloudXXXApplication</docker.image.project.main.class>
</properties>
<build>
<plugins>
<!-- 引入jib插件 -->
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2.3.2 集成sonarQube
Static Analysis采用sonarQube来实现,需要安装sonarQube服务。Sonar(SonarQube)是一个开源平台,用于管理源代码的质量。Sonar 不只是一个质量数据报告工具,更是代码质量管理平台。支持的语言包括:Java、PHP、C#、C、Cobol、PL/SQL、Flex 等。
1. 代码覆盖:通过单元测试,将会显示哪行代码被选中;
2. 改善编码规则;
3. 搜寻编码规则:按照名字,插件,激活级别和类别进行查询;
4. 项目搜寻:按照项目的名字进行查询;
5. 对比数据:比较同一张表中的任何测量的趋势;
进行代码静态分析时,需要准备以下条件:
- 安装sonar服务器端,这里不详细介绍;
- 生成Login Token;
- 修改maven的setting.xml文件,增加如下配置:
其中sonar.login是在sonar服务端生成的登录token。<pluginGroups> <pluginGroup>org.sonarsource.scanner.maven</pluginGroup> </pluginGroups> <profiles> <profile> <id>sonar</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <!-- Optional URL to server. Default value is http://localhost:9000 --> <sonar.host.url> http://127.0.0.1:9000 </sonar.host.url> <sonar.login> [上一步生成的Login Token] </sonar.login> </properties> </profile> </profiles>
- 访问sonar服务器,新建项目
具体过程不介绍,但最终会生成一个”项目标识",需要配置到下一步骤的。 - 配置项目pomx.xml文件
<properties> <sonar.projectKey>[在sonar服务器上新建项目的项目标识]</sonar.projectKey> </properties>
2.3.3 bootstrap.yml规范
微服务应用在通过Jenkins平台部署到K8S形成pod后,在pod中会采用边车模式运行Consul-Agent-Sidecar容器,微服务应用注册到Consul是采用localhost:8500的方式进行通信即可;
同时在Jenkins Library中运行jib,是默认采用"mvn clean compile jib:build -DsendCredentialsOverHttp=true -Dprofile.active=prod"来运行的,其中prod代表的是K8S线上环境(包括K8S测试环境和K8S正式环境等,不区分);
综上述,在配置bootstrap.yml中配置prod时一定保持如下:
server:
port: 8888
spring:
application:
name: egrand-cloud-platform-demo
profiles:
active: @profile.active@
cloud:
consul:
config:
# 设置配置的基本文件夹,默认值 config 可以理解为配置文件所在的最外层文件夹
prefix: platform
# 配置环境分隔符,默认值 "," 和 default-context 配置项搭配
# 例如应用 orderService 分别有环境 default、dev、test、prod
# 只需在 config 文件夹下创建 orderService、orderService-dev、orderService-test、orderService-prod 文件夹即可
profile-separator: '-'
# 指定配置格式为 yaml
format: YAML
# 本地开发环境
---
spring:
profiles: dev
cloud:
consul:
# consul注册中心的ip地址
host: ${CONSUL_HOST:10.1.10.179}
# consul注册中心端口
port: ${CONSUL_PORT:8600}
# 配置中心相关配置
config:
# 认证token
acl-token: ${CONSUL_TOKEN:6983d4bf-87d6-591a-c3d4-dde5c05c4f28}
# 线上环境
---
spring:
profiles: prod
cloud:
consul:
# consul注册中心的ip地址
host: localhost
# consul注册中心端口
port: 8500
# 配置中心相关配置
config:
# 认证token
acl-token: ${CONSUL_TOKEN}
4. Jenkins Library公共库
4.1 目标
Jenkins Library公共库目标是规范Jenkins发布步骤,将每个项目在构建中的步骤进行抽象,规范参数传递来实现不同项目的公共构建。用户可以在新建Jenkins任务时加载公共依赖,调用公共方法,达到重复利用的目的。
1. 规范化:对每个项目中的步骤进行抽象实现,同时规范化输入参数;
2. 统一化:如果有改动,改动这一处即可;
4.2 目录结构
Jenkins Library存储在GitLab上,具体目录结构如下:
egrand-cloud-jenkins-library
|--- deploy
| |--- Jenkinsfile // 公共的Jenkinsfile,项目在创建Jenkins任务时,引用该文件开始构建,该文件调用vars/build.groovy的build方法
|--- vars
|--- build.groovy // 构建主文件,为Jenkinsfile提供调用方法build
|--- gitlab.groovy // 子流程步骤,供build.groovy调用,完成从GitLab上下载源代码
|--- jib.groovy // 子流程步骤,供build.groovy调用,完成maven插件jib构建,构建镜像并推送到Harbor中
|--- kubecm.groovy // 子流程步骤,供build.groovy调用,完成kubectl config环境切换和Helm uninstall/install操作,部署到K8S集群
|--- sonar.groovy // 子流程步骤,供build.groovy调用,完成静态代码分析,并推送到SonarQube服务器;
4.3 运行步骤
如上图,Jenkins Library存放在GitLab上,其中包括了公共的Jenkinsfile和其他脚本文件。
- Jenkinsfile文件:
// 加载jenkins公共库
@Library('jenkins-library') _
/**
* 构建参数,具体参数如下:
* cloud 运行K8S的云节点,默认值为kubernetes,在Jenkins的"Configure Clouds(配置集群)"中配置
* serviceAccount K8S运行账号,默认是jenkins2,需要在K8S集群中分配账号信息
* chart Helm的自定义chart,默认为egrand/backend-deployment-chart
* profileActive Maven编译环境,默认为prod
* gitUrl Git源码地址
* branches Git源码分支,接收jenkins在任务中配置的branch参数值
* credentialsId Git认证ID,在jenkins中配置
* imageTag 镜像版本,默认值是根据gitlab提交信息生成
* preImageTag 上一镜像版本,从GitLab提交历史获取的
* moduleDir 多模块运行目录(对于多模块项目才需要设置,单模块不需要)
* deployToEnv 部署到的环境,包括dev:开发环境;prod:生成环境
* 注意:如果不填写该值,则自动根据branches字段值来判断
* 1. branches的值等"master"或者"refs/heads/master",则deployToEnv值为prod
* 2. branches的值等"dev"或者"refs/heads/dev",则deployToEnv值为dev
**/
build([
gitUrl:"${gitUrl}",
imageTag: "${gitCommitId}",
preImageTag: "${gitPreCommitId}",
branches: "${branch}",
moduleDir: "${env.moduleDir}"
])
如上,Jenkinsfile定义了公共的脚本,在新建项目的Jenkins任务时可以引用,通过调用build方法,进入执行流程,以下是相关参数说明:
参数名称 | 说明 |
---|---|
cloud | 运行K8S的云节点,默认值为kubernetes,在Jenkins的"Configure Clouds(配置集群)"中配置 |
serviceAccount | K8S运行账号,默认是jenkins2,需要在K8S集群中分配账号信息 |
gitUrl | Git源码地址 |
branches | Git源码分支,值包括:dev(部署到K8S的测试环境)、master(部署到K8S的正式环境) |
credentialsId | Git认证ID,在jenkins中配置 |
chart | Helm的自定义chart,包括:egrand/backend-deployment-chart、egrand/foreend-deployment-chart |
imageTag | 镜像版本,默认值是根据gitlab提交信息生成,截取前7位,与项目中jib插件生成的镜像版本保持一致 |
preImageTag | 上一次镜像版本,用于在部署时删除前一个部署,避免出现重复的pod |
profileActive | Maven编译环境,默认为prod |
moduleDir | 多模块运行目录(对于多模块项目才需要设置,单模块不需要) |
deployToEnv | 部署到的环境,包括dev:开发环境;prod:生成环境 如果不指定deployToEnv,则如下: 根据branches值自动生成发布环境 * master ---> 生产环境(k8s) * dev ---> 开发环境(k8s) |
- 执行脚本
执行脚本包括build.groovy、gitlab.groovy、sonar.groovy、jib.groovy和kubecm.groovy五个脚本,其中build.groovy作为脚本的进入口,同时定义了pipeline流水线。</pre>
脚本说明如下:
脚本 | 备注 |
---|---|
build.groovy | 构建主文件,为Jenkinsfile提供调用方法build |
gitlab.groovy | 子流程步骤,供build.groovy调用,完成从GitLab上下载源代码 |
sonar.groovy | 子流程步骤,供build.groovy调用,完成静态代码分析,并推送到SonarQube服务器; |
jib.groovy | 子流程步骤,供build.groovy调用,完成maven插件jib构建,构建镜像并推送到Harbor中 |
kubecm.groovy | 子流程步骤,供build.groovy调用,完成kubectl config环境切换和Helm uninstall/install操作,部署到K8S集群 |
5. Helm自定义Chart
5.1 概述
Helm是Kubernetes的包管理器,类似于Python的pip centos的yum,主要用来管理 Charts。Helm Chart是用来封装Kubernetes原生应用程序的一系列YAML文件。可以在你部署应用的时候自定义应用程序的一些Metadata,以便于应用程序的分发。
* 对于应用发布者而言,可以通过Helm打包应用、管理应用依赖关系、管理应用版本并发布应用到软件仓库。
* 对于使用者而言,使用Helm后不用需要编写复杂的应用部署文件,可以以简单的方式在Kubernetes上查找、安装、升级、回滚、卸载应用程序
5.2 介绍
backend-deployment-chart是基于Helm自定义的后端微服务发布chart,里面定义了K8S生成所需的所有资源和YAML定义,目的是简化和规范发布流程;
* 屏蔽K8S复杂的YAML配置文件,利用Helm的-f指定参数覆盖文件或通过--set命令覆盖参数,
就能够基于backend-deployment-chart发布项目的前端文件;
* 提供Skywalking Ageng功能,记录调用链路日志给服务器端;
* 提供Consul Client边车模式,让后端微服务访问本地Consul Client,而不需要关系Consul Server在哪里;
backend-deployment-chart目录如下:
foreend-deployment-chart
|---templates // 模板文件
| |---_helpers.tpl // 帮助模板,可以理解为定义公共的组合变量
| |---consulAgent-configMap.yaml // Consul Agent配置字典文件
| |---deployment.yaml // k8s的deployment方式yaml定义文件,用于生成Deployment pod
| |---harbor-secret.yaml // Harbor密文配置文件
| |---hpa.yaml // 水平动态扩展(暂时不用)
| |---ingress.yaml // ingress定义文件(内网采用NodePort方式,暂时不用)
| |---service.yaml // 服务YAML定义,用于暴露接口(目前采用NodePort方式)
| |---serviceaccount.yaml // K8S帐户YAML定义,默认为default
| |---skywalking-configMap.yaml // Skywalking Agent代理的配置字典文件
|---Chart.yaml // 包含了该chart的描述。你可以从模板中访问它。
|---values.yaml // 包含了chart的默认值 。这些值会在用户执行helm install 或 helm upgrade时被覆盖。
foreend-deployment-chart已经发布到harbor中,通过以下命令生成pod:
# 运行线上chart生成一个POD,默认的namespace为default
> helm install [pod名称] egrand/backend-deployment-chart
# 采用values.yaml复写参数运行线上的Chart并生成一个新的pod
> helm install -f values.yaml [pod名称] egrand/backend-deployment-chart
可以通过以下代码下载:
# 搜索镜像
> helm search repo backend
# 下载egrand源下的backend-deployment-chart并解压
> helm pull egrand/backend-deployment-chart --untar
5.3 部署约定
为规范后端微服务部署流程,制定的规定如下:
- Skywalking初始化容器
通过上面的架构图,可以知道,Skywalking的相关配置文件时通过初始化容器运行时拷贝进入主容器中的,其中Skywalking Agent连接Skywalking Server的配置文件是通过ConfigMap注入进来的,文件名为:agent.config,存储路径为:/usr/skywalking/agent/config/; - 微服务镜像规范
建议采用jib打包Docker镜像,平台Maven中已内置插件,运行命令即可; - Consul Client运行约定
一个微服务应用对应一个Consul Client,同生共死,相互之间通过127.0.0.1进行通信,其中Consul Client连接Consul Server的配置信息是通过ConfigMap注入进来的文件,文件名为:agent.json,存储路径为“/etc/consul/config/”;
5.4 部署
下面介绍如何通过覆盖参数配置来实现一个项目的微服务应用部署。
其实很简单,backend-deployment-chart已经帮我们定义好了部署需要的资源,
我们只需要覆盖对应默认参数即可,就像程序开发中调用一个已经写好的公共方法,只需要传入参数即可。
-
-f 覆盖默认参数部署
在新的目录下(随便哪个目录)新建文件一个文件名为values.yaml文件,加入如下内容:# Consul Agent ConfigMap配置 consulAgentConfigmap: | { "bind_addr": "0.0.0.0", "client_addr": "0.0.0.0", "datacenter": "egdPlatform", "primary_datacenter": "egdPlatform", "encrypt": "EXz7LFN8hpQ4id8EDYiFoQ==", "data_dir": "/consul/data", "acl": { "enabled": true, "default_policy": "deny", "enable_token_persistence": true, "tokens": { "agent": "b07df4e4-1183-5496-35fe-0ac6eb726d05" } }, "log_level": "INFO", "log_file": "/consul/consul.log", "log_rotate_duration": "24h", "enable_syslog": false, "enable_debug": true, "connect":{ "enabled": true }, "ui": true, "start_join":[ "consul-0.consul.kube-platform.svc.cluster.local", "consul-1.consul.kube-platform.svc.cluster.local", "consul-2.consul.kube-platform.svc.cluster.local" ] } # skywalking配置文件configMap skywalkingConfig: | agent.service_name=${SW_AGENT_NAME:Your_ApplicationName} collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:10.1.10.178:11800} logging.file_name=${SW_LOGGING_FILE_NAME:skywalking-api.log} logging.level=${SW_LOGGING_LEVEL:INFO} plugin.mount=${SW_MOUNT_FOLDERS:plugins,activations} #Consul SideCar镜像配置 consulSideCarImage: #是否开启 enabled: true # 初始化容器配置 initContainer: #是否开启 enabled: true #应用镜像配置 image: #仓库地址 repository: [微服务应用镜像地址] #镜像版本,默认为appVersion. tag: "[微服务应用镜像版本]"
将第一步生成镜像的地址和版本填入,运行以下命令部署
> helm install -f values.yaml demo egrand/backend-deployment-chart
即可完成部署。
5.5 values.yaml参数详解
# Default values for backend-deployment-chart.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# Pod副本数量
replicaCount: 1
# 中文名称
displayName: "微服务应用"
# 部署到的命名空间
namespace: ""
# 所属层级(方便在Kuboard中查看,默认为svc)
# svc:微服务层
# gateway;网关层
# cloud:中间件
# web:展现层
layer: ""
# 名称(覆盖变量backend-deployment-chart.name的值,默认值为Chart.Name)
# backend-deployment-chart.name变量用于定义标签app.kubernetes.io/name的值,
# 形成app.kubernetes.io/name: backend-deployment-chart.name
# 利用该标签和app.kubernetes.io/instance: .Release.Name进行标签关联selector选择用
nameOverride: ""
# 发布全名称,定义Pod的名称(覆盖变量backend-deployment-chart.fullname的值,默认[Release.Name]-[Chart.Name])
fullnameOverride: ""
# pod注解
podAnnotations: {}
# 安全设置
podSecurityContext: {}
# fsGroup: 2000
# 节点选择
nodeSelector: {}
# 容忍设置
tolerations: []
# 亲和性设置
affinity: {}
# pod上定义共享存储卷列表
volumes: {}
#镜像拉取密文配置
imageCredentials:
# 覆盖名称(与config是冲突的,如果填写该值,则在K8S namespace查找配置字典)
# nameOverride: "harborsecret"
config:
# 镜像仓库地址
registry: http://10.1.10.212:8082/
# 镜像登录名
username: admin
# 镜像登录密码
password: wiki2012
#Consul Agent代理配置字典
#consulAgentConfigMap:
# # 覆盖名称(与config是冲突的,如果填写该值,则在K8S namespace查找配置字典)
# nameOverride: "consul-agent"
# # 配置字典配置信息
# config:
# agent.json: |
# {
# "bind_addr": "0.0.0.0",
# "client_addr": "0.0.0.0",
# "datacenter": "egdPlatform",
# "primary_datacenter": "egdPlatform",
# "encrypt": "EXz7LFN8hpQ4id8EDYiFoQ==",
# "data_dir": "/consul/data",
# "acl": {
# "enabled": true,
# "default_policy": "deny",
# "enable_token_persistence": true,
# "tokens": {
# "agent": "b07df4e4-1183-5496-35fe-0ac6eb726d05"
# }
# },
# "log_level": "INFO",
# "log_file": "/consul/consul.log",
# "log_rotate_duration": "24h",
# "enable_syslog": false,
# "enable_debug": true,
# "connect":{
# "enabled": true
# },
# "ui": true,
# "start_join":[
# "consul-0.consul.kube-platform.svc.cluster.local",
# "consul-1.consul.kube-platform.svc.cluster.local",
# "consul-2.consul.kube-platform.svc.cluster.local"
# ]
# }
# skywalking配置字典
#skywalkingAgentConfigMap:
# # 覆盖名称(与key和value是冲突的,如果填写该值,则在K8S namespace查找配置字典)
# nameOverride: "skywalking-config"
# # 配置字典配置信息
# config:
# agent.config: |
# agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
# collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:10.1.10.178:11800}
# logging.file_name=${SW_LOGGING_FILE_NAME:skywalking-api.log}
# logging.level=${SW_LOGGING_LEVEL:INFO}
# plugin.mount=${SW_MOUNT_FOLDERS:plugins,activations}
#应用镜像配置
image:
#仓库地址
repository: 10.1.10.212:8082/library/nginx
#镜像版本,默认为appVersion.
tag: "latest"
#镜像拉去策略:Always(总是拉取 pull)、
# IfNotPresent(默认值,本地有则使用本地镜像,不拉取)、
# Never(只使用本地镜像,从不拉取)
pullPolicy: Always
#环境变量设置,采用name和value格式。
# env:
# - name: TZ
# value: Asia/Shanghai
# - name: spring.datasource.dynamic.datasource.master.url
# value: >-
# jdbc:mysql://10.1.10.188:3306/egrand-cloud-ky3h-cis?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&serverTimezone=GMT%2B8&connectTimeout=60000&socketTimeout=30000
# - name: springfox.documentation.swagger.v2.host
# value: >-
# 10.1.10.212/ky3h
# 安全设置
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
# 资源配置
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
#镜像挂载
volumeMounts: {}
#主机模式
# - mountPath: /usr/local/skywalking/agent
# mountPropagation: None
# name: skywalking-agent
#PVC模式
# - name: atm-data
# persistentVolumeClaim:
# claimName: kube-yuncang
#Consul SideCar镜像配置
consulSideCarImage:
#是否开启
enabled: false
#镜像名称
name: "consul-agent-sidecar"
#仓库地址
repository: 10.1.10.212:8082/egrand-cloud-deploy/consul-agent-sidecar
#镜像版本
tag: "latest"
#镜像拉去策略:Always(总是拉取 pull)、
# IfNotPresent(默认值,本地有则使用本地镜像,不拉取)、
# Never(只使用本地镜像,从不拉取)
pullPolicy: IfNotPresent
# 资源配置
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
# 资源配置
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
# 初始化容器配置
initContainer:
#是否开启
enabled: false
#镜像名称
name: "skywalking-agent-sidecar"
#仓库地址
repository: 10.1.10.212:8082/egrand-cloud-deploy/skywalking-agent-sidecar
#镜像版本
tag: "latest"
#镜像拉去策略:Always(总是拉取 pull)、
# IfNotPresent(默认值,本地有则使用本地镜像,不拉取)、
# Never(只使用本地镜像,从不拉取)
pullPolicy: IfNotPresent
# 资源配置
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
# 资源配置
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
# 运行参数配置
args:
- '-c'
- >-
mkdir -p /skywalking/agent && cp -r /usr/skywalking/agent/* /skywalking/agent
# 运行命令配置
command:
- sh
# 服务配置
service:
# service的类型访问方式。一般为NodePort、ClusterIP、LoadBalancer
type: NodePort
# 内部端口
ports: {}
# - name: names
# port: 80
# protocol: TCP
# targetPort: 80
# 帐户设置,create为false时,会自动设置帐户名为default
serviceAccount:
# 是否创建帐户
create: false
# 帐户注解
annotations: {}
# 帐户名,不设置并且create为true,则帐户名为backend-deployment-chart.fullname
# If not set and create is true, a name is generated using the fullname template
name: ""
ingress:
enabled: false
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: chart-example.local
paths:
- path: /
backend:
serviceName: chart-example.local
servicePort: 80
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
以上参数都可以通过定义values.yaml进行复写,在安装时使用helm install -f values.yaml demo egrand/backend-deployment-chart覆盖默认参数。
5.5.1 微服务应用配置说明
微服务应用镜像是由开发人员将开发好的微服务上传到Harbor,在生产容器时会根据指定Harbor镜像地址自动下载并启动。在配置中通过以下配置声明微服务镜像:
#应用镜像配置
image:
#仓库地址
repository: 10.1.10.212:8082/library/nginx
#镜像版本,默认为appVersion.
tag: "latest"
#镜像拉去策略:Always(总是拉取 pull)、
# IfNotPresent(默认值,本地有则使用本地镜像,不拉取)、
# Never(只使用本地镜像,从不拉取)
pullPolicy: Always
#环境变量设置,采用name和value格式。
# env:
# - name: TZ
# value: Asia/Shanghai
# - name: spring.datasource.dynamic.datasource.master.url
# value: >-
# jdbc:mysql://10.1.10.188:3306/egrand-cloud-ky3h-cis?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&serverTimezone=GMT%2B8&connectTimeout=60000&socketTimeout=30000
# - name: springfox.documentation.swagger.v2.host
# value: >-
# 10.1.10.212/ky3h
# 安全设置
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
# 资源配置
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
#镜像挂载
volumeMounts: {}
#主机模式
# - mountPath: /usr/local/skywalking/agent
# mountPropagation: None
# name: skywalking-agent
#PVC模式
# - name: atm-data
# persistentVolumeClaim:
# claimName: kube-yuncang
如上,可以通过repository和tag指定了镜像下载地址和版本,通过env指定容器运行的环境变量,通过resources可以设定资源限制等。
注意:环境变量如果是整形,要加单引号,如下:
#应用镜像配置
image:
#仓库地址
repository: 10.1.10.212:8082/egrand-cloud/egrand-cloud-demo-server
#镜像版本
tag: "prod-latest"
env:
- name: CONSUL_HOST
value: 10.1.10.179
- name: CONSUL_PORT
value: '8500'
5.5.2 Consul Client SideCar配置说明
该容器默认是关闭的,如果有需要可以开启,该容器采用SideCar模式运行在微服务应用容器的旁边,使微服务应用容器中的Consul能够使用127.0.0.1:8500方式实现与Consul Server的通信,而启用该容器需要设置连接Consul Server的配置信息,配置中采用ConfigMap实现,配置如下:
consulAgentConfigMap:
# 覆盖名称(与config是冲突的,如果填写该值,则在K8S namespace查找配置字典)
nameOverride: "consul-agent"
# 配置字典配置信息
config:
agent.json: |
{
"bind_addr": "0.0.0.0",
"client_addr": "0.0.0.0",
"datacenter": "egdPlatform",
"primary_datacenter": "egdPlatform",
"encrypt": "EXz7LFN8hpQ4id8EDYiFoQ==",
"data_dir": "/consul/data",
"acl": {
"enabled": true,
"default_policy": "deny",
"enable_token_persistence": true,
"tokens": {
"agent": "b07df4e4-1183-5496-35fe-0ac6eb726d05"
}
},
"log_level": "INFO",
"log_file": "/consul/consul.log",
"log_rotate_duration": "24h",
"enable_syslog": false,
"enable_debug": true,
"connect":{
"enabled": true
},
"ui": true,
"start_join":[
"consul-0.consul.kube-platform.svc.cluster.local",
"consul-1.consul.kube-platform.svc.cluster.local",
"consul-2.consul.kube-platform.svc.cluster.local"
]
}
如上,为Consul Client连接Consul Server的配置信息,可以采用两种配置方式:
-
如果在我们部署的K8S NameSpace下已经新建了一个ConfigMap,可以通过指定参数nameOverride值即可。
consulAgentConfigMap: # 覆盖名称(与config是冲突的,如果填写该值,则在K8S namespace查找配置字典) nameOverride: "consul-agent"
-
如果想新建一个ConfigMap,通过指定config参数值即可
consulAgentConfigMap: # 配置字典配置信息 config: agent.json: | { "bind_addr": "0.0.0.0", "client_addr": "0.0.0.0", "datacenter": "egdPlatform", "primary_datacenter": "egdPlatform", "encrypt": "EXz7LFN8hpQ4id8EDYiFoQ==", "data_dir": "/consul/data", "acl": { "enabled": true, "default_policy": "deny", "enable_token_persistence": true, "tokens": { "agent": "b07df4e4-1183-5496-35fe-0ac6eb726d05" } }, "log_level": "INFO", "log_file": "/consul/consul.log", "log_rotate_duration": "24h", "enable_syslog": false, "enable_debug": true, "connect":{ "enabled": true }, "ui": true, "start_join":[ "consul-0.consul.kube-platform.svc.cluster.local", "consul-1.consul.kube-platform.svc.cluster.local", "consul-2.consul.kube-platform.svc.cluster.local" ] }
5.5.3 Skywalking initContainer配置说明
微服务应用部署支持Skywalking配置,这要求微服务应用在启动命令java -cp 中要制定-javaagent=[skywalking包路径]方式才能使用,默认是关闭的,如下:
# 初始化容器配置
initContainer:
#是否开启
enabled: false
#镜像名称
name: "skywalking-agent-sidecar"
#仓库地址
repository: 10.1.10.212:8082/egrand-cloud-deploy/skywalking-agent-sidecar
#镜像版本
tag: "latest"
#镜像拉去策略:Always(总是拉取 pull)、
# IfNotPresent(默认值,本地有则使用本地镜像,不拉取)、
# Never(只使用本地镜像,从不拉取)
pullPolicy: IfNotPresent
# 资源配置
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
# 资源配置
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
# 运行参数配置
args:
- '-c'
- >-
mkdir -p /skywalking/agent && cp -r /usr/skywalking/agent/* /skywalking/agent
# 运行命令配置
command:
- sh
该容器的目的就是将Skywalking需要应用到的第三方包和配置拷比到容器组中,使得微服务应用容器能够访问到,在启用了skywalking之后,还要进行Skywalking服务器连接配置,指定服务器地址和参数,这样采用将微服务应中的链路日志推送到服务器上。这里采用ConfigMap挂接方式进行:
# skywalking配置字典
skywalkingAgentConfigMap:
# 覆盖名称(与key和value是冲突的,如果填写该值,则在K8S namespace查找配置字典)
nameOverride: "skywalking-config"
# 配置字典配置信息
config:
agent.config: |
agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:10.1.10.178:11800}
logging.file_name=${SW_LOGGING_FILE_NAME:skywalking-api.log}
logging.level=${SW_LOGGING_LEVEL:INFO}
plugin.mount=${SW_MOUNT_FOLDERS:plugins,activations}
如上,具有两种方式:
-
如果微服务应用运行的K8S Namespace中已经存在一个ConfigMap,则只需要指定其名称即可:
# skywalking配置字典 skywalkingAgentConfigMap: # 覆盖名称(与key和value是冲突的,如果填写该值,则在K8S namespace查找配置字典) nameOverride: "skywalking-config"
-
如果想新建一个ConfigMap,则配置config参数即可;
# skywalking配置字典 skywalkingAgentConfigMap: # 配置字典配置信息 config: agent.config: | agent.service_name=${SW_AGENT_NAME:Your_ApplicationName} collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:10.1.10.178:11800} logging.file_name=${SW_LOGGING_FILE_NAME:skywalking-api.log} logging.level=${SW_LOGGING_LEVEL:INFO} plugin.mount=${SW_MOUNT_FOLDERS:plugins,activations}
5.5.3 imagePullSecrets配置说明
Chart中通过定义如下参数来默认给出了镜像拉取认证:
#镜像拉取密文配置
imageCredentials:
# 覆盖名称(与config是冲突的,如果填写该值,则在K8S namespace查找配置字典)
# nameOverride: "harborsecret"
config:
# 镜像仓库地址
registry: http://10.1.10.212:8082/
# 镜像登录名
username: admin
# 镜像登录密码
password: wiki2012
如上,如果想复用命名空间已经存在的Secret,则修改本地的values.yaml如下:
#镜像拉取密文配置
imageCredentials:
# 覆盖名称(与config是冲突的,如果填写该值,则在K8S namespace查找配置字典)
nameOverride: "harborsecret"
5.5.4 Service服务配置说明
服务配置参数默认是采用ClusterIP方式暴露端口的,如果没有端口暴露,则无需配置,如果需要配置,可以通过以下方式复写默认配置:
# 服务配置
service:
# service的类型访问方式。一般为NodePort、ClusterIP、LoadBalancer
type: NodePort
# 端口配置
ports:
- name: names
port: 80
protocol: TCP
targetPort: 80
NodePort: 80
6. Jenkins&GitLab配置
本章节介绍Jenkins的公共库配置,如何新建任务并实现与GitLab的结合。
1. 利用Jenkins公共库配置,规范发布流程;
2. 利用Jenkins的WebHook功能实现与GitLab通信;
6.1 Jenkins Library公共库配置
配置Jenkins Library目的是能够在Jenkinsfile文件中通过"@Library"方式远程加载出来,所以需要指定其名称以及位置等信息。登录到Jenkins管理界面,依次点击”系统设置->系统配置“ 找到"Global Pipeline Libraries",然后如图配置即可:
6.2 Jenkins单模块任务配置
需要发布一个应用时,按如下步骤操作(以下以egrand-cloud-demo-server发布为例)
如上,就是一个单模块的微服务应用。
6.2.1 新建Jenkins任务
-
新建Jenkins任务
点击【新建任务】按钮,进入如下页面:
输入一个任务名称,选择”流水线“构建。
注:任务名称必须以英文开头,且长度不能超过30个字符;(该限制是在发布K8S POD时要求的限制) -
点击【确认】按钮,如下图:
-
配置”构建触发器“,点击页签”构建触发器“,如下图:
选择”Generic Webhook Trigger",并在“Post content parameters”中添加如下参数:
variable | Expression | Description |
---|---|---|
branch | $.ref JSONPath | 获取WebHook中GitLab的分支信息参数 |
gitUrl | $.project.git_http_url JSONPath | 获取WebHook中GitLab的http地址信息参数 |
gitCommitId | $.after JSONPath | 获取WebHook中GitLab最新的提交id号 |
gitPreCommitId | $.before JSONPath | 获取WebHook中GitLab上一次提交id号 |
然后,查找到以下界面:
设置GitLab需要传递的Token值,这个值会在GitLab发起WebHook的时候传递过来,用于关联GitLab项目和具体任务。
-
配置流水线,点击页签【流水线】,如下:
如上图,指定了Jenkins Library在GitLab上的地址,同时设置了Jenkinsfile的脚本路径。
- 点击【保存】即可。
6.2.2 GitLab WebHook配置
上一步我们已经完成了一个任务的创建,并且在第3步中得到了一个Token值,现在需要在GitLab上将项目和Jenkins任务关联起来,需要登录GitLab进行操作:
-
登录GitLab管理界面,查找到需要关联的GitLab项目
-
在该项目下选择菜单“Settings-->Integrations",进入Hook界面配置:
如上图,输入URL地址,规范为:http://[Jenkins访问地址]:[Jenkins访问端口]/generic-webhook-trigger/invoke?token=[在Jenkins任务中的设置的token值]
-
点击按钮[Save]即可。
- 可以通过[Test]下拉菜单来进行测试,测试是否能够正常触发Jenkins任务。
6.3 Jenkins多模块任务配置
需要发布一个应用时,按如下步骤操作(以下以egrand-cloud-project发布为例)
如上图,为多模块的应用,现在需要发布egrand-cloud-ram-server模块。
6.3.1 新建Jenkins任务
-
新建Jenkins任务
点击【新建任务】按钮,进入如下页面:
输入一个任务名称,选择”流水线“构建。
注:任务名称必须以英文开头,且长度不能超过30个字符;(该限制是在发布K8S POD时要求的限制) -
点击【确认】按钮,如下图:
-
配置”构建触发器“,点击页签”构建触发器“,如下图:
选择”Generic Webhook Trigger",并在“Post content parameters”中添加如下参数:
variable | Expression | Description |
---|---|---|
branch | $.ref JSONPath | 获取WebHook中GitLab的分支信息参数 |
gitUrl | $.project.git_http_url JSONPath | 获取WebHook中GitLab的http地址信息参数 |
gitCommitId | $.after JSONPath | 获取WebHook中GitLab最新的提交id号 |
gitPreCommitId | $.before JSONPath | 获取WebHook中GitLab上一次提交id号 |
commits | $.commits[0].['modified','added','removed'][*] JSONPath | 获取WebHook中GitLab提交的最新日志记录,用于判断是否为本模块。 |
配置GitLab在发起WebHook时的Token,配置以下界面:
设置GitLab需要传递的Token值,这个值会在GitLab发起WebHook的时候传递过来,用于关联GitLab项目和具体任务。
设置 Optional filter,用于对提交的最新日志做正则表达式运算,判断是否提交的代码包含该任务。
-
配置流水线,点击页签【流水线】,如下:
设置Jenkinsfile文件的GitLab地址和路径,这里引用Jenkins Library公共的Jenkinsfile文件。
- 点击【保存】即可。
6.3.2 GitLab WebHook配置
Jenkins Library存储在GitLab上,具体目录结构如下:
egrand-cloud-jenkins-library
|--- deploy
| |--- Jenkinsfile // 公共的Jenkinsfile,项目在创建Jenkins任务时,引用该文件开始构建,该文件调用vars/build.groovy的build方法
|--- vars
|--- build.groovy // 构建主文件,为Jenkinsfile提供调用方法build
|--- gitlab.groovy // 子流程步骤,供build.groovy调用,完成从GitLab上下载源代码
|--- jib.groovy // 子流程步骤,供build.groovy调用,完成maven插件jib构建,构建镜像并推送到Harbor中
|--- kubecm.groovy // 子流程步骤,供build.groovy调用,完成kubectl config环境切换和Helm uninstall/install操作,部署到K8S集群
|--- sonar.groovy // 子流程步骤,供build.groovy调用,完成静态代码分析,并推送到SonarQube服务器;
7. K8S集群环境
K8S集群环境分为测试环境和生成环境,为了保持发布时的统一处理,规定如下:
1. GitLab master分支 ----> K8S生产环境
2. GitLab dev分支 ----> K8S测试环境
具体切换时使用kubectl config 工具切换。
注:在部署时,会删除掉上次部署的pod和本次部署的pod先,然后再部署;