在传播了关于DevOps文化的一些想法之后,我想再次关注Jenkins主题。我将大部分时间都花在各种环境之间,而对于每种环境,我都在一个完全不同的Jenkins上工作。我测试了高级插件中的新功能,这些新功能可以改善和阐明开发环境中的软件交付过程。确认新功能正常运行后,我将花费更多时间将其推广到其他环境。这听起来像是一项重复性的任务,但实际上,我多年来倾向于避免采用此类任务,因为多年来我一直在追求采用EaC,“一切都作为代码”,但是由于某种原因,我还没有机会将其应用于Jenkins安装范围。
目标
我想要达到的理想状态是能够构建一个Jenkins实例,在该实例中,其所有配置和作业定义都将进入声明性文件。这样,我们就可以将不可变的Jenkins实例部署在任何环境中,无论何时添加插件或作业,或修改配置,它都会在Git上存储和版本化。这样,任何未知的配置都无法再破坏实例的所需状态,并且任何人都可以在其本地主机上部署确切的状态,例如,出于测试目的。
思路
我决定将项目构造为两个存储库。
有一个初始项目用于在Jenkins实例级别设置配置。在文件上,我们添加了插件来安装和锁定它们的版本。其中一个插件,即Jenkins配置为代码,使我们可以预先定义Jenkins和其余插件的全局配置,而无需与Jenkins UI进行交互,最后使用Dockerfile构建包含所有初始化文件的Docker映像。
第二个项目用于与Jenkins DSL插件进行交互。目标是将作业,文件夹和视图作为代码存储在groovy文件中,因此只有我们在Git存储库中定义的内容才适用于Jenkins实例。
构建Docker镜像 容器软件抽象的一种广为人知的实现用于打包,收集依赖关系并自动进行部署。我们将使用Dockerfile构建Jenkins实例。
FROM jenkins/jenkins:lts
COPY init-scripts /usr/share/jenkins/ref/init.groovy.d
ADD plugins.txt /usr/share/jenkins/ref/
ADD jenkins.yaml /usr/share/jenkins/ref/
RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt
ENV CASC_JENKINS_CONFIG /usr/share/jenkins/ref/
VOLUME /var/jenkins_home
以下shell脚本可以作为启动构建阶段的有用资源。有两个阶段,一个阶段是构建容器映像,另一个阶段是运行容器映像。
#!/usr/bin/env bash
docker build -t jenkins_as_code:0.1.0 .
为了自动化所需插件的安装,我们将使用Jenkins中包含的现有Shell脚本。该脚本位于容器内的/ usr / local / bin /处,名称为install-plugins.sh,用于安装插件,将其保存在文件中,并使用文件作为参数调用脚本。现在,我们可以存储需要安装的插件并锁定其版本。
workflow-aggregator:2.6
configuration-as-code:1.30
configuration-as-code-support:1.18
credentials:2.3.0
blueocean:1.19.0
job-dsl:1.74
在Jenkins上工作涉及许多插件安装,并且必须为每个插件设置特定的配置。所有这些配置更改随着时间的推移加总。Jenkins实例往往会根据软件交付过程的需求而发展。
GUI用于配置Jenkins。事实是,除了通过Web浏览之外,没有地方可以集中和存储应用了哪些配置。
大多数人已经使用Groovy初始化脚本解决了这个问题。它可以工作,但是由于涉及一些编码,因此不如所需的友好和可读性。
好消息是存在一个插件,您可以通过YAML文件定义全局配置和插件配置。很棒是因为它可以处理配置更改,并且我们可以使用所有已应用的配置来部署初始的Jenkins安装。
因此,我们可以朝着主要目标前进,由版本化配置文件定义不可变Jenkins实例的部署。
这个插件甚至可以让您定义一个种子作业,它是一个获取DSL文件并应用更改以创建其他作业,视图以及更多功能的作业。
在我们的情况下,以下jenkins.yaml文件用于提供配置。种子作业从Github获取另一个项目,该项目包含一些基于DSL的对象来创建资源。
jenkins:
systemMessage: "Jenkins As Code Concept."
views:
- myView:
name: "Jobs Config as Code"
security:
globalJobDslSecurityConfiguration:
useScriptSecurity: false
jobs:
- script: >
freeStyleJob("Jobs Generator") {
scm {
github('imanol-dev/jenkins_as_code_jobs', 'master')
}
steps {
dsl {
external('*.groovy')
}
}
}
关于此插件的一个很棒的事情是,您可以修改YAML文件并重新加载新配置,应用所有更改,而无需重新创建Jenkins实例。
在处理此问题时,我遇到了一个尝试通过配置文件自动创建默认管理员用户的问题。为了解决这个问题,我进行了一些研究,发现了一个使用Groovy初始化脚本的存储库。该脚本位于*/usr/share/jenkins/ref/init.groovy.d*目录中的容器内。
这样,创建用户,我们只需要填充以下环境变量:
ADMIN_USERNAME=
ADMIN_PASSWORD=
每次部署新的Jenkins实例时,第一次登录时,系统都会提示您配置向导,该向导可帮助您设置一些初始参数并安装一些建议的插件。
对于新手来说,这可能会有所帮助,但是我们正在尝试实现自动化功能,该功能可以部署配置文件中编写的内容,因此我们不需要此功能。
避免这种情况的方法是使用以下环境变量运行容器。
JAVA_OPTS=”-Djenkins.install.runSetupWizard=false”
我找到了一些创建Jenkins项目的方法。您可以通过Web界面手动创建它们,使用Jenkins CLI在XML文件上定义它们以导入它们或使用DSL插件。
在DSL插件可以让你定义工作的声明形式,可读性更强。
我已经在单独的存储库中定义了一些作业,使用种子作业,我引用了该存储库,因此在执行它之后,所有新作业都会自动出现。可以通过git更改触发种子作业,因此,如果您通过代码删除或修改作业,则无需手动执行即可在Jenkins实例上对其进行更新。
对于多环境部署问题,有很多更好的方法。跨所有环境的单个Jenkins都能胜任,但有时不仅是最佳技术解决方案。
就我而言,有时候,我必须适应完全隔离的环境,为同一项目使用独立的数据中心和不同的网络设置。在商业世界中已经有几年的经验告诉我,可能有些事情比我已经运行的想法更重要,我必须适应它。
我喜欢这项研究;我想找到一种自动执行一些重复性和手动任务的方法,以便我可以使用相同的配置但使用不同的Jobs部署多个Jenkins实例。
测试项目:https://github.com/imanol-dev