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