Henne oder Ei: Wir knacken IaC

Henne oder Ei: Wir knacken IaC
Was war zuerst da — das Huhn oder das Ei? Ein ziemlich seltsamer Auftakt fĂŒr einen Artikel ĂŒber Infrastructure-as-Code, oder?

Was ist ein Ei?

Meistens ist Infrastructure-as-Code (IaC) eine deklarative Methode zur Darstellung von Infrastruktur. Hier beschreiben wir den Zustand, den wir erreichen möchten, beginnend bei der Hardware bis hin zur Softwarekonfiguration. Daher wird IaC verwendet fĂŒr:

  1. Ressourcenzuteilung. Das sind VMs, S3, VPC usw. Die Hauptwerkzeuge sind: Terraform und CloudFormation.
  2. Softwarekonfiguration. Die Hauptwerkzeuge: Ansible, Chef usw.

Jeder Code befindet sich in Git-Repositorys. Irgendwann wird der Teamleiter entscheiden, dass es Zeit ist, Ordnung in diese zu bringen. Er wird refaktorisieren. Und er wird eine bestimmte Struktur erstellen. Und er wird feststellen, dass das gut ist.

Es ist auch gut, dass es bereits einen GitLab und GitHub-Provider fĂŒr Terraform (und das ist Softwarekonfiguration) gibt. Mit deren Hilfe kann man das gesamte Projekt verwalten: Teammitglieder, CI/CD, Git-Flow usw.

Woher stammt das Ei?

Hier nÀhern wir uns allmÀhlich der zentralen Frage.

Zuerst sollte man mit dem Repository beginnen, das die Struktur anderer Repositories, einschließlich sich selbst, beschreibt. Und natĂŒrlich muss man im Rahmen von GitOps CI hinzufĂŒgen, damit Änderungen automatisch ausgefĂŒhrt werden.

Wenn Git noch nicht erstellt ist?

  1. Wie speichert man es in Git?
  2. Wie fĂŒgt man CI hinzu?
  3. Wenn wir GitLab auch mit IaC bereitstellen und zusÀtzlich in Kubernetes?
  4. Und GitLab Runner ebenfalls in Kubernetes?
  5. Und Kubernetes bei einem Cloud-Anbieter?

Was war zuerst: GitLab, in das ich meinen Code hochlade, oder der Code, der beschreibt, welcher GitLab fĂŒr mich benötigt wird?

Das Huhn mit Eiern

«Oyakodon3 mit einem Dinosaurier» [src]

Lass uns versuchen, ein Gericht zuzubereiten, indem wir als Cloud-Anbieter Managed Kubernetes Selectel.

TL;DR

Kann man das nicht gleich in ein Team zusammenfassen?

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

Zutaten:

  • Ein Konto von my.selectel.ru;
  • Token vom Konto;
  • Kubernetes-Kenntnisse;
  • Helm-Kenntnisse;
  • Terraform-Kenntnisse;
  • Helm-Chart GitLab;
  • Helm-Chart GitLab Runner.

Rezept:

  1. Erhalte MY_SELECTEL_TOKEN ĂŒber das Dashboard my.selectel.ru.
  2. Erstelle einen Kubernetes-Cluster, indem du das Token von deinem Konto ĂŒbergibst.
  3. Erhalte KUBECONFIG vom erstellten Cluster.
  4. Installiere GitLab in Kubernetes.
  5. Erhalte ein GitLab-Token von dem erstellten GitLab fĂŒr den Benutzer. root.
  6. Erstelle eine Projektstruktur in GitLab mit dem GitLab-Token.
  7. Pushe den vorhandenen Code in GitLab.
  8. ???
  9. Gewinn!

Schritt 1. Das Token kann im Abschnitt API-SchlĂŒssel.

Henne oder Ei: Wir knacken IaCSchritt 2. Bereiten wir unser Terraform fĂŒr das "Backen" eines Clusters mit 2 Knoten vor. Wenn du dir sicher bist, dass du genĂŒgend Ressourcen hast, kannst du Auto-Quotas aktivieren:

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",
 }
}

Benutzer zum Projekt hinzufĂŒgen:

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
}

Ausgaben:

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
}

Wir starten:

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

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

Henne oder Ei: Wir knacken IaC
Schritt 3. Wir erhalten die kubectl-Konfiguration.

Um KUBECONFIG programmgesteuert herunterzuladen, muss ein Token von OpenStack erhalten werden:

openstack token issue -c id -f value > token

Und mit diesem Token eine Anfrage an die Managed Kubernetes Selectel API machen. k8s_id gibt aus terraform:

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

Die kubectl-Konfiguration kann auch ĂŒber das Dashboard abgerufen werden.

Henne oder Ei: Wir knacken IaC
Schritt 4. Nachdem der Cluster eingerichtet wurde und wir Zugang dazu haben, können wir dazu passende YAML hinzufĂŒgen.

Ich bevorzuge es, hinzuzufĂŒgen:

  • Namespace,
  • Speicherklasse,
  • Pod-Sicherheitsrichtlinie und weiteres.

Speicherklasse fĂŒr Selectel kann aus dem offiziellen Repository.

Entnommen werden, da ich ursprĂŒnglich einen Cluster in der Zone ru-3a, gewĂ€hlt habe, benötige ich auch die Speicherklasse aus dieser 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:
 Typ: fast.ru-3a
 VerfĂŒgbarkeit: ru-3a
AllowVolumeExpansion: true

Schritt 5. Wir stellen den Lastenausgleich ein.

Wir werden den Standard fĂŒr viele verwenden nginx-ingress. Es gibt bereits genĂŒgend Anleitungen zu seiner Installation, also werden wir an dieser Stelle nicht verweilen.

$ 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

Wir warten, bis er in etwa 3-4 Minuten eine externe IP erhÀlt:

Henne oder Ei: Wir knacken IaC
Externe IP erhalten:

Henne oder Ei: Wir knacken IaC
Schritt 6. Wir installieren 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"

Warten wir erneut, bis alle Pods hochgefahren sind.

kubectl get po -n gitlab
NAME                                      	READY   STATUS  	RESTARTS   ALTER
 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
Warten auf gitlab
./wait_gitlab.sh ../internal/gitlab/gitlab/.pods
Warten auf Pod...
Warten auf Pod...
Warten auf Pod...

Pods gestartet:

Henne oder Ei: Wir knacken IaC
Schritt 7. Wir erhalten das GitLab-Token.

Zuerst erfahren wir das Passwort fĂŒr den Login:

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

Jetzt authentifizieren wir uns und erhalten das Token:

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

Schritt 8. Wir bringen die Git-Repositories in die richtige Hierarchie mit dem Gitlab Provider.

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

Leider gibt es im Terraform GitLab Provider ein schwankendes Fehler. Dann mĂŒssen wir die konfliktbehafteten Projekte manuell löschen, damit der tf.state repariert wird. Starten Sie dann den Befehl `$ make all` erneut.

Schritt 9. Wir ĂŒbertragen die lokalen Repositories auf den Server.

$ make push

[master (root-commit) b61d977]  Erster Commit
 3 Dateien geĂ€ndert, 46 EinfĂŒgungen(+)
 Erstelle Modus 100644 .gitignore
 Erstelle Modus 100644 values.yml
ZĂ€hle Objekte: 5, erledigt.
ZĂ€hle Objekte: 100% (5/5), erledigt.
Delta-Kompression mit bis zu 8 Threads
Komprimieren von Objekten: 100% (5/5), erledigt.
Schreibe Objekte: 100% (5/5), 770 Bytes | 770.00 KiB/s, erledigt.
Insgesamt 5 (Delta 0), wiederverwendet 0 (Delta 0)

Fertig:

Henne oder Ei: Wir knacken IaC
Henne oder Ei: Wir knacken IaC
Henne oder Ei: Wir knacken IaC

Fazit

Wir haben es geschafft, dass wir von unserem lokalen Rechner aus alles deklarativ steuern können. Jetzt möchten wir all diese Aufgaben in die CI ĂŒbertragen und nur noch auf Knöpfe drĂŒcken. DafĂŒr mĂŒssen wir unsere lokalen ZustĂ€nde (Terraform-Zustand) in die CI ĂŒbergeben. Wie das funktioniert, erlĂ€utern wir im nĂ€chsten Abschnitt.

Abonnieren Sie unseren Blog, um die Veröffentlichungen neuer Artikel nicht zu verpassen!

Quelle: habr.com

ZuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz kaufen, VPS VDS Server đŸ”„ ZuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz kaufen, VPS VDS Server - ProHoster