Menyebarkan Jenkins sebagai kode

Catatan perev.: ini adalah terjemahan dari artikel dari blog teknik Preply tentang bagaimana Anda dapat menggunakan konfigurasi sebagai kode untuk alat CI / CD populer seperti Jenkins.

Di perusahaan kami, kami mencoba mengikuti praktik "Semuanya seperti kode", ini tidak hanya berlaku untuk sumber daya infrastruktur, tetapi juga untuk pemantauan, kerja Jenkins, dll. Dalam artikel ini, saya akan berbicara tentang bagaimana kami menggunakan praktik ini untuk menerapkan dan mendukung Jenkins. Dan ini tidak hanya berlaku untuk infrastruktur untuk server dan agen, tetapi juga untuk plug-in, akses, pekerjaan, dan banyak hal lainnya.

Selain itu, dalam artikel ini kami akan mencoba menemukan jawaban untuk pertanyaan seperti:

  • Apakah Jenkins kita menjadi lebih stabil?
  • Bisakah kita sering melakukan perubahan konfigurasi server dan pekerjaan?
  • Apakah pembaruan Jenkins masih menyakitkan bagi kita?
  • Bisakah kita mengendalikan semua perubahan kita?
  • Bisakah kita dengan cepat mengembalikan Jenkins jika ada fakap?

gambar


pengantar


Biasanya, hal pertama yang terlintas dalam pikiran ketika menyebutkan frasa β€œalat DevOps” adalah sistem CI / CD. Misalnya, kami menggunakan Jenkins karena kami menjalankan ratusan tugas setiap hari, dan itu puluhan ribu build. Beberapa fitur yang kami gunakan di Jenkins tidak tersedia di sistem CI / CD lain atau memiliki fungsi terbatas.


Kami ingin mengontrol Jenkins sepenuhnya dari kode, termasuk infrastruktur, konfigurasi, pekerjaan, dan plug-in. Kami mencoba menjalankan Jenkins di Kubernetes, tetapi tidak sesuai dengan kebutuhan kami, ditambah lagi tidak mudah untuk menskalakan karena arsitekturnya .

gambar
Ini akan dibahas

Infrastruktur untuk Jenkins


gambarKami menggunakan AWS dan mengonfigurasi seluruh infrastruktur menggunakan Terraform dan alat hash lainnya seperti Packer dan Vault .

Seperti yang disebutkan sebelumnya, kami mencoba menggunakan Jenkins di Kubernetes dan menghadapi beberapa masalah dengan penskalaan PVC , sumber daya, dan arsitektur yang tidak dirancang dengan baik.

Di sini, kami menggunakan sumber daya AWS yang biasa: instance EC2, sertifikat SSL, penyeimbang, Cloudfront, dll. Gambar OS ( AMI ) dikonfigurasi menggunakan Packer, yang terintegrasi sempurna dengan Terraform dan 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"]
    }]
}
Contoh konfigurasi OS image seperti apa yang terlihat di Packer.

Pada gilirannya, file tersebut packer_bootstrap.shberisi seperangkat perintah yang menginstal perangkat lunak di dalam gambar. Sebagai contoh, kita dapat menginstal Docker, docker-compose dan vaultenv atau Datadog-agent untuk pemantauan. Mengenai infrastruktur untuk gambar ini, kita dapat menggunakan Terraform, Cloudformation, Pulumi atau bahkan Ansible.

Berikut adalah contoh kemungkinan infrastruktur AWS untuk Jenkins.

Pengguna masuk ke Jenkins melalui penyeimbang internal, dan kait Github sampai ke server melalui yang eksternal. Kami menggunakan integrasi Jenkins dengan GitHub, sehingga beberapa tautan server harus dapat diakses dari Internet. Ada banyak solusi berbeda di sini (misalnya, daftar putih untuk alamat IP , URL atau token, dll.), Dalam kasus kami, kami menggunakan kombinasi URL yang diizinkan dan validasi token.
Jadi, setelah manipulasi yang kami lakukan, kami sudah memiliki infrastruktur siap pakai dengan gambar OS yang dirangkai, kemampuan untuk memantau dan mengakses ke toko rahasia perusahaan.

Kami menggunakan Docker untuk menginstal Jenkins dan plugin-nya


gambarHal berikutnya yang akan kita lakukan adalah menginstal Jenkins dan pluginsnya. Kami terus-menerus mengalami masalah dalam memperbarui plugin, jadi tujuan utamanya adalah untuk memiliki plug-in yang jelas dari plugins yang diinstal dan versi mereka dalam kode.
Dan di sini Docker akan membantu kami, karena kami dapat mengambil gambar Docker yang sudah dipasang sebelumnya dan menggunakannya sebagai basis untuk konfigurasi kami.

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

Di dalam gambar Docker, beberapa paket diinstal seperti Job Builder, yang akan saya bahas nanti, repositori juga terdaftar dan plugin yang ditentukan dalam file diinstal plugins.txt.

Jenkins.instance.pluginManager.plugins.each{
  plugin ->
    println ("${plugin.getShortName()}:${plugin.getVersion()}")
}
Anda bisa mendapatkan daftar plugin yang terpasang di Jenkins dengan mengklik tautan https://our-jenkins-url/scriptdan menyimpan output ke fileplugins.txt

. Akhirnya, konfigurasi untuk docker-compose, yang akan menjalankan Jenkins di Docker.

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
Kami juga menggunakan vaultenv untuk memalsukan rahasia dari Vault.

