Oul sau găina: revendicăm IaC

Oul sau găina: revendicăm IaC
Ce a apărut mai întâi — găina sau oul? O început destul de ciudat pentru un articol despre Infrastructure-as-Code, nu-i așa?

Ce este un ou?

Cel mai frecvent, Infrastructure-as-Code (IaC) este un mod declarativ de a reprezenta infrastructura. Aici descriem starea pe care dorim să o obținem, începând de la hardware și terminând cu configurația software-ului. Prin urmare, IaC este folosit pentru:

  1. Furnizarea de resurse. Acestea includ VMs, S3, VPC etc. Principalele instrumente utilizate sunt: Terraform și CloudFormation.
  2. Configurarea software-ului. Principalele instrumente: Ansible, Chef etc.

Oricum, orice cod se află în repozitorii git. Și mai devreme sau mai târziu, liderul de echipă va decide că trebuie să facă ordine în ele. Și va face refactoring. Și va crea o anumită structură. Și va observa că este bine.

De asemenea, este bine că deja există GitLab și GitHub-un provider pentru Terraform (și aceasta este Configurarea software-ului). Cu ajutorul lor, putem gestiona întregul proiect: membri ai echipei, CI/CD, git-flow etc.

De unde a apărut oul?

Iată că ne apropiem treptat de întrebarea principală.

În primul rând, trebuie să începem cu repozitoriul care descrie structura altor repozitorii, inclusiv pe sine. Și, bineînțeles, în cadrul GitOps, trebuie să adăugăm CI pentru ca modificările să fie executate automat.

Dacă Git încă nu a fost creat?

  1. Cum îl stocăm în Git?
  2. Cum integrăm CI?
  3. Dacă desfășurăm și GitLab cu ajutorul IaC, și în plus, în Kubernetes?
  4. Și GitLab Runner în Kubernetes?
  5. Și Kubernetes într-un provider cloud?

Ce a apărut mai întâi: GitLab, în care voi încărca codul meu, sau codul care descrie cum trebuie să fie GitLab-ul meu?

O găină cu ouă

«Oyakodon3 cu un dinozaur» [src]

Să încercăm să preparăm un fel de mâncare, folosind drept provider cloud Managed Kubernetes Selectel.

TL;DR

Se poate să fie toate într-o singură comandă?

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

Ingrediente:

  • Un cont de la my.selectel.ru;
  • Tokenul de la cont;
  • Abilități în Kubernetes;
  • Abilități în Helm;
  • Abilități în Terraform;
  • Chart Helm pentru GitLab;
  • Chart Helm pentru GitLab Runner.

Rețetă:

  1. Obțineți MY_SELECTEL_TOKEN din panou my.selectel.ru.
  2. Creează un cluster Kubernetes, trecând tokenul de la cont.
  3. Obțineți KUBECONFIG de la clusterul creat.
  4. Instalați GitLab în Kubernetes.
  5. Obțineți GitLab-token de la GitLab creat pentru utilizator root.
  6. Creează structura proiectelor în GitLab, folosind GitLab-token.
  7. Împingeți codul existent în GitLab.
  8. ???
  9. Profit!

Pasul 1. Tokenul poate fi obținut în secțiunea Chei API.

Oul sau găina: revendicăm IaCPasul 2. Ne pregătim Terraform-ul pentru „coacerea” cluster-ului din 2 noduri. Dacă sunteți sigur că aveți suficiente resurse pentru toată lumea, atunci puteți activa auto-limitările:

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

Adăugăm utilizatorul în proiect:

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
}

Ieșire:

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
}

Întâi deschidem:

$ 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

Oul sau găina: revendicăm IaC
Pasul 3. Obținem kubecfg.

Pentru a descărca programatic KUBECONFIG, trebuie să obținem un token de la OpenStack:

openstack token issue -c id -f value > token

Și deja cu acest token să facem o cerere către API-ul Managed Kubernetes Selectel. k8s_id returnează terraform:

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

KUBECONFIG poate fi obținut și prin panou.

Oul sau găina: revendicăm IaC
Pasul 4. După ce clusterul s-a creat și avem acces la el, putem adăuga yaml după bunul plac.

Prefer să adaug:

  • namespace,
  • clasa de stocare,
  • politica de securitate a podurilor și altele.

Clasa de Stocare pentru Selectel se poate lua din repository-ul oficial.

Deoarece inițial am ales clusterul în zona ru-3a, atunci și Clasa de Stocare îmi trebuie din această zonă.

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

Pasul 5. Instalăm un balancer de încărcare.

Vom folosi standardul pentru mulți nginx-ingress. Există deja destule instrucțiuni pentru instalarea sa, așa că nu ne vom opri asupra acestui lucru.

$ 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

Așteptăm să obținem IP-ul extern în aproximativ 3-4 minute:

Oul sau găina: revendicăm IaC
Am obținut IP-ul extern:

Oul sau găina: revendicăm IaC
Pasul 6. Instalăm 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"

Așteptăm din nou ca toate podurile să se ridice.

kubectl get po -n gitlab
NUME                                      	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
Așteptând gitlab
./wait_gitlab.sh ../internal/gitlab/gitlab/.pods
așteptând pod...
așteptând pod...
așteptând pod...

Podurile s-au ridicat:

Oul sau găina: revendicăm IaC
Pasul 7. Obținem GitLab-token.

Mai întâi aflăm parola de acces:

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

Acum ne autentificăm și obținem token-ul:

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

Pasul 8. Organizăm repo-urile Git în ierarhia corectă cu ajutorul Gitlab Provider.

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

Din păcate, în providerul GitLab din terraform există un conflict o eroare. Apoi va trebui să ștergem manual proiectele în conflict pentru a repara tf.state. Apoi reporniți comanda `$ make all`

Pasul 9. Transferăm repo-urile locale pe server.

$ make push

[master (root-commit) b61d977]  Commit inițial
 3 fișiere modificate, 46 inserții(+)
 create mode 100644 .gitignore
 create mode 100644 values.yml
Enumerarea obiectelor: 5, finalizată.
Contorizarea obiectelor: 100% (5/5), finalizată.
Compresia delta folosind până la 8 thread-uri
Compresând obiecte: 100% (5/5), finalizată.
Scrierea obiectelor: 100% (5/5), 770 bytes | 770.00 KiB/s, finalizată.
Total 5 (delta 0), reutilizate 0 (delta 0)

Gata:

Oul sau găina: revendicăm IaC
Oul sau găina: revendicăm IaC
Oul sau găina: revendicăm IaC

Concluzie

Am reușit să gestionăm declarativ totul de pe mașina noastră locală. Acum vrem să transferăm toate aceste sarcini în CI și să apăsăm doar butoanele. Pentru aceasta, trebuie să transmitem starea noastră locală (Terraform state) în CI. Despre cum se face acest lucru, în partea următoare.

Abonați-vă la canalul nostru blog, pentru a nu rata publicațiile de articole noi!

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster