Üzərində işlədiyimiz onlayn video məzmunu tövsiyə sistemi qapalı kommersiya inkişafıdır və texniki cəhətdən mülkiyyət və açıq mənbə komponentlərinin çoxkomponentli klasteridir. Bu məqaləni yazmaqda məqsəd məhdud vaxt ərzində proseslərimizin müəyyən edilmiş iş axını pozmadan bir quruluş saytı üçün docker swarm klaster sisteminin tətbiqini təsvir etməkdir. Diqqətinizə təqdim olunan hekayə iki hissəyə bölünür. Birinci hissə docker sürüsünü istifadə etməzdən əvvəl CI / CD-ni təsvir edir, ikincisi isə onun həyata keçirilməsi prosesini təsvir edir. Birinci hissəni oxumaqda maraqlı olmayanlar ikinci hissəyə təhlükəsiz keçə bilərlər.
I hissə
Uzaq, uzaq bir ildə CI / CD prosesini mümkün qədər tez qurmaq lazım idi. Şərtlərdən biri Docker-dən istifadə etməmək idi yerləşdirilməsi üçün bir neçə səbəbə görə hazırlanmış komponentlər:
- İstehsalda komponentlərin daha etibarlı və sabit işləməsi üçün (yəni əslində virtuallaşdırmadan istifadə etməmək tələbi)
- aparıcı tərtibatçılar Docker ilə işləmək istəmirdilər (qəribədir, amma belə idi)
- R&D rəhbərliyinin ideoloji mülahizələrinə uyğun olaraq
MVP üçün infrastruktur, yığın və təxmini ilkin tələblər aşağıdakı kimi təqdim edilmişdir:
- Debian ilə 4 Intel® X5650 serveri (daha bir güclü maşın tam işlənib hazırlanmışdır)
- Öz fərdi komponentlərinin inkişafı C ++, Python3-də həyata keçirilir
- İstifadə olunan əsas 3-cü tərəf alətləri: Kafka, Clickhouse, Airflow, Redis, Grafana, Postgresql, Mysql,…
- Sazlama və buraxılış üçün komponentlərin ayrıca qurulması və sınaqdan keçirilməsi üçün boru kəmərləri
İlkin mərhələdə həll edilməli olan ilk suallardan biri fərdi komponentlərin istənilən mühitdə (CI / CD) necə yerləşdiriləcəyidir.
Biz üçüncü tərəf komponentlərini sistemli şəkildə quraşdırmaq və onları sistemli şəkildə yeniləmək qərarına gəldik. C++ və ya Python-da hazırlanmış xüsusi proqramlar bir neçə yolla yerləşdirilə bilər. Onların arasında, məsələn: sistem paketləri yaratmaq, onları qurulmuş şəkillərin deposuna göndərmək və sonra onları serverlərə quraşdırmaq. Naməlum səbəbə görə başqa bir üsul seçildi, yəni: CI-dən istifadə edərək tətbiqin icra oluna bilən faylları tərtib edilir, virtual layihə mühiti yaradılır, tələblər.txt-dən py modulları quraşdırılır və bütün bu artefaktlar konfiqurasiyalar, skriptlər və sənədlərlə birlikdə göndərilir. serverlərə tətbiq mühitini müşayiət edən. Sonra tətbiqlər administrator hüquqları olmayan virtual istifadəçi kimi işə salınır.
CI/CD sistemi kimi Gitlab-CI seçilmişdir. Nəticədə boru kəməri belə görünürdü:
Struktur olaraq gitlab-ci.yml belə görünürdü
---
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
Qeyd etmək lazımdır ki, montaj və sınaq bütün lazımi sistem paketlərinin artıq quraşdırıldığı və digər parametrlərin edildiyi öz imicində həyata keçirilir.
İşlərdəki bu skriptlərin hər biri özünəməxsus şəkildə maraqlı olsa da, əlbəttə ki, onlar haqqında danışmayacağam.Onların hər birinin təsviri çox vaxt aparacaq və məqalənin məqsədi bu deyil. Diqqətinizi yalnız yerləşdirmə mərhələsinin çağırış skriptləri ardıcıllığından ibarət olduğuna yönəldəcəyəm:
- createconfig.py - sonrakı yerləşdirmə üçün müxtəlif mühitlərdə komponent parametrləri ilə settings.ini faylı yaradır (Qabaqcadan istehsal, İstehsal, Test, ...)
- install_venv.sh - müəyyən kataloqda py komponentləri üçün virtual mühit yaradır və onu uzaq serverlərə köçürür
- hazırlamaq_init.d.py — şablon əsasında komponent üçün start-stop skriptləri hazırlayır
- deploy.py - yeni komponentləri parçalayır və yenidən işə salır
Vaxt keçdi. Səhnə səhnəsi preproduction və istehsalla əvəz olundu. Daha bir paylamada məhsul üçün əlavə dəstək (CentOS). 5 daha güclü fiziki server və onlarla virtual server əlavə edildi. Tərtibatçılar və testçilər üçün iş vəziyyətinə az və ya çox yaxın bir mühitdə tapşırıqlarını sınamaq getdikcə çətinləşdi. Bu zaman məlum oldu ki, onsuz etmək mümkün deyil ...
II hissə
Beləliklə, klasterimiz Dockerfiles tərəfindən təsvir olunmayan bir neçə onlarla ayrı komponentdən ibarət möhtəşəm bir sistemdir. Siz onu yalnız ümumi olaraq müəyyən bir mühitə yerləşdirmə üçün konfiqurasiya edə bilərsiniz. Bizim vəzifəmiz buraxılışdan əvvəl testdən əvvəl klasteri sınamaq üçün quruluş mühitinə yerləşdirməkdir.
Nəzəri olaraq, eyni vaxtda işləyən bir neçə klaster ola bilər: tamamlanmış vəziyyətdə və ya tamamlanmağa yaxın olan vəzifələr qədər. Bizim ixtiyarımızda olan serverlərin imkanları bizə hər serverdə bir neçə klaster işlətməyə imkan verir. Hər bir quruluş klasteri təcrid olunmalıdır (portlarda, kataloqlarda və s. kəsişmə olmamalıdır).
Bizim ən dəyərli resursumuz vaxtımızdır və bizdə çox yox idi.
Daha sürətli başlanğıc üçün sadəliyi və memarlıq çevikliyinə görə Docker Swarm-ı seçdik. Etdiyimiz ilk şey uzaq serverlərdə menecer və bir neçə qovşaq yaratmaq oldu:
$ 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
Sonra, bir şəbəkə yaradın:
$ docker network create --driver overlay --subnet 10.10.10.0/24 nw_swarm
Sonra, CI-dən qovşaqların uzaqdan idarə edilməsi baxımından Gitlab-CI və Swarm qovşaqlarını birləşdirdik: sertifikatların quraşdırılması, gizli dəyişənlərin təyin edilməsi və idarəetmə serverində Docker xidmətinin qurulması. Bu bir
Sonra biz .gitlab-ci .yml-ə yığın yaratma və məhv etmə işləri əlavə etdik.
.gitlab-ci .yml-ə daha bir neçə iş əlavə edildi
## 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
Yuxarıdakı kod fraqmentindən siz iki düymənin (deploy_staging, stop_staging) Boru Kəmərlərinə əlavə edildiyini görə bilərsiniz ki, bu da əl ilə əməliyyat tələb edir.
Yığın adı filial adına uyğun gəlir və bu unikallıq kifayət olmalıdır. Yığındakı xidmətlər unikal IP ünvanları, portlar, kataloqlar və s. təcrid olunacaq, lakin yığından yığına eyni (çünki konfiqurasiya faylı bütün yığınlar üçün eynidir) - istədiyimiz şey. İstifadə edərək yığını (klaster) yerləşdiririk docker-compose.yml, bizim klasterimizi təsvir edir.
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
Burada komponentlərin bir şəbəkə (nw_swarm) ilə birləşdirildiyini və bir-biri üçün əlçatan olduğunu görə bilərsiniz.
Sistem komponentləri (redis, mysql əsasında) xüsusi komponentlərin ümumi hovuzundan ayrılır (planlarda və xüsusi olanlar xidmət kimi bölünür). Klasterimizin yerləşdirilməsi mərhələsi CMD-ni bir böyük konfiqurasiya edilmiş şəklimizə ötürməyə bənzəyir və ümumiyyətlə, I hissədə təsvir edilən yerləşdirmədən praktiki olaraq fərqlənmir. Mən fərqləri vurğulayacağam:
- git klonu... - yerləşdirmək üçün lazım olan faylları əldə edin (createconfig.py, install_venv.sh və s.)
- qıvrın... && kilidini açın... - qurma artefaktlarını yükləyin və açın (tərtib edilmiş yardım proqramları)
Yalnız bir hələ təsvir edilməmiş problem var: veb interfeysi olan komponentlər tərtibatçıların brauzerlərindən əlçatan deyil. Bu problemi əks proxy istifadə edərək həll edirik, beləliklə:
.gitlab-ci.yml-də, klaster yığınını yerləşdirdikdən sonra biz balanslaşdırıcının yerləşdirilməsi xəttini əlavə edirik (bu, yerinə yetirərkən yalnız onun konfiqurasiyasını yeniləyir (şablona uyğun olaraq yeni nginx konfiqurasiya faylları yaradır: /etc/nginx/conf.). d/${CI_COMMIT_REF_NAME}.conf) - docker-compose-nginx.yml koduna baxın)
- 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
İnkişaf kompüterlərində /etc/hosts; nginx-ə url təyin edin:
10.50.173.106 staging_BRANCH-1831_cluster.dev
Beləliklə, təcrid olunmuş mərhələ qruplarının yerləşdirilməsi həyata keçirildi və tərtibatçılar indi onları tapşırıqlarını yoxlamaq üçün kifayət qədər istənilən sayda işlədə bilərlər.
Gələcək planlar:
- Komponentlərimizi xidmətlər kimi ayırın
- Hər bir Dockerfile üçün var
- Yığında daha az yüklənmiş qovşaqları avtomatik aşkar edin
- Düyünləri ad nümunəsi ilə təyin edin (məqalədəki kimi id istifadə etmək əvəzinə)
- Yığın məhv olduğunu yoxlayın
- ...
üçün xüsusi təşəkkürlər
Mənbə: www.habr.com