Alkalmazások telepítése a Docker Swarm segítségével

Az online videótartalom-ajánló rendszer, amelyen dolgozunk, egy zárt kereskedelmi fejlesztés, és technikailag védett és nyílt forráskódú komponensek többkomponensű klasztere. A cikk megírásának célja, hogy leírja a docker swarm klaszterrendszer megvalósítását egy állomáshelyen anélkül, hogy korlátozott időn belül megzavarná a folyamataink kialakult munkafolyamatát. A figyelmedbe bocsátott narratíva két részre oszlik. Az első rész a CI / CD-t írja le a docker swarm használata előtt, a második pedig a megvalósítás folyamatát. Akit nem érdekel az első rész, az nyugodtan áttérhet a másodikra.

I. rész

A távoli, távoli évben szükség volt a CI / CD folyamat mielőbbi beállítására. Az egyik feltétel az volt, hogy ne használjuk a Dockert bevetésre több okból kifejlesztett komponenseket:

  • az összetevők megbízhatóbb és stabilabb működése érdekében a termelésben (vagyis a virtualizáció használatának mellőzése)
  • vezető fejlesztők nem akartak a Dockerrel dolgozni (fura, de így volt)
  • a K+F menedzsment ideológiai szempontjai szerint

Az MVP infrastruktúrája, verem és hozzávetőleges kezdeti követelményei az alábbiak szerint kerültek bemutatásra:

  • 4 Intel® X5650 szerver Debian-nal (egy nagyobb teljesítményű gép teljesen kifejlesztve)
  • Saját egyedi komponensek fejlesztése C ++, Python3 nyelven történik
  • Harmadik féltől származó főbb használt eszközök: Kafka, Clickhouse, Airflow, Redis, Grafana, Postgresql, Mysql,…
  • Csővezetékek az összetevők külön-külön történő felépítéséhez és teszteléséhez hibakereséshez és kiadáshoz

A kezdeti szakaszban megválaszolandó első kérdések egyike az, hogy az egyéni összetevők hogyan lesznek telepítve bármilyen környezetben (CI / CD).

Úgy döntöttünk, hogy harmadik féltől származó összetevőket szisztematikusan telepítünk és rendszerszinten frissítjük. A C++ vagy Python nyelven fejlesztett egyéni alkalmazások többféleképpen telepíthetők. Köztük például: rendszercsomagok létrehozása, elküldése a beépített képek tárházába, majd telepítése szerverekre. Ismeretlen okból egy másik módszert választottak, nevezetesen: CI segítségével az alkalmazás futtatható fájljait lefordítják, virtuális projektkörnyezetet hoznak létre, a követelmények.txt fájlból telepítik a py modulokat, és mindezeket a melléktermékeket elküldik a konfigurációkkal, szkriptekkel és a kísérő alkalmazáskörnyezet a szerverekhez. Ezután az alkalmazások rendszergazdai jogosultságok nélküli virtuális felhasználóként indulnak el.

A Gitlab-CI-t választottuk CI/CD rendszernek. A kapott csővezeték valahogy így nézett ki:

Alkalmazások telepítése a Docker Swarm segítségével
Szerkezetileg a gitlab-ci.yml így nézett ki

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

Érdemes megjegyezni, hogy az összeszerelés és a tesztelés saját képére történik, ahol már minden szükséges rendszercsomag telepítve van, és az egyéb beállítások megtörténtek.

Bár ezek a forgatókönyvek mindegyike érdekes a maga módján, de természetesen nem beszélek róluk, mindegyik leírása sok időt vesz igénybe, és nem ez a cikk célja. Csak arra hívnám fel a figyelmet, hogy a telepítési szakasz a meghívó szkriptek sorozatából áll:

  1. createconfig.py - létrehoz egy settings.ini fájlt az összetevő-beállításokkal különböző környezetekben a későbbi telepítéshez (előkészítés, gyártás, tesztelés stb.)
  2. install_venv.sh - virtuális környezetet hoz létre a py összetevők számára egy adott könyvtárban, és átmásolja a távoli szerverekre
  3. ready_init.d.py — a sablon alapján start-stop szkripteket készít a komponenshez
  4. deploy.py - lebontja és újraindítja az új komponenseket

Eltelt idő. A színpadi szakaszt felváltotta az előgyártás és a gyártás. A termék támogatása egy újabb disztribúción (CentOS). Hozzáadott 5 erősebb fizikai szervert és egy tucat virtuális szervert. A fejlesztők és tesztelők pedig egyre nehezebbé váltak feladataikat a működő állapothoz többé-kevésbé közeli környezetben tesztelni. Ekkor világossá vált, hogy nélküle lehetetlen ...

II. Rész

Alkalmazások telepítése a Docker Swarm segítségével

