Gunakan Aplikasi dengan Docker Swarm

Sistem pengesyoran kandungan video dalam talian yang kami sedang usahakan ialah pembangunan komersial tertutup dan secara teknikalnya merupakan kumpulan berbilang komponen komponen proprietari dan sumber terbuka. Tujuan menulis artikel ini adalah untuk menerangkan pelaksanaan sistem pengelompokan kawanan buruh pelabuhan untuk tapak pementasan tanpa mengganggu aliran kerja proses kami yang telah ditetapkan dalam masa yang terhad. Naratif yang disampaikan kepada perhatian anda dibahagikan kepada dua bahagian. Bahagian pertama menerangkan CI / CD sebelum menggunakan docker swarm, dan bahagian kedua menerangkan proses pelaksanaannya. Mereka yang tidak berminat membaca bahagian pertama dengan selamat boleh beralih ke bahagian kedua.

Bahagian I

Kembali pada tahun yang jauh dan jauh, adalah perlu untuk menyediakan proses CI / CD secepat mungkin. Salah satu syarat adalah untuk tidak menggunakan Docker untuk penempatan komponen yang dibangunkan untuk beberapa sebab:

  • untuk operasi komponen yang lebih dipercayai dan stabil dalam Pengeluaran (iaitu, sebenarnya, keperluan untuk tidak menggunakan virtualisasi)
  • pemaju terkemuka tidak mahu bekerja dengan Docker (pelik, tetapi begitulah keadaannya)
  • mengikut pertimbangan ideologi pengurusan R&D

Infrastruktur, tindanan dan anggaran keperluan awal untuk MVP dibentangkan seperti berikut:

  • 4 pelayan Intel® X5650 dengan Debian (satu lagi mesin berkuasa dibangunkan sepenuhnya)
  • Pembangunan komponen tersuai sendiri dijalankan dalam C ++, Python3
  • Alat pihak ketiga utama yang digunakan: Kafka, Clickhouse, Aliran Udara, Redis, Grafana, Postgresql, Mysql, …
  • Saluran paip untuk membina dan menguji komponen secara berasingan untuk nyahpepijat dan pelepasan

Salah satu soalan pertama yang perlu ditangani pada peringkat awal ialah bagaimana komponen tersuai akan digunakan dalam mana-mana persekitaran (CI / CD).

Kami memutuskan untuk memasang komponen pihak ketiga secara sistematik dan mengemas kininya secara sistematik. Aplikasi tersuai yang dibangunkan dalam C++ atau Python boleh digunakan dalam beberapa cara. Antaranya, sebagai contoh: mencipta pakej sistem, menghantarnya ke repositori imej terbina dan kemudian memasangnya pada pelayan. Atas sebab yang tidak diketahui, kaedah lain telah dipilih, iaitu: menggunakan CI, fail boleh laku aplikasi disusun, persekitaran projek maya dicipta, modul py dipasang daripada requirements.txt, dan semua artifak ini dihantar bersama dengan konfigurasi, skrip dan mengiringi persekitaran aplikasi ke pelayan. Seterusnya, aplikasi dilancarkan sebagai pengguna maya tanpa hak pentadbir.

Gitlab-CI dipilih sebagai sistem CI/CD. Saluran paip yang terhasil kelihatan seperti ini:

Gunakan Aplikasi dengan Docker Swarm
Secara struktur, gitlab-ci.yml kelihatan 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 diingat bahawa pemasangan dan ujian dijalankan pada imejnya sendiri, di mana semua pakej sistem yang diperlukan telah dipasang dan tetapan lain telah dibuat.

Walaupun setiap skrip dalam pekerjaan ini menarik dengan cara tersendiri, tetapi sudah tentu saya tidak akan bercakap mengenainya. Penerangan setiap satunya akan mengambil banyak masa dan ini bukan tujuan artikel itu. Saya hanya akan menarik perhatian anda kepada fakta bahawa peringkat penggunaan terdiri daripada urutan skrip panggilan:

  1. createconfig.py - mencipta fail settings.ini dengan tetapan komponen dalam pelbagai persekitaran untuk penggunaan berikutnya (Preproduction, Production, Testing, ...)
  2. install_venv.sh - mencipta persekitaran maya untuk komponen py dalam direktori tertentu dan menyalinnya ke pelayan jauh
  3. prepare_init.d.py — menyediakan skrip permulaan-henti untuk komponen berdasarkan templat
  4. deploy.py - mengurai dan memulakan semula komponen baharu

Masa berlalu. Peringkat pementasan digantikan dengan prapengeluaran dan pengeluaran. Menambah sokongan untuk produk pada satu lagi pengedaran (CentOS). Menambahkan 5 pelayan fizikal yang lebih berkuasa dan sedozen pelayan maya. Dan semakin sukar bagi pembangun dan penguji untuk menguji tugas mereka dalam persekitaran yang lebih kurang hampir dengan keadaan kerja. Pada masa ini, menjadi jelas bahawa mustahil untuk dilakukan tanpa dia ...

