Biz ustida ishlayotgan onlayn video kontentni tavsiya qilish tizimi yopiq tijorat ishlanmasi boʻlib, texnik jihatdan xususiy va ochiq manba komponentlarining koʻp komponentli klasteridir. Ushbu maqolani yozishdan maqsad cheklangan vaqt sharoitida jarayonlarimizning belgilangan ish oqimini buzmasdan, bosqichma-bosqich platforma uchun docker to'dasi klasterlash tizimini amalga oshirishni tasvirlashdir. Sizning e'tiboringizga taqdim etilgan hikoya ikki qismga bo'lingan. Birinchi qismda docker to'dasidan foydalanishdan oldin CI/CD tasvirlangan, ikkinchi qismda uni amalga oshirish jarayoni tasvirlangan. Birinchi qismni o'qishga qiziqmaganlar ikkinchi qismga ishonch bilan o'tishlari mumkin.
I qism
Bir vaqtlar CI/CD jarayonini imkon qadar tezroq o'rnatish zarurati bor edi. Shartlardan biri Docker-dan foydalanmaslik edi joylashtirish uchun Komponentlar bir necha sabablarga ko'ra ishlab chiqilmoqda:
- Ishlab chiqarishda komponentlarning yanada ishonchli va barqaror ishlashi uchun (ya'ni, virtualizatsiyadan foydalanmaslik talabi)
- Etakchi ishlab chiquvchilar Docker bilan ishlashni xohlamadilar (g'alati, lekin shunday edi)
- Ar-ge boshqaruvining mafkuraviy sabablari uchun
MVP uchun infratuzilma, stack va taxminiy dastlabki talablar quyidagicha edi:
- Debian bilan 4 ta Intel® X5650 serverlari (ishlab chiqish uchun yana bitta kuchli mashina)
- O'zingizning shaxsiy komponentlaringizni ishlab chiqish C++, Python3 da amalga oshiriladi
- Ishlatilgan asosiy uchinchi tomon vositalari: Kafka, Clickhouse, Airflow, Redis, Grafana, Postgresql, Mysql,…
- Nosozliklarni tuzatish va chiqarish uchun komponentlarni alohida qurish va sinovdan o'tkazish uchun quvurlar
Dastlabki bosqichda hal qilinishi kerak bo'lgan birinchi savollardan biri - har qanday muhitda (CI/CD) maxsus komponentlar qanday joylashtirilishi.
Biz uchinchi tomon komponentlarini tizimli ravishda o'rnatishga va ularni tizimli ravishda yangilashga qaror qildik. C++ yoki Python-da ishlab chiqilgan maxsus ilovalar bir necha usulda joylashtirilishi mumkin. Ular orasida, masalan: tizim paketlarini yaratish, ularni to'plangan tasvirlar omboriga yuborish va ularni keyinchalik serverlarga o'rnatish. Noma'lum sababga ko'ra, boshqa usul tanlandi, ya'ni: CI yordamida dasturning bajariladigan fayllari kompilyatsiya qilinadi, virtual loyiha muhiti yaratiladi, talablar.txt dan py modullari o'rnatiladi va bu barcha artefaktlar konfiguratsiyalar, skriptlar va fayllar bilan birga yuboriladi. serverlarga ilova muhiti. Keyinchalik, ilovalar administrator huquqlariga ega bo'lmagan virtual foydalanuvchidan ishga tushiriladi.
Gitlab-CI CI/CD tizimi sifatida tanlangan. Olingan quvur liniyasi quyidagicha ko'rinishga ega edi:
Strukturaviy ravishda gitlab-ci.yml quyidagicha ko'rinadi:
---
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
Ta'kidlash joizki, yig'ish va sinovdan o'tkazish o'z imidjida amalga oshiriladi, bu erda barcha kerakli tizim paketlari allaqachon o'rnatilgan va boshqa sozlamalar amalga oshiriladi.
Ishdagi ushbu skriptlarning har biri o'ziga xos tarzda qiziqarli bo'lsa-da, men ular haqida gapirmayman, ularning har birini tavsiflash ko'p vaqt talab etadi va bu maqolaning maqsadi emas. Sizning e'tiboringizni tarqatish bosqichi chaqiruv skriptlari ketma-ketligidan iboratligiga qarataman:
- createconfig.py — keyingi joylashtirish uchun turli muhitdagi komponentlar sozlamalari bilan settings.ini faylini yaratadi (Preproduction, Production, Testing, ...)
- install_venv.sh — maʼlum bir katalogdagi py komponentlari uchun virtual muhit yaratadi va uni masofaviy serverlarga koʻchiradi
- Preparat_init.d.py — shablon asosida start-stop komponentlari uchun skriptlarni tayyorlaydi
- deploy.py — yangi komponentlarni joylashtiradi va qayta ishga tushiradi
Vaqt o'tdi. Sahna bosqichi oldingi ishlab chiqarish va ishlab chiqarish bilan almashtirildi. Mahsulotni qo'llab-quvvatlash yana bir tarqatishda (CentOS) qo'shildi. Yana 5 ta kuchli jismoniy server va oʻnlab virtual serverlar qoʻshildi. Va ishlab chiquvchilar va testerlar uchun o'z vazifalarini ish holatiga ko'proq yoki kamroq yaqin muhitda sinab ko'rish tobora qiyinlashdi. Bu vaqtda usiz qilish mumkin emasligi ma'lum bo'ldi ...
II qism
Shunday qilib, bizning klasterimiz Dockerfiles tomonidan tasvirlanmagan o'nlab individual komponentlarning ajoyib tizimidir. Siz uni faqat umumiy holda ma'lum bir muhitga joylashtirish uchun sozlashingiz mumkin. Bizning vazifamiz klasterni relizdan oldingi sinovdan oldin sinab ko'rish uchun staging muhitiga joylashtirishdir.
Nazariy jihatdan, bir vaqtning o'zida bir nechta klasterlar bo'lishi mumkin: bajarilgan holatda yoki yakunlanishiga yaqin bo'lgan vazifalar qancha bo'lsa. Bizning ixtiyorimizdagi serverlarning kuchi har bir serverda bir nechta klasterlarni ishga tushirish imkonini beradi. Har bir bosqichli klaster izolyatsiyalangan bo'lishi kerak (portlar, kataloglar va hokazolarda bir-biriga o'xshash bo'lmasligi kerak).
Bizning eng qimmatli manbamiz - bu vaqt va bizda unchalik ko'p bo'lmagan.
Tezroq boshlash uchun biz soddaligi va moslashuvchan arxitekturasi tufayli Docker Swarm-ni tanladik. Biz qilgan birinchi narsa menejer va masofaviy serverlarda bir nechta tugunlarni yaratish edi:
$ 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
Keyin biz tarmoq yaratdik:
$ docker network create --driver overlay --subnet 10.10.10.0/24 nw_swarm
Keyinchalik, biz Gitlab-CI va Swarm tugunlarini CI-dan tugunlarni masofadan boshqarish nuqtai nazaridan bog'ladik: sertifikatlarni o'rnatish, maxfiy o'zgaruvchilarni o'rnatish, shuningdek boshqaruv serverida Docker xizmatini sozlash. Bunisi
Keyinchalik, .gitlab-ci .yml da stekni yaratish va yo'q qilish uchun ishlarni qo'shdik.
.gitlab-ci .yml ga yana bir nechta ish o'rinlari qo'shildi
## 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
Yuqoridagi kod bo'lagidan ko'rinib turibdiki, qo'lda harakat talab qiladigan Pipelines (deploy_staging, stop_staging) ga ikkita tugma qo'shilgan.
Stack nomi filial nomiga mos keladi va bu o'ziga xoslik etarli bo'lishi kerak. Stackdagi xizmatlar noyob IP-manzillar va portlar, kataloglar va boshqalarni oladi. izolyatsiya qilinadi, lekin stekdan stekga bir xil (chunki konfiguratsiya fayli barcha steklar uchun bir xil) - biz shuni xohladik. Biz yordamida stekni (klaster) joylashtiramiz docker-compose.yml, bu bizning klasterimizni tavsiflaydi.
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
Bu yerda siz komponentlar bir tarmoq (nw_swarm) orqali ulanganligini va bir-biriga kirish mumkinligini ko'rishingiz mumkin.
Tizim komponentlari (redis, mysql asosida) maxsus komponentlarning umumiy pulidan ajratiladi (rejalarda moslashtirilgan komponentlar ham xizmatlar sifatida ajratiladi). Klasterimizni joylashtirish bosqichi CMD-ni bitta katta konfiguratsiya qilingan rasmga o'tkazishga o'xshaydi va umuman olganda, I qismda tasvirlangan joylashtirishdan deyarli farq qilmaydi. Men farqlarni ta'kidlayman:
- git klon ... - biz joylashtirishni amalga oshirish uchun kerakli fayllarni olamiz (createconfig.py, install_venv.sh va boshqalar).
- jingalaklash... && arxivni ochish... — qurilish artefaktlarini yuklab oling va oching (kompilyatsiya qilingan yordam dasturlari)
Hali ta'riflanmagan bitta muammo bor: veb-interfeysga ega bo'lgan komponentlarga ishlab chiquvchilar brauzeridan kirish imkoni yo'q. Biz bu muammoni teskari proksi-server yordamida hal qilamiz, shunday qilib:
.gitlab-ci.yml da, klaster stekini joylashtirgandan so'ng, balanslashtiruvchini joylashtirish uchun qatorni qo'shing (bu bajarilganda faqat uning konfiguratsiyasini yangilaydi (shablonga muvofiq yangi nginx konfiguratsiya fayllarini yaratadi: /etc/nginx/conf.d). /${CI_COMMIT_REF_NAME}.conf) - docker-compose-nginx.yml kodiga qarang)
- 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
Ishlab chiquvchi kompyuterlarda /etc/hosts; urlni nginx ga o'rnating:
10.50.173.106 staging_BRANCH-1831_cluster.dev
Shunday qilib, izolyatsiyalangan bosqichli klasterlarni joylashtirish amalga oshirildi va endi ishlab chiquvchilar ularni o'z vazifalarini sinab ko'rish uchun etarli bo'lgan miqdorda ishga tushirishlari mumkin.
Kelgusi rejalar:
- Komponentlarimizni xizmatlar sifatida ajrating
- Har biri uchun Dockerfile yarating
- Stackdagi kamroq yuklangan tugunlarni avtomatik aniqlash
- Nod shablonidan foydalanib tugunlarni belgilang (maqoladagi kabi identifikatordan foydalanish o'rniga)
- Stack yo'q qilinganligini tasdiqlovchi belgi qo'shing
- ...
uchun alohida rahmat
Manba: www.habr.com