惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
WordPress大学
WordPress大学
云风的 BLOG
云风的 BLOG
Stack Overflow Blog
Stack Overflow Blog
MongoDB | Blog
MongoDB | Blog
腾讯CDC
V
V2EX
Martin Fowler
Martin Fowler
A
About on SuperTechFans
大猫的无限游戏
大猫的无限游戏
Blog — PlanetScale
Blog — PlanetScale
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
酷 壳 – CoolShell
酷 壳 – CoolShell
C
Check Point Blog
博客园 - 【当耐特】
Cisco Talos Blog
Cisco Talos Blog
The Hacker News
The Hacker News
K
Kaspersky official blog
Security Latest
Security Latest
H
Help Net Security
博客园_首页
美团技术团队
Spread Privacy
Spread Privacy
博客园 - 司徒正美
Hugging Face - Blog
Hugging Face - Blog
S
SegmentFault 最新的问题
G
Google Developers Blog
NISL@THU
NISL@THU
爱范儿
爱范儿
I
Intezer
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
N
News and Events Feed by Topic
P
Privacy International News Feed
Application and Cybersecurity Blog
Application and Cybersecurity Blog
S
Security @ Cisco Blogs
Schneier on Security
Schneier on Security
雷峰网
雷峰网
人人都是产品经理
人人都是产品经理
V
Vulnerabilities – Threatpost
W
WeLiveSecurity
P
Palo Alto Networks Blog
G
GRAHAM CLULEY
Hacker News: Ask HN
Hacker News: Ask HN
I
InfoQ
The Cloudflare Blog
F
Full Disclosure
SecWiki News
SecWiki News
宝玉的分享
宝玉的分享
N
Netflix TechBlog - Medium

陈少文的网站

巨变与机遇的未来十年 Kubernetes 平台管理软件压力测试方案 使用镜像部署 Hexo 静态页面 终于等到你 - GitHub 镜像仓库服务(ghcr.io) 一起来学 Go --(6)Interface 一起来学 Go --(5)Goroutine 和 Channel 什么是函数式编程 如何在 Kubernetes 集群集成 Kata 柯里化与偏函数 使用 PyGithub 自动创建 Label 软件产品是团队能力的输出 Helm 2 、Helm 3 比较 IoT 变现 Kubernetes 中的 DNS 服务 国内的 Helm 镜像源 Harbor 使用自签证书支持 Https 访问 DevOps 工具链之 Prow 如何使用 kfctl 安装 Kubeflow VS Code 无法下载 Go 插件的工具包 工程师更应具有服务精神 你不知道的 Docker 使用技巧 使用 Docker 运行 Tensorflow 论中国 什么是左移 如何清空 Git 仓库全部历史记录 一禅小和尚 有风吹过厨房 时间的玫瑰 如何在 CentOS 安装 GPU 驱动 开发 Tips(19) 使用 Velero 备份 Kubernetes 集群 Kubernetes Cheat Sheet 开发 Tips(18) 如何构建一个 Java 工程 开发 Tips(17) KubeSpray 安装 Kubernetes 报错 ip in ansible_all_ipv4_addresses 基于 Kubernetes 和 Jenkins 搭建自动化测试系统 在 Kubernetes 上动态创建 Jenkins Slave 使用 Jenkins 进行服务拨测 开发 Tips(16) Kubernetes 签发 Ingress 证书及日常故障运维 Kubernetes 中 Deployment 的基本操作 Kubernetes 中的证书 如何使用 KubeBuilder 开发一个 Operator Kubernetes 1.6.0 安装问题汇总 镜像管理工具 -- Harbor 开发 Tips(15) Docker 如何拉取镜像 开发 Tips(14) 使用 Helm 安装 harbor 开发 Tips(13) 使用 S2I 构建云原生应用 在 Kubernetes 中使用 emptyDir、hostPath、localVolume 开发 Tips(12) 开发 Tips(11) 代码质量分析工具 SonarQube 使用 Kubeadm 安装 Kubernetes 集群 一起来学 Go --(4)常用函数 Kubernetes 中的 Ceph Kubernetes 之 Volumes Kubernetes 之 Labels、Selectors 开发 Tips(10) 开源正在重构商业模式 Kubernetes 之网络 Kubernetes 之 API 使用 Helm 和 Operator 快速部署 Prometheus Kubernetes 复杂有状态应用管理框架 -- Operator Kubernetes 的包管理器 -- Helm 一起来学 Go --(3)Go Modules 如何一步一步地优化博客方案 kubectl 实用指南 Kubernetes 中的基本概念 搭建远程 Kubernetes 开发环境 大公司和小公司的 ToB 思路 开发 Tips(9) Go 入门指南 一起来学 Go --(2)数据与逻辑结构 如何预防 Web 富文本中的 XSS 攻击 django-xss-cleaner 云工作时代 一起来学 Go --(1)背景与特点 SaaS 开发团队的不同阶段 你不知道的 Git 使用技巧 输出既服务 微服务设计 继续奔跑 开发 Tips(8) 从账户安全到二次验证 Django 性能之数据库查询优化 Django 性能之分库分表 敏捷开发之研发流程 打造一致性的团队 开发 Tips(7) Pytest 进阶学习之 Mock PaaS 部署之 buildpack Go 开发配置 领域输出才是 PaaS 的核心竞争力 Pytest 入门学习 开发 Tips(6) 如何使用 Jenkins、Docker、GitLab 搭建 Django 自动化部署流程
KubeSphere DevOps 3.0 流水线开发指南
微信公众号 · 2020-10-13 · via 陈少文的网站

