Chaos Testing

testing platform

*file: 101-confidential-secrets.md *

SYSTÉMOVÉ SECRETY a jejich správa

1. SYSTÉMOVÉ SECRETY

Systémové certifikáty jsou uloženy v SYS ARGO repozitáři daného clusteru v adresáři secrets.
Ne všechny tyto certifikáty jsou zpracovávány GitOpsově. Řešíme často problém “slepice/vejce” takže některé secrets jsou aplikovány ručně po založení clusteru.

tree secrets/
├── api-certificate.yml             # Openshift api TLS certifikát
├── argocd-app                      # argocd app secrets
│   ├── argocd-secret.yml
│   ├── token-git-github-csas-ops.yml
│   ├── token-helm-artifactory-1.yml
│   └── token-helm-artifactory-2.yml
├── argocd-sys                      # argocd sys secrets
│   ├── argocd-cluster.yml
│   ├── token-git-bitbucket-ocp4.yml
│   ├── token-git-github-csas-ops.yml
│   ├── token-helm-artifactory-1.yml
│   └── token-helm-artifactory-2.yml
├── azure-auth.yml                  # OIDC setting for Azure Auth
├── azure-group-sync.yml            # Group sync operátor secret pro AAD group sync
├── backend-tprgnasbe02.yml         # Trident NFS
├── kafka-credentials.yaml          # kafka credentials pro logy
├── router-be-certificate.yml       # BE router TLS
├── router-default-certificate.yml  # default router TLS
├── router-dmz-certificate.yml      # dmz router TLS
├── router-fe-certificate.yml       # FE router TLS
└── sealed-secrets.yml              # Sealed secrets private KEY/CERT

Tyto secrets jsou ve standartní struktuře kind:Secrets a jsou zašifrovány pomocí ‘Ansible vault’.

2. GITOPS zpracování

Pro GITOPS zpracování secretů, Ansible vault secrety dešifrujeme, updatujeme a následně zašifrujeme certifikátem pro Kubeseal do adresáře confidential-secrets. Standartním procesem pak provedeme Gitops sync.

# secrety řízené GITOPS
tree secrets/
├── api-certificate.yml             # Openshift api TLS certifikát
├── azure-auth.yml                  # OIDC setting for Azure Auth
├── azure-group-sync.yml            # Group sync operátor secret pro AAD group sync
├── kafka-credentials.yaml          # kafka credentials pro logy
├── router-be-certificate.yml       # BE router TLS
├── router-default-certificate.yml  # default router TLS
├── router-dmz-certificate.yml      # dmz router TLS
└── router-fe-certificate.yml       # Sealed secrets private KEY/CERT

Provedení výměny secretů

#decrypt
ansible-vault decrypt $secret
# update obsahu secretu novými hodnotami
#encrypt
ansible-vault encrypt $secret
#pipe it through sealed-secrets
read ansible_vault_pass </dev/tty
#pokud chceme pouzit kubeseal certifikat lokalne
ansible-vault view $secret  --vault-password-file <(cat <<<"$ansible_vault_pass")|kubeseal --cert cert.pem --scope namespace-wide >confidential-secrets/$secret
#pokud chceme pouzit kubeseal certifikat ze serveru
ansible-vault view api-certificate.yml  --vault-password-file <(cat <<<"$ansible_vault_pass")|kubeseal --cert https://certificate-sealed-secrets.apps.<CLUSTER_NAME>.<BASE_DOMAIN>/v1/cert.pem --scope namespace-wide >confidential-secrets/$secret
# následuje standartní render a GIT commit/push 

3. Spracování neřízených GITOPS

Některé secrety jsou potřeba pro konfiguraci samotného clusteru a jeho komponent. Musí tedy být přítomny v clusteru ještě před jeho konfigurací a je tedy nutné je aplikovat ručně.

