Ota sovelluksia käyttöön Docker Swarmin avulla

Työskentelemme verkkovideosisällön suositusjärjestelmässä, joka on suljettu kaupallinen kehitystyö, ja se on teknisesti monikomponenttinen klusteri patentoituja ja avoimen lähdekoodin komponentteja. Tämän artikkelin kirjoittamisen tarkoituksena on kuvata docker-parviklusterointijärjestelmän käyttöönottoa pysähdyspaikalle häiritsemättä prosessiemme vakiintunutta työnkulkua rajoitetussa ajassa. Huomioillesi esitetty kertomus on jaettu kahteen osaan. Ensimmäisessä osassa kuvataan CI / CD ennen Docker Swarmin käyttöä ja toisessa sen toteutusprosessia. Ne, jotka eivät ole kiinnostuneita ensimmäisen osan lukemisesta, voivat siirtyä turvallisesti toiseen.

Osa I

Kaukana, kaukaisena vuonna, oli välttämätöntä määrittää CI / CD-prosessi mahdollisimman nopeasti. Yksi ehdoista oli olla käyttämättä Dockeria käyttöönottoa varten kehitetty komponentteja useista syistä:

  • Tuotannon komponenttien luotettavampi ja vakaampi toiminta (eli itse asiassa vaatimus olla käyttämättä virtualisointia)
  • johtavat kehittäjät eivät halunneet työskennellä Dockerin kanssa (outoa, mutta niin se oli)
  • T&K-johdon ideologisten näkökohtien mukaisesti

MVP:n infrastruktuuri, pino ja likimääräiset alkuvaatimukset esitettiin seuraavasti:

  • 4 Intel® X5650 -palvelinta Debianilla (yksi tehokkaampi kone on täysin kehitetty)
  • Omien räätälöityjen komponenttien kehitys tapahtuu C ++:lla, Python3:lla
  • Tärkeimmät käytetyt kolmannen osapuolen työkalut: Kafka, Clickhouse, Airflow, Redis, Grafana, Postgresql, Mysql,…
  • Putket komponenttien rakentamiseen ja testaamiseen erikseen virheenkorjausta ja julkaisua varten

Yksi ensimmäisistä kysymyksistä, joita on käsiteltävä alkuvaiheessa, on se, kuinka mukautettuja komponentteja otetaan käyttöön missä tahansa ympäristössä (CI / CD).

Päätimme asentaa kolmannen osapuolen komponentteja järjestelmällisesti ja päivittää ne järjestelmällisesti. C++:lla tai Pythonilla kehitettyjä mukautettuja sovelluksia voidaan ottaa käyttöön useilla tavoilla. Niitä ovat esimerkiksi: järjestelmäpakettien luominen, niiden lähettäminen rakennettujen kuvien arkistoon ja niiden asentaminen palvelimille. Tuntemattomasta syystä valittiin toinen menetelmä, nimittäin: CI:n avulla käännetään sovelluksen suoritettavat tiedostot, luodaan virtuaalinen projektiympäristö, asennetaan py-moduulit vaatimus.txt-tiedostosta ja kaikki nämä artefaktit lähetetään konfiguraatioiden, komentosarjojen ja mukana tuleva sovellusympäristö palvelimille. Seuraavaksi sovellukset käynnistetään virtuaalisena käyttäjänä ilman järjestelmänvalvojan oikeuksia.

CI/CD-järjestelmäksi valittiin Gitlab-CI. Tuloksena saatu putki näytti suunnilleen tältä:

Ota sovelluksia käyttöön Docker Swarmin avulla
Rakenteellisesti gitlab-ci.yml näytti tältä

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

On syytä huomata, että kokoonpano ja testaus suoritetaan omalla kuvallaan, jossa kaikki tarvittavat järjestelmäpaketit on jo asennettu ja muut asetukset tehty.

Vaikka jokainen näistä käsikirjoituksista työpaikoilla on omalla tavallaan mielenkiintoinen, mutta en tietenkään puhu niistä. Jokaisen kuvaus vie paljon aikaa, eikä tämä ole artikkelin tarkoitus. Kiinnitän huomionne vain siihen tosiasiaan, että käyttöönottovaihe koostuu sarjasta kutsuvia komentosarjoja:

  1. createconfig.py - luo settings.ini-tiedoston komponenttiasetuksineen eri ympäristöissä myöhempää käyttöönottoa varten (esituotanto, tuotanto, testaus jne.)
  2. install_venv.sh - luo virtuaalisen ympäristön py-komponenteille tietyssä hakemistossa ja kopioi sen etäpalvelimille
  3. ready_init.d.py — valmistelee komponentin aloitus-stop-komentosarjat mallipohjan perusteella
  4. deploy.py - hajottaa ja käynnistää uudet komponentit uudelleen

Aika kului. Lavastusvaihe korvattiin esituotannolla ja tuotannolla. Lisätty tuki tuotteelle yhdelle jakelulle (CentOS). Lisätty 5 tehokkaampaa fyysistä palvelinta ja tusina virtuaalista palvelinta. Ja kehittäjien ja testaajien oli yhä vaikeampaa testata tehtäviä ympäristössä, joka oli enemmän tai vähemmän lähellä työtilaa. Tällä hetkellä kävi selväksi, että oli mahdotonta tehdä ilman häntä ...

