Hinweis perev .: Dies ist eine Übersetzung eines Artikels aus dem technischen Blog von Preply darüber, wie Sie die Konfiguration als Code für ein so beliebtes CI / CD-Tool wie Jenkins verwenden können.In unserem Unternehmen versuchen wir, die Praxis von "Alles ist wie Code" zu befolgen. Dies gilt nicht nur für Infrastrukturressourcen, sondern auch für Überwachung, Jenkins-Arbeit usw. In diesem Artikel werde ich darüber sprechen, wie wir diese Vorgehensweise verwenden, um Jenkins bereitzustellen und zu unterstützen. Dies gilt nicht nur für die Infrastruktur für den Server und die Agenten, sondern auch für Plug-Ins, Zugriffe, Arbeit und viele andere Dinge.Darüber hinaus werden wir in diesem Artikel versuchen, Antworten auf folgende Fragen zu finden:- Sind unsere Jenkins stabiler geworden?
- Können wir häufige Änderungen an der Server- und Jobkonfiguration vornehmen?
- Ist das Jenkins-Update immer noch ein Schmerz für uns?
- Können wir alle unsere Änderungen kontrollieren?
- Können wir Jenkins im Falle eines Fakaps schnell wiederherstellen?
Einführung
Normalerweise fällt bei der Erwähnung des Ausdrucks „DevOps-Tools“ als erstes das CI / CD-System ein. Zum Beispiel verwenden wir Jenkins, weil wir jeden Tag Hunderte von Aufgaben ausführen, und das sind Zehntausende von Builds. Einige Funktionen, die wir in Jenkins verwenden, sind entweder in anderen CI / CD-Systemen nicht verfügbar oder verfügen nur über eingeschränkte Funktionen.Wir möchten Jenkins vollständig vom Code aus steuern, einschließlich Infrastruktur, Konfigurationen, Jobs und Plug-Ins. Wir haben versucht, Jenkins in Kubernetes auszuführen, aber es entsprach nicht unseren Anforderungen und war aufgrund seiner Architektur nicht einfach zu skalieren .Dies wird diskutiertInfrastruktur für Jenkins
Wir verwenden AWS und konfigurieren die gesamte Infrastruktur mit Terraform und anderen Hash-Tools wie Packer und Vault .Wie bereits erwähnt, haben wir versucht, Jenkins in Kubernetes zu verwenden, und hatten einige Probleme mit der Skalierung von PVC , Ressourcen und einer nicht so gut gestalteten Architektur.Hier verwenden wir die üblichen AWS-Ressourcen: EC2-Instanzen, SSL-Zertifikate, Balancer, Cloudfront usw. Das OS-Image ( AMI ) wird mit Packer konfiguriert, das sich perfekt in Terraform und Vault integrieren lässt.{
"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"]
}]
}
Ein Beispiel für die Konfiguration des Betriebssystemabbilds in Packer.Die Datei packer_bootstrap.sh
enthält wiederum eine Reihe von Befehlen, mit denen Software im Abbild installiert wird. Zum Beispiel können wir Docker, Docker-Compose und Vaultenv oder Datadog-Agent zur Überwachung installieren . In Bezug auf die Infrastruktur für dieses Image können wir Terraform, Cloudformation, Pulumi oder sogar Ansible verwenden.Hier ist ein Beispiel für eine mögliche AWS-Infrastruktur für Jenkins:Benutzer melden sich über einen internen Balancer bei Jenkins an, und Github-Hooks gelangen über einen externen Balancer zu einem Server. Wir verwenden die Jenkins-Integration mit GitHub, daher müssen einige Server-Links über das Internet zugänglich sein. Hier gibt es viele verschiedene Lösungen (z. B. eine weiße Liste für IP-Adressen , URLs oder Token usw.). In unserem Fall verwenden wir eine Kombination aus zulässigen URLs und Token-Validierung.Nach den vorgenommenen Manipulationen verfügen wir bereits über eine vorgefertigte Infrastruktur mit dem zusammengestellten Betriebssystem-Image, der Möglichkeit, den geheimen Unternehmensspeicher zu überwachen und darauf zuzugreifen.
Wir verwenden Docker, um Jenkins und seine Plugins zu installieren
Als nächstes installieren wir Jenkins und seine Plugins. Wir hatten ständig Probleme beim Aktualisieren der Plugins, daher war das Hauptziel, die installierten Plugins und ihre Versionen im Code klar zu definieren.Und hier hilft uns Docker, da wir ein vorgefertigtes vorinstalliertes Docker-Image als Basis für unsere Konfiguration verwenden können.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
Docker- Datei Im Docker-Image werden einige Pakete wie Job Builder installiert, auf die ich später noch eingehen werde. Die Repositorys werden ebenfalls registriert und die in der Datei angegebenen Plugins installiert plugins.txt
.Jenkins.instance.pluginManager.plugins.each{
plugin ->
println ("${plugin.getShortName()}:${plugin.getVersion()}")
}
Sie können eine Liste der in Jenkins installierten Plugins abrufen, indem Sie auf den Link klicken https://our-jenkins-url/script
und die Ausgabe in einer Datei speichernplugins.txt
. Schließlich die Konfiguration für Docker-Compose, mit der Jenkins in Docker ausgeführt wird.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
Wir verwenden vaultenv auch, um Geheimnisse aus Vault zu fälschen.Beachten Sie einige Java-Optionen, die uns bei der Speicherbereinigung und den Ressourcenbeschränkungen geholfen haben. Dieser Artikel ist sehr cool über das Stimmen von Jenkins.Und natürlich können wir jetzt lokal eine Kopie von Jenkins bereitstellen und mit neuen Versionen des Servers und der Plugins experimentieren. Es ist sehr bequem.Jetzt haben wir eine saubere Installation von Jenkins und Plugins, die einfach im Produkt gestartet werden können. Lassen Sie uns mehr Konfiguration für sie hinzufügen.
Konfigurieren des Jenkins als Code (JCaSC) -Plugin für die Serverkonfiguration
Im Allgemeinen gibt es ein Plugin namens Jenkins Configuration as Code ( JCasC ), mit dem Sie die Serverkonfiguration in einem für Menschen lesbaren Textformat speichern können.Mit diesem Plugin können Sie Sicherheitskonfigurationen, Zugriffe, Einstellungen für Plugins, Agenten, Registerkarten und vieles mehr beschreiben.Die Konfiguration wird im YAML-Format dargestellt und ist in 5 Blöcke unterteilt:- Anmeldeinformationen (Beschreibung der Systemgeheimnisse)
- Jenkins (Autorisierungs- und Cloud-Einstellungen, globale Einstellungen, Agentenbeschreibungen, einige Sicherheitseinstellungen und Registerkarten)
- Sicherheit (globale Sicherheitseinstellungen, z. B. zulässige Skripte)
- Tool (Konfiguration für externe Tools wie Git, Allure usw.)
- nicht klassifiziert (andere Einstellungen, wie z. B. Integration in Slack)