# secrety neřízené GITOPS
tree secrets/
├── argocd-app
│   ├── argocd-secret.yml
│   ├── token-git-github-csas-ops.yml
│   ├── token-helm-artifactory-1.yml
│   └── token-helm-artifactory-2.yml
├── argocd-sys
│   ├── argocd-cluster.yml
│   ├── token-git-bitbucket-ocp4.yml
│   ├── token-git-github-csas-ops.yml
│   ├── token-helm-artifactory-1.yml
│   └── token-helm-artifactory-2.yml
├── backend-tprgnasbe02.yml         # Trident NFS
└── sealed-secrets.yml              # Sealed secrets private KEY/CERT
## provadime update hodnot
#decrypt
ansible-vault decrypt $secret
# update obsahu secretu novými hodnotami
#encrypt
ansible-vault encrypt $secret

## aplikujeme nove nebo stavajici hodnoty
read ansible_vault_pass </dev/tty
ansible-vault view $secret  --vault-password-file <(cat <<<"$ansible_vault_pass")|oc apply -f -
*file: 141-TestovaciScenare.md *

141. Testovací scénáře

1. Výpadek master nodu v SRM poolu a jeho stěhování do druhé lokality

Očekávaný stav:
Nebude mít žádný dopad na funkčnost clusteru. Control plane bude stále v quoru.
Opravné kroky:
Provedeme failover SRM poolu na druhou lokalitu. Zjistíme stav memberů v ETCD, tedy zda jsou skutečně 3 členové.
Akceptační kritéria:
Počet master nodů=3, počet memberů v ETCD=3
Pracnost:
S

Výsledek: Výpadek master nodu neměl žádný dopad na funkčnost clusteru. SRM failover nebyl testován

2. Výpadek jedné lokality

Jelikož master nody jsou mezi lokalitami rozděleny disproporčně, provedeme výpadek na straně majority master nodu.
Očekávný stav:
Control plane přijde o quorum, API server se přepne do readonly nastavení. Jelikož je API server bez zápisu, nebude možné provést automatický rescheduling workloadu v postižené lokalitě na druhou lokalitu.
Opravné kroky:
Provedeme failover SRM poolu na druhou lokalitu a/nebo vytvoříme v druhé lokalitě nový master nod a přidáme ho do poolu. Zjistíme stav memberů v ETCD, tedy zda jsou skutečně 3 členové. Worload by se měl začít schedulovat na workernody v druhé lokalitě dle svých priorityclass. Akceptační kritéria:
Počet master nodů=3, počet memberů v ETCD=3, běžící workload do limitu zdrojů (nějaký workload může zůstat ve stavu “pending”) Pracnost:
S

Výsledek:
Openshift API není funkční, ETCD není funkční jelikož má na sobě “proby” kontrolující majoritu (tedy nejede v jedné instanci). Samotné aplikace jedou DC1/DC2, pokud je v jejich logice volání OCP API budou failovat.
Po nastartování master nodů došlo ke spojení ETCD a získání majority a nastartuje API.

3. Výpadek nodu s přidělenými více EgressIP

Očekávný stav:
Workload namespacu s definovaným Egress se nedostane po dobu failoveru na outbound, EgressIP bude automaticky přestěhována na dostupný nod.
Opravné kroky:
Vše by se mělo provést automaticky, jde jen o zjištění doby trvání failoveru pro EgressIP a vyhodnocení dopadu.
Akceptační kritéria:
Zjištění doby failoveru vícero egressIP adres na jiný nód.

Poznámka:
Otestovat myšlenku více egressIP pro jeden namespace, případně sdílení egressIP mezi vícero namespace(Openshift 4.12).
Pracnost:
S

Výsledek: Jakmile je nod labelován jako k8s.ovn.org/egress-assignable, EgressIP operator prezentován jako ovnkube-master pod bude periodicky kontrolovat zda je nod použitelný. EgressIP adresy přidělené nodu který není dosažitelný jsou přesunuty na jiný dosažitelný nod.
Periodická kontrola dostupnosti egres nodu je definovana v kubernetes OVN na periodu 5 sekund.
Aplikace používající egressIP z poolu vypnutého nodu budou mit packet lost pro outbound po dobu failoveru na jiný nód to je cca 10s. Nepovedlo se dokázat že větší množství egressIP pro které je potřeba provést failover mají vazbu na délku failoveru samotného a tedy dopad na dostupnost aplikačního outboundu.

