Frango ou ovo: divisão IaC



O que veio primeiro - uma galinha ou um ovo? Um começo bastante estranho para um artigo sobre Infraestrutura como Código, não é?



O que é um ovo?



Na maioria das vezes, a infraestrutura como código (IaC) é uma forma declarativa de representar a infraestrutura. Nele descrevemos o estado que queremos obter, começando pela parte de ferro, terminando com a configuração do software. Portanto, IaC é usado para:



  1. Provisão de recursos. São VMs, S3, VPC, etc. Ferramentas básicas de trabalho: Terraform e CloudFormation .
  2. Configuração de software . Ferramentas básicas: Ansible , Chef, etc.


Qualquer código está em repositórios git. E mais cedo ou mais tarde o líder da equipe decidirá que seria necessário colocar as coisas em ordem. E vai refatorar. E criará alguma estrutura. E ele verá que está bom.



Também é bom que já exista um provedor GitLab e GitHub para Terraform (e isso é uma configuração de software). Com a ajuda deles, você pode gerenciar todo o projeto: membros da equipe, CI / CD, git-flow, etc.



De onde veio o ovo?



Assim, gradualmente chegamos à questão principal.



Primeiro de tudo, você precisa começar com um repositório que descreve a estrutura de outros repositórios, incluindo você. E, claro, dentro do GitOps, você precisa adicionar um CI para que as mudanças sejam executadas automaticamente.



Se o Git ainda não foi construído?



  1. Como faço para armazená-lo no Git?
  2. Como aparafusar o CI?
  3. Se também implantarmos o Gitlab usando IaC, e até mesmo no Kubernetes?
  4. E o GitLab Runner também está no Kubernetes?
  5. E o Kubernetes em um provedor de nuvem?


O que veio primeiro: GitLab, onde irei carregar meu código, ou código que descreve qual GitLab eu preciso?


Frango com ovos



" Dinossauro Oyakodon 3 » [ src ]



Vamos tentar cozinhar um prato usando Managed Kubernetes Selectel como um provedor de nuvem .



TL; DR



É possível imediatamente e em uma equipe?



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




Ingredientes:



  • Conta de my.selectel.ru;
  • Token da conta;
  • Habilidades de Kubernetes;
  • Habilidades de leme;
  • Habilidades do Terraform;
  • Helm chart GitLab;
  • Executor GitLab do gráfico do Helm.


Receita:



  1. Obtenha MY_SELECTEL_TOKEN no painel my.selectel.ru .
  2. Crie um cluster Kubernetes transferindo o token da conta para ele.
  3. Obtenha KUBECONFIG do cluster criado.
  4. Instale o GitLab no Kubernetes.
  5. Obtenha o token GitLab do GitLab gerado para o usuário root .
  6. Crie uma estrutura de projeto no GitLab usando o token GitLab.
  7. Envie o código existente para o GitLab.
  8. ???
  9. Lucro!


Etapa 1 . O token pode ser obtido na seção Chaves de API .



Etapa 2 . Preparamos nosso Terraform para assar um cluster de 2 nós. Se você tiver certeza de que possui recursos suficientes para todos, poderá ativar as cotas 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",
 }
}


Adicione um usuário ao projeto:



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
}


Resultado:



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
}


Lançamento:



$ 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




Etapa 3 . Obtemos kubconfig.



Para baixar programaticamente o KUBECONFIG, você precisa obter um token do OpenStack:



openstack token issue -c id -f value > token


E com esse token, faça uma solicitação à API Managed Kubernetes Selectel. k8s_id produz terraform :



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


O Cubconfig também pode ser obtido por meio do painel.





Etapa 4 . Depois que o cluster estiver pronto e tivermos acesso a ele, podemos adicionar yaml por cima ao nosso gosto.



Prefiro acrescentar:



  • namespace,
  • classe de armazenamento,
  • política de segurança do pod e muito mais.


A classe de armazenamento para Selectel pode ser obtida no repositório oficial .



Como inicialmente selecionei um cluster na zona ru-3a , também preciso de uma classe de armazenamento desta 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


Etapa 5 . Instalamos um balanceador de carga.



Usaremos o ingresso nginx padrão para muitos . Já existem várias instruções para instalá-lo, então não vamos insistir nisso.



$ 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 ele receba um IP externo por cerca de 3-4 minutos:





IP externo recebido:





Etapa 6 . Instale o 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"


Estamos novamente esperando que todos os frutos subam.



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...


Pods subiram:





Etapa 7 . Obtemos o token do GitLab.



Primeiro, descobrimos a senha para inserir:



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


Agora, vamos fazer login e obter o token:



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


Etapa 8 . Trazendo repositórios Git para a hierarquia correta usando o Provedor Gitlab.



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


Infelizmente, o provedor terraform GitLab tem um bug flutuante . Em seguida, você deve remover os projetos conflitantes manualmente para que o tf.state seja corrigido. Então reinicie o comando `$ make all`


Etapa 9 . Transferimos repositórios locais para o 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)


Feito:











Conclusão



Conseguimos que podemos gerenciar tudo declarativamente em nossa máquina local. Agora quero transferir todas essas tarefas para o CI e apenas pressionar os botões. Para fazer isso, precisamos passar nossos estados locais (estado Terraform) para CI. Como fazer isso na próxima parte.



Assine nosso blog para não perder nenhum artigo novo!



All Articles