KubeSphere DevOps 包含 S2I 和 Pipeline 两部分。在社区中,openshift 提供了一个打包应用的工具 S2I,具体请参考 使用 S2I 构建云原生应用
。KubeSphere 将其做成了服务,采用 CRD 使用一个单独的 Operator 对其进行管理,功能比较独立。而在 3.0 中 Pipeline 与 KubeShere Core 耦合依然十分紧密,在搭建环境和调试上略显复杂。本篇主要提供开发者维护和二次开发 KubeSphere DevOps 3.0 指引。

1. DevOps 流水线架构

下图是流水线的整体架构:

1.1 存储模型

产品概念Kubernetes 对象Jenkins 对象
DevOps 工程DevopsProject文件夹
流水线Pipeline流水线/多分支流水线
凭证Credential文件夹下的凭据

1.2 数据流

主要涉及两类,一类是创建类型的操作,另一类是触发类型的操作。

创建类型的操作,主要包括三种 CRD 类型的创建,DevopsProject、Pipeline、Credential 。用户通过前端,调用 ks-apiserver 接口,创建对应资源存储在 Etcd 中,然后 ks-controller-manager 不断地将这些对象同步到 Jenkins 。

触发类型的操作,主要是执行、审核流水线等瞬时动作。用户通过前端,调用 ks-apiserver 经过数据转换,直接调用 Jenkins API 。

2. DevOps 流水线相关的组件

2.1 系统核心组件

  • ks-apiserver

ks-apiserver 是访问服务的 API 入口。在 3.0 中,ks-apigateway、ks-account 被合并到了 ks-apiserver。因此,ks-apiserver 承载了这两个组件的功能。

  • ks-controller-manager

在 3.0 中,DevOps 依然与 KubeSphere Core 代码紧密耦合,没有运行单独的 Operator 处理相关的 CRD 资源。DevOps 所有 CRD 资源的处理都在 ks-controller-manager 中进行。

2.2 Jenkins 流水线

  • ks-jenkins

Jenkins 采用的是 Helm 进行安装和维护,相关的配置可以查看 GitHub 上 ks-installer 仓库

其中 Jenkins 镜像使用的是官方的,没有进行任何定制。

  • uc-jenkins-update-center

uc 是提供给 Jenkins 下载插件的服务。有两方面的原因需要 uc: 一方面是适配离线环境,同时线上官方地址下载慢;另一方面是有自行开发的插件需要集成。

uc 提供的只是一个 Nginx 下载服务,相关的镜像内容也只是为了存储 Jenkins 插件而已。

3. 如何搭建流水线的开发环境

3.1 本地安装 Git、Go、Kubebuilder 基础环境

在此不会详细描述,仅以 OS X 为例。

  • 安装 Git

查看版本

1
2
3
git version

git version 2.26.2
  • 安装 Golang

查看版本

1
2
3
go version

go version go1.14.4 darwin/amd64
  • 安装 Kubebuilder
1
brew install kubebuilder

查看版本

1
2
3
kubebuilder version

Version: version.Version{KubeBuilderVersion:"2.3.0", KubernetesVendor:"1.16.4", GitCommit:"800f63a7e41a6a8016d4cb9d583e1705b0812c9d", BuildDate:"2020-02-28T19:15:41Z", GoOs:"unknown", GoArch:"unknown"}

3.2 安装并配置本地访问

  • 安装 Kubernetes 集群

推荐安装工具 Kubekey。现在主流的集群安装工具是基于 Kubeadm 的二次封装。Kubekey 的优势是国内安装快,配置简单。使用 Kubeadm 半小时的工作量,Kubekey 两分钟解决,还集成了不少插件。这也符合我提倡的,技能文档化,文档工具化,工具产品化,产品服务化 的想法。

