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

推荐订阅源

V
Visual Studio Blog
爱范儿
爱范儿
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
雷峰网
雷峰网
V
V2EX
博客园_首页
Engineering at Meta
Engineering at Meta
博客园 - 聂微东
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Apple Machine Learning Research
Apple Machine Learning Research
GbyAI
GbyAI
H
Help Net Security
A
About on SuperTechFans
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Blog — PlanetScale
Blog — PlanetScale
W
WeLiveSecurity
云风的 BLOG
云风的 BLOG
D
Docker
Security Archives - TechRepublic
Security Archives - TechRepublic
Help Net Security
Help Net Security
N
News and Events Feed by Topic
Simon Willison's Weblog
Simon Willison's Weblog
G
Google Developers Blog
A
Arctic Wolf
T
The Blog of Author Tim Ferriss
博客园 - 叶小钗
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Google DeepMind News
Google DeepMind News
博客园 - 三生石上(FineUI控件)
aimingoo的专栏
aimingoo的专栏
Hacker News: Ask HN
Hacker News: Ask HN
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 司徒正美
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Privacy International News Feed
T
Troy Hunt's Blog
T
Tenable Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Recorded Future
Recorded Future
F
Fortinet All Blogs
D
DataBreaches.Net
B
Blog
T
Threat Research - Cisco Blogs
MyScale Blog
MyScale Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
The GitHub Blog
The GitHub Blog
Security Latest
Security Latest
M
MIT News - Artificial intelligence

陈少文的网站

巨变与机遇的未来十年 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 搭建自动化测试系统 使用 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 自动化部署流程 开发 Tips(5)
在 Kubernetes 上动态创建 Jenkins Slave
微信公众号 · 2019-12-06 · via 陈少文的网站

1. Jenkins 的工作模式

Jenkins 是一个单 Master,多 Slave 架构。Master 负责分配任务、管理服务。 Slave 负责执行具体任务。

即使部署了多个 Master,这些 Master 之间依然相互独立,无法协同调度。在高可用的 Jenkins 方案中,需要借助外部的任务分发框架,协调多 Master 之间的调度,比如,gearman。

在每个 Master 节点上,安装 gearman 插件,连接到 gearman server。在 gearman server 的统一分发下,各个 Master 才能构成高可用的 Jenkins 应用。

那么,Master 和 Slave 之间是如何通信的呢?主要有两种方式:ssh,jnlp。

  • ssh 模式

将 Master 的 SSH 公钥配置到所有的 Slave 上。当有任务调度时,由 Master 使用 ssh 客户端进行远程通信,启动 Agent 执行任务。

在 【系统管理】->【节点管理】->【新建节点】页面中,启动方式选择 【Launch agent agents via SSH】,填入主机相关信息,保存即可。

  • jnlp 模式

在 Slave 上需要常驻一个守护进程 jnlp ,使用 HTTP 协议与 Master 进行通信。每个 jnlp 都需要配置一个单独的 secret。

在 【系统管理】->【节点管理】->【新建节点】页面中,启动方式选择 【通过Jave Web启动代理】。保存之后,点击查看代理,可以看到启动节点命令:

1
java -jar agent.jar -jnlpUrl http://dev.chenshaowen.com:8080/computer/jnlp%E6%A8%A1%E5%BC%8F/slave-agent.jnlp -secret 8c7f2a83ea2f29ab9e5427d137c324b8102dfab18f8750229e36e34839a9e9c8 -workDir "/data"

2. 安装 Kuernetes 和 Jenkins

安装不是本篇主要内容,这里主要提供相关文档或脚本,以保证内容连贯。

2.1 Kubernetes

提供两种安装方式:

  • KubeSpray

实际上 KubeSpray 也是使用 Kubeadm 进行安装,但 KubeSpray 提供了各种相关组件的集成。

  • Kubeadm

参考文档:使用 Kubeadm 安装 Kubernetes 集群

2.2 Jenkins

Jenkins 非常友好地提供了一个完整 war 包,有三种方式部署 Jenkins。

  • 直接在 Java 环境,运行 war 包
  • 使用 Docker Compose 运行
  • 在 Kubernetes 中部署 Jenkins,使用 yaml 文件或者 helm 包

这里,我使用的是 Docker Compose 的方式运行 Jenkins。其他方式类似,注意开放相关访问端口即可。

3. 在 Kubernetes 动态创建 Slave

3.1 创建 ServiceAccount

为了使 Jenkins 有权限访问 Kubernetes 集群,这里我们需要创建一个 ServiceAccount。

在 Kubernetes 集群主机上,创建文件 jenkins-rbac.yml。为了省略创建命名空间的步骤,这里 namespace 使用 default。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins
  namespace: default

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
  name: jenkins-rolebinding
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: admin
subjects:
  - kind: ServiceAccount
    name: jenkins
    namespace: default

创建 ServiceAccount

1
kubectl apply -f jenkins-rbac.yml

获取访问 token

1
kubectl describe  secret

忽略 default-token-xxx,获取 jenkins-token-xxx 中的 token 值:

Name:         jenkins-token-6vn2v
Namespace:    default
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: jenkins
              kubernetes.io/service-account.uid: e1c181ae-ac1a-4ca8-b696-c06087b8c87c