4. Znefunkčnění celého clusteru a jeho GITOPS obnova

Očekávný stav:
Nefunkční cluster
Opravné kroky:
Vytvoření nového clusteru, připojení systémového a aplikačního ArgoCD a jeho všech zdrojů. Validace průběhu vytvoření všech původních objektů.
Akceptační kritéria:
Množství řádků limitně se blížící nule.

oc get pods --field-selector status.phase!=Running,status.phase!=Succeeded  --all-namespaces

Pracnost:
S

Výsledek:
Test proveden s dostatečným množstvím dummy aplikací na testovacím clusteru. Chybějící kroky dopsány do GITOPS sys flow, ArgoCD SYS bootstrap.

5. Výpadek “network” nodu ve vazbě na ingressControler

Očekávný stav:
Nefunkční network nod, pod pro ingressControler ve stavu pending
Opravné kroky:
Funkční network nod
Akceptační kritéria:
Trafic směřující z venku přez ingress kontroler nebyl omezen.
Pracnost:
XS

Výsledek:
Ingress kontroler běží v RS=4, rozprostřeny přez všechny “network node” pro daný cluster. Ingresscontroller běží jako hostNetwork tedy na definovaném portu každého “network nodu”. V případě pádu ingress nodu jde o to po jaké době F5 jako loadbalancer přestane na neodpovídající nod posílat requesty. Proby na F5 jsou pro tcp nastany na 5s a po 3 neúspěšných pokusech je member vyřazen, celková doba vyřazení memberu z LB je tedy 16s.

6.Distribuce requestů mezi vícero ingress kontrolerů

Očekávný stav:
Requesty jsou dle nastavení F5 loadbalancer posílány na jednotlivé membery.
Akceptační kritéria:
Prověření normálního rozložení requestů mezi jednotlivé ingresscontrolery.
Pracnost:
XS

Výsledek:
Ingress kontroler běží v RS=4, rozprostřeny přez všechny “network node” pro daný cluster. Ingresscontroller běží jako hostNetwork tedy na definovaném portu každého “network nodu”. F5 na základě interních mechanismů odesílá střídavě requesty na jednotlivé membery. Pro tcp je použit roundrobin.

7.Test alertingu pro kritické prvky infrastruktu

Očekávný stav:
Alerty jsou doručeny dle konfigurace alertManager
Akceptační kritéria:
Alerty byli doručeny dle konfigurace alertManager
Pracnost:
S

Výsledek:

8.Jak se cluster zachová, když mu přetížíme jeden, dva X node. Jak rychle přestěhuje, jestli vůbec. Tady bych rád věděl, jak se cluster zachová, když v něm jeden nebo dva node (abych byl exaktní - cca 20% kapacity clusteru) vyžere výkon

Očekávný stav:
Nestane se nic, nový workload bude schedulován na nezatížené nódy.
Akceptační kritéria:
Nestalo se nic, nový worload byl schedulován na nezatížené nódy.
Pracnost:
S

Výsledek:
Workload na nodu se sám stěhovat nebude. Další workload bude plánován na nezatížené nody dle hodnotících kritérií a samozřejmě nastevení deploymentu samotného, ale pokud nedojde k pádu aplikace nebude přestěhována z původních zatížených nodů.

Scheduling na nod je v době deploymentu definován pouze na úrovni následujících váhových ohodnocení

{"name" : "LeastRequestedPriority", "weight" : 1},
{"name" : "BalancedResourceAllocation", "weight" : 1},
{"name" : "ServiceSpreadingPriority", "weight" : 1},
{"name" : "NodePreferAvoidPodsPriority", "weight" : 1},
{"name" : "NodeAffinityPriority", "weight" : 1},
{"name" : "TaintTolerationPriority", "weight" : 1},
{"name" : "ImageLocalityPriority", "weight" : 1},
{"name" : "SelectorSpreadPriority", "weight" : 1},
{"name" : "InterPodAffinityPriority", "weight" : 1},
{"name" : "EqualPriority", "weight" : 1}
  • LeastRequestedPriority: The node is prioritized based on the fraction of the node that would be free if the new Pod were scheduled onto the node. (In other words, (capacity - sum of requests of all Pods already on the node - request of Pod that is being scheduled) / capacity). CPU and memory are equally weighted. The node with the highest free fraction is the most preferred. Note that this priority function has the effect of spreading Pods across the nodes with respect to resource consumption.

  • CalculateNodeLabelPriority: Prefer nodes that have the specified label.

  • BalancedResourceAllocation: This priority function tries to put the Pod on a node such that the CPU and Memory utilization rate is balanced after the Pod is deployed.

  • CalculateSpreadPriority: Spread Pods by minimizing the number of Pods belonging to the same service on the same node. If zone information is present on the nodes, the priority will be adjusted so that pods are spread across zones and nodes.

  • CalculateAntiAffinityPriority: Spread Pods by minimizing the number of Pods belonging to the same service on nodes with the same value for a particular label.

9.Zjištění limitů ingress nodu

Budeme testovat přetěžování ingress nodu v izolovaném prostředí kde bude jako ingresscontroler sloužit pouze jeden pod a distribuovat zátěž na několik aplikačních cílových podů.
Očekávný stav:
Postupné zpomalování odpovědí, možné HTTP error.
Akceptační kritéria:
Definice limitů pro ingress.
Pracnost:
M

Výsledek:
Testované maximum bylo 4000 kind:Ingress per jeden IngressClass. Při tomto maximu nebyly pozorovány problémy s routerem pro danou IngressClass. Doporučená hodnota RH je 2000 kind:Ingress na jeden ingress controller.

Vyhodnocovací nástroje

Pro vyhodnocení dopadu jednotlivých testovacich scénářů využijeme Cerberus (celkový pohled na cluster) a pak standartní monitorovací nástroje Prometheus/Grafana.

*file: 27-definicePostupuProDR.md *

27. Definice postupu pro DR

Obnova cestou GITOPS

Openshift cluster se nebudeme snažit obnovovat ze zálohy, kompletní obnova spolu s obnovou ETCD by vyžadovala mít i stejnou hardware konvenci a i tak by byla obnova celé ETCD problematická.\ Z tohoto pohledu se jeví jako jednodušší,a hlavně proveditelné, obnovit cluster tak že postavíme nový základ tedy controllplane a přidáme potřebný pool worker nodů. Samotný systémový a aplikační workload obnovíme z příslušných GIT repozitářů.
Je tedy nutné aby aplikace běžící na Openshiftu tento princip dodržovali a všechny jejich definice byly v GITU obsažené.

Workflow v závislosti na Project/Application CRD

Openshift cluster používá applicationOperátor a projectOperátor pro automatické vytváření objektů pro jenotlivé aplikace. Všechny projekty pro cluster jsou uloženy v “projektovém repozitáři” a jsou synchronizovány přez Systémové argoCD do clusteru.

Worflow na základě zjednodušených manifestů:
—> z projektového repozitáře, sync přez ArgoCD sys

apiVersion: ops.csas.cz/v1
kind: Project
metadata:
  name: bokeh 
spec:
  environments:
    - name: lab
      type: lab

—> automaticky vytvořené přez projectOperator na základě project.ops.csas.cz

apiVersion: ops.csas.cz/v1
kind: ProjectEnvironment
metadata:
  labels:
    ops.csas.cz/environment-name: lab
    ops.csas.cz/project: bokeh
  name: bokeh-lab
spec:
  applicationSource:
    path: .
    repoURL: https://github.com/csas-ops/bokeh-ocp4s-apps.git
    targetRevision: env/lab

—> automaticky vytvořené přez projectOperator na základě projectenvironment.ops.csas.cz

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  labels:
    ops.csas.cz/environment-name: lab
    ops.csas.cz/environment-type: lab
    ops.csas.cz/project: bokeh
  name: bokeh-lab
  namespace: csas-argocd-app
spec:
  destinations:
  - namespace: bokeh-lab
    server: https://kubernetes.default.svc

—> automaticky vytvořené přez projectOperator na základě projectenvironment.ops.csas.cz

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  labels:
    ops.csas.cz/environment-name: lab
    ops.csas.cz/project: bokeh
  name: bokeh-lab-apps
  namespace: csas-argocd-app
spec:
  destination:
    namespace: bokeh-lab
    server: https://kubernetes.default.svc
  project: bokeh-lab
  source:
    path: .
    repoURL: https://github.com/csas-ops/bokeh-ocp4s-apps.git
    targetRevision: env/lab

—> definováno v Aplikačním repozitáři na který ukazuje předchozí application.argoproj.io

apiVersion: ops.csas.cz/v1
kind: Application
metadata:
  labels:
    argocd.argoproj.io/instance-app: bokeh-lab-apps
  name: deva-helloworld-be
  namespace: bokeh-lab
spec:
  source:
    chart: helloworld
    helm:
      values: |
        key: value1        
    repoURL: https://artifactory.csin.cz/artifactory/api/helm/bokeh-helm-virtual
    targetRevision: 0.17.0

—> vytvořeno applicationOperatorem na základě application.ops.csas.cz

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  labels:
    application.ops.csas.cz/owner-name: deva-helloworld-be
    application.ops.csas.cz/owner-namespace: bokeh-lab
  name: bokeh-lab-deva-helloworld-be
  namespace: csas-argocd-app
spec:
  destination:
    namespace: bokeh-lab
    server: https://kubernetes.default.svc
  project: bokeh-lab
  source:
    chart: helloworld
    helm:
      values: |
        key: value1        
    repoURL: https://artifactory.csin.cz/artifactory/api/helm/bokeh-helm-virtual
    targetRevision: 0.1.0
gitops diagram

gitops diagram

Popis procesu obnovy

Celá obnova je postavena na principech GITOPS, pro systémovou část může dojít k aplikaci některých objektů v rámci BootStrap fáze. Bootstrap fáze je kompletně skriptovaná.

  • Odstranění původního clusteru. Dostačující je smazání dat disků pro jednotlivé VM například utilitou dd.
  • Instalace nového clusteru
    • použití Ansible playbook instalace
  • Ověření stavu nově nainstalovaného clusteru (běžné ověření funkčnosti)
  • BOOTSTRAPING
    • rekonfigurace(reflektovat změny pro nový cluster, pokud bude znovupoužita stejná konfigurace infrastruktry nemusí se měnit nic) + spuštění shell scriptu běžící proti API, dojde k vytvoření a konfiguraci ARGOCD SYS, které následně vytvoří applikace definované v GITHUB repository
    • příprava a aplikace systémových “secrets” z bezpečného místa
  • ARGOCD SYS: vytvořeno během bootstrapu, aplikuje všechen infrastrukturní workload spolu s komponenty pro ArgoCDAPP
  • ARGOCD APP: sledování procesu množícího se deploymentu v ArgoCD APP \
  • kontrola běhu aplikací Dostačující je zevrubná kontrola běhu, založená na statusu aplikací oproti OC API.
    oc get pods --field-selector status.phase!=Running,status.phase!=Succeeded  --all-namespaces
    
    Bližší kontrola by měla být viditelná z metrik s vazbou na jednotlivé aplikace.

Časová náročnost

Celková náročnost se dá odhadnout na 2-3 hodiny

*file: 28-postupProUgrade.md *

28. Postup pro UPGRADE

vizualizace možných update cest

