⛴️[pt-BR] Ray no k8s - Criando cluster com k3d
Tags: python, kubernetes, k3d, ray
Published: 2023-08-14 02:51:22

Foto de <a href="https://unsplash.com/pt-br/@growtika?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Growtika</a> na <a href="https://unsplash.com/pt-br/fotografias/ZfVyuV8l7WU?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
  

## Motivação

Recentemente, estive buscando meios de executar aplicações do python paralelamente. Eu costumava usar a biblioteca _multiprocessing_ para paralelizar minhas aplicações. Entretanto, o _multiprocessing_ é focado em paralelizar processos na máquina local e eu precisava executar no kubernetes, após algumas buscas  encontrei o Ray. 

Assim, nesse tutorial, apresento alguns dos passos que segui para configurar o Ray em um _cluster_ local do _kubernetes_. A primeira parte é focada na configuração do cluster com o k3d e a segunda em usar esse cluster via Ray.
  
## 1. Preparando ambiente
Para começar, precisamos ter as seguintes ferramentas instaladas:

- [docker](https://docs.docker.com/get-docker/)
- [k3d](https://k3d.io/v5.5.1/#installation)
- [kubectl](https://kubernetes.io/docs/tasks/tools/)
- [helm](https://helm.sh/docs/intro/install/) 
- [ray](https://docs.ray.io/en/latest/ray-overview/getting-started.html)

### 1.1 Configuração base
O sistema operacional usado foi o Ubuntu 22.04 com um ambiente virtual python na versão 3.10. Já a versão do kubectl usada foi a v1.27.3.

```sh
docker --version
# Docker version 24.0.3, build 3713ee1

helm version --short
# v3.12.1+gf32a527

kubectl version --client --output=yaml
# clientVersion:
#   buildDate: "2023-06-14T09:53:42Z"
#   compiler: gc
#   gitCommit: 25b4e43193bcda6c7328a6d147b1fb73a33f1598
#   gitTreeState: clean
#   gitVersion: v1.27.3
#   goVersion: go1.20.5
#   major: "1"
#   minor: "27"
#   platform: linux/amd64
# kustomizeVersion: v5.0.1

k3d --version
# k3d version v5.5.1
# k3s version v1.26.4-k3s1 (default)

python --version
# Python 3.10.12

ray --version
# ray, version 2.6.1
```
### 1.2 Criando cluster local do kubernetes

Nós definimos um arquivo de configuração para subir o cluster com o k3d. Segundo a [documentação](https://k3d.io/v5.5.1/usage/configfile/#required-fields), os atributos `apiVersion` e `kind` são os únicos obrigatórios, ambos se referem as características do arquivo de configuração em si.

```yml
apiVersion: k3d.io/v1alpha5 # versão mais recente no momento
kind: Simple 
metadata:
    name: mycluster # nome do nosso cluster (k3d-mycluster)
servers: 1  # quantidade de servidores
agents: 2  # quantidade de nós que serão criados
image: rancher/k3s:v1.26.4-k3s1 # versão do k3s a ser usada
ports: # mapear as portas dos nós do container para o host (https://k3d.io/v5.5.1/usage/exposing_services/)
  - port: 8265:80
    nodeFilters: 
      - loadbalancer
options:
  k3s:
    nodeLabels: # adiciona rótulos aos nós do cluster
      - label: type=node1
        nodeFilters:
          - agent:0
      - label: type=node2
        nodeFilters:
          - agent:1
```

### 1.3 Criando cluster local

Para criar um cluster local, usamos o comando a seguir:

```sh
k3d cluster create --config k3d-config.yml
```

Se tudo correr como esperado, no final do comando é exibida a mensagem que o cluster foi criado com sucesso:

![exibição da mensagem de cluster criado com sucesso](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gkdxuqkymhtdd5dpt89x.png)

Rotulamos os nós para facilitar no gerenciamento desses nós, por exemplo, podemos buscar um nó específico com o comando abaixo:

```sh
# label de interesse (type=node1)
kubectl get nodes --selector type=node1 
# NAME                    STATUS   ROLES    AGE   VERSION
# k3d-mycluster-agent-0   Ready    <none>   21m   v1.26.4+k3s1
```
#### 1.3.1 _Labels_ e _selectors_
Os rótulos atribuídos em cada nó podem ser usados para definir qual nó um recurso do _kubernetes_ usará, nessa subseção fazemos isso em um _pod_.

Especificamos no campo `nodeSelector` o rótulo do nó de interesse a ser vinculad ao _pod_. No arquivo _yaml_ abaixo, definimos o rótulo do nó `k3d-mycluster-agent-1`. Para subir a aplicação usamos o comando `kubectl apply -f pod.yaml`.

```yml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeSelector: 
    type: node2 # atribuir esse pod ao nó de interesse
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
```

Em seguida, podemos verificar que o recurso foi atribuído ao nó designado ao consultar o campo _NODE_ da mensagem:
```sh
kubectl get pods --output=wide
# NAME    READY   STATUS    RESTARTS   AGE   IP          NODE                    NOMINATED NODE   READINESS GATES
# nginx   1/1     Running   0          18s   10.42.0.5   k3d-mycluster-agent-1   <none>           <none>
```

Como essa aplicação do nginx foi criada apenas para mostrar o uso de _labels_, podemos removê-la do nosso cluster com o seguinte comando.
```sh
kubectl delete -f pod.yaml
```
Para compreender melhor o conceito de _labels_ e _selectors_, a [documentação do kubernetes](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) pode ser consultada.