Initial Commit
3
Dockerfile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
FROM nginx:alpine
|
||||||
|
COPY . /usr/share/nginx/html
|
6
archetypes/default.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
title: "{{ replace .Name "-" " " | title }}"
|
||||||
|
date: {{ .Date }}
|
||||||
|
draft: true
|
||||||
|
---
|
||||||
|
|
6
config.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
baseURL: "http://example.org/"
|
||||||
|
languageCode: "en-us"
|
||||||
|
params:
|
||||||
|
landingPageName: "<i class='fas fa-home'></i> About Direktil"
|
||||||
|
theme: "learn"
|
||||||
|
title: "NOVIT's Direktil"
|
6
content/_index.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
Title: Documentation
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
9
content/cli/_index.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
Title: CLI
|
||||||
|
Weight: 50
|
||||||
|
---
|
||||||
|
|
||||||
|
NOVIT met à disposition des outils en ligne de commande faisant partie de la solution Direktil.
|
||||||
|
|
||||||
|
{{% children description="true" %}}
|
||||||
|
|
39
content/cli/dir2config.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
title: dir2config
|
||||||
|
description: Dir2config est un outil en ligne de commande utilisé pour générer la [configuration]({{< ref "configuration" >}}) *config.yaml* acceptée par le [Direktil Local Server]({{< ref "cli/dkl-local-server" >}}).
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dkl-dir2config
|
||||||
|
|
||||||
|
Dir2config est un outil en ligne de commande utilisé pour générer la [configuration]({{< ref "configuration" >}}) *config.yaml* acceptée par le [Direktil Local Server]({{< ref "cli/dkl-local-server" >}}).
|
||||||
|
|
||||||
|
Les sources peuvent être trouvées sur [le repository git de Direktil](https://novit.tech/direktil/local-server).
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone git@novit.tech:direktil/local-server.git
|
||||||
|
cd local-server/cmd/dkl-dir2config
|
||||||
|
go build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Ce outil s'utilise dans un dossier de configuration, et recherche à minima des dossiers *clusters* et *hosts* pour construire la configuration de ces derniers.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./dkl-dir2config
|
||||||
|
|
||||||
|
# Help
|
||||||
|
./dkl-dir2config -h
|
||||||
|
Usage of dkl-dir2config:
|
||||||
|
-debug string
|
||||||
|
debug
|
||||||
|
-in string
|
||||||
|
Source directory (default ".")
|
||||||
|
-out string
|
||||||
|
Output file (default "config.yaml")
|
||||||
|
-template-details-dir string
|
||||||
|
write details of template execute in this dir (default "/tmp/dkl-dir2config")
|
||||||
|
```
|
||||||
|
|
62
content/cli/dkl-local-server.md
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
---
|
||||||
|
title: dkl-local-server
|
||||||
|
description: Dkl-local-server est le nom du service HTTP en charge de la génération des images et couches (*layers*) systèmes. Il a besoin d'un fichier *config.yaml* généré antérieurement par [dir2config]({{< ref "cli/dir2config" >}}).
|
||||||
|
---
|
||||||
|
|
||||||
|
## Direktil-local-server
|
||||||
|
|
||||||
|
Dkl-local-server est le nom du service HTTP en charge de la génération des images et couches (*layers*) systèmes. Il a besoin d'un fichier *config.yaml* généré antérieurement par [dir2config]({{< ref "cli/dir2config" >}}).
|
||||||
|
|
||||||
|
Les sources peuvent être trouvées sur [le repository git de Direktil](https://novit.tech/direktil/local-server).
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
La dernière version de dkl-local-server peut être compilée facilement grâce à un compilateur **go**.
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone git@novit.tech:direktil/local-server.git
|
||||||
|
cd local-server/cmd/dkl-local-server
|
||||||
|
go build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
./dkl-local-server
|
||||||
|
```
|
||||||
|
|
||||||
|
Les paramètres par défaut importants impliquent que :
|
||||||
|
- **/var/lib/direktil** est le dossier data, c'est à dire là où doit se trouver le fichier *config.yaml*
|
||||||
|
- Le port d'écoute par défaut est **7606**
|
||||||
|
|
||||||
|
Ils peuvent être changés via les arguments en ligne de commande.
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
Docker peut être utilisé pour démarrer un dkl-local-server sans avoir à le compiler soi-même. Voici une ligne de commande utilisant le dossier courant comme dossier de configuration (où doit se trouver le fichier *config.yaml*).
|
||||||
|
|
||||||
|
{{< highlight "bash" >}}
|
||||||
|
docker run --rm --net=host --name dls \
|
||||||
|
-v /etc/ssl:/etc/ssl:ro \
|
||||||
|
-v /etc/ca-certificates:/etc/ca-certificates:ro \
|
||||||
|
-v .:/var/lib/direktil \
|
||||||
|
-v /dev:/dev \
|
||||||
|
--privileged \
|
||||||
|
-e http_proxy="$http_proxy" \
|
||||||
|
-e https_proxy="$https_proxy" \
|
||||||
|
-e HTTP_PROXY="$HTTP_PROXY" \
|
||||||
|
-e HTTPS_PROXY="$HTTPS_PROXY" \
|
||||||
|
novit.tech/direktil/local-server:latest
|
||||||
|
{{< / highlight >}}
|
||||||
|
|
||||||
|
### Secret-data
|
||||||
|
|
||||||
|
Dkl-local-server maintient un fichier **secret-data.json** qui sera créé dans le dossier data (par défaut **/var/lib/direktil**) s'il n'est pas trouvé durant un lancement, et qui contient toutes les données sensibles d'une configuration, à savoir :
|
||||||
|
- Certificats CA de clusters et leurs clés privées
|
||||||
|
- Certificats TLS clients/serveurs et leurs clés privées
|
||||||
|
- Clés de ServiceAccount
|
||||||
|
- Tokens (admin, bootstrap, keepalived, etc...)
|
||||||
|
|
||||||
|
{{% notice warning %}}
|
||||||
|
Ce fichier doit, dans l'idéal, être sauvegardé régulièrement et de façon securisée. Sa perte impliquerait la création de nouveaux certificats CA ce qui invaliderait toutes les connexions TLS déjà en place sur d'éventuelles machines en production.
|
||||||
|
{{% /notice %}}
|
17
content/configuration/_index.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
Title: Configuration
|
||||||
|
Weight: 30
|
||||||
|
---
|
||||||
|
|
||||||
|
En tant que solution orientée Infrastructure As Code, Direktil n'est que fait de configuration structurée. Son rôle est de construire des configurations d'hôtes à la volée à partir de ces données.
|
||||||
|
|
||||||
|
![Direktil Configuration](configuration.jpg)
|
||||||
|
|
||||||
|
{{% notice tip %}}
|
||||||
|
Il est conseillé que toute configuration soit gardée dans un dépot git. La fonctionnalité d'[includes]({{< ref "configuration/includes" >}}) permet d'ailleurs l'utilisation du branching git comme stratégie de gestion du code permettant de respecter la méthode "DRY".
|
||||||
|
{{% /notice %}}
|
||||||
|
|
||||||
|
Pour plus d'informations et d'exemples:
|
||||||
|
|
||||||
|
{{% children description="true" %}}
|
||||||
|
|
76
content/configuration/clusters.md
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
---
|
||||||
|
Title: Clusters
|
||||||
|
Description: Un cluster est un groupe d'hosts pouvant être de type différent mais travaillant ensemble dans un même environnement.
|
||||||
|
Weight: 20
|
||||||
|
---
|
||||||
|
|
||||||
|
Les **Clusters** représentent les différents clusters Kubernetes d'une organisation. Ils sont la plupart du temps nommés selon un environnement bien défini, par exemple *prod*, *qual*, *dev*, etc... et permettent la séparation facile des application qui y sont déployées. Il est néanmoins possible de nommer librement ses clusters selon ses objectifs et ses contraintes, comme par exemple selon le nom d'une équipe de développement, d'une large application, etc...
|
||||||
|
|
||||||
|
Les information des clusters sont stockés dans le dossier *clusters*, dans des fichiers yaml séparés selon les noms définis ci-dessus. Ces fichiers peuvent présenter un large nombre de variables permettant d'exprimer les différences entre tous les clusters gérés par la configuration globale. Ces variables vont s'appliquer à tous les [Hosts]({{< relref "configuration/hosts" >}}) déclarés comme faisant partie des-dits clusters, et à l'inverse, il n'est évidemment pas possible d'allouer un *host* à plusieurs *clusters* en même temps.
|
||||||
|
|
||||||
|
{{< highlight yaml >}}
|
||||||
|
domain: cluster.local
|
||||||
|
|
||||||
|
subnets:
|
||||||
|
services: 192.168.48.0/20
|
||||||
|
pods: 192.168.64.0/20
|
||||||
|
|
||||||
|
addons:
|
||||||
|
- essentials
|
||||||
|
|
||||||
|
vars:
|
||||||
|
kubernetes_version: v1.26.4
|
||||||
|
|
||||||
|
bootstrap_auths:
|
||||||
|
- name: "my-user"
|
||||||
|
sshKey: "ssh-ed25519 xxx my-user"
|
||||||
|
|
||||||
|
ssh_keys:
|
||||||
|
- "ssh-ed25519 xxx my-user"
|
||||||
|
|
||||||
|
devname_match: /dev/([shv]da|nmve[0-9]+n[0-9]+)
|
||||||
|
# to match a specific partition (here: 3):
|
||||||
|
#devname_match: /dev/([shv]da|nvme[0-9]+n[0-9]+p)3
|
||||||
|
|
||||||
|
vip_interface: main
|
||||||
|
public_vip: 10.42.0.10
|
||||||
|
|
||||||
|
netmask: 24
|
||||||
|
gateway: 10.42.0.254
|
||||||
|
dns:
|
||||||
|
- 10.42.0.1
|
||||||
|
|
||||||
|
dls_base_url: http://10.42.0.254:7606
|
||||||
|
|
||||||
|
etcd:
|
||||||
|
image: quay.io/coreos/etcd
|
||||||
|
version: v3.5.9
|
||||||
|
cluster_state: new # set to existing to secure existing clusters
|
||||||
|
|
||||||
|
keepalived:
|
||||||
|
image: novitnc/keepalived
|
||||||
|
version: 2.0.19
|
||||||
|
garp_master_refresh: 60
|
||||||
|
router_id: 1
|
||||||
|
|
||||||
|
control_plane:
|
||||||
|
api_port: 6443
|
||||||
|
reserve_resources: true
|
||||||
|
|
||||||
|
iface: "(en|eth).*"
|
||||||
|
containerd_size: 50%FREE
|
||||||
|
|
||||||
|
local_storage_class: local
|
||||||
|
|
||||||
|
encrypt_disks: false
|
||||||
|
|
||||||
|
cni_provider: knet-wg
|
||||||
|
ingress_controller: nginx
|
||||||
|
kube_proxy: proxy
|
||||||
|
|
||||||
|
k8s_registry: registry.k8s.io
|
||||||
|
|
||||||
|
kernel_modules: []
|
||||||
|
|
||||||
|
{{< / highlight >}}
|
||||||
|
|
19
content/configuration/config.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
Title: Configs
|
||||||
|
Description: Type de configuration très détaillé exploitant toutes les variables présentes dans les autres fichiers de configuration de type Infrastructure As Code (clusters et hosts), pour générer un système Direktil valide
|
||||||
|
Weight: 40
|
||||||
|
---
|
||||||
|
|
||||||
|
La *config* est le type de configuration le plus détaillé. Son rôle est de réunir toutes les variables spécifiées au sein des *clusters* et *hosts*, et de permettre la génération finale de systèmes à utiliser sur des machines virtuelles ou physiques.
|
||||||
|
|
||||||
|
La *config* décrit plus spécifiquement ce qui se passe au démarrage d'un système, par exemple
|
||||||
|
- Definir les *layers* du système (dont les versions sont référencées au niveau des {{< relref "configuration/hosts" >}}).
|
||||||
|
- Definir la configuration réseau.
|
||||||
|
- Créer les volumes nécessaire, au moins au premier démarrage.
|
||||||
|
- Créer les fichiers locaux statique, la plupart dans /etc/ (hosts, resolv.conf, sysctl.conf, services...)
|
||||||
|
- Inclure les certificats TLS
|
||||||
|
|
||||||
|
Le fichier de configuration utilise le [Go templating langage](https://pkg.go.dev/text/template) pour garantir un code concis et efficace respectant les préceptes du [DRY](https://fr.wikipedia.org/wiki/Ne_vous_répétez_pas).
|
||||||
|
|
||||||
|
|
||||||
|
|
1
content/configuration/configuration-schema.drawio
Normal file
@ -0,0 +1 @@
|
|||||||
|
<mxfile host="app.diagrams.net" modified="2023-05-07T23:02:24.269Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 OPR/98.0.0.0" etag="cVpR994JltxWoiEmGIby" version="20.2.8" type="device"><diagram id="YTLo56Nh1-BMgYtjPfZ_" name="Page-1">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</diagram></mxfile>
|
BIN
content/configuration/configuration.jpg
Normal file
After Width: | Height: | Size: 45 KiB |
33
content/configuration/hosts.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
Title: Hosts
|
||||||
|
Description: Réunit les variables propres aux rôles des machines prises individuellement.
|
||||||
|
Weight: 10
|
||||||
|
---
|
||||||
|
|
||||||
|
Les fichiers d'**Hosts** décrivent une machine d'un *cluster*, qui peut alors être une machine virtuelle ou physique. Ces fichiers permettent de lier différents types de configurations, en décrivant :
|
||||||
|
|
||||||
|
- Le nom du [cluster]({{< ref "configuration/clusters" >}}) de la machine
|
||||||
|
- Ses informations réseau, sa version de kernel, de layers systèmes, etc...
|
||||||
|
- Toute donnée unique à cette machine propre à son rôle au sein du cluster (par exemple master, compute node, etc...)
|
||||||
|
|
||||||
|
Quand le Direktil Local Server génère sa configuration, il utilise ces liens pour génerer une configuration complète pour chaque machine.
|
||||||
|
|
||||||
|
## Sample
|
||||||
|
|
||||||
|
{{% notice note %}}
|
||||||
|
A noter que toutes données déjà présente dans la configuration de cluster sera héritée par cette configuration. Certaines données ci-dessous sont donc dispensables et affichées par commodité.
|
||||||
|
{{% /notice %}}
|
||||||
|
|
||||||
|
{{< highlight yaml >}}
|
||||||
|
ip: 10.42.0.11
|
||||||
|
cluster: base
|
||||||
|
kernel: 5.15.84
|
||||||
|
versions:
|
||||||
|
init: 2.0.1
|
||||||
|
system: v22.52.0
|
||||||
|
kubernetes: v1.26.4_containerd.1.6.12
|
||||||
|
vars:
|
||||||
|
enable_minio: true
|
||||||
|
(...)
|
||||||
|
{{< / highlight >}}
|
||||||
|
|
53
content/configuration/includes.md
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
---
|
||||||
|
Title: Includes
|
||||||
|
Description: Compatible avec tous les types de fichiers décrits précédemment, ils représentent le meilleur moyen d'appliquer la méthode "DRY" en faisant référence à un autre fichier de référence.
|
||||||
|
Weight: 80
|
||||||
|
---
|
||||||
|
|
||||||
|
Au sein d'une organisation, les différents [clusters]({{< ref "configuration/clusters" >}}) ont la plupart du temps un vaste nombre de métriques en commun. Dans un souci de code "DRY", l'outil [dir2config]({{< ref "cli/dir2config" >}}) gère l'héritage de configurations par le biais d'un mécanisme intitulé "includes", et qui permet comme son nom l'indique d'inclure des fichiers parents depuis des enfants afin d'éviter d'en répéter la configuration sur ceux-ci.
|
||||||
|
|
||||||
|
Les [configurations]({{< ref "configuration" >}}) documentées ici (sauf les [hosts]({{< ref "configuration/hosts" >}}) bien entendu car forcément propres aux clusters) peuvent être définies dans un dossier parent au nom voulu et pouvant être placé n'importe où dans l'arborescence, elles seront alors appliquées par défaut à toutes les configurations. Par convention, il est tout de même conseillé d'utiliser le nom **defaults** pour ce dossier et c'est le nom qui sera utilisé dans la suite de cette documentation. Les différents clusters, hosts et configs du dossier courant pourront alors en hériter automatiquement.
|
||||||
|
|
||||||
|
{{% notice note %}}
|
||||||
|
Le dossier **defaults** PEUT être présent dans un répo git mais ce n'est pas obligatoire.
|
||||||
|
Egalement, il peut être situé dans un endroit totalement différent de l'arborescence et trouvable par dir2config grâce à l'utilisation d'un lien symbolique.
|
||||||
|
{{% /notice %}}
|
||||||
|
|
||||||
|
Voici un exemple commun d'arborescence :
|
||||||
|
|
||||||
|
```
|
||||||
|
./
|
||||||
|
├─ defaults/
|
||||||
|
│ ├─ addons/
|
||||||
|
│ ├─ cert-requests.yaml
|
||||||
|
│ ├─ clusters/
|
||||||
|
│ ├─ configs/
|
||||||
|
│ ├─ hosts/
|
||||||
|
│ ├─ static-pods/
|
||||||
|
│ ├─ ssl-config.json
|
||||||
|
├─ clusters/
|
||||||
|
├─ hosts/
|
||||||
|
├─ includes.yaml ## Ce fichier permet l'appel au dossier defaults
|
||||||
|
```
|
||||||
|
|
||||||
|
Les configurations héritées spécifient alors l'utilisation d'une configuration parente en appelant le dossier **defaults** voulu et la branche git optionnelle, par l'intermédiaire d'un fichier **includes.yaml** :
|
||||||
|
|
||||||
|
```
|
||||||
|
- path: defaults
|
||||||
|
branch: v1.25 ## Optionnel
|
||||||
|
```
|
||||||
|
|
||||||
|
Avec cette configuration, le dossier "defaults" est recherché à la racine du dossier de configuration, ce qui peut être atteignable par un lien symbolique. A la suite de cette spécification, il est possible d'inclure des fichiers grâce à la spécification `#!include` en première ligne de configurations *clusters* et *hosts*.
|
||||||
|
|
||||||
|
Par exemple, le contenu du fichier **clusters/prod.yml** pourrait être :
|
||||||
|
```
|
||||||
|
#!include clusters/metal
|
||||||
|
^--------------- mot clé invariable
|
||||||
|
^-------- nom du dossier à hériter, pouvant être présent localement ou dans le dossier defaults
|
||||||
|
^--- nom du fichier à hériter (omettre l'extension .yaml)
|
||||||
|
|
||||||
|
(... ajout des variables à écraser depuis le parent spécificé ci-dessus ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
Ainsi, avec l'exemple précédent, le fichier **defaults/clusters/metal** dans la branche git v1.25 serait utilisé comme parent avec overwrite des variables enfants.
|
||||||
|
|
12
content/installation/_index.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
Title: Installation
|
||||||
|
Description: Différentes méthodes d'installation de la solution Direktil
|
||||||
|
Weight: 20
|
||||||
|
---
|
||||||
|
|
||||||
|
{{% notice tip %}}
|
||||||
|
Il est conseillé de commencer par le [quick-start]({{< relref "quick-start" >}}) pour profiter d'une installation rapide d'un cluster local. Les méthodes ci-dessous s'adressent aux gestionnaires d'environnements de production ou ceux désireux d'installer la solution par eux-même.
|
||||||
|
{{% /notice %}}
|
||||||
|
|
||||||
|
|
||||||
|
|
162
content/quick-start/_index.md
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
---
|
||||||
|
Title: Quick Start
|
||||||
|
Description: Démarrez votre clusters Kubernetes en quelques étapes simples
|
||||||
|
Weight: 10
|
||||||
|
---
|
||||||
|
|
||||||
|
# Démarrage rapide
|
||||||
|
|
||||||
|
Direktil est un système d'exploitation basé sur Linux Gentoo, généré rapidement et efficacement grâce à de l'[Infrastructure As Code](https://fr.wikipedia.org/wiki/Infrastructure_as_code) (configuration au format Yaml). Ces systèmes permettant la mise à disposition d'un cluster Kubernetes complet, sécurisé, maintenable, sans vendor lock-in, et à destination de machines virtuelles ou des machines bare-metal.
|
||||||
|
|
||||||
|
Ces systèmes sont générés par un ensemble d'outil, notamment le Direktil Local Server, absorbant une configuration de base et générant les images système ainsi que les différents assets nécessaires à un cluster Kubernetes.
|
||||||
|
|
||||||
|
Dans ce quick-start, vous allez intéragir avec ce serveur pour créer votre propre cluster en quelque minutes, dépendamment de la qualité de votre connexion Internet. Nous allons utiliser Qemu localement à notre machine de travail, et des conteneurs Docker. Vous pouvez également vous référer à la [documentation d'installation]({{< relref "installation" >}}) pour plus rentrer dans les détails quant aux options d'installation disponibles.
|
||||||
|
|
||||||
|
## Prérequis
|
||||||
|
|
||||||
|
Pour cette installation rapide, nous allons avoir besoin :
|
||||||
|
- Un système basé sur le noyau Linux 3+
|
||||||
|
- [Docker](https://docs.docker.com/engine/install/)
|
||||||
|
- [Qemu](https://www.qemu.org/download/#linux)
|
||||||
|
- curl
|
||||||
|
|
||||||
|
## TL;DR
|
||||||
|
|
||||||
|
{{< highlight bash >}}
|
||||||
|
git clone git@novit.tech:direktil/config.git
|
||||||
|
cd config
|
||||||
|
|
||||||
|
# A lancer avec l'utilisateur root !
|
||||||
|
sudo ./scripts/0.start_dls.sh # Démarrage du serveur DLS
|
||||||
|
sudo ./scripts/1.qemu.sh # Démarrage de la ou des VMs et du cluster
|
||||||
|
# A lancer avec votre utilisateur local
|
||||||
|
./scripts/2.start_k8s.sh # Création du control plane
|
||||||
|
./scripts/3.install_addons.sh # Installation des additions
|
||||||
|
|
||||||
|
mkdir -p ~/.kube
|
||||||
|
cp secrets/kubeconfig ~/.kube/config
|
||||||
|
{{< /highlight >}}
|
||||||
|
|
||||||
|
## Récupération de la configuration de départ
|
||||||
|
|
||||||
|
Nous avons compilé une configuration suffisante à la plupart des cas de figure, disponible sur notre [repository git](https://novit.tech/direktil/config). Vous pouvez alors soit [télécharger l'archive complète](https://novit.tech/direktil/config/archive/main.tar.gz) comme base de travail, ou alors [cloner le repo directement](git@novit.tech:direktil/config.git).
|
||||||
|
|
||||||
|
A noter que cette configuration de départ présente une installation de cluster mono-noeud (master/compute). Il est tout à fait possible de la modifier pour spécifier 3 noeuds et ainsi avoir un cluster redondant et déjà prod-ready.
|
||||||
|
|
||||||
|
Vous pouvez faire référence à la [documentation de configuration]({{< relref "configuration" >}}) à tout moment pour l'adapter à vos besoins. En deux mots, il suffit juste de créer deux nouveaux fichiers dans le dossier *hosts*.
|
||||||
|
|
||||||
|
{{% notice tip %}}
|
||||||
|
Toutes les commandes qui vont suivre seront exécutées dans le contexte du dossier "config" correspondant à la racine du repo cloné.
|
||||||
|
{{% /notice %}}
|
||||||
|
|
||||||
|
## Modification de la configuration
|
||||||
|
|
||||||
|
Notre configuration est déjà fonctionnelle mais par souci d'automatisation, vous devriez y ajouter votre clé SSH publique afin que vous ayez accès aux VMs une fois créées, sans passer la console Qemu. Pour ce faire, modifiez avec l'éditeur de votre choix le fichier `clusters/base.yaml`, et ajouter les clés SSH dans le yaml `.vars.ssh_keys` :
|
||||||
|
|
||||||
|
{{< highlight bash >}}
|
||||||
|
vars:
|
||||||
|
ssh_keys:
|
||||||
|
- "ssh-ed25519 xxx my-user"
|
||||||
|
{{< /highlight >}}
|
||||||
|
|
||||||
|
Cette clé sera alors ajouté dans le trousseau de clés publiques de l'utilisateur root, vous permettant un accès direct post-installation.
|
||||||
|
|
||||||
|
{{% notice info %}}
|
||||||
|
Vous pouvez ignorer la clé yaml `.vars.bootstrap_auths.sshKey` pour le moment, elle ne sert que pour l'étape de démarrage de l'initrd.
|
||||||
|
{{% /notice %}}
|
||||||
|
|
||||||
|
## Démarrage du Direktil Local Server
|
||||||
|
|
||||||
|
Exécutons notre serveur DLS en étant placé dans notre dossier de configuration cloné.
|
||||||
|
|
||||||
|
{{< highlight bash >}}
|
||||||
|
# A lancer avec l'utilisateur root !
|
||||||
|
sudo ./scripts/0.start_dls.sh
|
||||||
|
{{< /highlight >}}
|
||||||
|
|
||||||
|
Dans ce script, deux outils NOVIT sont utilisés, [dir2config]({{< relref "cli/dir2config" >}}) et [dkl-local-server]({{< relref "cli/dkl-local-server" >}}). Le premier sert à transformer la configuration en un fichier intelligible pour le deuxième, qui lui sera responsable de la création de nos images systèmes et de la maintenance des fichiers secrets (certificats, tokens, etc...)
|
||||||
|
|
||||||
|
## Instanciation d'une machine virtuelle
|
||||||
|
|
||||||
|
{{< highlight bash >}}
|
||||||
|
# A lancer avec l'utilisateur root !
|
||||||
|
sudo ./scripts/1.qemu.sh
|
||||||
|
{{< /highlight >}}
|
||||||
|
|
||||||
|
Cette étape met en place un pont réseau (bridge), récupère les différents éléments nécessaire au démarrage d'une VM (kernel, initrd...) puis la démarre. Vous devriez voir un terminal apparaître si tout s'est bien passé. Lors du premier démarrage, l'étape dit du "bootstrap seed" se connectera au serveur DLS pour récupérations des couches systèmes permettant le démarrage du système complet.
|
||||||
|
|
||||||
|
{{% notice note %}}
|
||||||
|
L'utilisateur local `root` n'a pas de mot de passe spécifié mais ne peut évidemment pas être accessible par protocole SSH.
|
||||||
|
{{% /notice %}}
|
||||||
|
|
||||||
|
## Démarrage du cluster Kubernetes
|
||||||
|
|
||||||
|
Cette étape rapide demande de se connecter aux machines et d'activer le control plane pour démarrer le cluster. Cela ne peut se faire de façon automatisée seulement si vous avez ajouté votre clé SSH à la configuration avant l'installation (voir partie *Modification de la configuration*). La manuelle est disponible ci-dessous dans les autres cas.
|
||||||
|
|
||||||
|
{{< notice info >}}
|
||||||
|
Dans tous les cas, il n'est nécessaire de faire cette opération qu'une seule fois par cluster. Egalement, ces commandes doivent à partir de maintenance être lancées avec votre utilisateur système local et non *root*
|
||||||
|
{{< /notice >}}
|
||||||
|
|
||||||
|
{{< tabs >}}
|
||||||
|
{{% tab name="Automatisée" %}}
|
||||||
|
```bash
|
||||||
|
./scripts/2.start_k8s.sh
|
||||||
|
```
|
||||||
|
{{% /tab %}}
|
||||||
|
{{% tab name="Manuel" %}}
|
||||||
|
Sans connexion SSH, il est possible de d'activer le cluster Kubernetes en utilisant la console Qemu. Le compte à utiliser est "root", sans mot de passe. Y lancer alors les commandes suivantes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
loadkeys fr # Pour passer en clavier AZERTY, si besoin
|
||||||
|
mv /etc/kubernetes/manifests.static/* /var/lib/kubernetes/manifests/
|
||||||
|
```
|
||||||
|
{{% /tab %}}
|
||||||
|
{{< /tabs >}}
|
||||||
|
|
||||||
|
|
||||||
|
## Configuration des additions
|
||||||
|
|
||||||
|
{{< highlight bash >}}
|
||||||
|
./scripts/3.install_addons.sh
|
||||||
|
{{< /highlight >}}
|
||||||
|
|
||||||
|
Dans les addons devant être installés dans le cluster, nous pouvons citer un fournisseur d'overlay réseau, kube-proxy, un contrôleur ingress, un dashboard, un coredns local, etc...
|
||||||
|
|
||||||
|
Un cluster kubernetes sécurisé et fonctionnel nécessite des certificats TLS pour toute communication intra-cluster. Ce rôle de les générer est à majorité celui du DLS, à l'exception de deux certificats, tous deux utilisés par le processus Kubelet de la machine nouvellement installés (voir [TLS Bootstraping](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-tls-bootstrapping/)). Ceux-là sont générés automatiquement au sein de Kubernetes mais nécessitent une approbation manuelle, ce qui est géré par ce script par facilité.
|
||||||
|
|
||||||
|
## Utilisation du cluster
|
||||||
|
|
||||||
|
Lors du démarrage du cluster, un fichier *kubeconfig* a été créé dans le dossier "secrets". Il vous servira à vous connecter avec [kubectl](https://kubernetes.io/fr/docs/tasks/tools/install-kubectl/) ou d'autres outils tiers. Par commodité, il est conseillé de le déplacer dans votre dossier personnel (dans le cas d'un système Linux) pour qu'il doit reconnu et utilisé par défaut.
|
||||||
|
|
||||||
|
{{< highlight bash >}}
|
||||||
|
mkdir -p ~/.kube
|
||||||
|
cp secrets/kubeconfig ~/.kube/config
|
||||||
|
|
||||||
|
kubectl get nodes
|
||||||
|
(...)
|
||||||
|
{{< /highlight >}}
|
||||||
|
|
||||||
|
# Opérations futures
|
||||||
|
|
||||||
|
## Redémarrage des machines virtuelles
|
||||||
|
|
||||||
|
Dans le cas où les VMs ont été éteintes, il suffit de relancer le script de démarrage qemu, cela ne supprimera pas les données précédemment créées.
|
||||||
|
|
||||||
|
{{< highlight bash >}}
|
||||||
|
# A lancer avec l'utilisateur root !
|
||||||
|
sudo ./scripts/1.qemu.sh
|
||||||
|
{{< /highlight >}}
|
||||||
|
|
||||||
|
## Suppression des machines et du cluster
|
||||||
|
|
||||||
|
Pour repartir de zéro sur notre installation, il faut supprimer un ensemble de dossiers avant de relancer la procédure ci-dessus.
|
||||||
|
|
||||||
|
{{% notice warning %}}
|
||||||
|
Les commandes ci-dessous vont supprimer toutes machines virtuelles et clusters kubernetes créés précédemment.
|
||||||
|
{{% /notice %}}
|
||||||
|
|
||||||
|
{{< highlight bash >}}
|
||||||
|
# ATTENTION, CELA SUPPRIMERA TOUTES LES DONNEES
|
||||||
|
rm -rI data secrets kubeconfig
|
||||||
|
{{< /highlight >}}
|
||||||
|
|
21
plan.txt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
About
|
||||||
|
Getting Started
|
||||||
|
Direktil OS
|
||||||
|
Installation:
|
||||||
|
- By container
|
||||||
|
- By building the binary
|
||||||
|
Configuration:
|
||||||
|
- Clusters
|
||||||
|
- Groups
|
||||||
|
- Hosts
|
||||||
|
- Configs
|
||||||
|
- Bootstrap Pods
|
||||||
|
- Addons
|
||||||
|
- TLS configuration
|
||||||
|
- Defaults : Configurations inheritance
|
||||||
|
Maintenance:
|
||||||
|
- Backups
|
||||||
|
- Upgrade
|
||||||
|
CLI:
|
||||||
|
- Dir2config
|
||||||
|
- Direktil Local Server
|
BIN
static/android-chrome-192x192.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
static/android-chrome-512x512.png
Normal file
After Width: | Height: | Size: 95 KiB |
BIN
static/apple-touch-icon.png
Normal file
After Width: | Height: | Size: 24 KiB |
448
static/css/icon-font.css
Normal file
@ -0,0 +1,448 @@
|
|||||||
|
@charset "UTF-8";
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "linea-arrows-10";
|
||||||
|
src:url("fonts/linea-arrows-10.eot");
|
||||||
|
src:url("fonts/linea-arrows-10.eot?#iefix") format("embedded-opentype"),
|
||||||
|
url("fonts/linea-arrows-10.woff") format("woff"),
|
||||||
|
url("fonts/linea-arrows-10.ttf") format("truetype"),
|
||||||
|
url("fonts/linea-arrows-10.svg#linea-arrows-10") format("svg");
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-icon]:before {
|
||||||
|
font-family: "linea-arrows-10" !important;
|
||||||
|
content: attr(data-icon);
|
||||||
|
font-style: normal !important;
|
||||||
|
font-weight: normal !important;
|
||||||
|
font-variant: normal !important;
|
||||||
|
text-transform: none !important;
|
||||||
|
speak: none;
|
||||||
|
line-height: 1;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^="icon-arrows"]:before,
|
||||||
|
[class*=" icon-arrows"]:before {
|
||||||
|
font-family: "linea-arrows-10" !important;
|
||||||
|
font-style: normal !important;
|
||||||
|
font-weight: normal !important;
|
||||||
|
font-variant: normal !important;
|
||||||
|
text-transform: none !important;
|
||||||
|
speak: none;
|
||||||
|
line-height: 1;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-arrows-anticlockwise:before {
|
||||||
|
content: "\e000";
|
||||||
|
}
|
||||||
|
.icon-arrows-anticlockwise-dashed:before {
|
||||||
|
content: "\e001";
|
||||||
|
}
|
||||||
|
.icon-arrows-button-down:before {
|
||||||
|
content: "\e002";
|
||||||
|
}
|
||||||
|
.icon-arrows-button-off:before {
|
||||||
|
content: "\e003";
|
||||||
|
}
|
||||||
|
.icon-arrows-button-on:before {
|
||||||
|
content: "\e004";
|
||||||
|
}
|
||||||
|
.icon-arrows-button-up:before {
|
||||||
|
content: "\e005";
|
||||||
|
}
|
||||||
|
.icon-arrows-check:before {
|
||||||
|
content: "\e006";
|
||||||
|
}
|
||||||
|
.icon-arrows-circle-check:before {
|
||||||
|
content: "\e007";
|
||||||
|
}
|
||||||
|
.icon-arrows-circle-down:before {
|
||||||
|
content: "\e008";
|
||||||
|
}
|
||||||
|
.icon-arrows-circle-downleft:before {
|
||||||
|
content: "\e009";
|
||||||
|
}
|
||||||
|
.icon-arrows-circle-downright:before {
|
||||||
|
content: "\e00a";
|
||||||
|
}
|
||||||
|
.icon-arrows-circle-left:before {
|
||||||
|
content: "\e00b";
|
||||||
|
}
|
||||||
|
.icon-arrows-circle-minus:before {
|
||||||
|
content: "\e00c";
|
||||||
|
}
|
||||||
|
.icon-arrows-circle-plus:before {
|
||||||
|
content: "\e00d";
|
||||||
|
}
|
||||||
|
.icon-arrows-circle-remove:before {
|
||||||
|
content: "\e00e";
|
||||||
|
}
|
||||||
|
.icon-arrows-circle-right:before {
|
||||||
|
content: "\e00f";
|
||||||
|
}
|
||||||
|
.icon-arrows-circle-up:before {
|
||||||
|
content: "\e010";
|
||||||
|
}
|
||||||
|
.icon-arrows-circle-upleft:before {
|
||||||
|
content: "\e011";
|
||||||
|
}
|
||||||
|
.icon-arrows-circle-upright:before {
|
||||||
|
content: "\e012";
|
||||||
|
}
|
||||||
|
.icon-arrows-clockwise:before {
|
||||||
|
content: "\e013";
|
||||||
|
}
|
||||||
|
.icon-arrows-clockwise-dashed:before {
|
||||||
|
content: "\e014";
|
||||||
|
}
|
||||||
|
.icon-arrows-compress:before {
|
||||||
|
content: "\e015";
|
||||||
|
}
|
||||||
|
.icon-arrows-deny:before {
|
||||||
|
content: "\e016";
|
||||||
|
}
|
||||||
|
.icon-arrows-diagonal:before {
|
||||||
|
content: "\e017";
|
||||||
|
}
|
||||||
|
.icon-arrows-diagonal2:before {
|
||||||
|
content: "\e018";
|
||||||
|
}
|
||||||
|
.icon-arrows-down:before {
|
||||||
|
content: "\e019";
|
||||||
|
}
|
||||||
|
.icon-arrows-down-double:before {
|
||||||
|
content: "\e01a";
|
||||||
|
}
|
||||||
|
.icon-arrows-downleft:before {
|
||||||
|
content: "\e01b";
|
||||||
|
}
|
||||||
|
.icon-arrows-downright:before {
|
||||||
|
content: "\e01c";
|
||||||
|
}
|
||||||
|
.icon-arrows-drag-down:before {
|
||||||
|
content: "\e01d";
|
||||||
|
}
|
||||||
|
.icon-arrows-drag-down-dashed:before {
|
||||||
|
content: "\e01e";
|
||||||
|
}
|
||||||
|
.icon-arrows-drag-horiz:before {
|
||||||
|
content: "\e01f";
|
||||||
|
}
|
||||||
|
.icon-arrows-drag-left:before {
|
||||||
|
content: "\e020";
|
||||||
|
}
|
||||||
|
.icon-arrows-drag-left-dashed:before {
|
||||||
|
content: "\e021";
|
||||||
|
}
|
||||||
|
.icon-arrows-drag-right:before {
|
||||||
|
content: "\e022";
|
||||||
|
}
|
||||||
|
.icon-arrows-drag-right-dashed:before {
|
||||||
|
content: "\e023";
|
||||||
|
}
|
||||||
|
.icon-arrows-drag-up:before {
|
||||||
|
content: "\e024";
|
||||||
|
}
|
||||||
|
.icon-arrows-drag-up-dashed:before {
|
||||||
|
content: "\e025";
|
||||||
|
}
|
||||||
|
.icon-arrows-drag-vert:before {
|
||||||
|
content: "\e026";
|
||||||
|
}
|
||||||
|
.icon-arrows-exclamation:before {
|
||||||
|
content: "\e027";
|
||||||
|
}
|
||||||
|
.icon-arrows-expand:before {
|
||||||
|
content: "\e028";
|
||||||
|
}
|
||||||
|
.icon-arrows-expand-diagonal1:before {
|
||||||
|
content: "\e029";
|
||||||
|
}
|
||||||
|
.icon-arrows-expand-horizontal1:before {
|
||||||
|
content: "\e02a";
|
||||||
|
}
|
||||||
|
.icon-arrows-expand-vertical1:before {
|
||||||
|
content: "\e02b";
|
||||||
|
}
|
||||||
|
.icon-arrows-fit-horizontal:before {
|
||||||
|
content: "\e02c";
|
||||||
|
}
|
||||||
|
.icon-arrows-fit-vertical:before {
|
||||||
|
content: "\e02d";
|
||||||
|
}
|
||||||
|
.icon-arrows-glide:before {
|
||||||
|
content: "\e02e";
|
||||||
|
}
|
||||||
|
.icon-arrows-glide-horizontal:before {
|
||||||
|
content: "\e02f";
|
||||||
|
}
|
||||||
|
.icon-arrows-glide-vertical:before {
|
||||||
|
content: "\e030";
|
||||||
|
}
|
||||||
|
.icon-arrows-hamburger1:before {
|
||||||
|
content: "\e031";
|
||||||
|
}
|
||||||
|
.icon-arrows-hamburger-2:before {
|
||||||
|
content: "\e032";
|
||||||
|
}
|
||||||
|
.icon-arrows-horizontal:before {
|
||||||
|
content: "\e033";
|
||||||
|
}
|
||||||
|
.icon-arrows-info:before {
|
||||||
|
content: "\e034";
|
||||||
|
}
|
||||||
|
.icon-arrows-keyboard-alt:before {
|
||||||
|
content: "\e035";
|
||||||
|
}
|
||||||
|
.icon-arrows-keyboard-cmd:before {
|
||||||
|
content: "\e036";
|
||||||
|
}
|
||||||
|
.icon-arrows-keyboard-delete:before {
|
||||||
|
content: "\e037";
|
||||||
|
}
|
||||||
|
.icon-arrows-keyboard-down:before {
|
||||||
|
content: "\e038";
|
||||||
|
}
|
||||||
|
.icon-arrows-keyboard-left:before {
|
||||||
|
content: "\e039";
|
||||||
|
}
|
||||||
|
.icon-arrows-keyboard-return:before {
|
||||||
|
content: "\e03a";
|
||||||
|
}
|
||||||
|
.icon-arrows-keyboard-right:before {
|
||||||
|
content: "\e03b";
|
||||||
|
}
|
||||||
|
.icon-arrows-keyboard-shift:before {
|
||||||
|
content: "\e03c";
|
||||||
|
}
|
||||||
|
.icon-arrows-keyboard-tab:before {
|
||||||
|
content: "\e03d";
|
||||||
|
}
|
||||||
|
.icon-arrows-keyboard-up:before {
|
||||||
|
content: "\e03e";
|
||||||
|
}
|
||||||
|
.icon-arrows-left:before {
|
||||||
|
content: "\e03f";
|
||||||
|
}
|
||||||
|
.icon-arrows-left-double-32:before {
|
||||||
|
content: "\e040";
|
||||||
|
}
|
||||||
|
.icon-arrows-minus:before {
|
||||||
|
content: "\e041";
|
||||||
|
}
|
||||||
|
.icon-arrows-move:before {
|
||||||
|
content: "\e042";
|
||||||
|
}
|
||||||
|
.icon-arrows-move2:before {
|
||||||
|
content: "\e043";
|
||||||
|
}
|
||||||
|
.icon-arrows-move-bottom:before {
|
||||||
|
content: "\e044";
|
||||||
|
}
|
||||||
|
.icon-arrows-move-left:before {
|
||||||
|
content: "\e045";
|
||||||
|
}
|
||||||
|
.icon-arrows-move-right:before {
|
||||||
|
content: "\e046";
|
||||||
|
}
|
||||||
|
.icon-arrows-move-top:before {
|
||||||
|
content: "\e047";
|
||||||
|
}
|
||||||
|
.icon-arrows-plus:before {
|
||||||
|
content: "\e048";
|
||||||
|
}
|
||||||
|
.icon-arrows-question:before {
|
||||||
|
content: "\e049";
|
||||||
|
}
|
||||||
|
.icon-arrows-remove:before {
|
||||||
|
content: "\e04a";
|
||||||
|
}
|
||||||
|
.icon-arrows-right:before {
|
||||||
|
content: "\e04b";
|
||||||
|
}
|
||||||
|
.icon-arrows-right-double:before {
|
||||||
|
content: "\e04c";
|
||||||
|
}
|
||||||
|
.icon-arrows-rotate:before {
|
||||||
|
content: "\e04d";
|
||||||
|
}
|
||||||
|
.icon-arrows-rotate-anti:before {
|
||||||
|
content: "\e04e";
|
||||||
|
}
|
||||||
|
.icon-arrows-rotate-anti-dashed:before {
|
||||||
|
content: "\e04f";
|
||||||
|
}
|
||||||
|
.icon-arrows-rotate-dashed:before {
|
||||||
|
content: "\e050";
|
||||||
|
}
|
||||||
|
.icon-arrows-shrink:before {
|
||||||
|
content: "\e051";
|
||||||
|
}
|
||||||
|
.icon-arrows-shrink-diagonal1:before {
|
||||||
|
content: "\e052";
|
||||||
|
}
|
||||||
|
.icon-arrows-shrink-diagonal2:before {
|
||||||
|
content: "\e053";
|
||||||
|
}
|
||||||
|
.icon-arrows-shrink-horizonal2:before {
|
||||||
|
content: "\e054";
|
||||||
|
}
|
||||||
|
.icon-arrows-shrink-horizontal1:before {
|
||||||
|
content: "\e055";
|
||||||
|
}
|
||||||
|
.icon-arrows-shrink-vertical1:before {
|
||||||
|
content: "\e056";
|
||||||
|
}
|
||||||
|
.icon-arrows-shrink-vertical2:before {
|
||||||
|
content: "\e057";
|
||||||
|
}
|
||||||
|
.icon-arrows-sign-down:before {
|
||||||
|
content: "\e058";
|
||||||
|
}
|
||||||
|
.icon-arrows-sign-left:before {
|
||||||
|
content: "\e059";
|
||||||
|
}
|
||||||
|
.icon-arrows-sign-right:before {
|
||||||
|
content: "\e05a";
|
||||||
|
}
|
||||||
|
.icon-arrows-sign-up:before {
|
||||||
|
content: "\e05b";
|
||||||
|
}
|
||||||
|
.icon-arrows-slide-down1:before {
|
||||||
|
content: "\e05c";
|
||||||
|
}
|
||||||
|
.icon-arrows-slide-down2:before {
|
||||||
|
content: "\e05d";
|
||||||
|
}
|
||||||
|
.icon-arrows-slide-left1:before {
|
||||||
|
content: "\e05e";
|
||||||
|
}
|
||||||
|
.icon-arrows-slide-left2:before {
|
||||||
|
content: "\e05f";
|
||||||
|
}
|
||||||
|
.icon-arrows-slide-right1:before {
|
||||||
|
content: "\e060";
|
||||||
|
}
|
||||||
|
.icon-arrows-slide-right2:before {
|
||||||
|
content: "\e061";
|
||||||
|
}
|
||||||
|
.icon-arrows-slide-up1:before {
|
||||||
|
content: "\e062";
|
||||||
|
}
|
||||||
|
.icon-arrows-slide-up2:before {
|
||||||
|
content: "\e063";
|
||||||
|
}
|
||||||
|
.icon-arrows-slim-down:before {
|
||||||
|
content: "\e064";
|
||||||
|
}
|
||||||
|
.icon-arrows-slim-down-dashed:before {
|
||||||
|
content: "\e065";
|
||||||
|
}
|
||||||
|
.icon-arrows-slim-left:before {
|
||||||
|
content: "\e066";
|
||||||
|
}
|
||||||
|
.icon-arrows-slim-left-dashed:before {
|
||||||
|
content: "\e067";
|
||||||
|
}
|
||||||
|
.icon-arrows-slim-right:before {
|
||||||
|
content: "\e068";
|
||||||
|
}
|
||||||
|
.icon-arrows-slim-right-dashed:before {
|
||||||
|
content: "\e069";
|
||||||
|
}
|
||||||
|
.icon-arrows-slim-up:before {
|
||||||
|
content: "\e06a";
|
||||||
|
}
|
||||||
|
.icon-arrows-slim-up-dashed:before {
|
||||||
|
content: "\e06b";
|
||||||
|
}
|
||||||
|
.icon-arrows-square-check:before {
|
||||||
|
content: "\e06c";
|
||||||
|
}
|
||||||
|
.icon-arrows-square-down:before {
|
||||||
|
content: "\e06d";
|
||||||
|
}
|
||||||
|
.icon-arrows-square-downleft:before {
|
||||||
|
content: "\e06e";
|
||||||
|
}
|
||||||
|
.icon-arrows-square-downright:before {
|
||||||
|
content: "\e06f";
|
||||||
|
}
|
||||||
|
.icon-arrows-square-left:before {
|
||||||
|
content: "\e070";
|
||||||
|
}
|
||||||
|
.icon-arrows-square-minus:before {
|
||||||
|
content: "\e071";
|
||||||
|
}
|
||||||
|
.icon-arrows-square-plus:before {
|
||||||
|
content: "\e072";
|
||||||
|
}
|
||||||
|
.icon-arrows-square-remove:before {
|
||||||
|
content: "\e073";
|
||||||
|
}
|
||||||
|
.icon-arrows-square-right:before {
|
||||||
|
content: "\e074";
|
||||||
|
}
|
||||||
|
.icon-arrows-square-up:before {
|
||||||
|
content: "\e075";
|
||||||
|
}
|
||||||
|
.icon-arrows-square-upleft:before {
|
||||||
|
content: "\e076";
|
||||||
|
}
|
||||||
|
.icon-arrows-square-upright:before {
|
||||||
|
content: "\e077";
|
||||||
|
}
|
||||||
|
.icon-arrows-squares:before {
|
||||||
|
content: "\e078";
|
||||||
|
}
|
||||||
|
.icon-arrows-stretch-diagonal1:before {
|
||||||
|
content: "\e079";
|
||||||
|
}
|
||||||
|
.icon-arrows-stretch-diagonal2:before {
|
||||||
|
content: "\e07a";
|
||||||
|
}
|
||||||
|
.icon-arrows-stretch-diagonal3:before {
|
||||||
|
content: "\e07b";
|
||||||
|
}
|
||||||
|
.icon-arrows-stretch-diagonal4:before {
|
||||||
|
content: "\e07c";
|
||||||
|
}
|
||||||
|
.icon-arrows-stretch-horizontal1:before {
|
||||||
|
content: "\e07d";
|
||||||
|
}
|
||||||
|
.icon-arrows-stretch-horizontal2:before {
|
||||||
|
content: "\e07e";
|
||||||
|
}
|
||||||
|
.icon-arrows-stretch-vertical1:before {
|
||||||
|
content: "\e07f";
|
||||||
|
}
|
||||||
|
.icon-arrows-stretch-vertical2:before {
|
||||||
|
content: "\e080";
|
||||||
|
}
|
||||||
|
.icon-arrows-switch-horizontal:before {
|
||||||
|
content: "\e081";
|
||||||
|
}
|
||||||
|
.icon-arrows-switch-vertical:before {
|
||||||
|
content: "\e082";
|
||||||
|
}
|
||||||
|
.icon-arrows-up:before {
|
||||||
|
content: "\e083";
|
||||||
|
}
|
||||||
|
.icon-arrows-up-double-33:before {
|
||||||
|
content: "\e084";
|
||||||
|
}
|
||||||
|
.icon-arrows-upleft:before {
|
||||||
|
content: "\e085";
|
||||||
|
}
|
||||||
|
.icon-arrows-upright:before {
|
||||||
|
content: "\e086";
|
||||||
|
}
|
||||||
|
.icon-arrows-vertical:before {
|
||||||
|
content: "\e087";
|
||||||
|
}
|
6066
static/css/responsive.css
Normal file
2744
static/css/style.css
Normal file
BIN
static/favicon-16x16.png
Normal file
After Width: | Height: | Size: 542 B |
BIN
static/favicon-32x32.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
static/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
static/favicon.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
static/fonts/Manrope-Bold.woff
Normal file
BIN
static/fonts/Manrope-Bold.woff2
Normal file
BIN
static/fonts/Manrope-ExtraBold.woff
Normal file
BIN
static/fonts/Manrope-ExtraBold.woff2
Normal file
BIN
static/fonts/Manrope-ExtraLight.woff
Normal file
BIN
static/fonts/Manrope-ExtraLight.woff2
Normal file
BIN
static/fonts/Manrope-Light.woff
Normal file
BIN
static/fonts/Manrope-Light.woff2
Normal file
BIN
static/fonts/Manrope-Medium.woff
Normal file
BIN
static/fonts/Manrope-Medium.woff2
Normal file
BIN
static/fonts/Manrope-Regular.woff
Normal file
BIN
static/fonts/Manrope-Regular.woff2
Normal file
BIN
static/fonts/Manrope-SemiBold.woff
Normal file
BIN
static/fonts/Manrope-SemiBold.woff2
Normal file
BIN
static/image/about-banner.png
Normal file
After Width: | Height: | Size: 1002 KiB |
BIN
static/image/blue.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
static/image/card-4-background.png
Normal file
After Width: | Height: | Size: 7.9 KiB |
BIN
static/image/card-img-4.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
static/image/catalyst-icon-1.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
static/image/catalyst-icon-2.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
static/image/catalyst-icon-3.png
Normal file
After Width: | Height: | Size: 1016 B |
BIN
static/image/catalyst-img.png
Normal file
After Width: | Height: | Size: 96 KiB |
BIN
static/image/check-mark.png
Normal file
After Width: | Height: | Size: 342 B |
BIN
static/image/ckeckmark-2.png
Normal file
After Width: | Height: | Size: 291 B |
BIN
static/image/email-icon.png
Normal file
After Width: | Height: | Size: 257 B |
BIN
static/image/footer-logo.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
static/image/freedom-background.png
Normal file
After Width: | Height: | Size: 927 KiB |
BIN
static/image/glove-img.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
static/image/green-and-blue.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/image/green.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
static/image/hero-down.png
Normal file
After Width: | Height: | Size: 949 B |
BIN
static/image/hero-img.png
Normal file
After Width: | Height: | Size: 224 KiB |
BIN
static/image/innovative-border.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
static/image/logo.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
static/image/mobile-responsive.png
Normal file
After Width: | Height: | Size: 79 KiB |
BIN
static/image/novit-background.png
Normal file
After Width: | Height: | Size: 159 KiB |
BIN
static/image/novit.png
Normal file
After Width: | Height: | Size: 106 KiB |
BIN
static/image/orange-and-parpel.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
static/image/orange.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
static/image/perpal.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
static/image/pragmatic-icon-1.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
static/image/pragmatic-icon-2.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
static/image/pragmatic-icon-3.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
static/image/prices-banner.png
Normal file
After Width: | Height: | Size: 309 KiB |
BIN
static/image/reliability-banner.png
Normal file
After Width: | Height: | Size: 748 KiB |
BIN
static/image/text-background.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
static/img/novit-logo.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
1
static/site.webmanifest
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
1
themes/learn
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit e817f53d690d35f181c896e0e320cb40f797e88c
|