Obecně se postup pro upgrade clusteru skládá ze dvou částí

  • Cluster Version Operator (CVO) upgrade Postupný upgrade všech podů které definují jednotlivé CVO pro systémovou část Openshiftu. Nad touto částí není možné mít žádnou deklarativní kontrolu a jakmile se spustí dojde k upgrade. Případné problémy se řeší na úrovni jednotlivých operátorů CVO.
    Proto je vhodné upgrade nejdříve otestovat na nižších prostředích a zůstávat u stable upgrade kanálu.
    V této fázi nedochází k restartu žádných nodů.
  • Machine Config Operator (MCO) node updates
    • Cordon and drain all the nodes
    • Update the operating system (OS)
    • Reboot the nodes
    • Uncordon all nodes and schedule workloads on the node
      Default hodnota pro maxUnaviable je jedna takže v jeden okamžik bude updatován pouze jeden nod.

Update channel

Jako update channel bude použit pro všechna prostředí kanál stable

Prerekvizity

Vyřešené konflikty s životním cyklem API zdrojů dle dokumentace RedHat.

Časová náročnost upgrade

**Počítáme s množstvím worker nodů >10. Nastavení MCP pro “.spec.maxUnavailable” bude dle následující tabulky:

MCP rolemaxUnavailable
master1
worker10%
infra1

Nód může být součástí maximálně jednoho poolu a nody z každého poolu se upgradují nezávisle, takže podle našeho nastavení se bude najednou updatovat 1 nod z master MCP, 10% z worker MCP a 1 nod z infra MCP.

Celkový čas pak bude odpovídat součtu času pro CVO(cca 60 minut) a maxima času ze všech poolu. V testovacím clusteru který má 34 nodů (24 worker, 3 master,7 infra) bude tedy celkový čas:

CELKOVY_CAS = (60 + max((10*10),(3*10),(7*10)) ) + bufferzaokrouhlení ~ 200 minut

Zajištění HA pro aplikace

Aplikace které musí mít zajištěno HA během restartu, musí mít nastaven podDistruptionBudget například na minAvailable=1 a musí běžet v replicaSetu > 1.
Pro aplikace běžící v RS=1 nejsme schopni zajistit HA v průběhu upgrade procesu.

Canary Update

Pro upgrade kritických worker nodů lze použít canary update.
Kritický worker nod je nakonfigurován a vlastní prostředky tak jak to ostatní nody nemají, není tedy jednoduše zastupitelný obecným nodem. Zatím nejsou definovány kritické worker nody ale můžeme definovat kritický workload definujicí vlastně tento nód, jako deployment které mají RS=1 nebo prostě nemohou v jeden okamžik běžet ve více replikách. Případně to může být nód na kterém běží workload který vyžaduje velké množství resourců a nebylo by možné tento workload přeshedulovat na jiný nod.

Tento workload nebude stěhován na jiný nód automaticky(nod nebude automaticky update a tedy ani nebude potřeba auto drainu) ale proces přesunu vybraného workloadu bude řízen.

Zároveň pokud nejsme schopni se vejít do servisního okna je vhodné rozdělit pooly na vícero částí a provést upgrade na částech spojitě.
Je ale potřeba brát v potaz že upgrade není dokončen dokud nejsou upradovány všechny nody.

Nody které nechceme updatnout dáme do samostatného “canary MCP”, tento MCO zapauzujeme

oc label node workernode node-role.kubernetes.io/workerpool-canary=
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfigPool
metadata:
  name: workerpool-canary 
spec:
  machineConfigSelector:
    matchExpressions: 
      - {
         key: machineconfiguration.openshift.io/role,
         operator: In,
         values: [worker,workerpool-canary]
        }
  nodeSelector:
    matchLabels:
      node-role.kubernetes.io/workerpool-canary: ""

V této chvíli MCP zapauzujeme a nody v něm obsažené nebudou updatovány

oc patch mcp/workerpool-canary --patch '{"spec":{"paused":true}}' --type=merge

Pustíme update a počkáme až se provede na všech nodech kromě zapauzovaných.
Následně odpauzujeme MCP a update se začne provádět na nodech v tomto poolu

oc patch mcp/workerpool-canary --patch '{"spec":{"paused":false}}' --type=merge

Provedeme test aplikací které sjou vázány na tento kontrétní machineConfig (machineConfigPool).
V případě chyb, provedeme drain a cordon nodů v poolu a donutíme tak aplikaci přesídlit se na jiný nód ve vazbě “taint/tolleration”
Nod pak můžeme vrátit do původního MCP

 oc label node workernode node-role.kubernetes.io/workerpool-canary-

EgressIP worker upgrade

Upgrade může být citlivý u nodů držících EgressIP. Nody držicí egressIP jsou v MCP infra. Při použití OVN Kubernetes CNI pluginu však dochází k automatickému failoveru IP adress na jiný nód labelovaný jako k8s.ovn.org/egress-assignable="" v případě nedostupnosti nodů, tzn třeba jeho restart.

Dosažitelnost EgressIP nodu

Jakmile je nod labelován jako k8s.ovn.org/egress-assignable, EgressIP operator prezentován jako ovnkube-master pod bude periodicky kontrolovat zda je nod použitelný.
EgressIP adresy přidělené nodu který není dosažitelný jsou přesunuty na jiný dosažitelný nod.

Periodická kontrola dostupnosti egres nodu je “hard coded” na periodu 5 sekund.

DR scénář

V případě že se Openshift dostane do stavu nepoužitenosti v rámci upgrade, bude použit DR scénář stejný jako běžný DR scénář popsaný výše v bodě 27.
Tento stav by v rámci upgrade procesu neměl nastat, resp rozhodně to není běžný stav pokud budeme používat stabilní stable upgrade channel

*file: 30-minimalniPocetWorkerNodu.md *

30. Minimální počet worker nodu pro zajištění HA aplikací během upgrade

Minimální počet worker nodu se dá definovat jako 3 , rozprostřeny přez mezi dvěma lokalitami.
Při tomto malém počtu nodů je potřeba při HA upgrade počítat s minimálním množstvím volných resourců jako 1/počet_nodu z celkové kapacity worker poolu (jak CPU tak RAM). Zároveň je potřeba počítat s možností že nějaký workload může vyžadovat velké množství zdrojů které sice v celkovém součtu jsou ale nejsme schopni tento workload naschedulovat na jeden konkrétní nód. Podobný scénář bude vyžadovat servisní zásah a přesun některého workloadu tak aby byl požadované množství zdrojů na jednom nodu uvolněno.

počet worker nodumaxUnavailablevolná kapacita
3 - 911/počet_worker_nodu z celkové kapacity worker poolu
>1010%1/10 celkové kapacity worker poolu

Dá se však říci že pro clutery vyšších prostředí bude vždy množství worker nodů >10 a dále s tím tak budeme počítat.

Upgrade probíhá s nastavením “maxUnavailable=10%” tzn v jeden okamžik bude nedostupný maximálně 10% worker nodů. Zároveň v průběhu upgrade je proveden cordon a drain, tedy je zastaveno schedulování na postižený nody a aplikace jsou bezpečně terminovány a přesunuty na nod jiný.
HA pro aplikace jsme schopni udržet pouze pokud mají nastaven podDistruptionBudget například na minAvailable=1 a musí běžet v replicaSetu > 1.
Pro aplikace běžící v RS=1 nejsme schopni zajistit HA v průběhu upgrade procesu.

Z pohledu upgrade je vhodné držet minimální množství volných zdrojů tak aby byla možnost provést reschedule workloadu na ostatní běžící worker nody v průběhu upgrade. Tzn volná kapacita při stejné velikosti worker nodu by měla být > 10% (vhodnější je spíše 20%) jak pro CPU tak pro paměť.

Pro samotné applikace bude použit defaultně PodTopologySpread scheduler plugin.

defaultConstraints:
  - maxSkew: 3
    topologyKey: "kubernetes.io/hostname"
    whenUnsatisfiable: ScheduleAnyway
  - maxSkew: 5
    topologyKey: "topology.kubernetes.io/zone"
    whenUnsatisfiable: ScheduleAnyway

Aplikace si mohou zároveň definovat vlastní spreadTopologyConstraints na úrovni podAPI, tak aby repliky byly “rovnoměrně” rozprostřeny mezi lokalitami. Pokud má aplikace tento spec nastaven bude mít prioritu před defaultním nastavením scheduleru.
Je třeba říci že je vhodnější pokud by si aplikace nastavovali tento parametr sami jelikož chování scheduler pluginu je značně benevoletní.