在安装时,需要注意一个参数。

1
2
controlPlaneEndpoint:
    domain: k2

由于 kube-apiserver 采用的是 https 通信,这里的 domain 会被设置到 certSANs 中生成证书。通过 certSANs 中地址进行地访问才是合法的。

  • 开发环境配置 hosts

完成安装 Kubernetes 集群之后,在开发环境配置 hosts ,即可直接通过 domain 进行远程访问 kube-apiserver 。下面是我本地的 /etc/hosts 配置,一共有三个集群:

1
2
3
4
5
cat /etc/hosts

139.198.x.x  k1
139.198.x.x  k2
139.198.x.x  k3
  • 开发环境配置 kubeconfig

简单一点,可以直接拷贝服务器的文件到本地保存。这里提供一份脚本,可以快速切换多个环境。注意,替换 your_password 为你的远程登陆密码。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Switch K8s
function on_k8s() {
   if test -f ~/.kube/config.bk; then
     rm -rf ~/.kube/config.bk
   fi
   if test -f ~/.kube/config; then
     mv ~/.kube/config ~/.kube/config.bk
   fi
   sed -i'.s' -e '/$1/d'  ~/.ssh/known_hosts
   sshpass  -p "your_password" ssh -o StrictHostKeyChecking=no root@$1 "cat /etc/kubernetes/admin.conf" > ~/.kube/config
   sed -i'.s' -E 's/([0-9]{1,3}\.){3}[0-9]{1,3}'/$1/ ~/.kube/config
   sed -i'.s' -E 's/kubernetes-admin@cluster.local'/$1/ ~/.kube/config
}

使用时,执行 on_k8s k1 切换到 k1 环境,执行 on_k8s k2 切换到 k2 环境。

  • 验证配置是否成功
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 切换环境
on_k8s k2

# 执行 kubectl 命令
kubectl get node

NAME     STATUS   ROLES    AGE   VERSION
master   Ready    master   54d   v1.17.9
node1    Ready    worker   54d   v1.17.9
node2    Ready    worker   54d   v1.17.9

3.3 克隆 KubeSphere 仓库代码

star & fork GitHub 项目 kubesphere/kubesphere 。Git 的提交流程可以参考文档: 一个完整的 Git 提交流程

  • 克隆代码
1
git clone https://github.com/shaowenchen/kubesphere
  • 进入项目目录

3.4 配置 Webhook 证书

执行如下命令,在 $TMPDIR 目录下生成证书。

