Įdiekite programas naudodami „Docker Swarm“.

Internetinė vaizdo įrašų turinio rekomendacijų sistema, su kuria dirbame, yra uždara komercinė plėtra ir techniškai yra kelių komponentų patentuotų ir atvirojo kodo komponentų grupė. Šio straipsnio tikslas – apibūdinti dokerių spiečiaus klasterizacijos sistemos diegimą sustojimo vietoje, nesutrikdant nustatytos mūsų procesų darbo eigos per ribotą laiką. Jūsų dėmesiui pateiktas pasakojimas yra padalintas į dvi dalis. Pirmoje dalyje aprašomas CI / CD prieš naudojant docker spiečius, o antroje – jo įgyvendinimo procesas. Tie, kurie nesidomi skaityti pirmąja dalimi, gali drąsiai pereiti prie antrosios.

I dalis

Dar tolimais, tolimais metais reikėjo kuo greičiau nustatyti CI / CD procesą. Viena iš sąlygų buvo nenaudoti „Docker“. dislokavimui sukurti komponentai dėl kelių priežasčių:

  • patikimesniam ir stabilesniam komponentų veikimui gamyboje (tai iš tikrųjų yra reikalavimas nenaudoti virtualizacijos)
  • pagrindiniai kūrėjai nenorėjo dirbti su „Docker“ (keista, bet taip buvo)
  • pagal ideologinius MTEP valdymo sumetimus

Infrastruktūra, dėklas ir apytiksliai pradiniai MVP reikalavimai buvo pateikti taip:

  • 4 „Intel® X5650“ serveriai su „Debian“ (visiškai sukurtas dar vienas galingas įrenginys)
  • Savo pasirinktinių komponentų kūrimas atliekamas C ++, Python3
  • Pagrindiniai naudojami trečiųjų šalių įrankiai: Kafka, Clickhouse, Airflow, Redis, Grafana, Postgresql, Mysql,…
  • Vamzdynai, skirti komponentams kurti ir testuoti atskirai derinant ir išleidžiant

Vienas iš pirmųjų klausimų, kurį reikia išspręsti pradiniame etape, yra tai, kaip pasirinktiniai komponentai bus įdiegti bet kurioje aplinkoje (CI / CD).

Nusprendėme sistemingai įdiegti trečiųjų šalių komponentus ir sistemingai juos atnaujinti. Pasirinktinės programos, sukurtos C++ arba Python kalbomis, gali būti įdiegtos keliais būdais. Tarp jų, pavyzdžiui: sistemos paketų kūrimas, jų siuntimas į sukurtų vaizdų saugyklą ir įdiegimas serveriuose. Dėl neaiškios priežasties buvo pasirinktas kitas būdas, būtent: naudojant CI, sukompiliuojami vykdomieji programos failai, sukuriama virtuali projekto aplinka, diegiami py moduliai iš reikalavimų.txt ir visi šie artefaktai siunčiami kartu su konfigūracijomis, scenarijais ir serveriams pridedama taikomųjų programų aplinka. Tada programos paleidžiamos kaip virtualus vartotojas be administratoriaus teisių.

Gitlab-CI buvo pasirinkta kaip CI / CD sistema. Gautas dujotiekis atrodė maždaug taip:

Įdiekite programas naudodami „Docker Swarm“.
Struktūriškai gitlab-ci.yml atrodė taip

---
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

Verta paminėti, kad surinkimas ir bandymai atliekami pagal savo atvaizdą, kur jau yra įdiegti visi reikalingi sistemos paketai ir atlikti kiti nustatymai.

Nors kiekvienas iš šių scenarijų darbuose yra savaip įdomus, bet, žinoma, apie juos nekalbėsiu.Kiekvieno iš jų aprašymas užtruks daug laiko ir tai nėra straipsnio tikslas. Aš tik atkreipsiu jūsų dėmesį į tai, kad diegimo etapą sudaro scenarijų iškvietimo seka:

  1. createconfig.py - sukuria failą settings.ini su komponentų nustatymais įvairiose aplinkose, kad būtų galima vėliau diegti (išankstinė gamyba, gamyba, testavimas ir kt.)
  2. install_venv.sh - sukuria virtualią aplinką py komponentams konkrečiame kataloge ir nukopijuoja ją į nuotolinius serverius
  3. ready_init.d.py — pagal šabloną parengia komponento start-stop scenarijus
  4. deploy.py - suskaido ir iš naujo paleidžia naujus komponentus

Praėjęs laikas. Pastatymo etapą pakeitė parengimas ir gamyba. Pridėtas produkto palaikymas dar viename paskirstyme (CentOS). Pridėta 5 galingesni fiziniai serveriai ir keliolika virtualių. O kūrėjams ir bandytojams darėsi vis sunkiau išbandyti savo užduotis aplinkoje, daugmaž artimoje darbo būsenai. Tuo metu tapo aišku, kad be jo neįmanoma išsiversti ...

