انشر جنكينز كرمز

ملحوظة perev.: هذه ترجمة لمقال من مدونة الهندسة Preply حول كيفية استخدام التكوين كرمز لأداة CI / CD الشائعة مثل Jenkins.

في شركتنا ، نحاول اتباع ممارسة "كل شيء يشبه الرمز" ، وهذا لا ينطبق فقط على موارد البنية التحتية ، ولكن أيضًا على المراقبة ، وعمل Jenkins ، إلخ. في هذه المقالة ، سأتحدث عن كيفية استخدامنا لهذه الممارسة لنشر ودعم Jenkins. وهذا لا ينطبق فقط على البنية التحتية للخادم والوكلاء ، ولكن أيضًا على المكونات الإضافية والوصول والعمل والعمل وأشياء أخرى كثيرة.

بالإضافة إلى ذلك ، سنحاول في هذه المقالة العثور على إجابات لأسئلة مثل:

  • هل أصبح جنكينز أكثر استقرارًا؟
  • هل يمكننا إجراء تغييرات متكررة في تكوين الخادم والوظيفة؟
  • هل ما زال تحديث جنكينز مؤلمًا بالنسبة لنا؟
  • هل يمكننا التحكم في جميع تغييراتنا؟
  • هل يمكننا استعادة جينكينز بسرعة في حالة حدوث فاكاب؟

صورة


المقدمة


عادة ، أول ما يتبادر إلى الذهن عند ذكر عبارة "أدوات DevOps" هو نظام CI / CD. على سبيل المثال ، نستخدم Jenkins لأننا ندير مئات المهام كل يوم ، وهذا عشرات الآلاف من الإصدارات. بعض الميزات التي نستخدمها في Jenkins إما أنها غير متوفرة في أنظمة CI / CD الأخرى أو لديها وظائف محدودة.


نود التحكم في Jenkins تمامًا من الرمز ، بما في ذلك البنية التحتية والتكوينات والوظيفة والمكونات الإضافية. لقد حاولنا تشغيل Jenkins في Kubernetes ، لكنه لم يناسب احتياجاتنا ، بالإضافة إلى أنه لم يكن من السهل قياسه بسبب هندسته .

صورة
سيتم مناقشة هذا

البنية التحتية لجينكينز


صورةنستخدم AWS ونقوم بتكوين البنية التحتية بالكامل باستخدام Terraform وأدوات التجزئة الأخرى مثل Packer و Vault .

كما ذكرنا سابقًا ، حاولنا استخدام Jenkins في Kubernetes وواجهنا بعض المشكلات في تحجيم PVC والموارد وبنية غير جيدة التصميم.

هنا ، نستخدم موارد AWS المعتادة: مثيلات EC2 وشهادات SSL والموازنات و Cloudfront وما إلى ذلك. تم تكوين صورة نظام التشغيل ( AMI ) باستخدام 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.

بدوره ، packer_bootstrap.shيحتوي الملف على مجموعة من الأوامر التي يتم تثبيت البرنامج معها داخل الصورة. على سبيل المثال ، يمكننا تثبيت Docker و docker-compose و vaultenv أو Datadog-agent للمراقبة. فيما يتعلق بالبنية التحتية لهذه الصورة ، يمكننا استخدام Terraform أو Cloudformation أو Pulumi أو حتى Ansible.

في ما يلي مثال على بنية AWS محتملة لـ Jenkins. يقوم

المستخدمون بتسجيل الدخول إلى Jenkins من خلال الموازن الداخلي ، ووصلات Github تصل إلى الخادم من خلال الخادم الخارجي. نحن نستخدم تكامل Jenkins مع GitHub ، لذا يجب الوصول إلى بعض روابط الخادم من الإنترنت. هناك العديد من الحلول المختلفة هنا (على سبيل المثال ، قائمة بيضاء لعناوين IP أو عناوين URL أو الرموز المميزة وما إلى ذلك) ، في حالتنا نستخدم مجموعة من عناوين URL المسموح بها والتحقق من الرمز المميز.
لذا ، بعد التلاعبات التي قمنا بها ، لدينا بالفعل بنية تحتية جاهزة مع صورة نظام التشغيل المجمعة ، والقدرة على المراقبة والوصول إلى المتجر السري للشركة.

