Nasazujte aplikace pomocí Docker Swarm

Online systém doporučení videoobsahu, na kterém pracujeme, je uzavřený komerční vývoj a je technicky vícesložkovým seskupením proprietárních a open source komponent. Účelem napsání tohoto článku je popsat implementaci systému clusteringu docker swarm pro pracovní místo, aniž by došlo k narušení zavedeného pracovního postupu našich procesů v omezeném čase. Vyprávění, které vám bude předloženo, je rozděleno do dvou částí. První část popisuje CI/CD před použitím docker swarm a druhá popisuje proces jeho implementace. Kdo nemá zájem číst první díl, může klidně přejít k druhému.

Část I

Zpět ve vzdáleném, vzdáleném roce bylo nutné nastavit proces CI / CD co nejrychleji. Jednou z podmínek bylo nepoužívat Docker pro nasazení vyvinuté komponenty z několika důvodů:

  • pro spolehlivější a stabilnější provoz komponent ve výrobě (tedy fakticky požadavek nepoužívat virtualizaci)
  • přední vývojáři nechtěli pracovat s Dockerem (divné, ale bylo to tak)
  • podle ideových úvah vedení VaV

Infrastruktura, zásobník a přibližné počáteční požadavky na MVP byly prezentovány následovně:

  • 4 servery Intel® X5650 s Debianem (jeden výkonnější počítač je plně vyvinut)
  • Vývoj vlastních vlastních komponent probíhá v C++, Python3
  • Hlavní používané nástroje třetích stran: Kafka, Clickhouse, Airflow, Redis, Grafana, Postgresql, Mysql, …
  • Potrubí pro vytváření a testování komponent samostatně pro ladění a vydání

Jednou z prvních otázek, kterou je třeba vyřešit v počáteční fázi, je, jak budou vlastní komponenty nasazeny v jakémkoli prostředí (CI / CD).

Rozhodli jsme se instalovat komponenty třetích stran systémově a systémově je aktualizovat. Vlastní aplikace vyvinuté v C++ nebo Pythonu lze nasadit několika způsoby. Mezi ně patří například: vytváření systémových balíčků, jejich odesílání do úložiště vytvořených obrazů a jejich následná instalace na servery. Z neznámého důvodu byla zvolena jiná metoda, a to: pomocí CI se zkompilují spustitelné soubory aplikace, vytvoří se prostředí virtuálního projektu, nainstalují se py moduly z requirements.txt a všechny tyto artefakty se pošlou spolu s konfiguracemi, skripty a doprovodné aplikační prostředí k serverům. Dále jsou aplikace spouštěny jako virtuální uživatel bez administrátorských práv.

Jako CI/CD systém byl zvolen Gitlab-CI. Výsledné potrubí vypadalo asi takto:

Nasazujte aplikace pomocí Docker Swarm
Strukturálně vypadal gitlab-ci.yml takto

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

Za zmínku stojí, že sestavení a testování se provádí na vlastním obrazu, kde jsou již nainstalovány všechny potřebné systémové balíčky a provedena další nastavení.

Každý z těchto skriptů v jobech je sice svým způsobem zajímavý, ale o nich samozřejmě nebudu mluvit. Popis každého z nich zabere hodně času a to není účelem tohoto článku. Upozorňuji pouze na skutečnost, že fáze nasazení se skládá ze sekvence volajících skriptů:

  1. createconfig.py - vytvoří soubor settings.ini s nastavením komponent v různých prostředích pro následné nasazení (Preproduction, Production, Testing, ...)
  2. install_venv.sh - vytvoří virtuální prostředí pro py komponenty v určitém adresáři a zkopíruje je na vzdálené servery
  3. připravit_init.d.py — připraví start-stop skripty pro komponentu na základě šablony
  4. deploy.py - rozkládá a restartuje nové komponenty

Čas vypršel. Etapu inscenace nahradila předprodukce a produkce. Přidána podpora pro produkt na další distribuci (CentOS). Přidáno 5 výkonnějších fyzických serverů a tucet virtuálních. A pro vývojáře a testery bylo stále obtížnější otestovat své úkoly v prostředí více či méně blízkém pracovnímu stavu. V té době se ukázalo, že bez něj není možné udělat ...

Část II

