Poulet ou œuf: fractionnement IaC



Lequel est venu en premier - une poule ou un œuf? Un début assez étrange pour un article sur 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 voulons obtenir, en commençant par la partie en fer, en terminant par la configuration logicielle. Par conséquent, IaC est utilisé pour:



  1. Fourniture de ressources. Ce sont des VM, S3, VPC, etc. Outils de base pour le travail: Terraform et CloudFormation .
  2. Configuration du logiciel . Outils de base: Ansible , Chef, etc.


Tout code se trouve dans des référentiels git. Et tôt ou tard, le chef d'équipe décidera qu'il serait nécessaire de mettre les choses en ordre en eux. Et ça va refactoriser. Et cela créera une structure. Et il verra que c'est bien.



Il est également bon qu'il existe déjà un fournisseur GitLab et GitHub pour Terraform (et c'est une 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 arrivons donc progressivement à la question principale.



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



Si Git n'a pas encore été construit?



  1. Comment le stocker dans Git?
  2. Comment visser CI?
  3. Si nous déployons également Gitlab en utilisant IaC, et même dans Kubernetes?
  4. Et GitLab Runner est également sur Kubernetes?
  5. Qu'en est-il de Kubernetes dans un fournisseur de cloud?


Lequel est venu en premier: GitLab, où je vais télécharger mon code, ou un code décrivant de quel GitLab j'ai besoin?


Poulet aux oeufs



« Dinosaure Oyakodon 3 » [ src ]



Essayons de cuisiner un plat en utilisant Managed Kubernetes Selectel en tant que fournisseur de cloud .



TL; DR



Est-il possible de le faire immédiatement et en une seule équipe?



$ 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 du compte;
  • Compétences Kubernetes;
  • Compétences de barre;
  • Compétences Terraform;
  • Helm chart GitLab;
  • Helm chart GitLab Runner.


Recette:



  1. Obtenez MY_SELECTEL_TOKEN à partir du panneau my.selectel.ru .
  2. Créez un cluster Kubernetes en transférant le jeton du compte vers celui-ci.
  3. Obtenez KUBECONFIG à partir du cluster créé.
  4. Installez GitLab sur Kubernetes.
  5. Obtenez le jeton GitLab à partir du GitLab généré pour l' utilisateur root .
  6. Créez une structure de projet dans GitLab à l'aide du jeton GitLab.
  7. Poussez le code existant vers GitLab.
  8. ???
  9. Profit!


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



Étape 2 . Nous préparons notre Terraform pour la cuisson d'un cluster de 2 nœuds. Si vous êtes sûr de disposer de suffisamment de ressources pour tous, 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",
 }
}


Ajouter 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
}


Production:



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
}


Lancement:



$ 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




Étape 3 . Nous obtenons kubconfig.



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 produit terraform :



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


Cubconfig peut également être obtenu via le panneau.





Étape 4 . Une fois que le cluster est cuit et que nous y avons accès, nous pouvons ajouter yaml par-dessus à notre goût.



Je préfère ajouter:



  • espace de noms,
  • classe de stockage,
  • politique de sécurité du pod et plus encore.


La classe de stockage pour Selectel peut être extraite du référentiel officiel .



Depuis que j'ai initialement sélectionné un cluster dans la zone ru-3a , j'ai également besoin d'une 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 . Nous installons un équilibreur de charge.



Nous utiliserons le standard nginx-ingress pour beaucoup . Il existe déjà de nombreuses instructions pour l'installer, alors ne nous attardons pas là-dessus.



$ 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 adresse IP externe pendant environ 3-4 minutes:





IP externe reçue:





É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"


Nous attendons à nouveau que toutes les gousses 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 pods sont montés:





Étape 7 . Nous obtenons le jeton GitLab.



Tout d'abord, nous trouvons le mot de passe à saisir:



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


Maintenant, connectons-nous et récupérons le 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 bonne hiérarchie à l'aide du fournisseur Gitlab.



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


Malheureusement, le fournisseur terraform GitLab a un bogue flottant . Ensuite, vous devez supprimer manuellement les projets en conflit pour que tf.state soit réparé. Puis relancez la commande `$ make all`


Étape 9 . Nous transférons les référentiels locaux vers 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)


Terminé:











Conclusion



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



Abonnez-vous à notre blog pour ne manquer aucun nouvel article!



All Articles