
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:
- Ressourcenzuteilung. Das sind VMs, S3, VPC usw. Die Hauptwerkzeuge sind: und .
- . Die Hauptwerkzeuge: , 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 und -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?
- Wie speichert man es in Git?
- Wie fügt man CI hinzu?
- Wenn wir GitLab auch mit IaC bereitstellen und zusätzlich in Kubernetes?
- Und GitLab Runner ebenfalls in Kubernetes?
- 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
«3 mit einem Dinosaurier» []
Lass uns versuchen, ein Gericht zuzubereiten, indem wir als Cloud-Anbieter .
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 | bashZutaten:
- Ein Konto von my.selectel.ru;
- Token vom Konto;
- Kubernetes-Kenntnisse;
- Helm-Kenntnisse;
- Terraform-Kenntnisse;
- Helm-Chart GitLab;
- Helm-Chart GitLab Runner.
Rezept:
- Erhalte MY_SELECTEL_TOKEN über das Dashboard my.selectel.ru.
- Erstelle einen Kubernetes-Cluster, indem du das Token von deinem Konto übergibst.
- Erhalte KUBECONFIG vom erstellten Cluster.
- Installiere GitLab in Kubernetes.
- Erhalte ein GitLab-Token von dem erstellten GitLab für den Benutzer. root.
- Erstelle eine Projektstruktur in GitLab mit dem GitLab-Token.
- Pushe den vorhandenen Code in GitLab.
- ???
- Gewinn!
Schritt 1. Das Token kann im Abschnitt .
Schritt 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 
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 > tokenUnd 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.yamlDie kubectl-Konfiguration kann auch über das Dashboard abgerufen werden.

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.
für Selectel kann aus .
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: trueSchritt 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.ymlWir warten, bis er in etwa 3-4 Minuten eine externe IP erhält:

Externe IP erhalten:

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:

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 --decodeJetzt authentifizieren wir uns und erhalten das Token:
python3 get_gitlab_token.py root $GITLAB_PASSWORD http://gitlab.gitlab.$EXTERNAL_IP.nip.ioSchritt 8. Wir bringen die Git-Repositories in die richtige Hierarchie mit dem Gitlab Provider.
cd ../internal/gitlab/hierarchy && terraform apply -input=false -auto-approve planfileLeider gibt es im Terraform GitLab Provider ein schwankendes . 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:


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 , um die Veröffentlichungen neuer Artikel nicht zu verpassen!
Quelle: habr.com