Tehát a klaszterünk egy pár tucat különálló komponensből álló látványos rendszer, amelyet a Dockerfiles nem ír le. Csak általánosságban konfigurálhatja egy adott környezetben való üzembe helyezéshez. Az a feladatunk, hogy a fürtöt állomásoztatási környezetbe telepítsük, hogy teszteljük azt a kiadás előtti tesztelés előtt.

Elméletileg több fürt is futhat egyidejűleg: annyi, ahány feladat van kész állapotban vagy közel a befejezéshez. A rendelkezésünkre álló szerverek kapacitása lehetővé teszi, hogy minden szerveren több klasztert fusson. Minden állomásozó fürtnek el kell különülnie (nem lehet kereszteződés a portokban, könyvtárakban stb.).

A legértékesebb erőforrásunk az időnk, és nem sok volt belőle.

A gyorsabb kezdéshez az egyszerűsége és az architektúra rugalmassága miatt a Docker Swarm-ot választottuk. Az első dolgunk az volt, hogy létrehoztunk egy kezelőt és több csomópontot a távoli szervereken:

$ 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

Ezután hozzon létre egy hálózatot:


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

Ezután összekapcsoltuk a Gitlab-CI és a Swarm csomópontokat a csomópontok CI-ről történő távoli vezérlése szempontjából: tanúsítványok telepítése, titkos változók beállítása és a Docker szolgáltatás beállítása a vezérlőszerveren. Ezt cikk sok időt megtakarítottunk.

Ezután hozzáadtuk a veremlétrehozási és -megsemmisítési feladatokat a .gitlab-ci .yml fájlhoz.

Néhány további feladat hozzáadva a .gitlab-ci .yml fájlhoz

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

A fenti kódrészletből láthatja, hogy két gomb (deploy_staging, stop_staging) került hozzáadásra a folyamatokhoz, amelyek kézi műveletet igényelnek.

Alkalmazások telepítése a Docker Swarm segítségével
A verem neve megegyezik az ág nevével, és ennek az egyediségnek elegendőnek kell lennie. A veremben lévő szolgáltatások egyedi IP-címeket, portokat, könyvtárakat stb. izolált lesz, de veremről veremre ugyanaz (mert a konfigurációs fájl minden veremnél ugyanaz) - amit szerettünk volna. A verem (fürt) segítségével telepítjük dokkoló-compose.yml, amely a klaszterünket írja le.

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

Itt látható, hogy a komponensek egy hálózaton (nw_swarm) vannak összekötve és elérhetőek egymás számára.

A rendszerkomponensek (redis, mysql alapúak) elkülönülnek az egyéni komponensek általános készletétől (a tervekben az egyediek szolgáltatásként vannak felosztva). A klaszterünk telepítési szakasza úgy néz ki, mintha a CMD-t egyetlen nagy konfigurált képünkbe helyeznénk át, és általában véve gyakorlatilag nem különbözik az I. részben leírt telepítéstől. Kiemelném a különbségeket:

  • git klón... - szerezze be a telepítéshez szükséges fájlokat (createconfig.py, install_venv.sh stb.)
  • göndörítés... && kicipzár... - Töltse le és csomagolja ki az összeállítási műtermékeket (összeállított segédprogramok)

Egyetlen még le nem írt probléma van: a webes felülettel rendelkező komponensek nem érhetők el a fejlesztők böngészőiből. Ezt a problémát fordított proxy használatával oldjuk meg, így:

A .gitlab-ci.yml fájlban a fürtverem telepítése után hozzáadjuk a Balancer telepítésének sorát (amely véglegesítéskor csak a konfigurációját frissíti (új nginx konfigurációs fájlokat hoz létre a sablon szerint: /etc/nginx/conf. d/${CI_COMMIT_REF_NAME}.conf) – lásd a docker-compose-nginx.yml kódot)

    - 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

A fejlesztő számítógépeken frissítse az /etc/hosts fájlt; írd fel az url-t az nginx-nek:

10.50.173.106 staging_BRANCH-1831_cluster.dev

Így az elszigetelt átmeneti fürtök telepítése megtörtént, és a fejlesztők mostantól tetszőleges számban futtathatják azokat, amelyek elegendőek a feladataik ellenőrzéséhez.

Jövőbeli tervek:

  • Különítse el összetevőinket szolgáltatásként
  • Minden Docker-fájlhoz rendelkezzen
  • Automatikusan észleli a kevésbé terhelt csomópontokat a veremben
  • Adja meg a csomópontokat névmintával (a cikkben szereplő azonosító helyett)
  • Adjon hozzá egy csekket, hogy a verem megsemmisült
  • ...

Külön köszönet érte статью.

Forrás: will.com

Hozzászólás