Nasazujte aplikace pomocí Docker Swarm

Náš cluster je tedy velkolepý systém několika desítek samostatných komponent, které nejsou popsány v Dockerfiles. Můžete jej nakonfigurovat pouze pro nasazení do konkrétního prostředí obecně. Naším úkolem je nasadit cluster do pracovního prostředí, abychom jej otestovali před testováním před vydáním.

Teoreticky může být několik clusterů spuštěných současně: tolik, kolik je úloh ve stavu dokončeno nebo blízko dokončení. Kapacity serverů, které máme k dispozici, nám umožňují provozovat na každém serveru několik clusterů. Každý pracovní cluster musí být izolovaný (nesmí docházet k průsečíkům v portech, adresářích atd.).

Naším nejcennějším zdrojem je náš čas a toho jsme neměli mnoho.

Pro rychlejší start jsme zvolili Docker Swarm kvůli jeho jednoduchosti a flexibilitě architektury. První věc, kterou jsme udělali, bylo vytvoření správce a několika uzlů na vzdálených serverech:

$ 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

Dále vytvořte síť:


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

Dále jsme propojili uzly Gitlab-CI a Swarm z hlediska vzdáleného ovládání uzlů z CI: instalace certifikátů, nastavení tajných proměnných a nastavení služby Docker na řídicím serveru. Toto článek ušetřili nám spoustu času.

Dále jsme do .gitlab-ci .yml přidali úlohy vytváření a destrukce zásobníku.

Do .gitlab-ci .yml bylo přidáno několik dalších úloh

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

Z výše uvedeného fragmentu kódu můžete vidět, že do Pipelines byla přidána dvě tlačítka (deploy_staging, stop_staging), která vyžadují ruční zásah.

Nasazujte aplikace pomocí Docker Swarm
Název zásobníku se shoduje s názvem větve a tato jedinečnost by měla být dostatečná. Služby v zásobníku dostávají jedinečné adresy IP a porty, adresáře atd. bude izolovaný, ale stejný od zásobníku k zásobníku (protože konfigurační soubor je stejný pro všechny zásobníky) - co jsme chtěli. Zásobník (cluster) nasadíme pomocí docker-compose.yml, která popisuje náš cluster.

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

Zde vidíte, že komponenty jsou propojeny jednou sítí (nw_swarm) a jsou si navzájem dostupné.

Systémové komponenty (založené na redis, mysql) jsou odděleny od obecného fondu uživatelských komponent (v plánech a custom jsou rozděleny jako služby). Fáze nasazení našeho clusteru vypadá jako předání CMD do našeho jednoho velkého nakonfigurovaného obrazu a obecně se prakticky neliší od nasazení popsaného v části I. Zdůrazním rozdíly:

  • git klon... - získat soubory potřebné k nasazení (createconfig.py, install_venv.sh atd.)
  • zkroutit... && rozepnout... - stáhnout a rozbalit artefakty sestavení (kompilované nástroje)

Existuje pouze jeden dosud nepopsaný problém: komponenty, které mají webové rozhraní, nejsou přístupné z prohlížečů vývojářů. Tento problém řešíme pomocí reverzního proxy, tedy:

V .gitlab-ci.yml po nasazení zásobníku clusteru přidáme řádek nasazení balanceru (který při potvrzení pouze aktualizuje svou konfiguraci (vytvoří nové konfigurační soubory nginx podle šablony: /etc/nginx/conf. d/${CI_COMMIT_REF_NAME}.conf) – viz kód 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

Na vývojových počítačích aktualizujte /etc/hosts; předepsat url pro nginx:

10.50.173.106 staging_BRANCH-1831_cluster.dev

Bylo tedy implementováno nasazení izolovaných stagingových clusterů a vývojáři je nyní mohou spouštět v libovolném počtu dostatečném pro kontrolu jejich úkolů.

Plány do budoucna:

  • Oddělte naše komponenty jako služby
  • Mít pro každý Dockerfile
  • Automaticky detekuje méně zatížené uzly v zásobníku
  • Určete uzly podle vzoru názvu (spíše než pomocí id jako v článku)
  • Přidejte kontrolu, že je zásobník zničen
  • ...

Zvláštní poděkování za Článek.

Zdroj: www.habr.com

Přidat komentář