
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:
- Ressourcenzuweisung. Dazu gehören VMs, S3, VPC usw. Die wichtigsten Werkzeuge sind: und .
- . Die wichtigsten Werkzeuge: , 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 und -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?
- Wie speichert man es in Git?
- Wie füge ich CI hinzu?
- Wenn wir GitLab ebenfalls mit IaC bereitstellen und es in Kubernetes läuft?
- Und GitLab Runner auch in Kubernetes?
- 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
«3 mit einem Dinosaurier» []
Lass uns versuchen, das Gericht zuzubereiten, indem wir als Cloud-Anbieter verwenden .
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 | bashZutaten:
- 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:
- Erhalte MY_SELECTEL_TOKEN vom Dashboard my.selectel.ru.
- Erstelle ein Kubernetes-Cluster, indem du das Token vom Konto übergibst.
- Erhalte KUBECONFIG vom erstellten Cluster.
- Installiere GitLab in Kubernetes.
- Erhalte GitLab-Token vom erstellten GitLab für den Benutzer. root.
- Erstelle die Projektstruktur in GitLab unter Verwendung des GitLab-Tokens.
- Pushe den vorhandenen Code in GitLab.
- ???
- Gewinn!
Schritt 1. Das Token kann im Bereich .
Schritt 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 
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 > tokenUnd 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.yamlDie Kubeconfig kann auch über das Panel abgerufen werden.

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

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

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


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