Type:  kubernetes.io/service-account-token

Data
====
token:[这里的值,需要配置在 Jenkins 中]
ca.crt:     1025 bytes
namespace:  7 bytes

3.2 安装插件 Kubernetes Plugin

在【系统管理】->【插件管理】->【可选插件】中,搜索 Kubernetes ,找到插件 Kubernetes plugin,安装并重启 Jenkins 即可。

下图中已经安装插件,如果待安装,请选择【可选插件】Tab。

3.3 插件配置

在【系统管理】->【系统配置】中,滚动到页面底部,找到 cloud,新增加一个云。

Kubernetes 地址指的是 Apiserver 地址,Jenkins 地址指的是 Jenkins 页面的访问地址,Jenkins 通道指的是 jnlp 与 Jenkins 通信的地址,默认是 Master 的 50000 端口地址。

在【凭据】中添加 Secret text 类型的凭据,内容填写上面获取的 token 值。

凭证选择【jenkins-token】后,点击【连接测试】,提示 Connection test successful 则表示配置成功。最终配置参数如下图:

3.4 创建任务

创建流水线类型的任务,将以下脚本粘贴在流水线的编辑框内,保存执行。

  • 使用 podTemplate 语法,进行构建
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
podTemplate(containers: [
    containerTemplate(name: 'maven', image: 'maven:3.3.9-jdk-8-alpine', ttyEnabled: true, command: 'cat'),
    containerTemplate(name: 'golang', image: 'golang:1.8.0', ttyEnabled: true, command: 'cat')
  ]) {

    node(POD_LABEL) {
        stage('Maven project') {
            container('maven') {
                stage('Maven test') {
                    sh 'mvn -version'
                }
            }
        }
        stage('Golang project') {
            container('golang') {
                stage('Go test') {
                    sh 'go version'
                }
            }
        }

    }
}

执行日志:

  • 使用声明式语法,直接提供 Yaml 内容。也可以提供文件路径,指向 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
pipeline {
  agent {
    kubernetes {
      yaml """
apiVersion: v1
kind: Pod
metadata:
  labels:
    mylabel: myvalue
spec:
  containers:
  - name: maven
    image: maven:3.3.9-jdk-8-alpine
    command:
    - cat
    tty: true
  - name: go
    image: golang:1.8.0
    command:
    - cat
    tty: true
"""
    }
  }
  stages {
    stage('Run maven') {
      steps {
        container('maven') {
          sh 'mvn -version'
        }
        container('go') {
          sh 'go version'
        }
      }
    }
  }
}

执行日志:

4. 使用模板创建 Slave

Kubernetes Plugin 提供的 podTemplate 十分的灵活,能够为 Jenkins 提供各种各样的工作节点。

但是,如果每个流水线都需要这样配置模板,反而会变得十分繁琐。在 Kubernetes Plugin 中提供了内置的 podTemplate,当流水线配置的 agent label 与之匹配时,就可以直接用于 Pod 创建。

4.1 配置 PodTemplate

在【系统管理】->【系统配置】中,滚动到页面底部,找到 Pod Template,增加一个模板,填入相关信息。

这里需要特别注意的是标签列表值。在流水线中,可以通过标签列表选中当前 Pod Template。

如上图,如果仅增加 Python 容器,在流水线执行时,会一直等待调度。

Started by user admin
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Still waiting to schedule task
‘test-nqppr’ is offline

查看 Jenkins 的系统全局日志,可以发现:

Failed to send back a reply to the request hudson.remoting.Request$2@693aae9b: hudson.remoting.ChannelClosedException: Channel "hudson.remoting.Channel@376b1008:JNLP4-connect connection from 172.17.0.1/172.17.0.1:56788": channel is already closed

意思是 Pod 中没有 jnlp 与之通信。因此,除了运行时容器,还需要添加一个名为 jnlp 的容器用于与 Jenkins 通信。如下图:

最终的效果是,一个 Pod 模板,包含一个或多个指定的运行时容器,加一个 jnlp 容器。

如果没有填写 jnlp 容器,会自动创建 jnlp 容器,但有时会报错无法连接(可能是 Jenkins 的 Bug),所以建议显示指定一个 jnlp 容器。同时,jnlp 是默认容器,也就是没有被 container 包裹的运行环境都是 jnlp。为了方便,另外一种方案,就是定制 jnlp 。

【非必须】如果需要 Pod 中的容器能够共享宿主机上的 Docker,也就是 docker in docker,可以在【卷】中添加一个 【Host Path Volume】,将所主机上的 /var/run/docker.sock 挂载到容器的 /var/run/docker.sock 上,如下图。

4.2 创建模板任务

  • 创建一个流水线任务
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
pipeline {
  agent {
    node {
      label 'python'
    }
  }
  stages {
    stage('Run Test') {
      steps {
        container('python') {
          sh 'python --version'
        }
      }
    }
  }
}

执行日志:

  • 创建一个自由风格任务

构建中,选择【执行 shell】,填入如下内容:

1
2
uname -a
python  --version

执行日志:

可以看到 python --version 执行失败了。这是因为默认容器为 jnlp,而 jenkins/jnlp-slave:3.35-5-alpine 镜像中没有打包 python。这也意味着,这里仅能执行 jnlp 提供的命令。

5. 参考