将Jenkins部署为代码

注意 perev。:这是Preply工程博客中的一篇文章的翻译,内容涉及如何使用配置作为诸如Jenkins这样的流行CI / CD工具的代码。

在我们公司中,我们尝试遵循“一切都像代码”的做法,这不仅适用于基础结构资源,还适用于监视,Jenkins工作等。在本文中,我将讨论我们如何使用这种做法来部署和支持Jenkins。这不仅适用于服务器和代理的基础结构,而且还适用于插件,访问,工作以及许多其他事情。

此外,在本文中,我们将尝试找到以下问题的答案:

  • 我们的詹金斯会变得更稳定吗?
  • 我们可以经常更改服务器和作业配置吗?
  • 詹金斯更新是否仍然令我们感到痛苦?
  • 我们可以控制所有更改吗?
  • 如果出现fakap,我们可以快速恢复Jenkins吗?

图片


介绍


通常,提到短语“ DevOps工具”时首先想到的是CI / CD系统。例如,我们之所以使用Jenkins,是因为我们每天要运行数百个任务,因此需要数以万计的构建。我们在Jenkins中使用的某些功能在其他CI / CD系统中不可用或功能有限。


我们希望通过代码完全控制Jenkins,包括基础结构,配置,作业和插件。我们尝试在Kubernetes中运行Jenkins,但是它不符合我们的需求,而且由于其体系结构,因此不容易扩展

图片
这将被讨论

Jenkins的基础架构


图片我们使用AWS并使用Terraform和其他哈希工具(例如PackerVault)配置整个基础架构

如前所述,我们尝试在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)中有几种创建自由式工作的方法:

  • 使用网络界面(最简单的方法,继续前进)
  • 直接使用REST API
  • 使用Job DSL或JJB包装器之类的插件

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中的“任务”更熟悉。

All Articles