Henne oder Ei: Wir knacken IaC

Henne oder Ei: Wir knacken IaC
Was kam zuerst — das Huhn oder das Ei? Ein ziemlich seltsamer Anfang für einen Artikel über Infrastructure-as-Code, nicht wahr?

Was ist ein Ei?

In der Regel ist Infrastructure-as-Code (IaC) ein deklarativer Ansatz zur Darstellung von Infrastruktur. Dabei beschreiben wir den Zustand, den wir erreichen möchten, angefangen von der Hardware bis hin zur Softwarekonfiguration. Deshalb wird IaC verwendet für:

  1. Ressourcenzuweisung. Dazu gehören VMs, S3, VPC usw. Die wichtigsten Werkzeuge sind: Terraform und CloudFormation.
  2. Softwarekonfiguration. Die wichtigsten Werkzeuge: Ansible, Chef usw.

Jeder Code liegt in Git-Repositories. So oder so wird der Teamleiter irgendwann beschließen, Ordnung zu schaffen. Und er wird refaktorisieren. Und er wird eine gewisse Struktur schaffen. Und er wird feststellen, dass das gut ist.

Es ist auch gut, dass es bereits einen GitLab und GitHub-Provider für Terraform gibt (und das ist Softwarekonfiguration). Damit kann das gesamte Projekt verwaltet werden: Teammitglieder, CI/CD, Git-Flow usw.

Woher kommt das Ei?

Nun kommen wir allmählich zur Hauptfrage.

Zuerst müssen wir mit dem Repository beginnen, das die Struktur anderer Repositories beschreibt, einschließlich sich selbst. Und natürlich muss im Rahmen von GitOps CI hinzugefügt werden, damit Änderungen automatisch ausgeführt werden.

Wenn Git noch nicht erstellt wurde?

  1. Wie speichert man es in Git?
  2. Wie füge ich CI hinzu?
  3. Wenn wir GitLab ebenfalls mit IaC bereitstellen und es in Kubernetes läuft?
  4. Und GitLab Runner auch in Kubernetes?
  5. Und Kubernetes beim Cloud-Anbieter?

Was kam zuerst: GitLab, in das ich meinen Code hochlade, oder der Code, der beschreibt, wie GitLab aussehen soll?

Das Huhn mit den Eiern

«Oyakodon3 mit einem Dinosaurier» [src]

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

TL;DR

Kann es auch direkt in einem Befehl sein?

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

Zutaten:

  • Konto von my.selectel.ru;
  • Token vom Konto;
  • Kubernetes-Fähigkeiten;
  • Helm-Fähigkeiten;
  • Terraform-Fähigkeiten;
  • Helm-Chart GitLab;
  • Helm-Chart GitLab Runner.

Rezept:

  1. Erhalte MY_SELECTEL_TOKEN vom Dashboard my.selectel.ru.
  2. Erstelle ein Kubernetes-Cluster, indem du das Token vom Konto übergibst.
  3. Erhalte KUBECONFIG vom erstellten Cluster.
  4. Installiere GitLab in Kubernetes.
  5. Erhalte GitLab-Token vom erstellten GitLab für den Benutzer. root.
  6. Erstelle die Projektstruktur in GitLab unter Verwendung des GitLab-Tokens.
  7. Pushe den vorhandenen Code in GitLab.
  8. ???
  9. Gewinn!

Schritt 1. Das Token kann im Bereich API-Schlüssel.

Henne oder Ei: Wir knacken IaCSchritt 2. Bereiten wir unser Terraform vor, um ein Cluster aus 2 Knoten zu 'backen'. Wenn du sicher bist, dass du genügend Ressourcen hast, kannst du die Auto-Quota 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",
 }
}

Fügen Sie einen Benutzer zum Projekt hinzu:

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
}

Ausgabe:

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
}

Starte:

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

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

Henne oder Ei: Wir knacken IaC
Schritt 3. Wir erhalten die Kubeconfig.

Um KUBECONFIG programmgesteuert herunterzuladen, müssen Sie ein Token von OpenStack erhalten:

openstack token issue -c id -f value > token

Und mit diesem Token eine Anfrage an die Managed Kubernetes Selectel API stellen. 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 Kubeconfig kann auch über das Panel abgerufen werden.

Henne oder Ei: Wir knacken IaC
Schritt 4. Nachdem der Cluster bereitgestellt wurde und wir Zugriff darauf haben, können wir YAML nach Belieben hinzufügen.

Ich bevorzuge es, Folgendes hinzuzufügen:

  • namespace,
  • Speicherklasse,
  • Pod-Sicherheitsrichtlinie und andere.

Storage Class Für Selectel können Sie aus dem offiziellen Repository auswählen..

Da ich ursprünglich einen Cluster in der Zone ru-3a, benötige ich auch die Storage-Klasse 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:
 type: fast.ru-3a
 availability: ru-3a
allowVolumeExpansion: true

Schritt 5. Wir setzen einen Lastenausgleich auf.

Wir werden den Standard für viele verwenden nginx-ingress. Es gibt bereits genügend Anleitungen zur Installation, daher halten wir damit nicht auf.

$ 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 eine externe IP erhält, in etwa 3-4 Minuten:

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"

Wir warten erneut, bis alle Pods hochfahren.

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
Warte auf gitlab
./wait_gitlab.sh ../internal/gitlab/gitlab/.pods
warte auf Pod...
warte auf Pod...
warte auf Pod...

Pods sind gestartet:

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

Zuerst erhalten wir das Passwort für den Zugang:

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. Bringen Sie die Git-Repositories in die richtige Hierarchie mit Gitlab Provider.

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

Leider gibt es im Terraform GitLab Provider ein fluktuierendes Problem. FehlerDann müssen konfliktierende Projekte manuell entfernt werden, damit tf.state repariert wird. Starten Sie dann den Befehl `$ make all` neu.

Schritt 9Wir übertragen lokale Repositories auf den Server.

$ make push

[master (root-commit) b61d977]  Erster Commit
 3 Dateien geändert, 46 Einfügungen(+)
 Erstellen des Modus 100644 .gitignore
 Erstellen des Modus 100644 values.yml
Objekte werden aufgezählt: 5, erledigt.
Objekte zählen: 100% (5/5), erledigt.
Delta-Komprimierung mit bis zu 8 Threads
Objekte komprimieren: 100% (5/5), erledigt.
Objekte schreiben: 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 deklarativ alles verwalten können. Nun möchten wir all diese Aufgaben in CI übertragen und nur noch Knöpfe drücken. Dazu müssen wir unsere lokalen Zustände (Terraform state) in CI übertragen. Wie das geht, erfahren Sie im nächsten Abschnitt.

Abonnieren Sie unseren блог, um keine neuen Artikel zu verpassen!

Quelle: habr.com

Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen 🔥 Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen | ProHoster