Docker Swarm ile Uygulamaları Dağıtın

Üzerinde çalıştığımız çevrimiçi video içerik öneri sistemi, kapalı bir ticari geliştirmedir ve teknik olarak tescilli ve açık kaynaklı bileşenlerden oluşan çok bileşenli bir kümedir. Bu makaleyi yazmamın amacı, sınırlı bir süre içinde süreçlerimizin kurulu iş akışını bozmadan bir hazırlama sitesi için docker swarm kümeleme sisteminin uygulanmasını anlatmaktır. Dikkatinize sunulan anlatı iki bölüme ayrılmıştır. İlk bölüm, liman işçisi sürüsünü kullanmadan önce CI / CD'yi açıklar ve ikincisi, uygulama sürecini açıklar. İlk bölümü okumakla ilgilenmeyenler ikinci bölüme güvenle geçebilirler.

Bölüm I

Uzak, uzak bir yılda, CI / CD sürecini mümkün olan en kısa sürede kurmak gerekiyordu. Koşullardan biri Docker kullanmamaktı. dağıtım için bileşenleri birkaç nedenden dolayı geliştirdi:

  • Üretimdeki bileşenlerin daha güvenilir ve istikrarlı çalışması için (yani sanallaştırma kullanmama gerekliliği)
  • önde gelen geliştiriciler Docker ile çalışmak istemediler (garip, ama böyleydi)
  • Ar-Ge yönetiminin ideolojik düşüncelerine göre

MVP için altyapı, yığın ve yaklaşık başlangıç ​​gereksinimleri şu şekilde sunuldu:

  • Debian'lı 4 Intel® X5650 sunucu (bir tane daha güçlü makine tamamen geliştirildi)
  • Kendi özel bileşenlerinin geliştirilmesi C++, Python3'te gerçekleştirilir
  • Kullanılan ana 3. parti araçlar: Kafka, Clickhouse, Airflow, Redis, Grafana, Postgresql, Mysql, …
  • Hata ayıklama ve serbest bırakma için bileşenleri ayrı ayrı oluşturmaya ve test etmeye yönelik işlem hatları

İlk aşamada ele alınması gereken ilk sorulardan biri, özel bileşenlerin herhangi bir ortamda (CI / CD) nasıl dağıtılacağıdır.

Üçüncü taraf bileşenleri sistematik olarak kurmaya ve bunları sistematik olarak güncellemeye karar verdik. C++ veya Python'da geliştirilen özel uygulamalar çeşitli şekillerde dağıtılabilir. Bunların arasında, örneğin: sistem paketleri oluşturmak, bunları yerleşik görüntülerin bulunduğu depoya göndermek ve ardından bunları sunuculara yüklemek. Bilinmeyen bir nedenle, başka bir yöntem seçildi: CI kullanılarak, uygulama çalıştırılabilir dosyaları derlenir, sanal bir proje ortamı oluşturulur, py modülleri gereklilikler.txt dosyasından yüklenir ve tüm bu yapılar, yapılandırmalar, komut dosyaları ve sunuculara eşlik eden uygulama ortamı. Daha sonra uygulamalar, yönetici hakları olmadan sanal bir kullanıcı olarak başlatılır.

CI/CD sistemi olarak Gitlab-CI seçilmiştir. Ortaya çıkan boru hattı şuna benziyordu:

Docker Swarm ile Uygulamaları Dağıtın
Yapısal olarak, gitlab-ci.yml şöyle görünüyordu

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

Montaj ve testin, gerekli tüm sistem paketlerinin kurulu olduğu ve diğer ayarların yapıldığı kendi görüntüsü üzerinde yapıldığını belirtmekte fayda var.

Jobs'taki bu betiklerin her biri kendince ilginç olsa da, elbette onlardan bahsetmeyeceğim, her birinin açıklaması çok zaman alacak ve bu makalenin amacı değil. Yalnızca dağıtım aşamasının bir dizi çağrı komut dosyasından oluştuğu gerçeğine dikkatinizi çekeceğim:

  1. yapılandırma.py oluştur - sonraki dağıtım için çeşitli ortamlarda bileşen ayarlarıyla bir settings.ini dosyası oluşturur (Üretim Öncesi, Üretim, Test, ...)
  2. install_venv.sh - belirli bir dizindeki py bileşenleri için sanal bir ortam oluşturur ve bunu uzak sunuculara kopyalar
  3. hazır_init.d.py — şablona dayalı olarak bileşen için start-stop komut dosyaları hazırlar
  4. konuşlandırma.py - yeni bileşenleri ayrıştırır ve yeniden başlatır

Zaman Geçti. Sahneleme aşamasının yerini ön prodüksiyon ve prodüksiyon aldı. Bir dağıtımda (CentOS) ürün için destek eklendi. 5 daha güçlü fiziksel sunucu ve bir düzine sanal sunucu eklendi. Ve geliştiricilerin ve testçilerin görevlerini çalışır duruma aşağı yukarı yakın bir ortamda test etmeleri giderek daha zor hale geldi. Şu anda onsuz yapmanın imkansız olduğu anlaşıldı ...