kind: Pod
apiVersion: v1
metadata:
  name: mypod
  labels:
    app: part1
spec:
  topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone 
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        app: part1
*file: 46-definicekomponentyLoki.md *

46. Definice komponenty LOKI

*file: 94-centralnitruststore.md *

94. Integrace na centralni trustStore

Potřebné CA certifikáty ve formátu PEM, JKS a jejich provisioning směrem k workloadu.

1. custom CA trust (X509)

certifikáty pro CA trust vloženy do CM

apiVersion: v1
data:
  ca-bundle.crt: |
    # CAIR3 CSAS
    -----BEGIN CERTIFICATE-----
    -----END CERTIFICATE-----

    #CAIMS2
    -----BEGIN CERTIFICATE-----
    -----END CERTIFICATE-----

    #CAIMST2
    -----BEGIN CERTIFICATE-----
    -----END CERTIFICATE-----

    #CAIRT3
    -----BEGIN CERTIFICATE-----
    -----END CERTIFICATE-----    
kind: ConfigMap
metadata:
  name: user-ca-bundle
  namespace: openshift-config

Injekce certifikátu do ConfigMapy:

apiVersion: v1
kind: ConfigMap
metadata:
  name: trusted-ca
  namespace: appnamespace
  labels:
    config.openshift.io/inject-trusted-cabundle: "true"

Takto labelovaná configmapa bude obsahovat jak náš custom trust tak i obecný RH CA trust

Reference v aplikaci:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-example-custom-ca-deployment
  namespace: my-example-custom-ca-ns
spec:
  ...
    spec:
      containers:
        - name: my-container-that-needs-custom-ca
          volumeMounts:
          - name: trusted-ca
            mountPath: /etc/pki/ca-trust/extracted/pem
            readOnly: true
      volumes:
      - name: trusted-ca
        configMap:
          name: trusted-ca
          items:
            - key: ca-bundle.crt
              path: tls-ca-bundle.pem

2. JKS trust

Pro vytvoření JKS trustu z CA trust bundlu využijeme funkcionalitu cert-utils-operatoru který přez interní keystore vytvoří JKS trust z CA trust bundlu a injektne zpátky do configmapy.

apiVersion: v1
kind: ConfigMap
metadata:
  name: trusted-ca
  namespace: appnamespace
  labels:
    config.openshift.io/inject-trusted-cabundle: "true"
  annotations:
    cert-utils-operator.redhat-cop.io/generate-java-truststore: "true"

Configmapa pak vypadá:

apiVersion: v1
kind: ConfigMap
metadata:
  name: trusted-ca
  namespace: appnamespace
  labels:
    config.openshift.io/inject-trusted-cabundle: "true"
  annotations:
    cert-utils-operator.redhat-cop.io/generate-java-truststore: "true"
binaryData:
  truststore.jks: ...
data:
  ca-bundle.crt: ...

Reference v aplikaci pak může vypadat jako:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-example-custom-ca-deployment
  namespace: my-example-custom-ca-ns
spec:
  ...
    spec:
      containers:
        - name: my-container-that-needs-custom-ca
          volumeMounts:
          - name: trusted-ca
            mountPath: /etc/pki/ca-trust/extracted/pem
            readOnly: true
          - mountPath: /etc/pki/ca-trust/extracted/java
            name: jks-trust
            readOnly: true
      volumes:
      - name: trusted-ca
        configMap:
          name: trusted-ca
          items:
            - key: ca-bundle.crt
              path: tls-ca-bundle.pem
      - name: jks-trust
        configMap:
          name: trusted-ca
          items:
            - key: truststore.jks
              path: cacerts

Defaultní heslo pro keystore je changeit. Dá se změnit přez anotaci konfigmapy

annotation:
  cert-utils-operator.redhat-cop.io/java-keystore-password: heslo

Alias pro certifikáty v keystoru je alias.

*file: loki.md *