Vendosni aplikacione me Docker Swarm

Sistemi i rekomandimit të përmbajtjes së videove në internet për të cilin po punojmë është një zhvillim i mbyllur tregtar dhe teknikisht është një grup me shumë komponentë i përbërësve të pronarit dhe me burim të hapur. Qëllimi i shkrimit të këtij artikulli është të përshkruajë zbatimin e sistemit të grupimit të tufës së dokerit për një vend vendosjeje pa ndërprerë rrjedhën e vendosur të punës të proceseve tona në një kohë të kufizuar. Rrëfimi i paraqitur në vëmendjen tuaj është i ndarë në dy pjesë. Pjesa e parë përshkruan CI / CD para përdorimit të docker swarm, dhe e dyta përshkruan procesin e zbatimit të tij. Ata që nuk janë të interesuar të lexojnë pjesën e parë, mund të kalojnë me siguri në të dytën.

Pjesa I

Në vitin e largët, të largët, ishte e nevojshme të konfigurohej procesi CI / CD sa më shpejt që të ishte e mundur. Një nga kushtet ishte të mos përdorej Docker për vendosje komponentë të zhvilluar për disa arsye:

  • për funksionim më të besueshëm dhe të qëndrueshëm të komponentëve në prodhim (që është, në fakt, kërkesa për të mos përdorur virtualizimin)
  • zhvilluesit kryesorë nuk donin të punonin me Docker (e çuditshme, por kështu ishte)
  • sipas konsideratave ideologjike të menaxhimit të R&D

Infrastruktura, pirgu dhe kërkesat fillestare të përafërta për MVP u prezantuan si më poshtë:

  • 4 serverë Intel® X5650 me Debian (një makinë më e fuqishme është zhvilluar plotësisht)
  • Zhvillimi i komponentëve të personalizuar kryhet në C ++, Python3
  • Mjetet kryesore të palëve të treta të përdorura: Kafka, Clickhouse, Airflow, Redis, Grafana, Postgresql, Mysql,…
  • Tubacionet për ndërtimin dhe testimin e komponentëve veçmas për korrigjim dhe lëshim

Një nga pyetjet e para që duhet të adresohet në fazën fillestare është se si do të vendosen komponentët e personalizuar në çdo mjedis (CI / CD).

Ne vendosëm të instalojmë komponentë të palëve të treta në mënyrë sistematike dhe t'i përditësojmë ato në mënyrë sistematike. Aplikacionet e personalizuara të zhvilluara në C++ ose Python mund të vendosen në disa mënyra. Midis tyre, për shembull: krijimi i paketave të sistemit, dërgimi i tyre në depon e imazheve të ndërtuara dhe më pas instalimi i tyre në serverë. Për një arsye të panjohur, u zgjodh një metodë tjetër, domethënë: duke përdorur CI, përpilohen skedarët e ekzekutueshëm të aplikacionit, krijohet një mjedis virtual i projektit, instalohen modulet py nga kërkesat.txt dhe të gjitha këto objekte dërgohen së bashku me konfigurimet, skriptet dhe mjedisi shoqërues i aplikacionit te serverët. Më pas, aplikacionet lëshohen si përdorues virtual pa të drejta administratori.

Gitlab-CI u zgjodh si sistemi CI/CD. Tubacioni që rezulton dukej diçka si kjo:

Vendosni aplikacione me Docker Swarm
Strukturisht, gitlab-ci.yml dukej kështu

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

Vlen të përmendet se montimi dhe testimi kryhet në imazhin e tij, ku tashmë janë instaluar të gjitha paketat e nevojshme të sistemit dhe janë bërë cilësime të tjera.

Edhe pse secili prej këtyre skripteve në punë është interesant në mënyrën e vet, por sigurisht që nuk do të flas për to. Përshkrimi i secilit prej tyre do të marrë shumë kohë dhe nuk është ky qëllimi i artikullit. Unë do të tërheq vëmendjen tuaj vetëm për faktin se faza e vendosjes përbëhet nga një sekuencë e skripteve të thirrjes:

  1. createconfig.py - krijon një skedar settings.ini me cilësimet e komponentëve në mjedise të ndryshme për vendosjen e mëvonshme (Paraprodhimi, Prodhimi, Testimi, ...)
  2. instaloj_venv.sh - krijon një mjedis virtual për komponentët py në një direktori specifike dhe e kopjon atë në serverë të largët
  3. përgatit_init.d.py — përgatit skriptet start-stop për komponentin bazuar në shabllon
  4. vendos.py - zbërthehet dhe rinis komponentët e rinj

Koha kaloi. Faza e vënies në skenë u zëvendësua nga paraprodhimi dhe prodhimi. Mbështetje e shtuar për produktin në një shpërndarje tjetër (CentOS). U shtuan 5 serverë fizikë më të fuqishëm dhe një duzinë virtuale. Dhe u bë gjithnjë e më e vështirë për zhvilluesit dhe testuesit të testonin detyrat e tyre në një mjedis pak a shumë afër gjendjes së punës. Në këtë kohë, u bë e qartë se ishte e pamundur të bëhej pa të ...