1
2
3
4
5
mkdir -p .keys && openssl req -nodes -new -x509 -keyout ./.keys/ca.key -out ./.keys/ca.crt -subj "/CN=cronprimer CA"
openssl genrsa -out ./.keys/tls.key 2048
openssl req -new -key ./.keys/tls.key -subj "/CN=webhook-server.webhook.svc" | openssl x509 -req -CA ./.keys/ca.crt -CAkey ./.keys/ca.key -CAcreateserial -out ./.keys/tls.crt
mkdir -p $TMPDIR/k8s-webhook-server/serving-certs
cp ./.keys/* $TMPDIR/k8s-webhook-server/serving-certs/
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
tree $TMPDIR/k8s-webhook-server

/Users/shaowenchen/Temp/k8s-webhook-server
└── serving-certs
    ├── ca.crt
    ├── ca.key
    ├── ca.srl
    ├── tls.crt
    └── tls.key

1 directory, 5 files

3.5 配置 kubesphere.yaml

  • 在项目根目录下,新增 kubesphere.yaml 文件。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
kubernetes:
  kubeconfig: "/Users/shaowenchen/.kube/config"
  master: k2:6443
  qps: 1e+06
  burst: 1000000

devops:
  host: http://k2:30180/
  username: admin
  password: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImFkbWluQGt1YmVzcGhlcmUuaW8iLCJ1c2VybmFtZSI6ImFkbWluIiwidG9rZW5fdHlwZSI6InN0YXRpY190b2tlbiJ9.eoVAs9uWPi54YTknQ4NaaomVdq3q-THsZMOb4TwChU4
  maxConnections: 100

sonarQube:
  host: http://k2:30594
  token: cfa96640569d9ce3b6f84ae287bcc1a970973958
s3:
  endpoint: http://k2:9001
  region: us-east-1
  disableSSL: true
  forcePathStyle: true
  accessKeyID: openpitrixminioaccesskey
  secretAccessKey: openpitrixminiosecretkey
  bucket: s2i-binaries
authentication:
  authenticateRateLimiterMaxTries: 10
  authenticateRateLimiterDuration: 10m0s
  loginHistoryRetentionPeriod: 168h
  maximumClockSkew: 10s
  multipleLogin: true
  kubectlImage: kubesphere/kubectl:v1.0.0
  jwtSecret: "2b0WJPoacvbvMB82bTEWO4s4vFlmzoPd"
  oauthOptions:
    accessTokenMaxAge: 0
    AccessTokenInactivityTimeout: 0
  authorization:
    mode: "RBAC"
    # mode: "AlwaysAllow"
monitoring:
  endpoint: FAKE
ldap:
  host: FAKE
redis:
  host: FAKE

这里我直接使用远程环境的访问地址,比使用 telepresence 通过集群服务地址访问效率更高。kubesphere.yaml 中相关的配置值,可以从 kubectl get cm kubesphere-config -n kubesphere-system -o yaml 的输出中获取,粘贴到开发环境中即可。

值得注意的是 3.0 中,采用外置的 Sonarqube ,因此,需要根据官方文档进行单独配置。kubeconfig 字段指向的是开发环境 kubeconfig 文件地址,而线上使用的是 serviceaccount 。S2I 依赖于 S3 服务存储二进制文件,流水线不需要 S3。

3.6 本地运行测试服务

  • 运行 ks-apiserver
1
go run cmd/ks-apiserver/apiserver.go --logtostderr=true --v=8 --debug=true

服务启动之后,会打印 Start listening on :9090 表示,ks-apiserver 监听在 9090 端口,可以访问。

通过 Postman 进行访问时,需要带上集群前端的 Token,也可以使用 kubesphere-config 中的永久 Token,还可以将 mode 改为 AlwaysAllow 关掉鉴权。

在 Postman 中,可以设置一下变量,通过 {{ VAR_NAME }} 的形式可以引用,十分方便。下面有两类 API 的调用示例:

一种是 CRD 资源的增删改查,带上 Token 即可。

另一种是透传 Jenkins API ,不仅需要带上 Token,还需要带上 Jenkins Crumb 。这些参数通过页面访问时,在 Cookies 中都可以拿到。

  • 运行 ks-controller-manager

为了避免干扰,需要先暂停集群中的 ks-controller-manager 。

1
kubectl scale deploy ks-controller-manager --replicas=0 -n kubesphere-system

运行本地的 ks-controller-manager

1
go run cmd/controller-manager/controller-manager.go --logtostderr=true --v=8 --multiple-clusters=false

4. 如何发布到集群环境

建议将相关服务的 imagePullPolicy 改为 Always ,确保每次使用的都是最新的镜像。

4.1 更新插件

建立如下目录结构:

1
2
3
4
5
6
tree -L 1
.
|-- Dockerfile
`-- webroot

1 directory, 2 files

Dockerfile 内容

FROM busybox:1.29.3

COPY webroot/ /webroot/

webroot 中的内容,可以先运行 docker run -it -d kubesphere/jenkins-uc:v3.0.0 获取到容器 ID ,然后使用 docker cp {UC_ContainerID}:/webroot ./ 命令拷贝插件,自由替换、增删其中的离线插件。

最后使用 docker build . -t shaowenchen/jenkins-uc:latest 命令打包,推送镜像。然后执行命令 kubectl -n kubesphere-devops-system edit deploy uc-jenkins-update-center ,修改 uc 的服务镜像为 shaowenchen/jenkins-uc:latest ,重启 deploy 即可。

这里需要注意的是 Jenkins 只有在首次初始化时,访问 uc 获取插件。初始化插件列表在 kubectl -n kubesphere-devops-system get cm ks-jenkins -o yaml 中可以查看。

4.2 更新 ks-apiserver 或 ks-controller-manger

  • 编译 ks-apiserver
  • 编译并推送 ks-apiserver 镜像
docker build -f build/ks-apiserver/Dockerfile -t shaowenchen/ks-apiserver:latest .
docker push shaowenchen/ks-apiserver:latest
  • 更新 ks-apiserver 服务

执行命令,更新镜像为 shaowenchen/ks-apiserver:latest 即可。

1
kubectl -n kubesphere-system edit deploy ks-apiserver
  • 编译 ks-controller-manager
1
make controller-manager
  • 编译并推送 ks-controller-manager 镜像
docker build -f build/ks-controller-manager/Dockerfile -t shaowenchen/ks-controller-manager:latest .
docker push shaowenchen/ks-controller-manager:latest
  • 更新 ks-controller-manger 服务

执行命令,更新镜像为 shaowenchen/ks-controller-manager:latest 即可。

1
kubectl -n kubesphere-system edit deploy ks-controller-manager

5. 关于鉴权插件

kubesphere-token-auth-plugin 插件主要是为了集成 KubeSphere 的权限体系,使 Jenkins 与之保持一致。如下图,无论是 CRD 资源类型,还是触发动作类型,在调用 Jenkins 时,都需要经过 ks-apiserver 进行 token 的 review。

在 KubeSphere 中 Token 是 bearer 类型,但是插件是基于 Basic 鉴权进行的扩展,所以需要转换。代码如下:

https://github.com/kubesphere/kubesphere/blob/release-3.0/pkg/simple/client/devops/jenkins/request.go#L47:6

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
func SetBasicBearTokenHeader(header *http.Header) error {
	bearTokenArray := strings.Split(header.Get("Authorization"), " ")
	bearFlag := bearTokenArray[0]
	var err error
	if strings.ToLower(bearFlag) == "bearer" {
		bearToken := bearTokenArray[1]
		if err != nil {
			return err
		}
		claim := authtoken.Claims{}
		parser := jwt.Parser{}
		_, _, err = parser.ParseUnverified(bearToken, &claim)
		if err != nil {
			return err
		}
		creds := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", claim.Username, bearToken)))
		header.Set("Authorization", fmt.Sprintf("Basic %s", creds))
	}
	return nil
}

插件中的逻辑主要是,调用 ks-apiserver 鉴权接口,返回合法用户。

6. 后端代码结构及逻辑

6.1 代码目录

代码路径以 https://github.com/kubesphere/kubesphere/tree/release-3.0 为例。

  • pkg/apiserver/apiserver.go

通过 ks-apiserver 对外提供的接口,都需要在这里进行注册,配置 GVR 等。

  • pkg/kapis/devops

KubeSphere 以 /kapis 为前缀提供 API, 在这里还需要对每个 URL 进行更详细的描述和处理,通常会调用到很多 models 中的函数方法。API 文档也是在这里进行描述的。

  • pkg/models/devops

对于数据层的操作,被聚合在 models 中。这里提供了很多对数据的操作方法。

  • pkg/controller/devopscredential

credential 的 controller 处理部分。

  • pkg/controller/devopsproject

devopsproject 的 controller 处理部分。

  • pkg/controller/pipeline

pipeline 的 controller 处理部分。

  • pkg/simple/client/devops

上面的代码理解起来相对容易,这部分会有些难度。这里的主要功能是提供对 Jenkins 的操作函数方法。在实现时,抽象了一个 Interface ,希望能够对接不同的编排工具。

简单说了下代码目录,可能还是不够清晰。下面一起通过调用逻辑看看代码。

6.2 关于 CRD 类型的代码逻辑

以创建 DevOps 工程为例。

  1. 前端调用 /kapis/devops.kubesphere.io/v1alpha3/workspaces/liuxin-test/devops/ ,传递参数

  2. 后端处理 https://github.com/kubesphere/kubesphere/blob/release-3.0/pkg/kapis/devops/v1alpha3/register.go#L154 ,通过生成的 client 写入 Etcd

  3. ks-controller-manager 处理 https://github.com/kubesphere/kubesphere/blob/release-3.0/pkg/controller/devopsproject/devopsproject_controller.go#L205 ,这里单步运行,可以缕清整个链路。最终是调用 pkg/simple/client/devops 中的接口,在 Jenkins 中,创建一个文件夹。

6.3 关于触发类型的代码逻辑

以触发代码扫描为例。

  1. 前端调用 kapis/devops.kubesphere.io/v1alpha2/devops/test2-projectwvb2n/pipelines/test1-pipeline/scan/ , 传递参数

  2. 后端处理 https://github.com/kubesphere/kubesphere/blob/release-3.0/pkg/kapis/devops/v1alpha2/register.go#L479 ,这是就不需要经过 ks-controller-manager,单步运行调试会发现,依然会进入 pkg/simple/client/devops 然后组装 xml 调用 Jenkins API 。

7. 前端代码结构和逻辑

前端的代码结构清晰,非常直观,文件名能与页面对应上。下面以仓库地址 https://github.com/kubesphere/console/tree/release-3.0 为例进行说明。另外,前端采用的是 React 框架。

7.1 代码目录

主要的逻辑都在 src/pages/devops 目录。

  • components

流水线相关的组件。而 src/components 中是整个项目公共的组件。

  • containers

对应流水线相关的页面。如下图,左侧选项卡与文件夹中文件名一一对应,包括流水线图形化编辑页面。

  • routes

单页面应用的路由配置。

7.2 环境搭建

请参考 https://github.com/kubesphere/console 的文档。