Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Jenkins 中文社区
Jenkins 中文社区官方网站
提交
5a1b6770
J
Jenkins 中文社区官方网站
项目概览
Jenkins 中文社区
/
Jenkins 中文社区官方网站
通知
0
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
Jenkins 中文社区官方网站
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
5a1b6770
编写于
8月 23, 2019
作者:
LinuxSuRen
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Auto commit by hugo-plugin.
上级
ab0812ef
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
26 addition
and
17 deletion
+26
-17
index.html
index.html
+9
-9
index.json
index.json
+1
-1
wechat/articles/2019/05/2019-05-27-docs-sig-announcement/index.html
...icles/2019/05/2019-05-27-docs-sig-announcement/index.html
+2
-2
wechat/articles/2019/05/2019-05-29-jenkins-release/index.html
...at/articles/2019/05/2019-05-29-jenkins-release/index.html
+2
-2
wechat/articles/2019/07/2019-07-29-leveraging-jenkins-on-kubernetes/index.html
...07/2019-07-29-leveraging-jenkins-on-kubernetes/index.html
+2
-2
wechat/articles/2019/08/2019-08-23-cloud-native-jenkins-on-aws/index.html
...2019/08/2019-08-23-cloud-native-jenkins-on-aws/index.html
+10
-1
未找到文件。
index.html
浏览文件 @
5a1b6770
...
...
@@ -1839,11 +1839,8 @@ RU5ErkJggg==" />
<a
href=
"/event/beijing-2019-07-27/"
class=
"tile lazyload cover dib f4 ml1 mr4 bg-black relative mw-100 shadow-5"
>
<img
width=
"400px"
height=
"200px"
src=
"/images/meetup/ci-cd.jpeg"
></img>
<a
href=
"/event/beijing-2019-08-24/"
class=
"tile lazyload cover dib f4 ml1 mr4 bg-black relative mw-100 shadow-5"
>
<img
width=
"400px"
height=
"200px"
src=
"/images/meetup/kaiyuan.jpg"
></img>
</a>
...
...
@@ -1856,15 +1853,18 @@ RU5ErkJggg==" />
<a
href=
"/event/
beijing-2019-08-24
/"
class=
"tile lazyload cover dib f4 ml1 mr4 bg-black relative mw-100 shadow-5"
>
<img
width=
"400px"
height=
"200px"
src=
"/images/meetup/
kaiyuan.jp
g"
></img>
<a
href=
"/event/
shanghai-2019-09
/"
class=
"tile lazyload cover dib f4 ml1 mr4 bg-black relative mw-100 shadow-5"
>
<img
width=
"400px"
height=
"200px"
src=
"/images/meetup/
shanghai.jpe
g"
></img>
</a>
<a
href=
"/event/shanghai-2019-09/"
class=
"tile lazyload cover dib f4 ml1 mr4 bg-black relative mw-100 shadow-5"
>
<img
width=
"400px"
height=
"200px"
src=
"/images/meetup/shanghai.jpeg"
></img>
<a
href=
"/event/beijing-2019-07-27/"
class=
"tile lazyload cover dib f4 ml1 mr4 bg-black relative mw-100 shadow-5"
>
<img
width=
"400px"
height=
"200px"
src=
"/images/meetup/ci-cd.jpeg"
></img>
</a>
...
...
index.json
浏览文件 @
5a1b6770
...
...
@@ -21,7 +21,7 @@
"description"
:
"我们如何运用 Terraform、Packer、Docker、Vault、ELB、ASG、ALB 或 EFS 等 AWS 服务实现 Jenkins Cloud-native,以及我们一路走来的收获"
,
"content"
:
" 我们使用 Jenkins 搭建持续交付流水线,和其他很多团队一样,这些年我们围绕 Jenkins 创建了很多工作流程和自动化。Jenkins 是我们团队取得成功的关键,让我们能够在上一季度顺利进入生产677次,搭建及部署时长平均为12分钟。
\n
我们的大部分应用和基础设施可以看作云原生,但当时 Jenkins 服务并不完全适合这个分类:服务在单个服务器上运行,同时很多任务直接在 master 上运行,其部分手动配置包括 secret、插件、定时任务和 startup hacking 的普通膨胀,该膨胀是自2014年首次搭建起不断累积而成。
\n
Jenkins 不仅变成了单体服务和单点故障,而且拆除及重建 Jenkins 对企业也是很大的风险。
\n
我们决定必须做出改变。这篇博客说明了我们如何运用 Terraform、Packer、Docker、Vault、和 ELB、ASG、ALB 或 EFS 等 AWS 服务实现 Jenkins Cloud-native,以及我们一路走来的收获。
\n
Jenkins 状态 当时不得不面对的关键问题是:如果我们将 Jenkins 服务置于一个容器/自动缩放实例中,我们需要恢复何种状态?
\n
问题的答案并不简单,值得一提的是,有个 Jenkins 特别兴趣小组(SIG)已经识别出所有导致这一 Jenkins 状态的存储组件。这是一个很棒的起点,因为我们至少得确保那篇文章列出的所有存储类型都考虑在内。
\n
捷径 这不是新问题。很多团队使用 Docker 容器运行 Jenkins,官方 Jenkins Docker 镜像也得到良好维护。如《Jenkins Dokcer 镜像》文档中解释的:
\n
docker run -p 8080:8080 -p 50000:50000 -v jenkins_home:/var/jenkins_home jenkins/jenkins:lts 这会把 workspace 存在 /var/jenkins_home。所有的 Jenkins 数据(包括插件和配置)都存在上述目录里。创建一个明确的 volume 可以方便管理和附加到另一个容器进行升级。
\n
上述示例装载主机上的 jenkins_home,其中包括所有 Jenkins 状态。然后该目录可以存在一个外部磁盘上,比如 Kubernetes 持久化存储卷。或者,如果 Jenkins 在 EC2 上运行,该目录可存在一个外部 EBS 或 EFS 卷上。
\n
这是一种有效的方法,但我们认为这个方法不能达到我们的标准,因为 jenkins_home 不仅包括状态,还包括配置。Block storage 拥有大量用户案例,但一个小小的配置修改就必须进行 snapshot 恢复操作,这似乎并不算是好的解决方案。此外,我们并不是想转移问题:外部存储无法免去手动配置、凭据储存在文件系统等问题。
\n
SCM 救援 过去,我们用了 Jenkins 备份插件,该插件基本上把配置修改备份在源码控制里,允许配置恢复。这个插件的设计想法很棒,但我们决定不使用它,因为我们无法轻松控制哪些数据实现备份,而且该插件自2011年就没有任何更新了。
\n
这样的话,如果我们把 jenkins_home 创建成个人 Git repo,并自动提交对 Jenkins 所做的修改呢?此处的关键是排除单独储存的任何二进制文件、secrets 或大型文件(稍后详细介绍)。我们的 .gitignore 文件如下所示:
\n
/.bash_history /.java/ /.kube/ /.ssh/ /.viminfo /identity.key.enc /jobs/ /logs/ /caches/ # Track static worker and exclude ephemeral ones /nodes/** !nodes/static-node/config.xml /org.jenkinsci.plugins.github_branch_source.GitHubSCMProbe.cache/ /plugins/ /saml-idp-metadata.xml /saml-jenkins-keystore.jks /saml-jenkins-keystore.xml /saml-sp-metadata.xml /scm-sync-configuration/ /scm-sync-configuration.success.log /secret.key /secret.key.not-so-secret /secrets/ /updates/ /workspaces/ 几乎所有的纯文本配置都正在 Git 实现持久化。为了给 Jenkins 提供这一配置,我们要做的就是检查 startup 上的 repo;事情渐渐成形。
\n
Secrets Jenkins 要访问很多地方,也就是说我们需要一个安全的 secret 存储空间。因为我们是 HashiCorpVault 的重度用户,所以自然而然就选了这个工具,不过遗憾的是,Vault 无法涵盖所有场景。比如,scm-branch-source 流水线插件需要 SCM 的认证凭据,并默认为 Jenkins 凭据插件。每次从 Vault 动态检索这些,我们都需要同步一个仓库,这可能导致错误,也会需要额外的精力去维护。
\n
这就是为什么我们采用 Vault 与 Jenkins 凭据混合的方法: 1. 在 startup 实例中,Jenkins 进行认证,VAult采用 IAM 认证方法。 2. 一个引导脚本检索 Jenkins master.key 和凭据插件所用的其他加密密钥。更多详情请参阅这篇文章。 3. 储存在 jenkins_home/credentials.xml 上的凭据现在可由 Jenkins 解密和访问。
\n
用 Vault 完全取代凭据插件是我们未来可能探索的问题,不过我们很开心这个方法满足了安全性要求, 同时能轻松与 Jenkins 的其余功能实现集成。
\n
任务和 workspace 数据 问题从这一步开始变得棘手:jenkins_home/jobs and jenkins_home/workspaces 都含有介于非结构化数据、创建制品和纯文本之间的混合体。这个信息很有价值,可以帮助我们审计、理解之前的流水线 build。这些 build 尺寸很大,而且不太适合 SCM 同步,因此这两个目录都排除在 .gitignore 之外了。
\n
那我们把这些储存在哪儿呢?我们认为 block storage 最适合存储这种数据。作为 AWS 的重度用户,使用 EFS 完全说得通,因为 EFS 的文件存储可扩展、可用性高并可以通过网络访问,非常易于使用。我们使用 Terraform 整合了 AWS EFS资源,并用 AWS 备份服务制定了一份定期备份计划。
\n
在 startup,我们将 EFS 卷 、符号链接 jenkins_home/jobs 和 jenkins_home/workspaces 装载到 EFS 目录上,然后启动 Jenkins 服务。
\n
接下来,Jenkins 服务是唯一可以读写任务 /workspace 数据的界面。值得一提的是,我们有一个 Jenkins 任务定期删除几周前的任务和 workspace 数据,这样数据不会一直增加。
\n
Packer 和 Terraform 实现编码化 Jenkins 你可能想知道这些是如何凑在一起的?我甚至没说过在哪里运行 Jenkins!我们广泛使用 Kubernetes,花了一些时间思考将 Jenkins 作为容器来运行,可我们决定使用 Packer 和 EC2 来运行 Jenkins master,用短暂 EC2 实例运行这些任务。
\n
尽管将 master 和 worker 双双作为容器运行的想法很有用,但我们在当前 Kubernetes 集群里没有找到存储 Jenkins 的地方。而且只是为了 Jenkins 就新建一个集群似乎有点儿“杀鸡用牛刀”。此外,我们想保留从其余服务中解耦的基础设施的关键部分。这样的话,如果 Kubernetes 升级对我们的 app 有影响,我们希望至少可以运用 Jenkins 进行回滚。 运行“Docker in Docker”还有另一个问题,这个问题有解,不过还是需要说明一下,因为我们的 build 经常用到 Docker 命令。
\n
其体系架构如下: 能使用 EC2 实例让过渡更顺畅:我们当时通过 Jenkins EC2 插件用临时 worker node 运行流水线工作,并在声明式流水线代码上调用了这一逻辑,所以不必重构就能用 Dokcer 代理节点是一个加分项。其余工作就是 Packer 和 Terraform 代码,这是我们已经很熟悉的部分了。
\n
插件 因为插件也是状态!我们在这个项目里想要解决的问题之一就是更好地审计、管理插件。在手动场景中,插件管理可能不受控制,很难了解安装插件的时间和原因。
\n
大多数 Jenkins 级别的插件配置可以在常规 Jenkins 配置 xml 文档中找到,但安装插件也导致 jar 制品、元数据、图片和其他文件存在 jenkins_home/plugin 目录。
\n
一种方法是在 EFS 中存储插件,不过我们想将 EFS 使用率保持在最低水平,这无法解决问题,只是转移问题。这就是为什么我们选择对插件安装进行“Packer 化”。
\n
基本上,在我们的 AMI 定义中,有一个插件文件罗列了插件和版本,大致如下:
\n
# Datadog Plugin required to send build metrics to Datadog datadog:0.7.1# Slack Plugin required to send build notifications to Slack slack:2.27 然后,我们的 AMI provision 脚本解析该文件,用 Jenkins CLI 安装插件和所选版本:
\n
# Wrapper function for jenkins_cli jenkins_cli() { java -jar
\u
0026quot;$JENKINS_CLI_JAR
\u
0026quot; -http -auth
\u
0026quot;${user}:${pw}
\u
0026quot;
\u
0026quot;$@
\u
0026quot; }for plugin in
\u
0026quot;${plugins[@]}
\u
0026quot;; do echo
\u
0026quot;Installing $plugin
\u
0026quot; jenkins_cli install-plugin
\u
0026quot;$plugin
\u
0026quot; -deploy done 然后,任何需要安装的新插件或升级到当前安装版本的版本升级都需要 GitHub Pull Request,这会触发搭建新 AMI。完美!
\n
安装其他软件 根据定义,Jenkins 要安装很多软件才能创建、测试和部署。首先,我们不想让 master node 运行任何任务,所以我们避免安装任何与任务相关的软件。Master 的主要任务是在其他短暂 worker node 上提供界面、编排 builds。
\n
这意味着我们可以在 worker node 上安装所需工具,但我们决定尽可能多地使用 docker run。这是因为我们是使用 Scala、Java、Node、Golang、Python等其他编程语言的多语言组织。为所有这些软件栈维护不同 build 工具可能让 worker node 设置变得有点儿复杂。
\n
以 JavaScript 为例,我们想让 Jenkins 针对 install 和 test 等 app 运行 yarn 命令。简单将加载检查过的 repo 目录作为一个 volume 安装到 Docker 容器里,从该容器中运行任何命令。以下为运用 Groovy 工作流代码的例子:
\n
def node(command, image) { def nodeCmd = [ 'docker run -i --rm', '-u 1000', // Run as non-root user '-v ~/.npmrc:/home/node/.npmrc:ro', '-v ~/.yarn:/home/node/.yarn', '-e YARN_CACHE_FOLDER=/home/node/.yarn/cache',
\u
0026quot;-v ${env.WORKSPACE}:/app
\u
0026quot;, '--workdir /app',
\u
0026quot;${image}
\u
0026quot; ].join(' ') sh
\u
0026quot;${nodeCmd} ${command}
\u
0026quot; } 然后,我们检查仓库后可以调用这个功能:
\n
checkout scm node('yarn install --frozen-lockfile', 'node:12.6.0-alpine') 漂亮收尾!因为除了 Docker 后台程序或 kubectl,我们不必在 worker machine 上安装、维护所用工具的多个版本。我们也相信 build 命令在本地和 CI 环境之间是一致的,因为用的是同一个 Docker 镜像。
\n
运用临时 node 创建时要记得缓存依赖。比如,一个 worker node 重建后,我们丢失了 sbt 缓存,由于缓存必须重建,这导致创建时间变慢。如果外部依赖不可用,这甚至会导致失败。我们决定将相关依赖缓存在另一个外部 EFS 上,以求获得更快、更可靠的 build。
\n
结语 Jenkins 是一个很棒的工具,但在管理外部状态上略有不足,因此以 cloud native 的方式创建 Jenkins 较有难度。我们的方法并不完美,但我们相信这个方法结合了两者的精华,而且确保安全性、操作简单、有弹性。令人高兴的是,我们完成这个项目,并把所有的生产 build 迁移到新的 Jenkins 服务之后,可以终止 master server,让自动缩放在几分钟内完成重建,而不会影响以前储存的状态。
\n
"
,
"auhtor"
:
"Alberto Alvarez"
,
"translator"
:
""
,
"translator"
:
"
shunw
"
,
"original"
:
"https://medium.com/bench-engineering/cloud-native-jenkins-on-aws-b5c957c4fe18"
,
"poster"
:
"butler-in-action.png"
},
...
...
wechat/articles/2019/05/2019-05-27-docs-sig-announcement/index.html
浏览文件 @
5a1b6770
...
...
@@ -366,10 +366,10 @@ var trackOutboundLink = function(id, url) {
<li><a
href=
"/wechat/articles/2019/07/2019-07-29-leveraging-jenkins-on-kubernetes/"
>
在 Kubernetes 上使用 Jenkins
</a></li>
<li><a
href=
"/wechat/articles/2019/07/2019-07-04-performance-testing-jenkins/"
>
Jenkins 插件的微基准测试框架
</a></li>
<li><a
href=
"/wechat/articles/2019/07/2019-07-10-phase-1-multibranch-pipeline-support-for-gitlab/"
>
多分支流水线任务对 GitLab SCM 的支持
</a></li>
<li><a
href=
"/wechat/articles/2019/07/2019-07-04-performance-testing-jenkins/"
>
Jenkins 插件的微基准测试框架
</a></li>
</ul>
</div>
...
...
wechat/articles/2019/05/2019-05-29-jenkins-release/index.html
浏览文件 @
5a1b6770
...
...
@@ -344,10 +344,10 @@ var trackOutboundLink = function(id, url) {
<h2>
参考
</h2>
<ul>
<li><a
href=
"/wechat/articles/2019/07/2019-07-09-jenkins-release/"
>
Jenkins 长期支持版更新
</a></li>
<li><a
href=
"/wechat/articles/2019/07/2019-07-18-jenkins-weekly-release/"
>
Jenkins 每周版更新
</a></li>
<li><a
href=
"/wechat/articles/2019/07/2019-07-09-jenkins-release/"
>
Jenkins 长期支持版更新
</a></li>
</ul>
</div>
...
...
wechat/articles/2019/07/2019-07-29-leveraging-jenkins-on-kubernetes/index.html
浏览文件 @
5a1b6770
...
...
@@ -380,10 +380,10 @@ var trackOutboundLink = function(id, url) {
<li><a
href=
"/wechat/articles/2019/08/2019-08-05-jenkins-multi-branch-pipeline/"
>
在大型企业里维护多分支流水线
</a></li>
<li><a
href=
"/wechat/articles/2019/07/2019-07-10-phase-1-multibranch-pipeline-support-for-gitlab/"
>
多分支流水线任务对 GitLab SCM 的支持
</a></li>
<li><a
href=
"/wechat/articles/2019/07/2019-07-04-performance-testing-jenkins/"
>
Jenkins 插件的微基准测试框架
</a></li>
<li><a
href=
"/wechat/articles/2019/07/2019-07-10-phase-1-multibranch-pipeline-support-for-gitlab/"
>
多分支流水线任务对 GitLab SCM 的支持
</a></li>
<li><a
href=
"/wechat/articles/2019/05/2019-05-27-docs-sig-announcement/"
>
Jenkins 文档特别兴趣小组
</a></li>
</ul>
...
...
wechat/articles/2019/08/2019-08-23-cloud-native-jenkins-on-aws/index.html
浏览文件 @
5a1b6770
...
...
@@ -197,12 +197,14 @@ var trackOutboundLink = function(id, url) {
<aside
class=
"mw5 br3 mv3 nested-links"
>
<a
href=
""
target=
"_blank"
class=
"link dim v-mid dib"
>
<a
href=
"
https://github.com/shunw
"
target=
"_blank"
class=
"link dim v-mid dib"
>
<svg
version=
"1.1"
fill=
"gray"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"16"
height=
"18"
viewBox=
"0 0 27 32"
>
<path
d=
"M9.28 21.44q0.064-0.128-0.064-0.256-0.16-0.128-0.256-0.032-0.064 0.128 0.064 0.224 0.16 0.128 0.256 0.064zM8.768 20.704q-0.096-0.128-0.224-0.096-0.096 0.096 0 0.224 0.128 0.16 0.224 0.096t0-0.224zM8.032 19.968q0.032-0.064-0.096-0.128-0.128-0.032-0.128 0.032-0.064 0.096 0.064 0.16 0.16 0.032 0.16-0.064zM8.416 20.384q0.032 0 0.032-0.064t-0.064-0.096q-0.128-0.128-0.192-0.064t0.032 0.192q0.096 0.096 0.192 0.032zM9.952 21.728q0.032-0.128-0.16-0.192-0.16-0.064-0.224 0.064t0.16 0.192q0.16 0.064 0.224-0.064zM10.688 21.792q0-0.16-0.192-0.16t-0.192 0.16 0.192 0.128 0.192-0.128zM11.392 21.664q-0.032-0.128-0.224-0.096t-0.16 0.16q0.032 0.16 0.192 0.096t0.192-0.16zM22.848 16q0-3.776-2.656-6.464t-6.464-2.688-6.464 2.688-2.688 6.464q0 2.976 1.76 5.376t4.48 3.296q0.32 0.064 0.48-0.096t0.16-0.352q0-0.928-0.032-1.696-0.096 0.032-0.256 0.064t-0.64 0.032-0.864-0.096-0.768-0.352-0.544-0.736q-0.416-1.056-1.024-1.312-0.032-0.032-0.064-0.064l-0.16-0.16t-0.096-0.16 0.064-0.128 0.352-0.064q0.096 0 0.256 0.032t0.544 0.288 0.576 0.64q0.288 0.48 0.672 0.736t0.768 0.256 0.704-0.064 0.512-0.16q0.128-0.864 0.608-1.248-0.896-0.096-1.536-0.32t-1.312-0.704-0.992-1.344-0.352-2.144q0-1.408 0.96-2.464-0.448-1.088 0.096-2.4 0.32-0.128 0.96 0.128t1.088 0.512l0.448 0.288q1.056-0.288 2.304-0.288t2.272 0.288q0.192-0.128 0.512-0.32t0.992-0.448 1.024-0.16q0.512 1.312 0.096 2.4 0.928 1.056 0.928 2.464 0 1.024-0.256 1.792t-0.64 1.248-0.928 0.8-1.12 0.448-1.216 0.224q0.608 0.544 0.608 1.696 0 0.704 0 1.6t-0.032 0.896q0 0.224 0.16 0.352t0.48 0.096q2.752-0.928 4.512-3.296t1.728-5.376zM27.424 7.424v17.152q0 2.112-1.504 3.616t-3.648 1.536h-17.12q-2.144 0-3.648-1.536t-1.504-3.616v-17.152q0-2.112 1.504-3.616t3.648-1.536h17.12q2.144 0 3.648 1.536t1.504 3.616z"
></path>
</svg>
...
...
@@ -210,6 +212,13 @@ var trackOutboundLink = function(id, url) {
</a>
<div>
作者:
<span
class=
"originalAuthor"
>
Alberto Alvarez
</span>
<div>
<a
class=
"originalLink"
href=
"https://medium.com/bench-engineering/cloud-native-jenkins-on-aws-b5c957c4fe18"
target=
"_blank"
>
原文链接
</a>
</div>
</div>
</aside>
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录