استقرار برنامه ها با Docker Swarm

سیستم توصیه محتوای ویدیویی آنلاین که ما روی آن کار می کنیم، یک توسعه تجاری بسته است و از نظر فنی یک خوشه چند جزئی از اجزای اختصاصی و منبع باز است. هدف از نوشتن این مقاله توصیف پیاده‌سازی سیستم خوشه‌بندی ازدحام docker برای یک سایت مرحله‌بندی بدون ایجاد اختلال در گردش کار ایجاد شده فرآیندهای ما در مدت زمان محدود است. روایت ارائه شده به دو بخش تقسیم می شود. بخش اول CI / CD را قبل از استفاده از Docker Swarm توصیف می کند و قسمت دوم روند اجرای آن را شرح می دهد. کسانی که علاقه ای به خواندن قسمت اول ندارند می توانند با خیال راحت به قسمت دوم بروند.

قسمت اول

در سالهای دور و دور، لازم بود که فرآیند CI / CD در اسرع وقت راه اندازی شود. یکی از شرایط استفاده نکردن از داکر بود برای استقرار اجزای توسعه یافته به چند دلیل:

  • برای عملکرد مطمئن تر و پایدارتر کامپوننت ها در تولید (یعنی در واقع نیاز به استفاده نکردن از مجازی سازی)
  • توسعه دهندگان پیشرو نمی خواستند با Docker کار کنند (عجیب است، اما اینطور بود)
  • با توجه به ملاحظات ایدئولوژیک مدیریت تحقیق و توسعه

زیرساخت، پشته و الزامات اولیه تقریبی برای MVP به شرح زیر ارائه شد:

  • 4 سرور Intel® X5650 با Debian (یک دستگاه قدرتمند دیگر کاملاً توسعه یافته است)
  • توسعه مولفه های سفارشی خود در C ++، Python3 انجام می شود
  • ابزارهای اصلی شخص ثالث مورد استفاده: Kafka، Clickhouse، Airflow، Redis، Grafana، Postgresql، Mysql، …
  • خطوط لوله برای ساخت و آزمایش اجزا به طور جداگانه برای رفع اشکال و انتشار

یکی از اولین سوالاتی که در مرحله اولیه باید به آن پرداخته شود این است که چگونه اجزای سفارشی در هر محیطی (CI / CD) مستقر خواهند شد.

ما تصمیم گرفتیم اجزای شخص ثالث را به صورت سیستمی نصب کنیم و آنها را به صورت سیستمی به روز کنیم. برنامه های سفارشی توسعه یافته در C++ یا Python می توانند به روش های مختلفی مستقر شوند. از جمله: ایجاد بسته های سیستمی، ارسال آنها به مخزن تصاویر ساخته شده و سپس نصب آنها بر روی سرورها. به دلیل نامعلومی، روش دیگری انتخاب شد، یعنی: با استفاده از CI، فایل‌های اجرایی برنامه کامپایل می‌شوند، یک محیط پروژه مجازی ایجاد می‌شود، ماژول‌های py از request.txt نصب می‌شوند و همه این آرتیفکت‌ها به همراه تنظیمات، اسکریپت‌ها و محیط برنامه همراه با سرورها در مرحله بعد، برنامه ها به عنوان یک کاربر مجازی بدون حقوق سرپرست راه اندازی می شوند.

Gitlab-CI به عنوان سیستم CI/CD انتخاب شد. خط لوله حاصل چیزی شبیه به این بود:

استقرار برنامه ها با Docker Swarm
از نظر ساختاری، gitlab-ci.yml شبیه این بود

---
variables:
  # минимальная версия ЦПУ на серверах, где разворачивается кластер
  CMAKE_CPUTYPE: "westmere"

  DEBIAN: "MYREGISTRY:5000/debian:latest"

before_script:
  - eval $(ssh-agent -s)
  - ssh-add <(echo "$SSH_PRIVATE_KEY")
  - mkdir -p ~/.ssh && echo -e "Host *ntStrictHostKeyChecking nonn" > ~/.ssh/config