Bölüm II

Docker Swarm ile Uygulamaları Dağıtın

Dolayısıyla kümemiz, Dockerfiles tarafından açıklanmayan birkaç düzine ayrı bileşenden oluşan muhteşem bir sistemdir. Genel olarak yalnızca belirli bir ortama dağıtım için yapılandırabilirsiniz. Görevimiz, yayın öncesi testten önce test etmek için kümeyi bir hazırlama ortamına yerleştirmektir.

Teorik olarak, aynı anda çalışan birkaç küme olabilir: tamamlanmış durumda veya tamamlanmak üzere olan görev sayısı kadar. Elimizdeki sunucuların kapasiteleri, her sunucuda birkaç küme çalıştırmamıza izin veriyor. Her hazırlama kümesi izole edilmelidir (bağlantı noktalarında, dizinlerde vb. kesişme olmamalıdır).

En değerli kaynağımız zamanımız ve fazlasına sahip değildik.

Daha hızlı bir başlangıç ​​için, basitliği ve mimari esnekliği nedeniyle Docker Swarm'ı seçtik. Yaptığımız ilk şey, uzak sunucularda bir yönetici ve birkaç düğüm oluşturmaktı:

$ 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

Ardından, bir ağ oluşturun:


$ docker network create --driver overlay --subnet 10.10.10.0/24 nw_swarm

Ardından, Gitlab-CI ve Swarm düğümlerini CI'den düğümlerin uzaktan kontrolü açısından bağladık: sertifikaların yüklenmesi, gizli değişkenlerin ayarlanması ve kontrol sunucusunda Docker hizmetini kurma. Bu makale bize çok zaman kazandırdı.

Ardından, .gitlab-ci .yml'ye yığın oluşturma ve yok etme işleri ekledik.

.gitlab-ci .yml dosyasına birkaç iş daha eklendi

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

Yukarıdaki kod parçacığından, İşlem Hatlarına manuel işlem gerektiren iki düğmenin (deploy_staging, stop_staging) eklendiğini görebilirsiniz.

Docker Swarm ile Uygulamaları Dağıtın
Yığın adı, dal adıyla eşleşir ve bu benzersizlik yeterli olmalıdır. Yığındaki hizmetler benzersiz ip adresleri ve bağlantı noktaları, dizinler vb. alır. izole edilecek, ancak yığından yığına aynı (çünkü yapılandırma dosyası tüm yığınlar için aynıdır) - istediğimiz şey. Yığını (kümeyi) kullanarak dağıtıyoruz liman işçisi-compose.yml, kümemizi açıklayan.

liman işçisi-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 bileşenlerin bir ağ (nw_swarm) ile birbirine bağlı olduğunu ve birbirlerine açık olduğunu görebilirsiniz.

Sistem bileşenleri (redis, mysql tabanlı) özel bileşenlerin genel havuzundan ayrılır (planlarda ve özel olanlar servisler olarak ayrılır). Kümemizin dağıtım aşaması, CMD'yi tek bir büyük yapılandırılmış görüntümüze geçirmeye benzer ve genel olarak, pratik olarak Bölüm I'de açıklanan dağıtımdan farklı değildir. Farklılıkları vurgulayacağım:

  • git klonu... - dağıtmak için gereken dosyaları edinin (createconfig.py, install_venv.sh, vb.)
  • kıvırın... && zip'i açın... - yapı eserlerini indirin ve sıkıştırılmış dosyayı açın (derlenmiş yardımcı programlar)

Henüz açıklanmayan tek bir sorun var: web arayüzüne sahip bileşenlere geliştiricilerin tarayıcılarından erişilemiyor. Bu sorunu ters proxy kullanarak çözüyoruz, böylece:

.gitlab-ci.yml'de, küme yığınını dağıttıktan sonra, dengeleyiciyi konuşlandırma satırını ekliyoruz (ki bu, taahhüt edildiğinde yalnızca yapılandırmasını günceller (şablona göre yeni nginx yapılandırma dosyaları oluşturur: /etc/nginx/conf.conf). d/${CI_COMMIT_REF_NAME}.conf) - docker-compose-nginx.yml koduna bakı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

Geliştirme bilgisayarlarında /etc/hosts güncelleyin; url'yi nginx'e yaz:

10.50.173.106 staging_BRANCH-1831_cluster.dev

Bu nedenle, yalıtılmış hazırlama kümelerinin dağıtımı uygulandı ve geliştiriciler artık bunları görevlerini kontrol etmeye yetecek kadar herhangi bir sayıda çalıştırabilir.

Gelecek planları:

  • Bileşenlerimizi hizmet olarak ayırın
  • Her Dockerfile için sahip olun
  • Yığındaki daha az yüklü düğümleri otomatik olarak algıla
  • Düğümleri ad modeline göre belirtin (makalede olduğu gibi kimliği kullanmak yerine)
  • Yığının yok edildiğini kontrol edin
  • ...

için özel teşekkürler Makale.

Kaynak: habr.com

Yorum ekle