Das Plugin unterstützt das Importieren von Konfigurationen aus einer vorhandenen Jenkins-Installation.Darüber hinaus bietet das Plugin Unterstützung für verschiedene geheime Anbieter . In diesem Beispiel werden jedoch nur Umgebungsvariablen verwendet.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}
...
So können Geheimnisse beschrieben werden.Wir verwenden auch das Amazon EC2- Plugin , um Agenten in AWS zu aktivieren, und seine Konfiguration kann auch mit diesem Plugin beschrieben werden. Mit der Matrix-Autorisierung können wir den Benutzerzugriff mithilfe von Code konfigurieren.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
...
Beschreibung der Agenten und ZugriffeDas Plugin unterstützt einige andere Dinge, die wir verwenden. Mit einem ordnungsgemäß organisierten lokalen Jenkins-Testprozess können Sie Fehler effektiv finden und beheben, bevor sie möglicherweise in den Jenkins-Vertrieb gelangen.Jetzt haben wir eine reproduzierbare Konfiguration für den Server, es bleibt der Fall für kleine, nämlich - den Job.
Wir verwenden Job Builder für Freestyle-Projekte
Es gibt verschiedene Möglichkeiten, Freestyle-Jobs in Jenkins zu erstellen:- über das Webinterface (der einfachste Weg, sprang auf und ging weiter)
- direkt mit der REST-API
- mit Plugins wie Job DSL oder JJB Wrapper
Mit Jenkins Job Builder (JJB) können Sie Jobs mit YAML oder JSON konfigurieren. Dies ist sehr praktisch, da Sie alle Jobs konfigurieren und ihren Status in einem bedingten Git speichern können. Das heißt, wir können mithilfe von JJB einen CI / CD-Prozess für unser CI / CD-Tool erstellen..
├── config.ini
├── jobs
│ ├── Job1.yaml
│ | ...
│ └── Job2.yaml
└── scripts
├── job1.sh
| ...
└── job2.sh
So sieht (vereinfacht) die Struktur der Konfiguration des Jobs auf dem FS aus- 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
Und so sieht der Job in der Datei aus Job1.yaml
, Schritte im Skript. job1.sh
Die JJB- Konfigurationsdatei sieht auch einfach aus.$ 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/
Die Anwendung neuer Änderungen kann einfach mit dem Befehl "Selbst" gestartet werden. Derjenkins-jobs update
Benutzer, für den das Token erstellt wurde, muss über die entsprechenden Berechtigungen zum Erstellen und Konfigurieren des Jobs verfügen. Wir müssen nur einen Initialisierungsjob (Seed-Job) anwenden, der die Änderungen mit JJB in Jenkins anwendet.Es ist erwähnenswert, dass JJB keine „Silberkugel“ ist, da einige nicht sehr beliebte Plugins nicht unterstützt werden. Es ist jedoch ein sehr flexibles Tool zum Speichern von Jobs im Code, einschließlich Makrounterstützung .Zusammenfassung
Nachdem wir das Ende dieses Artikels erreicht haben, möchte ich zum Anfang zurückkehren und die am Anfang gestellten Fragen beantworten. Wir können jede der gestellten Fragen mit „Ja“ beantworten.In diesem Artikel haben wir uns nicht mit den Feinheiten des Einrichtens bestimmter Technologien oder der korrekten Konfiguration von Jenkins befasst . Wir teilen lediglich unsere Erfahrungen, die auch für Sie nützlich sein können.PS In dem Artikel verwende ich oft das Wort "Job" (aus dem Englischen "Job", "Aufgabe"), für mich klingt es vertrauter als die "Aufgabe" im Kontext von CI / CD im Allgemeinen oder Jenkins.