stages:
  - build
  - testing
  - deploy

debug.debian:
  stage: build
  image: $DEBIAN
  script:
    - cd builds/release && ./build.sh
    paths:
      - bin/
      - builds/release/bin/
    when: always
release.debian:
  stage: build
  image: $DEBIAN
  script:
    - cd builds/release && ./build.sh
    paths:
      - bin/
      - builds/release/bin/
    when: always

## testing stage
tests.codestyle:
  stage: testing
  image: $DEBIAN
  dependencies:
    - release.debian
  script:
    - /bin/bash run_tests.sh -t codestyle -b "${CI_COMMIT_REF_NAME}_codestyle"
tests.debug.debian:
  stage: testing
  image: $DEBIAN
  dependencies:
    - debug.debian
  script:
    - /bin/bash run_tests.sh -e codestyle/test_pylint.py -b "${CI_COMMIT_REF_NAME}_debian_debug"
  artifacts:
    paths:
      - run_tests/username/
    when: always
    expire_in: 1 week
tests.release.debian:
  stage: testing
  image: $DEBIAN
  dependencies:
    - release.debian
  script:
    - /bin/bash run_tests.sh -e codestyle/test_pylint.py -b "${CI_COMMIT_REF_NAME}_debian_release"
  artifacts:
    paths:
      - run_tests/username/
    when: always
    expire_in: 1 week

## staging stage
deploy_staging:
  stage: deploy
  environment: staging
  image: $DEBIAN
  dependencies:
    - release.debian
  script:
    - cd scripts/deploy/ &&
        python3 createconfig.py -s $CI_ENVIRONMENT_NAME &&
        /bin/bash install_venv.sh -d -r ../../requirements.txt &&
        python3 prepare_init.d.py &&
        python3 deploy.py -s $CI_ENVIRONMENT_NAME
  when: manual

شایان ذکر است که مونتاژ و آزمایش بر روی تصویر خود انجام می شود ، جایی که تمام بسته های سیستمی لازم قبلاً نصب شده و سایر تنظیمات نیز انجام شده است.

اگرچه هر یک از این اسکریپت ها در مشاغل به نوع خود جالب هستند، اما البته من در مورد آنها صحبت نمی کنم. شرح هر یک از آنها زمان زیادی می برد و این هدف مقاله نیست. من فقط توجه شما را به این واقعیت جلب می کنم که مرحله استقرار شامل دنباله ای از اسکریپت های فراخوانی است:

  1. createconfig.py - یک فایل settings.ini با تنظیمات کامپوننت در محیط های مختلف برای استقرار بعدی (پیش تولید، تولید، تست، ...) ایجاد می کند.
  2. install_venv.sh - یک محیط مجازی برای اجزای py در یک دایرکتوری خاص ایجاد می کند و آن را در سرورهای راه دور کپی می کند
  3. përgatit_init.d.py - اسکریپت های start-stop را برای کامپوننت بر اساس الگو آماده می کند
  4. deploy.py - اجزای جدید را تجزیه و راه اندازی مجدد می کند

زمان گذشت. پیش تولید و تولید جایگزین مرحله صحنه سازی شد. پشتیبانی از محصول در یک توزیع دیگر (CentOS) اضافه شده است. اضافه شدن 5 سرور فیزیکی قوی تر و ده ها سرور مجازی. و برای توسعه‌دهندگان و آزمایش‌کنندگان سخت‌تر می‌شد که وظایف خود را در محیطی کم و بیش نزدیک به حالت کار آزمایش کنند. در این زمان مشخص شد که بدون او غیرممکن است ...

قسمت دوم

استقرار برنامه ها با Docker Swarm

بنابراین، خوشه ما یک سیستم دیدنی از چند دوجین مؤلفه جداگانه است که توسط Dockerfiles توضیح داده نشده است. شما فقط می توانید آن را برای استقرار در یک محیط خاص به طور کلی پیکربندی کنید. وظیفه ما این است که خوشه را در یک محیط مرحله بندی مستقر کنیم تا آن را قبل از آزمایش قبل از انتشار آزمایش کنیم.

