注意 perev。:这是Preply的工程博客中的一篇文章的翻译,内容涉及如何使用配置作为诸如Jenkins这样的流行CI / CD工具的代码。在我们公司中,我们尝试遵循“一切都像代码”的做法,这不仅适用于基础结构资源,还适用于监视,Jenkins工作等。在本文中,我将讨论我们如何使用这种做法来部署和支持Jenkins。这不仅适用于服务器和代理的基础结构,而且还适用于插件,访问,工作以及许多其他事情。此外,在本文中,我们将尝试找到以下问题的答案:- 我们的詹金斯会变得更稳定吗?
- 我们可以经常更改服务器和作业配置吗?
- 詹金斯更新是否仍然令我们感到痛苦?
- 我们可以控制所有更改吗?
- 如果出现fakap,我们可以快速恢复Jenkins吗?
介绍
通常,提到短语“ DevOps工具”时首先想到的是CI / CD系统。例如,我们之所以使用Jenkins,是因为我们每天要运行数百个任务,因此需要数以万计的构建。我们在Jenkins中使用的某些功能在其他CI / CD系统中不可用或功能有限。我们希望通过代码完全控制Jenkins,包括基础结构,配置,作业和插件。我们尝试在Kubernetes中运行Jenkins,但是它不符合我们的需求,而且由于其体系结构,因此不容易扩展。这将被讨论Jenkins的基础架构
我们使用AWS并使用Terraform和其他哈希工具(例如Packer和Vault)配置整个基础架构。如前所述,我们尝试在Kubernetes中使用Jenkins,并且在扩展PVC,资源和设计欠佳的体系结构方面遇到了一些问题。在这里,我们使用常规的AWS资源:EC2实例,SSL证书,平衡器,Cloudfront等。操作系统映像(AMI)使用Packer进行配置,Packer与Terraform和Vault完美集成。{
"variables": {
"aws_access_key": "{{vault `packer/aws_access_key_id` `key`}}",
"aws_secret_key": "{{vault `packer/aws_secret_access_key` `key`}}",
"aws_region": "{{vault `packer/aws_region` `key`}}",
"vault_token": "{{env `VAULT_TOKEN`}}"
},
"builders": [{
"access_key": "{{ user `aws_access_key` }}",
"secret_key": "{{ user `aws_secret_key` }}",
"region": "{{ user `aws_region` }}",
"type": "amazon-ebs",
"communicator": "ssh",
"ssh_username": "ubuntu",
"instance_type": "c5.xlarge",
"security_group_id": "sg-12345",
"iam_instance_profile": "packer-role-profile",
"ami_name": "packer-jenkins-master-{{timestamp}}",
"ami_description": "Jenkins master image",
"launch_block_device_mappings": [{
"device_name": "/dev/sda1",
"volume_size": 50,
"volume_type": "gp2",
"delete_on_termination": true
}],
"source_ami_filter": {
"filters": {
"virtualization-type": "hvm",
"name": "ubuntu/images/*ubuntu-bionic-18.04-amd64-server-*",
"root-device-type": "ebs"
},
"owners": ["099720109477"],
"most_recent": true
}
}],
"provisioners": [{
"type": "shell",
"environment_vars": ["VAULT_TOKEN={{ user `vault_token` }}"],
"scripts": ["packer_bootstrap.sh"]
}]
}
Packer中OS映像的配置示例,该文件又packer_bootstrap.sh
包含一组命令,这些命令用于在映像中安装软件。例如,我们可以安装Docker,docker -compose和vaultenv或Datadog-agent进行监视。关于此图像的基础架构,我们可以使用Terraform,Cloudformation,Pulumi甚至Ansible。这是一个可能的Jenkins AWS基础设施示例:用户通过内部平衡器登录Jenkins,Github挂钩通过外部平衡器连接到服务器。我们将Jenkins与GitHub集成在一起,因此必须可以从Internet访问某些服务器链接。这里有很多不同的解决方案(例如,IP地址,URL或令牌等的白名单),在我们的情况下,我们结合使用允许的URL和令牌验证。因此,在完成操作之后,我们已经拥有带有组装好的OS映像的现成基础架构,并且具有监视和访问公司机密存储的能力。
我们使用Docker安装Jenkins及其插件
接下来,我们将安装Jenkins及其插件。我们一直在更新插件方面遇到问题,因此主要目标是在代码中清楚地显示已安装的插件及其版本。在这里Docker将为我们提供帮助,因为我们可以获取现成的预安装Docker映像并将其用作我们配置的基础。FROM jenkins/jenkins:2.215
ENV CASC_JENKINS_CONFIG /jenkins_configs
USER root
RUN apt update && \
apt install -y python3 python3-pip && \
pip3 install awscli jenkins-job-builder jjb-reactive-choice-param --no-cache-dir
USER jenkins
VOLUME /jenkins_configs
VOLUME /var/jenkins_home
COPY plugins.txt /usr/share/jenkins/ref/
RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt
Dockerfile在Docker映像中,安装了一些软件包,如Job Builder,我将在后面进行讨论,还注册了存储库,并安装了文件中指定的插件plugins.txt
。Jenkins.instance.pluginManager.plugins.each{
plugin ->
println ("${plugin.getShortName()}:${plugin.getVersion()}")
}
您可以通过单击链接https://our-jenkins-url/script
并将输出保存到文件中来获取Jenkins中已安装插件的列表plugins.txt
。最后是docker-compose的配置,它将在Docker中运行Jenkins。version: "3"
services:
jenkins:
build: .
container_name: jenkins
restart: always
ports:
- "50000:50000"
- "8080:8080"
volumes:
- ./configs/:/jenkins_configs/:ro
- ./jenkins_home/:/var/jenkins_home/:rw
environment:
- VAULT_TOKEN
- GITHUB_TOKEN
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- JAVA_OPTS=-Xms4G -Xmx8G -Xloggc:/var/jenkins_home/gc-%t.log -XX:NumberOfGCLogFiles=5 -XX:+UseGCLogFileRotation -XX:GCLogFileSize=20m -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintHeapAtGC -XX:+PrintGCCause -XX:+PrintTenuringDistribution -XX:+PrintReferenceGC -XX:+PrintAdaptiveSizePolicy -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent -XX:+ParallelRefProcEnabled -XX:+UseStringDeduplication -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=20 -XX:+UnlockDiagnosticVMOptions -XX:G1SummarizeRSetStatsPeriod=1
volumes:
configs:
driver: local
jenkins_home:
driver: local
我们还使用vaultenv伪造Vault的机密,请注意一些Java选项可以帮助我们进行垃圾收集和资源限制。此文章是非常酷的有关调整詹金斯。当然,现在我们可以在本地部署Jenkins的副本,并尝试使用新版本的服务器和插件。很舒服现在,我们有了全新安装的Jenkins和插件,可以轻松在产品中启动它。让我们为她添加更多配置。
将Jenkins配置为代码(JCaSC)插件以进行服务器配置
通常,有一个名为Jenkins Configuration as Code(JCasC)的插件,它允许您以人类可读的文本格式存储服务器配置。使用此插件,您可以描述安全性配置,访问权限,插件设置,代理,选项卡等等。该配置以YAML格式表示,分为5个块:- 凭据(系统秘密的描述)
- jenkins(授权和云设置,全局设置,代理说明,一些安全设置和选项卡)
- 安全性(全局安全性设置,例如允许的脚本)
- 工具(用于配置git,allure等的外部工具)
- 未分类(其他设置,例如与Slack集成)

