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:

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:
- createconfig.py â loob settings.ini faili, mis sisaldab komponentide seadeid erinevates keskkondades edasiseks deploiimiseks (Eelkvaliteet, Tootmine, Testimine, âŠ)
- install_venv.sh â loob virtuaalse keskkonna py-komponentide jaoks kindlas kaustas ja kopeerib selle kaugserveritesse
- prepare_init.d.py â valmistab ette komponentide kĂ€ivitus- ja peatamis skripte mallide pĂ”hjal
- 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

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

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 .
Allikas: habr.com