نستخدم 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()}")
}
يمكنك الحصول على قائمة بالمكونات الإضافية المثبتة في Jenkins عن طريق النقر على الرابط https://our-jenkins-url/scriptوحفظ الناتج في ملفplugins.txt

، وأخيرًا ، تكوين تكوين عامل الميناء ، والذي سيتم تشغيل Jenkins في 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
نستخدم أيضًا vaultenv لتزييف الأسرار من Vault.

لاحظ بعض خيارات جافا التي ساعدتنا في جمع البيانات المهملة وحدود الموارد. هذه المقالة رائعة جدًا حول ضبط Jenkins.

وبالطبع ، يمكننا الآن نشر نسخة من Jenkins محليًا وتجربة إصدارات جديدة من الخادم والمكونات الإضافية. إنه مريح للغاية.
الآن لدينا تثبيت نظيف من Jenkins والمكونات الإضافية ، والتي يمكن إطلاقها بسهولة في المنتج. دعنا نضيف المزيد من التكوين لها.

تكوين Jenkins كبرنامج مساعد (JCaSC) لتكوين الخادم


صورةبشكل عام ، هناك مكون إضافي يسمى Jenkins Configuration كـ 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}
      ...
هذه هي الكيفية التي يمكن من خلالها وصف الأسرار.

نستخدم أيضًا المكون الإضافي Amazon 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
        ...
وصف الوكلاء والوصول

يدعم المكون الإضافي بعض الأشياء الأخرى التي نستخدمها. من خلال عملية اختبار محلية لجينكينز منظمة بشكل صحيح ، يمكنك العثور على الأخطاء وإصلاحها بشكل فعال قبل أن تتمكن من الدخول في مبيعات جينكينز.
الآن لدينا تكوين قابل للتكرار للخادم ، ويظل الحال بالنسبة للصغار ، أي - الوظيفة.

نحن نستخدم Job Builder لمشاريع حرة


صورةهناك عدة طرق لخلق وظائف حرة في جينكينز:


يتيح لك Jenkins Job Builder (JJB) تكوين الوظائف باستخدام YAML أو JSON. وهو مناسب تمامًا ، لأنه يمكنك تهيئة جميع الوظائف وتخزين حالتها في بوابة شرطية. هذا ، في الواقع ، يمكننا بناء عملية CI / CD لأداة CI / CD الخاصة بنا باستخدام JJB.

.
├── 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

بنفسه ، يجب أن يمتلك المستخدم الذي تم إنشاء الرمز المميز له الامتيازات المناسبة لإنشاء المهمة وتكوينها. نحتاج فقط إلى تطبيق وظيفة تهيئة واحدة (وظيفة أولية) ، والتي ستطبق التغييرات باستخدام JJB في Jenkins.

من الجدير بالذكر أن JJB ليست "رصاصة فضية" ، لأن بعض الإضافات غير الشائعة جدًا غير مدعومة. ومع ذلك ، فهي أداة مرنة للغاية لتخزين المهام في التعليمات البرمجية ، بما في ذلك دعم الماكرو .

ملخص


الآن بعد أن وصلنا إلى نهاية هذه المقالة ، أود العودة إلى البداية والإجابة على الأسئلة المطروحة في البداية. يمكننا الإجابة بـ "نعم" على كل الأسئلة المطروحة.

في هذه المقالة ، لم نتعمق في تعقيدات إعداد تقنيات معينة أو كيفية تكوين Jenkins بشكل صحيح ، نحن فقط نشارك تجربتنا ، والتي قد تكون مفيدة لك أيضًا.

ملاحظة: في المقالة ، غالبًا ما أستخدم كلمة "وظيفة" (من اللغة الإنجليزية. "وظيفة" ، "مهمة") ، تبدو بالنسبة لي أكثر شيوعًا من "المهمة" في سياق CI / CD بشكل عام أو جنكينز.

All Articles