Työskentelemme verkkovideosisällön suositusjärjestelmässä, joka on suljettu kaupallinen kehitystyö, ja se on teknisesti monikomponenttinen klusteri patentoituja ja avoimen lähdekoodin komponentteja. Tämän artikkelin kirjoittamisen tarkoituksena on kuvata docker-parviklusterointijärjestelmän käyttöönottoa pysähdyspaikalle häiritsemättä prosessiemme vakiintunutta työnkulkua rajoitetussa ajassa. Huomioillesi esitetty kertomus on jaettu kahteen osaan. Ensimmäisessä osassa kuvataan CI / CD ennen Docker Swarmin käyttöä ja toisessa sen toteutusprosessia. Ne, jotka eivät ole kiinnostuneita ensimmäisen osan lukemisesta, voivat siirtyä turvallisesti toiseen.
Osa I
Kaukana, kaukaisena vuonna, oli välttämätöntä määrittää CI / CD-prosessi mahdollisimman nopeasti. Yksi ehdoista oli olla käyttämättä Dockeria käyttöönottoa varten kehitetty komponentteja useista syistä:
- Tuotannon komponenttien luotettavampi ja vakaampi toiminta (eli itse asiassa vaatimus olla käyttämättä virtualisointia)
- johtavat kehittäjät eivät halunneet työskennellä Dockerin kanssa (outoa, mutta niin se oli)
- T&K-johdon ideologisten näkökohtien mukaisesti
MVP:n infrastruktuuri, pino ja likimääräiset alkuvaatimukset esitettiin seuraavasti:
- 4 Intel® X5650 -palvelinta Debianilla (yksi tehokkaampi kone on täysin kehitetty)
- Omien räätälöityjen komponenttien kehitys tapahtuu C ++:lla, Python3:lla
- Tärkeimmät käytetyt kolmannen osapuolen työkalut: Kafka, Clickhouse, Airflow, Redis, Grafana, Postgresql, Mysql,…
- Putket komponenttien rakentamiseen ja testaamiseen erikseen virheenkorjausta ja julkaisua varten
Yksi ensimmäisistä kysymyksistä, joita on käsiteltävä alkuvaiheessa, on se, kuinka mukautettuja komponentteja otetaan käyttöön missä tahansa ympäristössä (CI / CD).
Päätimme asentaa kolmannen osapuolen komponentteja järjestelmällisesti ja päivittää ne järjestelmällisesti. C++:lla tai Pythonilla kehitettyjä mukautettuja sovelluksia voidaan ottaa käyttöön useilla tavoilla. Niitä ovat esimerkiksi: järjestelmäpakettien luominen, niiden lähettäminen rakennettujen kuvien arkistoon ja niiden asentaminen palvelimille. Tuntemattomasta syystä valittiin toinen menetelmä, nimittäin: CI:n avulla käännetään sovelluksen suoritettavat tiedostot, luodaan virtuaalinen projektiympäristö, asennetaan py-moduulit vaatimus.txt-tiedostosta ja kaikki nämä artefaktit lähetetään konfiguraatioiden, komentosarjojen ja mukana tuleva sovellusympäristö palvelimille. Seuraavaksi sovellukset käynnistetään virtuaalisena käyttäjänä ilman järjestelmänvalvojan oikeuksia.
CI/CD-järjestelmäksi valittiin Gitlab-CI. Tuloksena saatu putki näytti suunnilleen tältä:
Rakenteellisesti gitlab-ci.yml näytti tältä
---
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
On syytä huomata, että kokoonpano ja testaus suoritetaan omalla kuvallaan, jossa kaikki tarvittavat järjestelmäpaketit on jo asennettu ja muut asetukset tehty.
Vaikka jokainen näistä käsikirjoituksista työpaikoilla on omalla tavallaan mielenkiintoinen, mutta en tietenkään puhu niistä. Jokaisen kuvaus vie paljon aikaa, eikä tämä ole artikkelin tarkoitus. Kiinnitän huomionne vain siihen tosiasiaan, että käyttöönottovaihe koostuu sarjasta kutsuvia komentosarjoja:
- createconfig.py - luo settings.ini-tiedoston komponenttiasetuksineen eri ympäristöissä myöhempää käyttöönottoa varten (esituotanto, tuotanto, testaus jne.)
- install_venv.sh - luo virtuaalisen ympäristön py-komponenteille tietyssä hakemistossa ja kopioi sen etäpalvelimille
- ready_init.d.py — valmistelee komponentin aloitus-stop-komentosarjat mallipohjan perusteella
- deploy.py - hajottaa ja käynnistää uudet komponentit uudelleen
Aika kului. Lavastusvaihe korvattiin esituotannolla ja tuotannolla. Lisätty tuki tuotteelle yhdelle jakelulle (CentOS). Lisätty 5 tehokkaampaa fyysistä palvelinta ja tusina virtuaalista palvelinta. Ja kehittäjien ja testaajien oli yhä vaikeampaa testata tehtäviä ympäristössä, joka oli enemmän tai vähemmän lähellä työtilaa. Tällä hetkellä kävi selväksi, että oli mahdotonta tehdä ilman häntä ...
Osa II
Joten klusterimme on näyttävä järjestelmä, jossa on parikymmentä erillistä komponenttia, joita Dockerfiles ei kuvaile. Voit määrittää sen käyttöön otettaviksi vain tietyssä ympäristössä yleensä. Tehtävämme on ottaa klusteri käyttöön vaiheistusympäristössä testatakseen sitä ennen julkaisua edeltävää testausta.
Teoriassa voi olla useita klustereita käynnissä samanaikaisesti: niin monta kuin on tehtäviä valmiissa tilassa tai lähellä valmistumista. Käytössämme olevien palvelimien kapasiteetit mahdollistavat useiden klustereiden ajamisen kullakin palvelimella. Jokainen vaiheklusteri on eristettävä (porteissa, hakemistoissa jne. ei saa olla risteyksiä).
Arvokkain voimavaramme on aikamme, eikä meillä ollut sitä paljoakaan.
Nopeampaa alkua varten valitsimme Docker Swarmin sen yksinkertaisuuden ja arkkitehtuurin joustavuuden vuoksi. Ensimmäinen asia, jonka teimme, oli luoda hallinta ja useita solmuja etäpalvelimille:
$ 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
Luo seuraavaksi verkko:
$ docker network create --driver overlay --subnet 10.10.10.0/24 nw_swarm
Seuraavaksi liitimme Gitlab-CI- ja Swarm-solmut solmujen etäohjauksen kannalta CI:stä: varmenteiden asentaminen, salaisten muuttujien asettaminen ja Docker-palvelun määrittäminen ohjauspalvelimelle. Tämä
Seuraavaksi lisäsimme pinon luonti- ja hävitystyöt .gitlab-ci .yml -tiedostoon.
Muutama työ on lisätty tiedostoon .gitlab-ci .yml
## 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
Yllä olevasta koodinpätkästä näet, että kaksi painiketta (deploy_staging, stop_staging) on lisätty putkiin, jotka edellyttävät manuaalisia toimia.
Pinon nimi vastaa haaran nimeä ja tämän yksilöllisyyden pitäisi olla riittävä. Pinon palvelut saavat yksilölliset IP-osoitteet ja portit, hakemistot jne. on eristetty, mutta sama pinosta pinoon (koska asetustiedosto on sama kaikille pinoille) - mitä halusimme. Otamme pinon (klusterin) käyttöön käyttämällä docker-compose.yml, joka kuvaa klusteriamme.
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
Tästä näet, että komponentit on kytketty yhteen verkkoon (nw_swarm) ja ovat toistensa käytettävissä.
Järjestelmäkomponentit (perustuvat redis, mysql) on erotettu yleisestä mukautettujen komponenttien joukosta (suunnitelmissa ja mukautetut jaetaan palveluiksi). Klusterimme käyttöönottovaihe näyttää siltä, että siirtäisimme CMD:n yhteen suureen konfiguroituun imagoomme, ja yleensä se ei käytännössä eroa osassa I kuvatusta käyttöönotosta. Korostan eroja:
- git klooni... - hanki käyttöönottoon tarvittavat tiedostot (createconfig.py, install_venv.sh jne.)
- curl... && pura vetoketju... - lataa ja pura koontiartefakteja (käännetyt apuohjelmat)
On vain yksi vielä kuvaamaton ongelma: komponentit, joilla on verkkokäyttöliittymä, eivät ole käytettävissä kehittäjien selaimista. Ratkaisemme tämän ongelman käyttämällä käänteistä välityspalvelinta, näin:
Lisäämme .gitlab-ci.yml-tiedostoon klusteripinon käyttöönoton jälkeen rivin, jolla balansoija otetaan käyttöön (joka sitoutuessaan päivittää vain kokoonpanonsa (luo uusia nginx-määritystiedostoja mallin mukaan: /etc/nginx/conf. d/${CI_COMMIT_REF_NAME}.conf) – katso docker-compose-nginx.yml-koodi)
- 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
Päivitä kehitystietokoneissa /etc/hosts; määrätä url nginxille:
10.50.173.106 staging_BRANCH-1831_cluster.dev
Joten erillisten vaiheistusklustereiden käyttöönotto on otettu käyttöön, ja kehittäjät voivat nyt käyttää niitä missä tahansa määrässä, joka riittää tehtäviensä tarkistamiseen.
Tulevaisuuden suunnitelmat:
- Erottele komponenttimme palveluiksi
- On jokaiselle Docker-tiedostolle
- Tunnista automaattisesti vähemmän ladatut solmut pinossa
- Määritä solmut nimimallin mukaan (sen sijaan, että käytät id:tä, kuten artikkelissa)
- Lisää tarkistus, että pino on tuhoutunut
- ...