Perhatikan beberapa opsi Java yang membantu kami dalam pengumpulan sampah dan batasan sumber daya. Ini artikel yang sangat dingin sekitar tala Jenkins.

Dan tentu saja, sekarang kita dapat menyebarkan salinan Jenkins secara lokal dan bereksperimen dengan server dan plugin versi baru. Sangat nyaman.
Sekarang kami memiliki instalasi Jenkins dan plugin yang bersih, yang dapat dengan mudah diluncurkan di prod. Mari kita tambahkan lebih banyak konfigurasi untuknya.

Mengkonfigurasi plugin Jenkins sebagai Kode (JCaSC) untuk konfigurasi server


gambarSecara umum, ada plugin yang disebut Jenkins Configuration as Code ( JCasC ), yang memungkinkan Anda untuk menyimpan konfigurasi server dalam format teks yang dapat dibaca manusia.

Dengan menggunakan plugin ini, Anda dapat menjelaskan konfigurasi keamanan, akses, pengaturan untuk plugin, agen, tab, dan banyak lagi.

Konfigurasi disajikan dalam format YAML dan dibagi menjadi 5 blok:

  • kredensial (deskripsi rahasia sistem)
  • jenkins (pengaturan otorisasi dan cloud, pengaturan global, deskripsi agen, beberapa pengaturan keamanan dan tab)
  • keamanan (pengaturan keamanan global, seperti skrip yang diizinkan)
  • tool (konfigurasi untuk alat eksternal seperti git, allure, dll.)
  • tidak terklasifikasi (pengaturan lain, seperti integrasi dengan Slack)

gambargambarPlugin mendukung impor konfigurasi dari instalasi Jenkins yang ada.Selain

itu, plugin menyediakan dukungan untuk berbagai penyedia rahasia , namun, dalam contoh ini kita hanya akan menggunakan variabel lingkungan.

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}
      ...
Beginilah rahasia dapat diuraikan.

Kami juga menggunakan plugin Amazon EC2 untuk meningkatkan agen di AWS, dan konfigurasinya juga dapat dijelaskan menggunakan plugin ini. Otorisasi matriks memungkinkan kita untuk mengkonfigurasi akses pengguna menggunakan kode.

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
        ...
Deskripsi agen dan akses

Plugin mendukung beberapa hal lain yang kami gunakan. Dengan proses pengujian lokal Jenkins yang terorganisir dengan baik, Anda dapat secara efektif menemukan dan memperbaiki bug sebelum mereka berpotensi masuk ke penjualan Jenkins.
Sekarang kita memiliki konfigurasi yang dapat direproduksi untuk server, itu tetap berlaku untuk kecil, yaitu - pekerjaan.

Kami menggunakan Job Builder untuk proyek gaya bebas


gambarAda beberapa cara untuk menciptakan pekerjaan gaya bebas di Jenkins:

  • menggunakan antarmuka web (cara termudah, melompat dan melanjutkan)
  • langsung menggunakan API REST
  • menggunakan plugin seperti Job DSL atau JJB wrapper

Jenkins Job Builder (JJB) memungkinkan Anda untuk mengonfigurasi pekerjaan menggunakan YAML atau JSON. Dan itu cukup nyaman, karena Anda dapat mengonfigurasi semua pekerjaan dan menyimpan statusnya di git bersyarat. Faktanya, kita dapat membangun proses CI / CD untuk alat CI / CD menggunakan JJB.

.
β”œβ”€β”€ config.ini
β”œβ”€β”€ jobs
β”‚   β”œβ”€β”€ Job1.yaml
β”‚   | ...
β”‚   └── Job2.yaml
└── scripts
    β”œβ”€β”€ job1.sh
    | ...
    └── job2.sh
Ini adalah bagaimana (disederhanakan) struktur konfigurasi pekerjaan pada FS terlihat

- 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
Dan ini adalah bagaimana pekerjaan dalam file terlihat Job1.yaml, langkah-langkah dalam skrip. job1.sh

File konfigurasi JJB juga terlihat sederhana.

$ 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/
Aplikasi perubahan baru dapat dengan mudah diluncurkan menggunakan perintahjenkins-jobs update

Sendiri, pengguna yang membuat token harus memiliki hak istimewa yang sesuai untuk membuat dan mengonfigurasi pekerjaan. Kami hanya perlu menerapkan satu pekerjaan inisialisasi (pekerjaan awal), yang akan menerapkan perubahan menggunakan JJB di Jenkins.

Perlu disebutkan bahwa JJB bukan "peluru perak", karena beberapa plugin yang tidak terlalu populer tidak didukung. Namun, ini adalah alat yang sangat fleksibel untuk menyimpan pekerjaan dalam kode, termasuk dukungan makro .

Ringkasan


Sekarang kita telah mencapai akhir artikel ini, saya ingin kembali ke awal dan menjawab pertanyaan yang diajukan di awal. Kita bisa menjawab "ya" untuk setiap pertanyaan yang diajukan.

Dalam artikel ini, kami tidak menyelidiki seluk-beluk pengaturan teknologi tertentu atau cara mengkonfigurasi Jenkins dengan benar , kami hanya berbagi pengalaman kami, yang mungkin berguna bagi Anda juga.

PS Dalam artikel saya sering menggunakan kata "pekerjaan" (dari bahasa Inggris "pekerjaan", "tugas"), bagi saya itu terdengar lebih akrab daripada "tugas" dalam konteks CI / CD secara umum atau Jenkins.

All Articles