Pjesa II

Vendosni aplikacione me Docker Swarm

Pra, grupi ynë është një sistem spektakolar i disa dhjetëra komponentëve të veçantë që nuk përshkruhen nga Dockerfiles. Mund ta konfiguroni vetëm për vendosje në një mjedis specifik në përgjithësi. Detyra jonë është të vendosim grupin në një mjedis skenik për ta testuar atë përpara testimit para publikimit.

Teorikisht, mund të ketë disa grupime që funksionojnë njëkohësisht: aq sa ka detyra në gjendjen e përfunduar ose afër përfundimit. Kapacitetet e serverëve që kemi në dispozicion na lejojnë të ekzekutojmë disa grupime në secilin server. Çdo grup grupimi duhet të jetë i izoluar (nuk duhet të ketë kryqëzim në porte, drejtori, etj.).

Burimi ynë më i vlefshëm është koha jonë, dhe ne nuk kishim shumë prej saj.

Për një fillim më të shpejtë, ne zgjodhëm Docker Swarm për shkak të thjeshtësisë dhe fleksibilitetit të arkitekturës. Gjëja e parë që bëmë ishte krijimi i një menaxheri dhe disa nyjeve në serverët e largët:

$ 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

Më pas, krijoni një rrjet:


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

Më pas, lidhëm nyjet Gitlab-CI dhe Swarm për sa i përket kontrollit të largët të nyjeve nga CI: instalimi i certifikatave, vendosja e variablave sekrete dhe vendosja e shërbimit Docker në serverin e kontrollit. Këtë artikull na kurseu shumë kohë.

Më pas, shtuam punët e krijimit dhe shkatërrimit të stackave në .gitlab-ci .yml.

Disa vende të tjera janë shtuar në .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

Nga pjesa e kodit të mësipërm, mund të shihni se dy butona (deploy_staging, stop_staging) janë shtuar në Pipelines, që kërkojnë veprim manual.

Vendosni aplikacione me Docker Swarm
Emri i pirgut përputhet me emrin e degës dhe kjo veçanti duhet të jetë e mjaftueshme. Shërbimet në stack marrin adresa ip unike, porte, direktori, etj. do të jetë i izoluar, por i njëjti nga rafti në pirg (sepse skedari i konfigurimit është i njëjtë për të gjitha raftet) - ajo që dëshironim. Ne vendosim pirgun (grupin) duke përdorur prerës-compose.yml, i cili përshkruan grupin tonë.

prerës-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

Këtu mund të shihni se komponentët janë të lidhur nga një rrjet (nw_swarm) dhe janë të disponueshëm për njëri-tjetrin.

Komponentët e sistemit (bazuar në redis, mysql) ndahen nga grupi i përgjithshëm i komponentëve me porosi (në plane dhe ato me porosi ndahen si shërbime). Faza e vendosjes së grupit tonë duket si kalimi i CMD në imazhin tonë të vetëm të konfiguruar dhe, në përgjithësi, praktikisht nuk ndryshon nga vendosja e përshkruar në Pjesën I. Unë do të theksoj ndryshimet:

  • klon git... - merrni skedarët e nevojshëm për t'u vendosur (createconfig.py, install_venv.sh, etj.)
  • përkulem... && çzip... - shkarkoni dhe çzipni objektet e ndërtimit (shërbimet e përpiluara)

Ekziston vetëm një problem ende i papërshkruar: komponentët që kanë një ndërfaqe ueb nuk janë të aksesueshëm nga shfletuesit e zhvilluesve. Ne e zgjidhim këtë problem duke përdorur përfaqësuesin e kundërt, kështu:

Në .gitlab-ci.yml, pas vendosjes së grumbullit të grupit, shtojmë linjën e vendosjes së balancuesit (i cili, kur kryen, përditëson vetëm konfigurimin e tij (krijon skedarë të rinj të konfigurimit të nginx sipas shabllonit: /etc/nginx/conf. d/${CI_COMMIT_REF_NAME}.conf) - shih kodin 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

Në kompjuterët e zhvillimit, përditësoni /etc/hosts; përshkruani url në nginx:

10.50.173.106 staging_BRANCH-1831_cluster.dev

Pra, vendosja e grupimeve të izoluara të vendosjes është zbatuar dhe zhvilluesit tani mund t'i ekzekutojnë ato në çdo numër të mjaftueshëm për të kontrolluar detyrat e tyre.

Planet e ardhshme:

  • Ndani komponentët tanë si shërbime
  • Keni për çdo Dockerfile
  • Zbuloni automatikisht nyjet më pak të ngarkuara në pirg
  • Specifikoni nyjet sipas modelit të emrit (në vend që të përdorni id si në artikull)
  • Shtoni një kontroll që pirgja është shkatërruar
  • ...

Faleminderit të veçantë për një artikull.

Burimi: www.habr.com

Shto një koment