Osa II

Ota sovelluksia käyttöön Docker Swarmin avulla

Joten klusterimme on näyttävä järjestelmä, jossa on parikymmentä erillistä komponenttia, joita Dockerfiles ei kuvaile. Voit määrittää sen käyttöön otettaviksi vain tietyssä ympäristössä yleensä. Tehtävämme on ottaa klusteri käyttöön vaiheistusympäristössä testatakseen sitä ennen julkaisua edeltävää testausta.

Teoriassa voi olla useita klustereita käynnissä samanaikaisesti: niin monta kuin on tehtäviä valmiissa tilassa tai lähellä valmistumista. Käytössämme olevien palvelimien kapasiteetit mahdollistavat useiden klustereiden ajamisen kullakin palvelimella. Jokainen vaiheklusteri on eristettävä (porteissa, hakemistoissa jne. ei saa olla risteyksiä).

Arvokkain voimavaramme on aikamme, eikä meillä ollut sitä paljoakaan.

Nopeampaa alkua varten valitsimme Docker Swarmin sen yksinkertaisuuden ja arkkitehtuurin joustavuuden vuoksi. Ensimmäinen asia, jonka teimme, oli luoda hallinta ja useita solmuja etäpalvelimille:

$ 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

Luo seuraavaksi verkko:


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

Seuraavaksi liitimme Gitlab-CI- ja Swarm-solmut solmujen etäohjauksen kannalta CI:stä: varmenteiden asentaminen, salaisten muuttujien asettaminen ja Docker-palvelun määrittäminen ohjauspalvelimelle. Tämä artikkeli säästi meiltä paljon aikaa.

Seuraavaksi lisäsimme pinon luonti- ja hävitystyöt .gitlab-ci .yml -tiedostoon.

Muutama työ on lisätty tiedostoon .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

Yllä olevasta koodinpätkästä näet, että kaksi painiketta (deploy_staging, stop_staging) on ​​lisätty putkiin, jotka edellyttävät manuaalisia toimia.

Ota sovelluksia käyttöön Docker Swarmin avulla
Pinon nimi vastaa haaran nimeä ja tämän yksilöllisyyden pitäisi olla riittävä. Pinon palvelut saavat yksilölliset IP-osoitteet ja portit, hakemistot jne. on eristetty, mutta sama pinosta pinoon (koska asetustiedosto on sama kaikille pinoille) - mitä halusimme. Otamme pinon (klusterin) käyttöön käyttämällä docker-compose.yml, joka kuvaa klusteriamme.

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

Tästä näet, että komponentit on kytketty yhteen verkkoon (nw_swarm) ja ovat toistensa käytettävissä.

Järjestelmäkomponentit (perustuvat redis, mysql) on erotettu yleisestä mukautettujen komponenttien joukosta (suunnitelmissa ja mukautetut jaetaan palveluiksi). Klusterimme käyttöönottovaihe näyttää siltä, ​​että siirtäisimme CMD:n yhteen suureen konfiguroituun imagoomme, ja yleensä se ei käytännössä eroa osassa I kuvatusta käyttöönotosta. Korostan eroja:

  • git klooni... - hanki käyttöönottoon tarvittavat tiedostot (createconfig.py, install_venv.sh jne.)
  • curl... && pura vetoketju... - lataa ja pura koontiartefakteja (käännetyt apuohjelmat)

On vain yksi vielä kuvaamaton ongelma: komponentit, joilla on verkkokäyttöliittymä, eivät ole käytettävissä kehittäjien selaimista. Ratkaisemme tämän ongelman käyttämällä käänteistä välityspalvelinta, näin:

Lisäämme .gitlab-ci.yml-tiedostoon klusteripinon käyttöönoton jälkeen rivin, jolla balansoija otetaan käyttöön (joka sitoutuessaan päivittää vain kokoonpanonsa (luo uusia nginx-määritystiedostoja mallin mukaan: /etc/nginx/conf. d/${CI_COMMIT_REF_NAME}.conf) – katso docker-compose-nginx.yml-koodi)

    - 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

Päivitä kehitystietokoneissa /etc/hosts; määrätä url nginxille:

10.50.173.106 staging_BRANCH-1831_cluster.dev

Joten erillisten vaiheistusklustereiden käyttöönotto on otettu käyttöön, ja kehittäjät voivat nyt käyttää niitä missä tahansa määrässä, joka riittää tehtäviensä tarkistamiseen.

Tulevaisuuden suunnitelmat:

  • Erottele komponenttimme palveluiksi
  • On jokaiselle Docker-tiedostolle
  • Tunnista automaattisesti vähemmän ladatut solmut pinossa
  • Määritä solmut nimimallin mukaan (sen sijaan, että käytät id:tä, kuten artikkelissa)
  • Lisää tarkistus, että pino on tuhoutunut
  • ...

Erityiset kiitokset Artikkeli.

Lähde: will.com

Lisää kommentti