
¿Qué apareció primero, el pollo o el huevo? Es un comienzo curioso para un artículo sobre Infrastructure-as-Code, ¿no crees?
¿Qué es un huevo?
En la mayoría de los casos, Infrastructure-as-Code (IaC) es un método declarativo de representar la infraestructura. En él describimos el estado que queremos lograr, desde el hardware hasta la configuración del software. Por lo tanto, IaC se utiliza para:
- Provisión de recursos. Estos son VMs, S3, VPC, etc. Las principales herramientas para trabajar son: y .
- . Herramientas clave: , Chef, etc.
Todo el código se almacena en repositorios de git. Tarde o temprano, el líder del equipo decidirá que es hora de organizarlo. Entonces se encargará del refactorizado. Creará una estructura. Y verá que esto es bueno.
También es bueno que ya exista y -proveedor para Terraform (y esto es configuración de software). Con ellos se puede gestionar todo el proyecto: miembros del equipo, CI/CD, git-flow, etc.
¿De dónde vino el huevo?
Aquí estamos, acercándonos gradualmente a la pregunta principal.
Primero, debemos comenzar con un repositorio que describe la estructura de otros repositorios, incluido el propio. Y, por supuesto, en el marco de GitOps, debemos agregar CI para que los cambios se ejecuten automáticamente.
¿Y si Git aún no se ha creado?
- ¿Cómo almacenar en Git?
- ¿Cómo añadir CI?
- ¿Y si también desplegamos GitLab usando IaC, y aún en Kubernetes?
- ¿Y GitLab Runner también en Kubernetes?
- ¿Y Kubernetes en un proveedor de nube?
¿Qué apareció primero: GitLab, donde subiré mi código, o el código que describe qué GitLab necesito?
Pollo con huevos
«3 con dinosaurios» []
Intentemos preparar el plato, utilizando como proveedor de nube .
TL;DR
¿Se puede hacer todo en un solo comando?
$ export MY_SELECTEL_TOKEN=
$ curl https://gitlab.com/chicken-or-egg/mks/make/-/snippets/2002106/raw | bashIngredientes:
- Cuenta de my.selectel.ru;
- Token de la cuenta;
- Habilidades de Kubernetes;
- Habilidades de Helm;
- Habilidades de Terraform;
- Gráfico de Helm GitLab;
- Gráfico de Helm GitLab Runner.
Receta:
- Obtener MY_SELECTEL_TOKEN del panel my.selectel.ru.
- Crear un clúster de Kubernetes, pasando el token de la cuenta.
- Obtener KUBECONFIG del clúster creado.
- Instalar GitLab en Kubernetes.
- Obtener el token de GitLab del GitLab creado para el usuario root.
- Crear la estructura de proyectos en GitLab, utilizando el token de GitLab.
- Subir el código existente a GitLab.
- ???
- ¡Beneficio!
Compra una suscripción. Se puede obtener el token en la sección .
Paso 2. Preparamos nuestro Terraform para "hornear" un clúster de 2 nodos. Si estás seguro de que tienes suficientes recursos, puedes activar 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",
}
}Agregando 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
}Salidas:
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
}Iniciamos:
$ 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 
Paso 3. Obteniendo el kubeconfig.
Para descargar KUBECONFIG programáticamente, necesitas obtener un token de OpenStack:
openstack token issue -c id -f value > tokenY ya con este token hacer una solicitud a la API de Kubernetes Administrado de Selectel. k8s_id devuelve terraform:
curl -XGET -H "x-auth-token: $(cat token)" "https://ru-3.mks.selcloud.ru/v1/clusters/$(cat k8s_id)/kubeconfig" -o kubeConfig.yamlEl kubeconfig también se puede obtener a través del panel.

Paso 4. Una vez que el clúster ha sido creado y tenemos acceso, podemos agregar un YAML al gusto.
Prefiero agregar:
- namespace,
- clase de almacenamiento,
- política de seguridad de pod, y más.
para Selectel se puede tomar de .
Dado que inicialmente elegí un clúster en la zona es-3a, también necesito que la Clase de Almacenamiento provenga de esta zona.
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: fast.es-3a
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: cinder.csi.openstack.org
parameters:
type: fast.es-3a
availability: es-3a
allowVolumeExpansion: truePaso 5. Colocamos el balanceador de carga.
Usaremos el estándar para muchos nginx-ingress. Ya hay suficientes instrucciones sobre su instalación, así que no nos detendremos en eso.
$ 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.ymlEsperamos a que obtenga una IP externa durante aproximadamente 3-4 minutos:

Obtenemos la IP externa:

Paso 6. Instalamos 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"Nuevamente, esperamos a que todos los pods se inicien.
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...Los pods se han iniciado:

Paso 7. Obtenemos el token de GitLab.
Primero, averiguamos la contraseña para iniciar sesión:
kubectl get secret -n gitlab gitlab-gitlab-initial-root-password -o jsonpath='{.data.password}' | base64 --decodeAhora nos autenticamos y obtenemos el token:
python3 get_gitlab_token.py root $GITLAB_PASSWORD http://gitlab.gitlab.$EXTERNAL_IP.nip.ioPaso 8. Organizamos los repositorios de Git en la jerarquía correcta con el Proveedor de GitLab.
cd ../internal/gitlab/hierarchy && terraform apply -input=false -auto-approve planfileDesafortunadamente, en el proveedor de GitLab de terraform hay un problema flotante . Entonces, tendrás que eliminar los proyectos en conflicto manualmente para que el tf.state se repare. Luego, reinicia el comando `$ make all`
Paso 9. Transferimos los repositorios locales al servidor.
$ make push
[master (root-commit) b61d977] Commit inicial
3 archivos cambiados, 46 inserciones(+)
modo de creación 100644 .gitignore
modo de creación 100644 values.yml
Enumerando objetos: 5, hecho.
Contando objetos: 100% (5/5), hecho.
Compresión delta utilizando hasta 8 hilos
Comprimiendo objetos: 100% (5/5), hecho.
Escribiendo objetos: 100% (5/5), 770 bytes | 770.00 KiB/s, hecho.
Total 5 (delta 0), reutilizados 0 (delta 0)Listo:


Conclusión
Hemos logrado que desde nuestra máquina local podamos gestionar todo de manera declarativa. Ahora queremos trasladar todas estas tareas a CI y simplemente presionar botones. Para ello, necesitamos transferir nuestros estados locales (Terraform state) a CI. Sobre cómo hacerlo, hablaremos en la siguiente parte.
Suscríbete a nuestro , ¡para no perderte la publicación de nuevos artículos!
Fuente: habr.com