该插件支持从现有的Jenkins安装中导入配置,此外,该插件还提供了对各种秘密提供程序的支持,但是在本示例中,我们将仅使用环境变量。credentials:
system:
domainCredentials:
- credentials:
- usernamePassword:
description: "AWS credentials"
id: "aws-creds"
password: ${AWS_SECRET_ACCESS_KEY}
scope: GLOBAL
username: ${AWS_ACCESS_KEY_ID}
- string:
description: "Vault token"
id: "vault-token"
scope: GLOBAL
secret: ${VAULT_TOKEN}
...
这是秘密,如何才能加以说明。我们还使用了亚马逊的EC2插件在AWS提高剂,也可以使用这个插件描述其配置。矩阵授权使我们能够使用代码配置用户访问权限。jenkins:
authorizationStrategy:
projectMatrix:
permissions:
- "Overall/Administer:ivan.a@example.org"
- "Credentials/View:petr.d@example.org"
...
clouds:
- amazonEC2:
cloudName: "AWS"
privateKey: ${EC2_PRIVATE_KEY}
region: "${AWS_REGION}"
templates:
- ami: "ami-12345678"
amiType:
unixData:
sshPort: "22"
connectionStrategy: PRIVATE_IP
deleteRootOnTermination: true
description: "jenkins_agent"
idleTerminationMinutes: "20"
instanceCapStr: "100"
minimumNumberOfInstances: 0
mode: EXCLUSIVE
numExecutors: 1
remoteAdmin: "jenkins"
remoteFS: "/home/jenkins"
securityGroups: "sg-12345678"
subnetId: "subnet-12345678"
type: C52xlarge
...
代理和访问的描述该插件支持我们使用的其他一些功能。借助井井有条的Jenkins本地测试流程,您可以有效地发现并修复错误,然后再将其潜在地纳入Jenkins销售。现在我们有了服务器的可重现配置,对于小型服务器(即工作),情况仍然如此。
我们将Job Builder用于自由式项目
在詹金斯(Jenkins)中有几种创建自由式工作的方法:Jenkins Job Builder(JJB)允许您使用YAML或JSON配置作业。而且非常方便,因为您可以配置所有作业并将其状态存储在条件git中。也就是说,实际上,我们可以使用JJB为CI / CD工具构建CI / CD流程。.
├── config.ini
├── jobs
│ ├── Job1.yaml
│ | ...
│ └── Job2.yaml
└── scripts
├── job1.sh
| ...
└── job2.sh
这是(简化的)FS上作业的配置结构的外观- job:
name: Job1
project-type: freestyle
auth-token: mytoken
disabled: false
concurrent: false
node: jenkins_agent
triggers:
- timed: '0 3 * * *'
builders:
- shell:
!include-raw: ../scripts/job1.sh
这就是文件中工作的外观Job1.yaml
,脚本中的步骤,job1.sh
JJB配置文件也看起来很简单。$ cat config.ini
[job_builder]
ignore_cache=True
exclude=jobs/Job2
[jenkins]
url=https://jenkins.example.org
user=some_user
password=some_password
$ jenkins-jobs --conf config.ini test -r jobs/
$ jenkins-jobs --conf config.ini update -r jobs/
可以使用“按jenkins-jobs update
自身” 命令轻松启动新更改的应用程序,为其创建令牌的用户必须具有创建和配置作业的适当特权。我们只需要应用一个初始化作业(种子作业),它将使用Jenkins中的JJB应用更改。值得一提的是,JJB并不是“银弹”,因为不支持某些不是很流行的插件。但是,它是一种非常灵活的工具,用于在代码中存储作业,包括宏支持。摘要
现在我们已经到了本文的结尾,我想回到开头,并回答开头提出的问题。我们可以对提出的每个问题回答“是”。在本文中,我们没有深入研究设置某些技术或如何正确配置Jenkins的复杂性,我们只是分享我们的经验,这也可能对您有用。PS在文章中,我经常使用“作业”一词(英文,“ Job”,“ task”),对我来说,听起来比一般CI / CD或Jenkins中的“任务”更熟悉。