از نظر تئوری، می‌تواند چندین خوشه به طور همزمان در حال اجرا باشد: به تعداد وظایفی که در حالت تکمیل شده یا نزدیک به اتمام وجود دارد. ظرفیت سرورهای در اختیار ما به ما این امکان را می دهد که چندین کلاستر را روی هر سرور اجرا کنیم. هر خوشه مرحله بندی باید ایزوله باشد (هیچ تقاطعی در پورت ها، دایرکتوری ها و غیره نباید وجود داشته باشد).

با ارزش ترین منبع ما زمان ما است و ما مقدار زیادی از آن را نداشتیم.

برای شروع سریع‌تر، Docker Swarm را به دلیل سادگی و انعطاف‌پذیری معماری آن انتخاب کردیم. اولین کاری که انجام دادیم ایجاد یک مدیر و چندین گره در سرورهای راه دور بود:

$ docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
kilqc94pi2upzvabttikrfr5d     nop-test-1     Ready               Active                                  19.03.2
jilwe56pl2zvabupryuosdj78     nop-test-2     Ready               Active                                  19.03.2
j5a4yz1kr2xke6b1ohoqlnbq5 *   nop-test-3     Ready               Active              Leader              19.03.2

بعد، یک شبکه ایجاد کنید:


$ docker network create --driver overlay --subnet 10.10.10.0/24 nw_swarm

بعد، گره‌های Gitlab-CI و Swarm را از نظر کنترل از راه دور گره‌ها از CI به هم وصل کردیم: نصب گواهی‌ها، تنظیم متغیرهای مخفی و راه‌اندازی سرویس Docker در سرور کنترل. این یکی مقاله در زمان ما صرفه جویی زیادی کرد.

در مرحله بعد، کارهای ایجاد پشته و تخریب را به .gitlab-ci .yml اضافه کردیم.

چند شغل دیگر به .gitlab-ci .yml اضافه شده است

## staging stage
deploy_staging:
  stage: testing
  before_script:
    - echo "override global 'before_script'"
  image: "REGISTRY:5000/docker:latest"
  environment: staging
  dependencies: []
  variables:
    DOCKER_CERT_PATH: "/certs"
    DOCKER_HOST: tcp://10.50.173.107:2376
    DOCKER_TLS_VERIFY: 1
    CI_BIN_DEPENDENCIES_JOB: "release.centos.7"
  script:
    - mkdir -p $DOCKER_CERT_PATH
    - echo "$TLSCACERT" > $DOCKER_CERT_PATH/ca.pem
    - echo "$TLSCERT" > $DOCKER_CERT_PATH/cert.pem
    - echo "$TLSKEY" > $DOCKER_CERT_PATH/key.pem
    - docker stack deploy -c docker-compose.yml ${CI_ENVIRONMENT_NAME}_${CI_COMMIT_REF_NAME} --with-registry-auth
    - rm -rf $DOCKER_CERT_PATH
  when: manual

## stop staging stage
stop_staging:
  stage: testing
  before_script:
    - echo "override global 'before_script'"
  image: "REGISTRY:5000/docker:latest"
  environment: staging
  dependencies: []
  variables:
    DOCKER_CERT_PATH: "/certs"
    DOCKER_HOST: tcp://10.50.173.107:2376
    DOCKER_TLS_VERIFY: 1
  script:
    - mkdir -p $DOCKER_CERT_PATH
    - echo "$TLSCACERT" > $DOCKER_CERT_PATH/ca.pem
    - echo "$TLSCERT" > $DOCKER_CERT_PATH/cert.pem
    - echo "$TLSKEY" > $DOCKER_CERT_PATH/key.pem
    - docker stack rm ${CI_ENVIRONMENT_NAME}_${CI_COMMIT_REF_NAME}
    # TODO: need check that stopped
  when: manual

