Modrá/zelená nasazení portainer pomocí gitlab CI/CD

0

Otázka

Mám webservice pomocí websockets, a je třeba realizovat nulové prostoje nasazení. Protože nechci drop existující připojení na nasazení, jsem se rozhodl realizovat modrá/zelená nasazení. Mé skutečné řešení vypadá:

  1. Vytvořil jsem dvě identické služby v portainer, poslech na různých portech. Každá služba má nastavit v uzlu prostředí nějaký identifikátor, například alfa a beta
  2. Obě služby jsou skryté za load balancer, vyvažovací zařízení je pravidelně kontrolovat stav jednotlivých služeb. Pokud služba reaguje na konkrétní trase (/vyvažovací zařízení-keepalive-check) s string "OK", tato služba je aktivní a balancer může směrování k této službě. Pokud služba odpovídá řetězec "STOP", vyvažovací označit tuto službu jako nepřístupné, ale aktivní spojení bude zachována
  3. která služba je aktivní a který je zastaven, je synchronizovat přes redis. V redis existuje klíče lb.service.alfa a lb.service.beta které mohou obsahuje hodnoty 1 pro aktivní a 0 pro neaktivní. Příklad realizace /vyvažovací zařízení-keepalive-podívejte se na trasy v nestjs:
    import {Controller, Get} from '@nestjs/common';
    import {RedisClient} from "redis";
    const { promisify } = require("util");
    
    
    @Controller()
    export class AppController {
    
        private redisClient = new RedisClient({host: process.env.REDIS_HOST});
        private serviceId:string = process.env.ID;  //alfa, beta
    
        @Get('balancer-keepalive-check')
        async balancerCheckAlive(): Promise<string> {
            const getAsync = promisify(this.redisClient.get).bind(this.redisClient);
            return getAsync(`lb-status-${this.serviceId}`).then(status => {
                const reply: string = status == 1 ? 'OK' : 'STOP';
                return `<response>${reply}</response>`;
            })
        }
    }
  1. v gitlab CI vytvořit docker image tagged podle značek na potvrdit a restartovat službu volání portainer webhook pro konkrétní služby. To funguje dobře pro 1 službu, ale nevím, jak používat 2 různé DEPLOY_WEBHOOK CI proměnných a přepínat mezi nimi.
image: registry.rassk.work/pokec/pokec-nodejs-build-image:p1.0.1
services:
  - name: docker:dind

variables:
  DOCKER_TAG: platform-websocket:$CI_COMMIT_TAG

deploy:
  tags:
    - dtm-builder
  environment:
    name: $CI_COMMIT_TAG
  script:
    - npm set registry http://some-private-npm-registry-url.sk
    - if [ "$ENV_CONFIG" ]; then cp $ENV_CONFIG $PWD/.env; fi
    - if [ "$PRIVATE_KEY" ]; then cp $PRIVATE_KEY $PWD/privateKey.pem; fi
    - if [ "$PUBLIC_KEY" ]; then cp $PUBLIC_KEY $PWD/publicKey.pem; fi
    - docker build -t $DOCKER_TAG .
    - docker tag $DOCKER_TAG registry.rassk.work/community/$DOCKER_TAG
    - docker push registry.rassk.work/community/$DOCKER_TAG
    - curl --request POST $DEPLOY_WEBHOOK
  only:
    - tags

Na mé otázky, které nevím, jak řešit, jsou:

  • Když jsem si 2 služby, mám 2 různé nasadit webhooks, z nichž musím zavolat jeden po nasazení, protože nechci, aby restart obou služeb. Jak určit, který z nich? Jak implementovat nějaký čítač, pokud to nasazení je "alfa" nebo "beta" provozu? Mám použít gitlab api a aktualizace DEPLOY_WEBHOOK po každém nasazení? Nebo se mám zbavit tohoto gitlab CI/CD proměnné a použít nějaké API pro služby, které mi řekne, webhook url?
  • Jak aktualizovat hodnoty v redis? Měl jsem implementovat vlastní rozhraní API pro?
  • Existuje lepší způsob, jak toho dosáhnout?

kromě info: nelze použít gitlab api od serviceses, protože naše gitlab je self-hostované na doméně přístupný pouze z naší privátní sítě.

1

Nejlepší odpověď

0

Upravil jsem AppController. K dispozici jsou 2 nové koncové body teď, jeden pro určení, které služby běží, druhý pro přepnutí hodnoty v redis:

private serviceId:string = process.env.ID || 'alfa';

    @Get('running-service-id')
    info(){
        return this.serviceId
    }

    @Get('switch')
    switch(){
        const play = this.serviceId == 'alfa' ? `lb-status-beta` : `lb-status-alfa`;
        const stop = `lb-status-${this.serviceId}`;
        this.redisClient.set(play, '1', (err) => {
            if(!err){
                this.redisClient.set(stop, '0');
            }
        })
    }

po tom, upravil jsem můj gitlab-ci.yml takto:

image: registry.rassk.work/pokec/pokec-nodejs-build-image:p1.0.1
services:
  - name: docker:dind

stages:
  - build
  - deploy
  - switch

variables:
  DOCKER_TAG: platform-websocket:$CI_COMMIT_TAG

test:
  stage: build
  allow_failure: true
  tags:
    - dtm-builder
  script:
    - npm set registry http://some-private-npm-registry-url.sk
    - npm install
    - npm run test

build:
  stage: build
  tags:
    - dtm-builder
  environment:
    name: $CI_COMMIT_TAG
  script:
    - if [ "$ENV_CONFIG" ]; then cp $ENV_CONFIG $PWD/.env; fi
    - if [ "$PRIVATE_KEY" ]; then cp $PRIVATE_KEY $PWD/privateKey.pem; fi
    - if [ "$PUBLIC_KEY" ]; then cp $PUBLIC_KEY $PWD/publicKey.pem; fi
    - docker build -t $DOCKER_TAG .
    - docker tag $DOCKER_TAG registry.rassk.work/community/$DOCKER_TAG
    - docker push registry.rassk.work/community/$DOCKER_TAG
  only:
    - tags

deploy:
  stage: deploy
  needs: [build, test]
  environment:
    name: $CI_COMMIT_TAG
  script:
    - 'SERVICE_RUNNING=$(curl --request GET http://172.17.101.125/running-service-id)'
    - echo $SERVICE_RUNNING
    - if [ "$SERVICE_RUNNING" == "1" ]; then curl --request POST $DEPLOY_WEBHOOK_2; fi
    - if [ "$SERVICE_RUNNING" == "2" ]; then curl --request POST $DEPLOY_WEBHOOK_1; fi
  only:
    - tags

switch:
  stage: switch
  needs: [deploy]
  environment:
    name: $CI_COMMIT_TAG
  script:
    - sleep 10
    - curl --request GET http://172.17.101.125/switch
  only:
    - tags

V práci postavit na docker image je stavět. Po, která provozuje pracovní nasazení, které se žádost /běh-service-id a určuje, které služby je podnožka. Pak nasadit obrázek zastavil službu. Poslední práce je spínač, který bude žádost /spínač trasu, která bude přepínat hodnoty v redis.

To funguje dobře. Poslední věc, kterou je třeba realizovat, je nějaký druh tajemství pro tyto dvě trasy (jwt pro příklad)

2021-12-02 07:39:41

V jiných jazycích

Tato stránka je v jiných jazycích

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................