II dalis

Įdiekite programas naudodami „Docker Swarm“.

Taigi, mūsų klasteris yra įspūdinga sistema, susidedanti iš kelių dešimčių atskirų komponentų, kurių Dockerfiles neaprašė. Jį galite konfigūruoti tik tam, kad jis būtų įdiegtas konkrečioje aplinkoje. Mūsų užduotis yra įdiegti klasterį į sustojimo aplinką, kad ją išbandytume prieš atliekant išankstinį išleidimą.

Teoriškai vienu metu gali veikti keli klasteriai: tiek, kiek yra užduočių baigtos būsenos arba beveik baigtos. Mūsų turimų serverių pajėgumai leidžia kiekviename serveryje paleisti keletą grupių. Kiekvienas sustojimo klasteris turi būti izoliuotas (prievaduose, kataloguose ir pan. neturi būti sankirtos).

Mūsų vertingiausias išteklius yra mūsų laikas, ir mes jo neturėjome daug.

Norėdami pradėti greičiau, pasirinkome Docker Swarm dėl jo paprastumo ir architektūros lankstumo. Pirmas dalykas, kurį padarėme, buvo sukurti tvarkyklę ir kelis mazgus nuotoliniuose serveriuose:

$ 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

Tada sukurkite tinklą:


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

Toliau sujungėme „Gitlab-CI“ ir „Swarm“ mazgus nuotoliniu būdu valdydami mazgus iš CI: įdiegėme sertifikatus, nustatėme slaptus kintamuosius ir „Docker“ paslaugą valdymo serveryje. Šitas straipsnis sutaupėme daug laiko.

Tada į .gitlab-ci .yml pridėjome dėklo kūrimo ir naikinimo užduotis.

Dar keli darbai buvo įtraukti į .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

Iš anksčiau pateikto kodo fragmento matote, kad du mygtukai (deploy_staging, stop_staging) buvo pridėti prie konvejerių, todėl reikia atlikti rankinį veiksmą.

Įdiekite programas naudodami „Docker Swarm“.
Krūvos pavadinimas sutampa su filialo pavadinimu ir šio unikalumo turėtų pakakti. Stekuose esančios paslaugos gauna unikalius IP adresus ir prievadus, katalogus ir kt. bus izoliuotas, bet tas pats nuo stack iki stack (nes konfigūracijos failas yra vienodas visiems stackams) - ko mes norėjome. Mes diegiame steką (klasterį) naudodami docker-compose.yml, kuris apibūdina mūsų klasterį.

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

Čia matote, kad komponentai yra sujungti vienu tinklu (nw_swarm) ir yra prieinami vienas kitam.

Sistemos komponentai (pagrįsti redis, mysql) yra atskirti nuo bendro pasirinktinių komponentų telkinio (planuose ir pasirinktiniai skirstomi kaip paslaugos). Mūsų klasterio diegimo etapas atrodo kaip CMD perdavimas į vieną didelį sukonfigūruotą vaizdą ir apskritai praktiškai nesiskiria nuo I dalyje aprašyto diegimo. Pabrėžsiu skirtumus:

  • git klonas... - Gaukite diegti reikalingus failus (createconfig.py, install_venv.sh ir kt.)
  • susisukti... && atsegti... - Atsisiųskite ir išpakuokite kūrimo artefaktus (sudarytas priemones)

Yra tik viena dar neaprašyta problema: komponentai, turintys žiniatinklio sąsają, nepasiekiami kūrėjų naršyklėse. Šią problemą išsprendžiame naudodami atvirkštinį tarpinį serverį, taigi:

Į .gitlab-ci.yml, įdiegę klasterio krūvą, pridedame balansavimo priemonės diegimo eilutę (kuris, kai įsipareigojamas, tik atnaujina konfigūraciją (sukuria naujus nginx konfigūracijos failus pagal šabloną: /etc/nginx/conf. d/${CI_COMMIT_REF_NAME}.conf) – žr. docker-compose-nginx.yml kodą)

    - 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

Kūrimo kompiuteriuose atnaujinkite /etc/hosts; nurodyti nginx URL:

10.50.173.106 staging_BRANCH-1831_cluster.dev

Taigi, buvo įdiegtas izoliuotų sustojimo grupių diegimas ir kūrėjai dabar gali juos paleisti bet kokiu kiekiu, kurio pakanka savo užduotims patikrinti.

Ateities planai:

  • Atskirkite mūsų komponentus kaip paslaugas
  • Turėkite kiekvienam Dockerfile
  • Automatiškai aptikti mažiau įkeltus mazgus krūvoje
  • Nurodykite mazgus pagal pavadinimo šabloną (o ne naudokite ID, kaip nurodyta straipsnyje)
  • Pridėkite čekį, kad kaminas sunaikintas
  • ...

Ypatingas ačiū už straipsnis.

Šaltinis: www.habr.com

Добавить комментарий