Bahagian II

Gunakan Aplikasi dengan Docker Swarm

Jadi, kluster kami ialah sistem yang menakjubkan bagi beberapa dozen komponen berasingan yang tidak diterangkan oleh Dockerfiles. Anda hanya boleh mengkonfigurasinya untuk penggunaan ke persekitaran tertentu secara umum. Tugas kami adalah untuk menggunakan kluster ke dalam persekitaran pementasan untuk mengujinya sebelum ujian pra-keluaran.

Secara teorinya, terdapat beberapa kluster yang berjalan serentak: seberapa banyak yang terdapat tugasan dalam keadaan siap atau hampir siap. Kapasiti pelayan yang kami gunakan membolehkan kami menjalankan beberapa kluster pada setiap pelayan. Setiap kelompok pementasan mesti diasingkan (mesti tidak ada persimpangan dalam port, direktori, dll.).

Sumber kami yang paling berharga ialah masa kami, dan kami tidak mempunyai banyak masa.

Untuk permulaan yang lebih pantas, kami memilih Docker Swarm kerana kesederhanaan dan fleksibiliti seni binanya. Perkara pertama yang kami lakukan ialah mencipta pengurus dan beberapa nod pada pelayan 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

Seterusnya, buat rangkaian:


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

Seterusnya, kami menyambungkan nod Gitlab-CI dan Swarm dari segi kawalan jauh nod daripada CI: memasang sijil, menetapkan pembolehubah rahsia dan menyediakan perkhidmatan Docker pada pelayan kawalan. Yang ini artikel telah menjimatkan banyak masa.

Seterusnya, kami menambah kerja penciptaan tindanan dan pemusnahan pada .gitlab-ci .yml.

Beberapa kerja lagi telah ditambahkan pada .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

Daripada coretan kod di atas, anda boleh melihat bahawa dua butang (deploy_staging, stop_staging) telah ditambahkan pada Pipelines, yang memerlukan tindakan manual.

Gunakan Aplikasi dengan Docker Swarm
Nama tindanan sepadan dengan nama cawangan dan keunikan ini sepatutnya mencukupi. Perkhidmatan dalam tindanan menerima alamat ip unik, dan port, direktori, dsb. akan diasingkan, tetapi sama dari tindanan ke tindanan (kerana fail konfigurasi adalah sama untuk semua tindanan) - apa yang kita mahu. Kami menggunakan timbunan (kelompok) menggunakan docker-compose.yml, yang menerangkan kluster 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 boleh melihat bahawa komponen disambungkan oleh satu rangkaian (nw_swarm) dan tersedia antara satu sama lain.

Komponen sistem (berdasarkan redis, mysql) dipisahkan daripada kumpulan umum komponen tersuai (dalam pelan dan yang tersuai dibahagikan sebagai perkhidmatan). Peringkat penggunaan kluster kami kelihatan seperti menghantar CMD ke dalam satu imej terkonfigurasi besar kami dan, secara amnya, secara praktikalnya tidak berbeza daripada penggunaan yang diterangkan dalam Bahagian I. Saya akan menyerlahkan perbezaannya:

  • klon git... - dapatkan fail yang diperlukan untuk digunakan (createconfig.py, install_venv.sh, dll.)
  • keriting... && buka zip... - muat turun dan unzip binaan artifak (utiliti yang disusun)

Hanya ada satu masalah yang belum dijelaskan: komponen yang mempunyai antara muka web tidak boleh diakses daripada pelayar pembangun. Kami menyelesaikan masalah ini menggunakan proksi terbalik, dengan itu:

Dalam .gitlab-ci.yml, selepas menggunakan timbunan kluster, kami menambah barisan menggunakan pengimbang (yang, apabila melakukan, hanya mengemas kini konfigurasinya (mencipta fail konfigurasi nginx baharu mengikut templat: /etc/nginx/conf. d/${CI_COMMIT_REF_NAME}.conf) - lihat kod docker-compose-nginx.yml)

    - 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

Pada komputer pembangunan, kemas kini /etc/hosts; tetapkan url ke nginx:

10.50.173.106 staging_BRANCH-1831_cluster.dev

Jadi, penggunaan kluster pementasan terpencil telah dilaksanakan dan pembangun kini boleh menjalankannya dalam sebarang bilangan yang mencukupi untuk menyemak tugas mereka.

Rancangan masa hadapan:

  • Asingkan komponen kami sebagai perkhidmatan
  • Ada untuk setiap Dockerfile
  • Mengesan nod yang kurang dimuatkan secara automatik dalam timbunan
  • Tentukan nod mengikut corak nama (daripada menggunakan id seperti dalam artikel)
  • Tambah semak bahawa tindanan telah dimusnahkan
  • ...

Terima kasih khas untuk artikel.

Sumber: www.habr.com

Tambah komen