از قطعه کد بالا، می بینید که دو دکمه (deploy_staging، stop_staging) به Pipelines اضافه شده است که نیاز به اقدام دستی دارد.

استقرار برنامه ها با Docker Swarm
نام پشته با نام شاخه مطابقت دارد و این منحصر به فرد بودن باید کافی باشد. سرویس‌های موجود در پشته آدرس‌های IP منحصربه‌فرد و پورت‌ها، دایرکتوری‌ها و غیره را دریافت می‌کنند. جدا می شود، اما از پشته به پشته یکسان است (زیرا فایل پیکربندی برای همه پشته ها یکسان است) - آنچه ما می خواستیم. ما پشته (خوشه) را با استفاده از docker-compose.yml، که خوشه ما را توصیف می کند.

docker-compose.yml

---
version: '3'

services:
  userprop:
    image: redis:alpine
    deploy:
      replicas: 1
      placement:
        constraints: [node.id == kilqc94pi2upzvabttikrfr5d]
      restart_policy:
        condition: none
    networks:
      nw_swarm:
  celery_bcd:
    image: redis:alpine
    deploy:
      replicas: 1
      placement:
        constraints: [node.id == kilqc94pi2upzvabttikrfr5d]
      restart_policy:
        condition: none
    networks:
      nw_swarm:

  schedulerdb:
    image: mariadb:latest
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
      MYSQL_DATABASE: schedulerdb
      MYSQL_USER: ****
      MYSQL_PASSWORD: ****
    command: ['--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci', '--explicit_defaults_for_timestamp=1']
    deploy:
      replicas: 1
      placement:
        constraints: [node.id == kilqc94pi2upzvabttikrfr5d]
      restart_policy:
        condition: none
    networks:
      nw_swarm:

  celerydb:
    image: mariadb:latest
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
      MYSQL_DATABASE: celerydb
      MYSQL_USER: ****
      MYSQL_PASSWORD: ****
    deploy:
      replicas: 1
      placement:
        constraints: [node.id == kilqc94pi2upzvabttikrfr5d]
      restart_policy:
        condition: none
    networks:
      nw_swarm:

  cluster:
    image: $CENTOS7
    environment:
      - CENTOS
      - CI_ENVIRONMENT_NAME
      - CI_API_V4_URL
      - CI_REPOSITORY_URL
      - CI_PROJECT_ID
      - CI_PROJECT_URL
      - CI_PROJECT_PATH
      - CI_PROJECT_NAME
      - CI_COMMIT_REF_NAME
      - CI_BIN_DEPENDENCIES_JOB
    command: >
      sudo -u myusername -H /bin/bash -c ". /etc/profile &&
        mkdir -p /storage1/$CI_COMMIT_REF_NAME/$CI_PROJECT_NAME &&
        cd /storage1/$CI_COMMIT_REF_NAME/$CI_PROJECT_NAME &&
            git clone -b $CI_COMMIT_REF_NAME $CI_REPOSITORY_URL . &&
            curl $CI_API_V4_URL/projects/$CI_PROJECT_ID/jobs/artifacts/$CI_COMMIT_REF_NAME/download?job=$CI_BIN_DEPENDENCIES_JOB -o artifacts.zip &&
            unzip artifacts.zip ;
        cd /storage1/$CI_COMMIT_REF_NAME/$CI_PROJECT_NAME/scripts/deploy/ &&
            python3 createconfig.py -s $CI_ENVIRONMENT_NAME &&
            /bin/bash install_venv.sh -d -r ../../requirements.txt &&
            python3 prepare_init.d.py &&
            python3 deploy.py -s $CI_ENVIRONMENT_NAME"
    deploy:
      replicas: 1
      placement:
        constraints: [node.id == kilqc94pi2upzvabttikrfr5d]
      restart_policy:
        condition: none
    tty: true
    stdin_open: true
    networks:
      nw_swarm:

networks:
  nw_swarm:
    external: true

در اینجا می بینید که کامپوننت ها توسط یک شبکه (nw_swarm) به هم متصل شده اند و در دسترس یکدیگر هستند.

