Pollo o huevo: dividir IaC



¿Qué fue primero, un huevo o una gallina? Un comienzo bastante extraño para un artículo sobre Infraestructura como código, ¿no?



¿Qué es un huevo?



Muy a menudo, Infraestructura como código (IaC) es una forma declarativa de representar la infraestructura. En él describimos el estado que queremos obtener, comenzando por la parte de hierro, terminando con la configuración del software. Por tanto, IaC se utiliza para:



  1. Provisión de recursos. Se trata de VM, S3, VPC, etc. Herramientas básicas para el trabajo: Terraform y CloudFormation .
  2. Configuración de software . Herramientas básicas: Ansible , Chef, etc.


Cualquier código está en repositorios de git. Y tarde o temprano el líder del equipo decidirá que sería necesario poner las cosas en orden en ellos. Y se refactorizará. Y creará alguna estructura. Y verá que está bien.



También es bueno que ya exista un proveedor de GitLab y GitHub para Terraform (y esa es una configuración de software). Con su ayuda, puede administrar todo el proyecto: miembros del equipo, CI / CD, git-flow, etc.



¿De dónde vino el huevo?



Así llegamos gradualmente a la cuestión principal.



En primer lugar, debe comenzar con un repositorio, que describe la estructura de otros repositorios, incluido usted mismo. Y, por supuesto, dentro de GitOps, debe agregar un CI para que los cambios se ejecuten automáticamente.



¿Si Git aún no se ha construido?



  1. ¿Cómo lo guardo en Git?
  2. ¿Cómo atornillar CI?
  3. ¿Si también desplegamos Gitlab usando IaC, e incluso en Kubernetes?
  4. ¿Y GitLab Runner también está en Kubernetes?
  5. ¿Qué pasa con Kubernetes en un proveedor de nube?


¿Qué fue primero: GitLab, donde cargaré mi código, o el código que describe qué GitLab necesito?


Pollo con huevos



" Dinosaurio Oyakodon 3 » [ src ]



Intentemos cocinar un plato utilizando Managed Kubernetes Selectel como proveedor en la nube .



TL; DR



¿Es posible de inmediato y en un solo equipo?



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




Ingredientes:



  • Cuenta de my.selectel.ru;
  • Token de la cuenta;
  • Habilidades de Kubernetes;
  • Habilidades de timón;
  • Habilidades de terraform;
  • Gráfico de timón GitLab;
  • Gráfico de timón GitLab Runner.


Receta:



  1. Obtenga MY_SELECTEL_TOKEN desde el panel my.selectel.ru .
  2. Cree un clúster de Kubernetes transfiriéndole el token de la cuenta.
  3. Obtenga KUBECONFIG del clúster creado.
  4. Instale GitLab en Kubernetes.
  5. Obtenga el token de GitLab del GitLab generado para el usuario root .
  6. Cree una estructura de proyecto en GitLab usando GitLab-token.
  7. Envíe el código existente a GitLab.
  8. ???
  9. ¡Lucro!


Paso 1 . El token se puede obtener en la sección de claves API .



Paso 2 . Preparamos nuestro Terraform para hornear un cluster de 2 nodos. Si está seguro de que tiene suficientes recursos para todos, puede habilitar las cuotas automáticas:



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


Agrega un usuario al proyecto:



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
}


Salida:



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
}


Lanzamiento:



$ env \
TF_VAR_region=ru-3 \
TF_VAR_username=diamon \
TF_VAR_my_selectel_token=<token> \
terraform plan -out planfile

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




Paso 3 . Obtenemos kubconfig.



Para descargar KUBECONFIG mediante programación, debe obtener un token de OpenStack:



openstack token issue -c id -f value > token


Y con este token, realice una solicitud a la API Managed Kubernetes Selectel. k8s_id produce terraform :



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


Cubconfig también se puede obtener a través del panel.





Paso 4 . Después de que el racimo esté horneado y tengamos acceso a él, podemos agregar yaml encima a nuestro gusto.



Prefiero agregar:



  • espacio de nombres,
  • clase de almacenamiento,
  • política de seguridad de pod y más.


La clase de almacenamiento para Selectel se puede obtener del repositorio oficial .



Dado que inicialmente seleccioné un clúster en la zona ru-3a , también necesito una clase de almacenamiento de esta zona.



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


Paso 5 . Instalamos un equilibrador de carga.



Usaremos el estándar nginx-ingress para muchos . Ya hay muchas instrucciones para instalarlo, así que no nos detengamos en esto.



$ 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


Estamos esperando que reciba una IP externa durante unos 3-4 minutos:





IP externa recibida:





Paso 6 . Instala 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"


De nuevo estamos esperando que suban todas las vainas.



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
Waiting gitlab
./wait_gitlab.sh ../internal/gitlab/gitlab/.pods
waiting for pod...
waiting for pod...
waiting for pod...


Las vainas subieron:





Paso 7 . Obtenemos el token de GitLab.



Primero, averiguamos la contraseña para ingresar:



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


Ahora iniciemos sesión y obtengamos el token:



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


Paso 8 . Llevando los repositorios de Git a la jerarquía correcta usando el proveedor de Gitlab.



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


Desafortunadamente, hay un error flotante en el proveedor terraform GitLab . Luego, debe eliminar los proyectos en conflicto a mano para que tf.state sea reparado. Luego reinicia el comando `$ make all`


Paso 9 . Transferimos repositorios locales al servidor.



$ make push

[master (root-commit) b61d977]  Initial commit
 3 files changed, 46 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 values.yml
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 770 bytes | 770.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0)


Hecho:











Conclusión



Hemos logrado que podamos administrar de forma declarativa todo desde nuestra máquina local. Ahora quiero transferir todas estas tareas a CI y solo presionar los botones. Para hacer esto, necesitamos pasar nuestros estados locales (estado de Terraform) a CI. Cómo hacer esto en la siguiente parte.



¡Suscríbete a nuestro blog para no perderte ningún artículo nuevo!



All Articles