Rakenduste juurutamine Docker Swarmiga

Meie töötatav online soovituslik videosisustussĂŒsteem on suletud kommertstoode, mis tehniliselt esindab mitmekomponendilist klastri struktuuri, koosnedes nii meie enda kui ka avatud lĂ€htekoodiga komponentidest. KĂ€esoleva artikli eesmĂ€rk on kirjeldada docker swarm klastri sĂŒsteemi rakendamist staging-keskkonnas, rikkumata meie protsesside kehtestatud töövoogu piiratud aja tingimustes. Esitatud narratiiv on jagatud kaheks osaks. Esimene osa kirjeldab CI/CD-d enne docker swarm kasutuselevĂ”ttu ning teine — selle rakendamise protsessi. Need, kes ei soovi lugeda esimest osa, vĂ”ivad julgelt liikuda teise juurde.

Osa I

Kauges kauges minevikus oli vajalik vĂ”imalikult kiiresti seadistada CI/CD protsess. Üheks tingimuseks oli Dockerit mitte kasutada komponentide juurutamiseks mitmel pĂ”hjusel:

  • komponentide usaldusvÀÀrse ja stabiilse töö tagamiseks tootmises (ehk siis, sisuliselt nĂ”ue mitte kasutada virtualiseerimist)
  • peamised arendajad ei soovinud Dockeriga töötada (imelik, aga nii see oli)
  • R&D juhtkonna ideoloogilistel kaalutlustel

MVP infrastruktuuri, tehnoloogiate ja umbkaudsete algsetest nÔuetest andmed olid jÀrgmised:

  • 4 serverit IntelÂź X5650 Debianiga (ĂŒks vĂ”imsam masin ainult arenduseks)
  • Oma kohandatud komponentide arendus toimub C++ ja Python3 keeles
  • Peamised kolmandate osapoolte tööriistad: Kafka, Clickhouse, Airflow, Redis, Grafana, Postgresql, Mysql, 

  • Komponentide ehitamise ja testimise pipingud eraldi debug ja release jaoks

Üks esimesi kĂŒsimusi, mida algfaasis lahendada tuleb, on, kuidas juurutatakse kohandatud komponente mingis keskkonnas (CI/CD).

Kolmandate osapoolte komponente otsustati hallata sĂŒsteemselt ja neid ka sĂŒsteemselt uuendada. Kohandatud rakendusi, mis on arendatud C++ vĂ”i Pythonis, saab aga kasutada mitmel viisil. NĂ€iteks: sĂŒsteemipakettide loomine, nende saatmine kogutud piltide hoidlasse ja hilisem installimine serveritesse. Teataval mÀÀral tundmatu pĂ”hjusel valiti aga teine meetod, nimelt: CI abil kompileeritakse rakenduste kĂ€ivitatavad failid, luuakse projekti virtuaalne keskkond, installitakse py-moodulid requirements.txt failist ning kĂ”ik need artefaktid saadetakse koos konfigureerimisfailide, skriptide ja rakenduste lisakeskkonnaga serveritesse. Edasi kĂ€ivitatakse rakendused virtuaalse kasutajana, kellel pole administraatori Ă”igusi.

CI/CD sĂŒsteemina valiti Gitlab-CI. Valminud pipeline nĂ€gi vĂ€lja umbes nii:

Rakenduste juurutamine Docker Swarmiga
Struktuurselt nÀgi gitlab-ci.yml vÀlja jÀrgmiselt

---
variables:
  # minimaalne CPU versioon serverites, kus kluster vÀlja arendatakse
  CMAKE_CPUTYPE: "westmere"

  DEBIAN: "MYREGISTRY:5000/debian:latest"

before_script:
  - eval $(ssh-agent -s)
  - ssh-add  ~/.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

Oluline on mĂ€rkida, et koostamine ja testimine toimub omaenda pildil, kus on juba installitud kĂ”ik vajalikud sĂŒsteemipakettid ja tehtud muud seadistused.

Kuigi iga skript job-ides on huvitav omamoodi, ei hakka ma neist rÀÀkima, kuna nende kohta kirjeldamine vÔtaks mÀrkimisvÀÀrselt aega ja see ei ole artikli eesmÀrk. Toodan tÀhelepanu sellele, et deployment'i etapp koosneb skriptide jÀrjestikustest kutsetest:

  1. createconfig.py — loob settings.ini faili, mis sisaldab komponentide seadeid erinevates keskkondades edasiseks deploiimiseks (Eelkvaliteet, Tootmine, Testimine, 
)
  2. install_venv.sh — loob virtuaalse keskkonna py-komponentide jaoks kindlas kaustas ja kopeerib selle kaugserveritesse
  3. prepare_init.d.py — valmistab ette komponentide kĂ€ivitus- ja peatamis skripte mallide pĂ”hjal
  4. deploy.py — paigutab ja taaskĂ€ivitab uusi komponente

Aeg möödus. Staging' etapp asendati eelkvaliteediga ja tootmisega. Toote tugi lisandus veel ĂŒhes distributsioonis (CentOS). Lisandusid veel 5 vĂ”imsat fĂŒĂŒsilist serverit ja kĂŒmme virtuaalset. Arendajatel ja testijatel muutus jĂ€rjest keerulisem oma ĂŒlesandeid katsetada keskkonnas, mis oleks veidi rohkem tööolekule lĂ€hedane. Sel ajal sai selgeks, et sellest ei saa ilma jÀÀda...

Osa II

Rakenduste juurutamine Docker Swarmiga

Nii et meie klaster on pĂ€ris eksootiline sĂŒsteem, mis koosneb paarikĂŒmnest eraldi komponendist, mis ei ole kirjeldatud Dockerfile'ide kaudu. Selle konfigureerimine kindlasse keskkonda deploiimiseks on vĂ”imalik ainult ĂŒldiselt. Meie ĂŒlesanne on deploida klaster staging-keskkonda selle katsetamiseks enne eelravimiste testimist.

Teoreetiliselt vĂ”ib korraga olla mitu töötavat klastrit: nii palju kui on ĂŒlesandeid lĂ”petamisprotsessis vĂ”i sellele lĂ€hedal. Meie kĂ€sutuses olev serverite vĂ”imsus vĂ”imaldab kĂ€ivitada mitu klastrit igas serveris. Iga staging-klaster peab olema isoleeritud (portide, kaustade jne ĂŒlekatte vĂ€ltimiseks).

KÔige vÀÀrtuslikum ressurs on meie aeg, ja seda oli meil vÀhe.

Kiirema kÀivituse jaoks valisime Docker Swarmi selle lihtsuse ja arhitektuuri paindlikkuse tÔttu. Esimene asi, mida tegime, oli luua kaugserverites haldur ja mitu nodi:

$ docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
kilqc94pi2upzvabttikrfr5d     nop-test-1     Valmis               Aktivne                                  19.03.2
jilwe56pl2zvabupryuosdj78     nop-test-2     Valmis               Aktivne                                  19.03.2
j5a4yz1kr2xke6b1ohoqlnbq5 *   nop-test-3     Valmis               Aktivne              Juht              19.03.2

SeejÀrel loodi vÔrk:


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

SeejÀrel sidusime Gitlab-CI ja Swarmi sÔlmed CI kaugjuhtimise osas: sertifikaatide seadistamine, saladusmuutujate seadistamine, samuti Docker teenuse seadistamine haldusteenuses. See artikkel sÀÀstis meelt lÀhedane aega.

SeejĂ€rel lisasime .gitlab-ci .yml-infose stĂ€ki loomise ja hĂ€vitamise tĂ¶Ă¶ĂŒlesandeid.

.gitlab-ci .yml lisandus veel mĂ”ned tĂ¶Ă¶ĂŒlesanded

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

Ülaltoodud koodilĂ”igust on nĂ€ha, et Pipelines'i on lisatud kaks nuppu (deploy_staging, stop_staging), mis nĂ”uavad kĂ€sitsi sekkumist.

Rakenduste juurutamine Docker Swarmiga
StĂ€ki nimi vastab haru nimele ja see ainulaadsus peaks olema piisav. Teenused stĂ€kis saavad unikaalsed ip-aadressid ja sadamad, kataloogid jne on isolatsioonis, kuid igas stĂ€kis ĂŒhesugused (kuna konfiguratsioonifail on kĂ”ikide stĂ€kide jaoks ĂŒhesugune) — seda, mida me soovisime. StĂ€kki (kluster) kĂ€ivitame docker-compose.yml, kus on kirjeldatud meie kloster.

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

Siit on nĂ€ha, et komponendid on ĂŒhendatud ĂŒhe vĂ”rguga (nw_swarm) ja saavad ĂŒksteisele ligi.

SĂŒsteemikomponendid (baseeruvad redis'il, mysql'il) on eraldatud kohandatud komponentide ĂŒldisest basseinist (plaanides on ka kohandatud eraldada teenustena). Meie klastri juurutamise etapp nĂ€eb vĂ€lja nagu CMD edastamine meie ĂŒhte suuresse konfigureeritud image'i ning ei erine ĂŒldiselt juurutamisest, mis on kirjeldatud I osas. Toodud ajakohasused:

  • git clone 
 — saame failid, mis on vajalikud juurutamiseks (createconfig.py, install_venv.sh jne.)
  • curl
 && unzip 
 — laadime alla ja dekomprimeerime kogumise artefaktid (kompileeritud utiliidid)

Alles, mis on veel lahtine probleem: komponentide veebiliidesed ei ole arendajate brauseritest ligipÀÀsetavad. Me lahendame selle probleemi reverse proxy abil jÀrgmisel viisil:

Failis .gitlab-ci.yml, pĂ€rast klastrite kasitluse depoolimist, lisame tasakaalustaja depoolimise rea (mis commitide ajal vĂ€rskendab ainult oma konfiguratsiooni (loon uusi nginx konfiguratsioonifaile mallist: /etc/nginx/conf.d/${CI_COMMIT_REF_NAME}.conf) — vt koodi 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

Arendajate arvutites uuendame /etc/hosts; kirjutame url nginx'i juurde:

10.50.173.106 staging_BRANCH-1831_cluster.dev

Nii, isoleeritud staging-klastrite depoolimine on ellu viidud ning arendajad saavad nĂŒĂŒd neid kĂ€ivitada piisavas koguses oma ĂŒlesannete kontrollimiseks.

Edasised plaanid:

  • Meie komponentide jagamine teenusteks
  • Iga Dockerfile'i loomine
  • Automaatne vĂ€hem koormatud sĂ”lmedes tuvastamine klastris
  • Noodide mÀÀramine nime mallide jĂ€rgi (mitte kasutada id-d nagu artiklis)
  • Kontrollida, et klaster on hĂ€vitatud
  • 


Eriline tÀnu artiklit.

Allikas: habr.com

Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster