La poule ou l’œuf : diviser l’IaC

La poule ou l’œuf : diviser l’IaC
Qu'est-ce qui est arrivé en premier : la poule ou l'œuf ? Un début assez étrange pour un article sur l’Infrastructure-as-Code, n’est-ce pas ?

Qu'est-ce qu'un œuf ?

Le plus souvent, Infrastructure-as-Code (IaC) est une manière déclarative de représenter l'infrastructure. Nous y décrivons l'état que nous souhaitons atteindre, en commençant par la partie matérielle et en terminant par la configuration logicielle. Par conséquent, IaC est utilisé pour :

  1. Mise à disposition des ressources. Ce sont des VM, S3, VPC, etc. Outils de base pour le travail : Terraform и Formation Nuage.
  2. Configuration logicielle. Outils de base : Ansible, Cuisinier, etc.

Tout code se trouve dans les référentiels git. Et tôt ou tard, le chef d'équipe décidera qu'il faut les remettre en ordre. Et il va refactoriser. Et cela créera une certaine structure. Et il verra que c'est bien.

C'est bien aussi que ça existe déjà gitlab ce и GitHub-provider pour Terraform (et ceci est la configuration logicielle). Avec leur aide, vous pouvez gérer l'ensemble du projet : membres de l'équipe, CI/CD, git-flow, etc.

D'où vient l'œuf ?

Nous approchons donc progressivement de la question principale.

Tout d’abord, vous devez commencer par un référentiel qui décrit la structure d’autres référentiels, y compris vous-même. Et bien sûr, dans le cadre de GitOps, vous devez ajouter CI pour que les modifications soient exécutées automatiquement.

Si Git n’a pas encore été créé ?

  1. Comment le stocker dans Git ?
  2. Comment installer CI ?
  3. Si on déployait aussi Gitlab en utilisant IaC, et même en Kubernetes ?
  4. Et GitLab Runner également dans Kubernetes ?
  5. Qu’en est-il de Kubernetes chez le fournisseur de cloud ?

Qu'est-ce qui est venu en premier : le GitLab où je vais télécharger mon code, ou le code qui décrit le type de GitLab dont j'ai besoin ?

Poulet aux oeufs

«Oyakodon3 avec un dinosaure" [src]

Essayons de cuisiner un plat en utilisant comme fournisseur de cloud Kubernetes Selectel géré.

TL; DR

Est-il possible de rejoindre une équipe à la fois ?

$ export MY_SELECTEL_TOKEN=<token>
$ curl https://gitlab.com/chicken-or-egg/mks/make/-/snippets/2002106/raw | bash

Ingrédients:

  • Compte de my.selectel.ru ;
  • Jeton de compte ;
  • Compétences Kubernetes ;
  • Compétences de barre ;
  • Compétences en terraformation ;
  • Graphique de barre GitLab ;
  • Graphique de barre GitLab Runner.

Recette:

  1. Obtenez MY_SELECTEL_TOKEN à partir du panneau mon.selectel.ru.
  2. Créez un cluster Kubernetes en y transférant un jeton de compte.
  3. Récupérez KUBECONFIG à partir du cluster créé.
  4. Installez GitLab sur Kubernetes.
  5. Obtenez le jeton GitLab de GitLab créé pour l'utilisateur racine.
  6. Créez une structure de projet dans GitLab à l'aide du jeton GitLab.
  7. Transférez le code existant vers GitLab.
  8. Vous pouvez télécharger toutes les images dont vous avez besoin à partir du serveur de la caméra, de l'application ou du logiciel.
  9. Profit!

Étape 1. Le jeton peut être obtenu dans la section Clés API.

La poule ou l’œuf : diviser l’IaCÉtape 2. Nous préparons notre Terraform pour « cuire » un cluster de 2 nœuds. Si vous êtes sûr de disposer de suffisamment de ressources pour tout, vous pouvez activer les quotas automatiques :

provider "selectel" {
 token = var.my_selectel_token
}

variable "my_selectel_token" {}
variable "username" {}
variable "region" {}


resource "selectel_vpc_project_v2" "my-k8s" {
 name = "my-k8s-cluster"
 theme = {
   color = "269926"
 }
 quotas {
   resource_name = "compute_cores"
   resource_quotas {
     region = var.region
     zone = "${var.region}a"
     value = 16
   }
 }
 quotas {
   resource_name = "network_floatingips"
   resource_quotas {
     region = var.region
     value = 1
   }
 }
 quotas {
   resource_name = "load_balancers"
   resource_quotas {
     region = var.region
     value = 1
   }
 }
 quotas {
   resource_name = "compute_ram"
   resource_quotas {
     region = var.region
     zone = "${var.region}a"
     value = 32768
   }
 }
 quotas {
   resource_name = "volume_gigabytes_fast"
   resource_quotas {
     region = var.region
     zone = "${var.region}a"
     # (20 * 2) + 50 + (8 * 3 + 10)
     value = 130
   }
 }
}

resource "selectel_mks_cluster_v1" "k8s-cluster" {
 name         = "k8s-cluster"
 project_id   = selectel_vpc_project_v2.my-k8s.id
 region       = var.region
 kube_version = "1.17.9"
}

resource "selectel_mks_nodegroup_v1" "nodegroup_1" {
 cluster_id        = selectel_mks_cluster_v1.k8s-cluster.id
 project_id        = selectel_mks_cluster_v1.k8s-cluster.project_id
 region            = selectel_mks_cluster_v1.k8s-cluster.region
 availability_zone = "${var.region}a"
 nodes_count       = 2
 cpus              = 8
 ram_mb            = 16384
 volume_gb         = 15
 volume_type       = "fast.${var.region}a"
 labels            = {
   "project": "my",
 }
}

Ajoutez un utilisateur au projet :

resource "random_password" "my-k8s-user-pass" {
 length = 16
 special = true
 override_special = "_%@"
}

resource "selectel_vpc_user_v2" "my-k8s-user" {
 password = random_password.my-k8s-user-pass.result
 name = var.username
 enabled  = true
}

resource "selectel_vpc_keypair_v2" "my-k8s-user-ssh" {
 public_key = file("~/.ssh/id_rsa.pub")
 user_id    = selectel_vpc_user_v2.my-k8s-user.id
 name = var.username
}

resource "selectel_vpc_role_v2" "my-k8s-role" {
 project_id = selectel_vpc_project_v2.my-k8s.id
 user_id    = selectel_vpc_user_v2.my-k8s-user.id
}

Données de sortie:

output "project_id" {
 value = selectel_vpc_project_v2.my-k8s.id
}

output "k8s_id" {
 value = selectel_mks_cluster_v1.k8s-cluster.id
}

output "user_name" {
 value = selectel_vpc_user_v2.my-k8s-user.name
}

output "user_pass" {
 value = selectel_vpc_user_v2.my-k8s-user.password
}

Lançons :

$ env 
TF_VAR_region=ru-3 
TF_VAR_username=diamon 
TF_VAR_my_selectel_token=<token> 
terraform plan -out planfile

$ terraform apply -input=false -auto-approve planfile

La poule ou l’œuf : diviser l’IaC
Étape 3. Nous obtenons le cubeconfig.

Pour télécharger KUBECONFIG par programme, vous devez obtenir un jeton d'OpenStack :

openstack token issue -c id -f value > token

Et avec ce jeton, faites une demande à l'API Managed Kubernetes Selectel. k8s_id donne terraform:

curl -XGET -H "x-auth-token: $(cat token)" "https://ru-3.mks.selcloud.ru/v1/clusters/$(cat k8s_id)/kubeconfig" -o kubeConfig.yaml

Cupconfig est également accessible via le panneau.

La poule ou l’œuf : diviser l’IaC
Étape 4. Une fois que le cluster est cuit et que nous y avons accès, nous pouvons ajouter du yaml dessus au goût.

Je préfère ajouter :

  • espace de noms,
  • classe de stockage
  • politique de sécurité du pod, etc.

Classe de stockage pour Selectel peut être extrait de dépôt officiel.

Depuis que j'ai initialement sélectionné un cluster dans la zone ru-3a, alors j'ai besoin de la classe de stockage de cette zone.

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
 name: fast.ru-3a
 annotations:
   storageclass.kubernetes.io/is-default-class: "true"
provisioner: cinder.csi.openstack.org
parameters:
 type: fast.ru-3a
 availability: ru-3a
allowVolumeExpansion: true

Étape 5. Installez un équilibreur de charge.

Nous utiliserons le modèle standard pour de nombreux nginx-entrée. Il existe déjà de nombreuses instructions pour l’installer, nous ne nous y attarderons donc pas.

$ helm repo add nginx-stable https://helm.nginx.com/stable
$ helm upgrade nginx-ingress nginx-stable/nginx-ingress -n ingress --install -f ../internal/K8S-cluster/ingress/values.yml

Nous attendons qu'il reçoive une IP externe pendant environ 3-4 minutes :

La poule ou l’œuf : diviser l’IaC
IP externe reçue :

La poule ou l’œuf : diviser l’IaC
Étape 6. Installez GitLab.

$ helm repo add gitlab https://charts.gitlab.io
$ helm upgrade gitlab gitlab/gitlab -n gitlab  --install -f gitlab/values.yml --set "global.hosts.domain=gitlab.$EXTERNAL_IP.nip.io"

Encore une fois, nous attendons que toutes les cosses se lèvent.

kubectl get po -n gitlab
NAME                                      	READY   STATUS  	RESTARTS   AGE
gitlab-gitaly-0                           	0/1 	Pending 	0      	0s
gitlab-gitlab-exporter-88f6cc8c4-fl52d    	0/1 	Pending 	0      	0s
gitlab-gitlab-runner-6b6867c5cf-hd9dp     	0/1 	Pending 	0      	0s
gitlab-gitlab-shell-55cb6ccdb-h5g8x       	0/1 	Init:0/2	0      	0s
gitlab-migrations.1-2cg6n                 	0/1 	Pending 	0      	0s
gitlab-minio-6dd7d96ddb-zd9j6             	0/1 	Pending 	0      	0s
gitlab-minio-create-buckets.1-bncdp       	0/1 	Pending 	0      	0s
gitlab-postgresql-0                       	0/2 	Pending 	0      	0s
gitlab-prometheus-server-6cfb57f575-v8k6j 	0/2 	Pending 	0      	0s
gitlab-redis-master-0                     	0/2 	Pending 	0      	0s
gitlab-registry-6bd77b4b8c-pb9v9          	0/1 	Pending 	0      	0s
gitlab-registry-6bd77b4b8c-zgb6r          	0/1 	Init:0/2	0      	0s
gitlab-shared-secrets.1-pc7-5jgq4         	0/1 	Completed   0      	20s
gitlab-sidekiq-all-in-1-v1-54dbcf7f5f-qbq67   0/1 	Pending 	0      	0s
gitlab-task-runner-6fd6857db7-9x567       	0/1 	Pending 	0      	0s
gitlab-webservice-d9d4fcff8-hp8wl         	0/2 	Pending 	0      	0s
Waiting gitlab
./wait_gitlab.sh ../internal/gitlab/gitlab/.pods
waiting for pod...
waiting for pod...
waiting for pod...

Les cosses se sont levées :

La poule ou l’œuf : diviser l’IaC
Étape 7. Nous recevons le jeton GitLab.

Tout d'abord, recherchez le mot de passe de connexion :

kubectl get secret -n gitlab gitlab-gitlab-initial-root-password -o jsonpath='{.data.password}' | base64 --decode

Maintenant, connectons-nous et obtenons un jeton :

python3 get_gitlab_token.py root $GITLAB_PASSWORD http://gitlab.gitlab.$EXTERNAL_IP.nip.io

Étape 8. Amener les référentiels Git à la hiérarchie correcte à l'aide du fournisseur Gitlab.

cd ../internal/gitlab/hierarchy && terraform apply -input=false -auto-approve planfile

Malheureusement, le fournisseur Terraform GitLab a un flottant bug. Ensuite, vous devrez supprimer manuellement les projets en conflit pour que tf.state soit corrigé. Puis réexécutez la commande `$make all`

Étape 9. Nous transférons les référentiels locaux sur le serveur.

$ make push

[master (root-commit) b61d977]  Initial commit
 3 files changed, 46 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 values.yml
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 770 bytes | 770.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0)

Fait:

La poule ou l’œuf : diviser l’IaC
La poule ou l’œuf : diviser l’IaC
La poule ou l’œuf : diviser l’IaC

Conclusion

Nous avons réussi à tout gérer de manière déclarative à partir de notre machine locale. Maintenant, je veux transférer toutes ces tâches vers CI et appuyer simplement sur des boutons. Pour ce faire, nous devons transférer nos états locaux (état Terraform) vers CI. Comment procéder est dans la partie suivante.

Abonnez-vous à notre Blogpour ne pas rater la sortie de nouveaux articles !

Source: habr.com

Ajouter un commentaire