اجزای سیستم (بر اساس redis، mysql) از مجموعه کلی اجزای سفارشی جدا می شوند (در پلن ها و موارد سفارشی به عنوان خدمات تقسیم می شوند). مرحله استقرار خوشه ما به نظر می رسد که CMD را به یک تصویر پیکربندی شده بزرگ منتقل می کنیم و به طور کلی، عملاً با استقرار شرح داده شده در قسمت اول تفاوتی ندارد. من تفاوت ها را برجسته می کنم:

  • git clone... - دریافت فایل های مورد نیاز برای استقرار (createconfig.py، install_venv.sh، و غیره)
  • حلقه کردن... && باز کردن زیپ... - آرتیفکت های ساخت را دانلود و از حالت فشرده خارج کنید (ابزارهای کامپایل شده)

تنها یک مشکل هنوز توصیف نشده وجود دارد: اجزایی که دارای رابط وب هستند از مرورگرهای توسعه دهندگان قابل دسترسی نیستند. ما این مشکل را با استفاده از پروکسی معکوس حل می کنیم، به این ترتیب:

در gitlab-ci.yml، پس از استقرار پشته کلاستر، خط استقرار متعادل کننده را اضافه می کنیم (که در هنگام commit، فقط پیکربندی آن را به روز می کند (فایل های پیکربندی جدید nginx را مطابق الگو ایجاد می کند: /etc/nginx/conf. d/${CI_COMMIT_REF_NAME}.conf) - کد docker-compose-nginx.yml را ببینید)

    - docker stack deploy -c docker-compose-nginx.yml ${CI_ENVIRONMENT_NAME} --with-registry-auth

docker-compose-nginx.yml

---
version: '3'

services:
  nginx:
    image: nginx:latest
    environment:
      CI_COMMIT_REF_NAME: ${CI_COMMIT_REF_NAME}
      NGINX_CONFIG: |-
            server {
                listen 8080;
                server_name staging_${CI_COMMIT_REF_NAME}_cluster.dev;

                location / {
                    proxy_pass http://staging_${CI_COMMIT_REF_NAME}_cluster:8080;
                }
            }
            server {
                listen 5555;
                server_name staging_${CI_COMMIT_REF_NAME}_cluster.dev;

                location / {
                    proxy_pass http://staging_${CI_COMMIT_REF_NAME}_cluster:5555;
                }
            }
    volumes:
      - /tmp/staging/nginx:/etc/nginx/conf.d
    command:
      /bin/bash -c "echo -e "$$NGINX_CONFIG" > /etc/nginx/conf.d/${CI_COMMIT_REF_NAME}.conf;
        nginx -g "daemon off;";
        /etc/init.d/nginx reload"
    ports:
      - 8080:8080
      - 5555:5555
      - 3000:3000
      - 443:443
      - 80:80
    deploy:
      replicas: 1
      placement:
        constraints: [node.id == kilqc94pi2upzvabttikrfr5d]
      restart_policy:
        condition: none
    networks:
      nw_swarm:

networks:
  nw_swarm:
    external: true

در رایانه های توسعه دهنده، /etc/hosts را به روز کنید. url را برای nginx تجویز کنید:

10.50.173.106 staging_BRANCH-1831_cluster.dev

بنابراین، استقرار خوشه های مرحله بندی ایزوله اجرا شده است و توسعه دهندگان اکنون می توانند آنها را به هر تعداد کافی برای بررسی وظایف خود اجرا کنند.

برنامه های آینده:

  • اجزای ما را به عنوان خدمات جدا کنید
  • برای هر Dockerfile داشته باشید
  • به طور خودکار گره های کمتر بارگذاری شده در پشته را شناسایی کنید
  • گره ها را با الگوی نام مشخص کنید (به جای استفاده از شناسه در مقاله)
  • چکی اضافه کنید که پشته از بین رفته است
  • ...

تشکر ویژه برای یک مقاله.

منبع: www.habr.com

اضافه کردن نظر