Sistem rekomendasi konten video online yang sedang kami kerjakan adalah pengembangan komersial tertutup dan secara teknis merupakan kelompok multi-komponen dari komponen berpemilik dan sumber terbuka. Tujuan penulisan artikel ini adalah untuk menjelaskan implementasi sistem pengelompokan kawanan buruh pelabuhan untuk situs pementasan tanpa mengganggu alur kerja proses kami yang sudah mapan dalam waktu terbatas. Narasi yang disajikan untuk perhatian Anda dibagi menjadi dua bagian. Bagian pertama menjelaskan CI/CD sebelum menggunakan docker swarm, dan bagian kedua menjelaskan proses implementasinya. Mereka yang tidak tertarik membaca bagian pertama dapat dengan aman melanjutkan ke bagian kedua.
Bagian I
Kembali ke tahun yang sangat jauh, proses CI / CD perlu diatur secepat mungkin. Salah satu syaratnya adalah tidak menggunakan Docker untuk penerapan mengembangkan komponen karena beberapa alasan:
- untuk operasi komponen yang lebih andal dan stabil dalam Produksi (yaitu, pada kenyataannya, persyaratan untuk tidak menggunakan virtualisasi)
- pengembang terkemuka tidak ingin bekerja dengan Docker (aneh, tapi begitulah)
- sesuai dengan pertimbangan ideologis manajemen R&D
Infrastruktur, tumpukan, dan perkiraan persyaratan awal untuk MVP disajikan sebagai berikut:
- 4 server Intel® X5650 dengan Debian (satu mesin yang lebih kuat telah dikembangkan sepenuhnya)
- Pengembangan komponen kustom sendiri dilakukan di C ++, Python3
- Alat pihak ketiga utama yang digunakan: Kafka, Clickhouse, Airflow, Redis, Grafana, Postgresql, Mysql, …
- Pipeline untuk membuat dan menguji komponen secara terpisah untuk debug dan rilis
Salah satu pertanyaan pertama yang perlu dijawab pada tahap awal adalah bagaimana komponen kustom akan diterapkan di lingkungan apa pun (CI/CD).
Kami memutuskan untuk menginstal komponen pihak ketiga secara sistemik dan memperbaruinya secara sistemik. Aplikasi khusus yang dikembangkan dalam C++ atau Python dapat digunakan dalam beberapa cara. Diantaranya, misalnya: membuat paket sistem, mengirimkannya ke repositori gambar yang dibuat, lalu menginstalnya di server. Untuk alasan yang tidak diketahui, metode lain dipilih, yaitu: menggunakan CI, file aplikasi yang dapat dieksekusi dikompilasi, lingkungan proyek virtual dibuat, modul py diinstal dari requirements.txt, dan semua artefak ini dikirim bersama dengan konfigurasi, skrip, dan lingkungan aplikasi yang menyertai ke server. Selanjutnya, aplikasi diluncurkan sebagai pengguna virtual tanpa hak administrator.
Gitlab-CI dipilih sebagai sistem CI/CD. Pipa yang dihasilkan terlihat seperti ini:
Secara struktural, gitlab-ci.yml terlihat seperti ini
---
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
Perlu dicatat bahwa perakitan dan pengujian dilakukan pada citranya sendiri, di mana semua paket sistem yang diperlukan telah diinstal dan pengaturan lainnya telah dibuat.
Meskipun masing-masing skrip dalam pekerjaan ini menarik dengan caranya sendiri, tetapi tentu saja saya tidak akan membicarakannya, deskripsi masing-masing akan memakan banyak waktu dan ini bukan tujuan artikel. Saya hanya akan menarik perhatian Anda pada fakta bahwa tahap penerapan terdiri dari urutan skrip panggilan:
- buatconfig.py - membuat file settings.ini dengan pengaturan komponen di berbagai lingkungan untuk penerapan selanjutnya (Praproduksi, Produksi, Pengujian, ...)
- install_venv.sh - membuat lingkungan virtual untuk komponen py di direktori tertentu dan menyalinnya ke server jarak jauh
- siapkan_init.d.py — menyiapkan skrip start-stop untuk komponen berdasarkan template
- menyebarkan.py - terurai dan restart komponen baru
Waktu berlalu. Tahap pementasan digantikan oleh praproduksi dan produksi. Menambahkan dukungan untuk produk di satu distribusi lagi (CentOS). Menambahkan 5 server fisik yang lebih kuat dan selusin server virtual. Dan semakin sulit bagi pengembang dan penguji untuk menguji tugas mereka di lingkungan yang kurang lebih dekat dengan kondisi kerja. Pada saat ini, menjadi jelas bahwa tidak mungkin dilakukan tanpa dia ...
Bagian II
Jadi, kluster kami adalah sistem spektakuler dari beberapa lusin komponen terpisah yang tidak dijelaskan oleh Dockerfiles. Anda hanya dapat mengonfigurasinya untuk diterapkan ke lingkungan tertentu secara umum. Tugas kita adalah menerapkan klaster ke lingkungan pementasan untuk mengujinya sebelum pengujian pra-rilis.
Secara teoritis, beberapa cluster dapat berjalan secara bersamaan: sebanyak tugas dalam keadaan selesai atau hampir selesai. Kapasitas server yang kami miliki memungkinkan kami menjalankan beberapa cluster di setiap server. Setiap cluster pementasan harus diisolasi (tidak boleh ada persimpangan di port, direktori, dll.).
Sumber daya kita yang paling berharga adalah waktu kita, dan kita tidak memiliki banyak waktu.
Untuk permulaan yang lebih cepat, kami memilih Docker Swarm karena kesederhanaan dan fleksibilitas arsitekturnya. Hal pertama yang kami lakukan adalah membuat pengelola dan beberapa node di server jarak jauh:
$ 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
Selanjutnya, buat jaringan:
$ docker network create --driver overlay --subnet 10.10.10.0/24 nw_swarm
Selanjutnya, kami menghubungkan node Gitlab-CI dan Swarm dalam hal kendali jarak jauh node dari CI: memasang sertifikat, menyetel variabel rahasia, dan menyiapkan layanan Docker di server kontrol. Yang ini
Selanjutnya, kami menambahkan tugas pembuatan dan penghancuran tumpukan ke .gitlab-ci .yml.
Beberapa pekerjaan lagi telah ditambahkan ke .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
Dari cuplikan kode di atas, Anda dapat melihat bahwa dua tombol (deploy_staging, stop_staging) telah ditambahkan ke Pipelines, yang memerlukan tindakan manual.
Nama tumpukan cocok dengan nama cabang dan keunikan ini sudah cukup. Layanan dalam tumpukan menerima alamat ip unik, dan port, direktori, dll. akan diisolasi, tetapi sama dari tumpukan ke tumpukan (karena file konfigurasinya sama untuk semua tumpukan) - yang kami inginkan. Kami menyebarkan tumpukan (cluster) menggunakan docker-compose.yml, yang menggambarkan klaster kami.
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
Di sini Anda dapat melihat bahwa komponen terhubung oleh satu jaringan (nw_swarm) dan tersedia satu sama lain.
Komponen sistem (berdasarkan redis, mysql) dipisahkan dari kumpulan umum komponen khusus (dalam paket dan yang khusus dibagi sebagai layanan). Tahap penerapan klaster kami terlihat seperti meneruskan CMD ke dalam satu gambar konfigurasi besar kami dan, secara umum, secara praktis tidak berbeda dari penerapan yang dijelaskan di Bagian I. Saya akan menyoroti perbedaannya:
- klon git... - dapatkan file yang diperlukan untuk digunakan (createconfig.py, install_venv.sh, dll.)
- ikal... && buka zip... - unduh dan unzip build artefak (utilitas yang dikompilasi)
Hanya ada satu masalah yang belum dijelaskan: komponen yang memiliki antarmuka web tidak dapat diakses dari browser pengembang. Kami mengatasi masalah ini menggunakan proxy terbalik, dengan demikian:
Di .gitlab-ci.yml, setelah menerapkan tumpukan cluster, kami menambahkan baris penerapan penyeimbang (yang, saat dilakukan, hanya memperbarui konfigurasinya (membuat file konfigurasi nginx baru sesuai dengan templat: /etc/nginx/conf. d/${CI_COMMIT_REF_NAME}.conf) - lihat kode docker-compose-nginx.yml)
- docker stack deploy -c docker-compose-nginx.yml ${CI_ENVIRONMENT_NAME} --with-registry-auth
buruh pelabuhan-menulis-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
Pada komputer pengembangan, perbarui /etc/hosts; resepkan url ke nginx:
10.50.173.106 staging_BRANCH-1831_cluster.dev
Jadi, penerapan cluster staging terisolasi telah diterapkan dan pengembang sekarang dapat menjalankannya dalam jumlah yang cukup untuk memeriksa tugas mereka.
Rencana masa depan:
- Pisahkan komponen kami sebagai layanan
- Miliki untuk setiap Dockerfile
- Secara otomatis mendeteksi node yang kurang dimuat dalam tumpukan
- Tentukan node berdasarkan pola nama (daripada menggunakan id seperti di artikel)
- Tambahkan tanda centang bahwa tumpukan telah dihancurkan
- ...
Terima kasih khusus untuk
Sumber: www.habr.com