Alcançando as estrelas: dominando os operadores responsáveis ​​pelo gerenciamento de aplicativos no Kubernetes

Vamos ver como usar as funções publicadas no Ansible Galaxy como operadores que gerenciam aplicativos no Kubernetes e veremos como criar um operador que simplesmente instale o aplicativo e ajuste seu comportamento de maneira flexível, dependendo do ambiente.



Usaremos o Ansible Operator e o módulo k8s para mostrar como usar o Ansible para criar aplicativos Kubernetes.

O Operador Ansible faz parte do SDK do Operador e permite formular os regulamentos operacionais do aplicativo (como ele deve ser instalado e mantido) no idioma dos papéis e manuais do Ansible. O módulo k8s, por sua vez, expande a capacidade de gerenciar objetos no Kubernetes ao criar essas funções e playbooks.

Um operador é criado assim assim.

FROM quay.io/operator-framework/ansible-operator RUN ansible-galaxy install djzager.hello_world_k8s RUN echo $'--- \n\ - version: v1alpha1\n\ group: examples.djzager.io\n\ kind: HelloWorld\n\ role: /opt/ansible/roles/djzager.hello_world_k8s' > ${HOME}/watches.yaml 

Tecla Iniciar


Primeiro, algumas palavras sobre o módulo Ansible do k8s . Ele apareceu no Ansible 2.6 e amplia as possibilidades de trabalhar com objetos Kubernetes da Ansible e em qualquer distribuição do Kubernetes, incluindo o Red Hat OpenShift. O blog Ansible tinha um post separado sobre esse módulo e o cliente Python dinâmico do Red Hat OpenShift . Em nossa opinião, trabalhar com objetos Kubernetes através do Ansible sem usar o módulo k8s está errado. O mecanismo do operador foi originalmente criado para executar aplicativos no Kubernetes, e o Operator SDK fornece ferramentas para montagem, teste e empacotamento de operadores. Por sua vez, o Operador Ansible é necessário para definir os regulamentos operacionais do aplicativo no idioma Ansible. O fluxo de trabalho correspondente é organizado de forma simples: primeiro, fazemos o operator-sdk new --type = Ansible para gerar os arquivos necessários para o operador Ansible, depois pintamos o Ansible e, finalmente, fazemos o operator-sdk build para criar o aplicativo para trabalhar no Kubernetes. Mas se já temos um papel no Ansible Galaxy, que controla o aplicativo no Kubernetes, as coisas ficam ainda mais fáceis. Abaixo faremos o seguinte:

  1. Vamos criar uma função Ansible para gerenciar o aplicativo Hello World no Kubernetes, o que nos ajudará a demonstrar os recursos do módulo Ansible do k8s.
  2. Publicaremos esse papel no Ansible Galaxy.

Então, vamos montar o operador Ansible usando a função publicada no Ansible Galaxy. Por que criar um operador usando uma função do Ansible Galaxy? Existem dois motivos:

  1. Para não repetir . Se já programamos a função Ansible para gerenciar o aplicativo Hello World e o publicamos no Ansible Galaxy, é lógico usá-lo ao criar o operador Ansible.
  2. Devido à separação de responsabilidades . Queremos que a função Hello World Ansible gerencie o aplicativo com o mesmo nome no Kubernetes e que a lógica operacional (operacional) permaneça dentro do operador. Em nosso exemplo, a lógica operacional é extremamente simples: ela simplesmente chama a função djzager.hello_world_k8s toda vez que você cria ou modifica um recurso personalizado do HelloWorld. No entanto, no futuro, essa separação se tornará mais significativa, por exemplo, adicionaremos validação ao aplicativo Hello World por meio da função Ansible e implementaremos o controle de status dos recursos personalizados do HelloWorld por meio da lógica do operador.

Olá Kubernetes, conheça Ansible


Do que precisamos


  1. Ansible - consulte o guia de instalação se você não tiver o Ansible instalado.
  2. Cliente Python para OpenShift (opcional). Necessário apenas para lançamento local. As instruções de instalação estão aqui .

Vamos começar. Primeiro, crie um esqueleto de papel usando a galáxia ansible:

 # I like clear names on projects. # In meta/main.yml I will make role_name: hello-world-k8s $ ansible-galaxy init ansible-role-hello-world-k8s 

Imediatamente após a criação de uma nova função Ansible, definiremos todos os valores padrão para, ao mesmo tempo, documentar seus parâmetros de configuração válidos. Além disso, nosso exemplo do Hello World não é particularmente complicado nesse sentido. É assim que nosso arquivo padrão / main.yml se parece:

 --- # NOTE: meta.name(space) comes from CR metadata when run with Ansible Operator # deploy/crds has an example CR for reference name: "{{ meta.name | default('hello-world') }}" namespace: "{{ meta.namespace | default('hello-world') }}" image: docker.io/ansibleplaybookbundle/hello-world:latest # To uninstall from the cluster # state: absent state: present # The size of the hello-world deployment size: 1 

Depois de definir os valores padrão, é necessário decidir o que a função fará. O aplicativo Hello World precisará fazer o seguinte:

  1. Obtenha informações sobre as APIs disponíveis no cluster.
  2. Crie vários modelos e verifique se eles estão presentes ou ausentes no cluster.

Portanto, nosso arquivo tasks / main.yml se parece com o seguinte:

 --- - name: "Get information about the cluster" set_fact: api_groups: "{{ lookup('k8s', cluster_info='api_groups') }}" - name: 'Set hello-world objects state={{ state }}' k8s: state: '{{ state }}' definition: "{{ lookup('template', item.name) | from_yaml }}" when: item.api_exists | default(True) loop: - name: deployment.yml.j2 - name: service.yml.j2 - name: route.yml.j2 api_exists: "{{ True if 'route.openshift.io' in api_groups else False }}" 

Antes de passar para os modelos, preste atenção a esta linha no arquivo de tarefas:

 api_exists: "{{ True if 'route.openshift.io' in api_groups else False }}" 

Usando set_fact, obtemos uma lista de todas as APIs disponíveis no cluster para que possamos gerar seletivamente modelos, dependendo da existência de uma API - nesse caso, route.openshift.io. Por padrão, no cluster Kubernetes do OpenShift, as rotas não estão disponíveis e não precisamos delas, portanto, trabalhamos apenas com o objeto Route quando houver route.openshift.io no cluster.

Não apenas podemos gerenciar objetos seletivamente no cluster, dependendo da disponibilidade de determinadas APIs, mas também usar os modelos Jinja2 para usar o OpenShift DeploymentConfig em nosso modelo de Implantação, se o cluster tiver a API apps.openshift.io. Aqui está a aparência do nosso arquivo templates / deployment.yml.j2:

 --- {% if 'apps.openshift.io' in api_groups %} apiVersion: apps.openshift.io/v1 kind: DeploymentConfig {% else %} apiVersion: apps/v1 kind: Deployment {% endif %} metadata: name: {{ name }} namespace: {{ namespace }} labels: app: {{ name }} service: {{ name }} spec: replicas: {{ size }} {% if 'apps.openshift.io' in api_groups %} selector: app: {{ name }} service: {{ name }} {% else %} selector: matchLabels: app: {{ name }} service: {{ name }} {% endif %} template: metadata: labels: app: {{ name }} service: {{ name }} spec: containers: - image: {{ image }} name: hello-world ports: - containerPort: 8080 protocol: TCP 

Modelos de arquivo / service.yml.j2:

 --- apiVersion: v1 kind: Service metadata: name: {{ name }} namespace: {{ namespace }} labels: app: {{ name }} service: {{ name }} spec: ports: - name: web port: 8080 protocol: TCP targetPort: 8080 selector: app: {{ name }} service: {{ name }} 

E, finalmente, o arquivo templates / route.yml.j2:

 --- apiVersion: route.openshift.io/v1 kind: Route metadata: name: {{ name }} namespace: {{ namespace }} labels: app: {{ name }} service: {{ name }} spec: port: targetPort: web to: kind: Service name: {{ name }} 

Omitimos o arquivo meta / main.yml, mas ele pode ser encontrado aqui .

Como resultado, temos a função Ansible gerenciando o aplicativo Hello World no Kubernetes e podemos usar as APIs disponíveis no cluster. Em outras palavras, o módulo k8s e o cliente dinâmico simplificam o trabalho com objetos no Kubernetes. Esperamos que, com o exemplo desse papel, possamos mostrar o potencial do Ansible ao trabalhar com o Kubernetes.

Olá galáxia, conheça o Kubernetes


O Ansible Galaxy possui várias funções para configurar servidores e gerenciar aplicativos, mas não existem muitas funções para gerenciar aplicativos Kubernetes; portanto, faremos uma pequena contribuição.

Depois que postamos nossa função no GitHub , tudo o que restava foi:

  1. Faça login no Ansible Galaxy para dar acesso aos nossos repositórios no GitHub.
  2. Importe nosso papel.

É isso aí, agora nossa função hello_world_k8s está disponível publicamente no Ansible Galaxy, aqui .

Olá Operador Ansible, Conheça o Galaxy


Se você estudar cuidadosamente nosso projeto Hello World no GitHub , notará que adicionamos várias coisas necessárias para criar um operador Ansible, a saber:

  1. Um arquivo do Watches que mapeia os recursos personalizados do Kubernetes para funções ou playbooks Ansible.
  2. Dockerfile para criar nosso operador.
  3. Implante o diretório com os objetos Kubernetes necessários para executar nosso operador.

Se você precisar aprender mais sobre como criar suas próprias instruções Ansible, use o Guia do Usuário . Mas como prometemos construir um operador Ansible usando a função publicada no Ansible Galaxy, tudo o que realmente precisamos é de um Dockerfile:

 FROM quay.io/operator-framework/ansible-operator RUN ansible-galaxy install djzager.hello_world_k8s RUN echo $'--- \n\ - version: v1alpha1\n\ group: examples.djzager.io\n\ kind: HelloWorld\n\ role: /opt/ansible/roles/djzager.hello_world_k8s' > ${HOME}/watches.yaml 

Agora coletamos o operador:

 $ docker build -t hello-world-operator -f Dockerfile . Sending build context to Docker daemon 157.2 kB Step 1/3 : FROM quay.io/operator-framework/ansible-operator latest: Pulling from operator-framework/ansible-operator Digest: sha256:1156066a05fb1e1dd5d4286085518e5ce15acabfff10a8145eef8da088475db3 Status: Downloaded newer image for quay.io/water-hole/ansible-operator:latest ---> 39cc1d19649d Step 2/3 : RUN ansible-galaxy install djzager.hello_world_k8s ---> Running in 83ba8c21f233 - downloading role 'hello_world_k8s', owned by djzager - downloading role from https://github.com/djzager/ansible-role-hello-world-k8s/archive/master.tar.gz - extracting djzager.hello_world_k8s to /opt/ansible/roles/djzager.hello_world_k8s - djzager.hello_world_k8s (master) was installed successfully Removing intermediate container 83ba8c21f233 ---> 2f303b45576c Step 3/3 : RUN echo $'--- \n- version: v1alpha1\n group: examples.djzager.io\n kind: HelloWorld\n role: /opt/ansible/roles/djzager.hello_world_k8s' > ${HOME}/watches.yaml ---> Running in cced495a9cb4 Removing intermediate container cced495a9cb4 ---> 5827bc3c1ca3 Successfully built 5827bc3c1ca3 Successfully tagged hello-world-operator:latest 

É claro que, para usar esse operador, você precisa do conteúdo do diretório de implantação do nosso projeto para criar uma Conta de Serviço, Função e Vinculação de Função, Definição de Recurso Personalizado, bem como implantar o próprio operador. E depois de implantar o operador, você precisará criar um Recurso Customizado para obter uma instância do aplicativo Hello World:

 apiVersion: examples.djzager.io/v1alpha1 kind: HelloWorld metadata: name: example-helloworld namespace: default spec: size: 3 

Escopos do operador: namespace e cluster


Um pouco mais alto, já sugerimos explorar nosso diretório de implantação e procurar objetos Kubernetes necessários para iniciar o operador. Há três coisas que limitam o escopo do operador ao gerenciar recursos personalizados com o espaço para nome no qual o próprio operador está implantado, a saber:

  1. A variável de ambiente WATCH_NAMESPACE no arquivo operator.yaml que informa ao operador onde procurar recursos personalizados
  2. role.yaml
  3. role_binding

Essa limitação é certamente útil no desenvolvimento de operadores. Mas se quisermos que nosso aplicativo seja acessível a todos os usuários do cluster, precisaremos da ajuda de um administrador. Eu teria que fazer o seguinte:

  1. Crie ClusterRole em vez de função.
  2. Crie uma instrução ServiceAccount no espaço para nome em que a instrução será implantada.
  3. Crie um ClusterRoleBinding que associe um ServiceAccount de um espaço de nome específico a um ClusterRole.
  4. Expanda a instrução com uma variável de ambiente indefinida WATCH_NAMESPACE (ou seja, "").

Se você fizer tudo isso, o restante dos usuários do cluster poderá implantar instâncias do nosso aplicativo Hello World. Se você estiver interessado neste tópico, recomendamos que você estude o Operator Lifecycle Manager (parte da Estrutura do Operador).

Star trek


Mostramos como criar uma função Ansible para controlar um aplicativo no Kubernetes, publicar essa função no Ansible Galaxy e usá-lo no operador Ansible. Esperamos que você agora:

  1. Você usará o módulo Ansible do k8s .
  2. Comece a publicar suas funções para gerenciar aplicativos Kubernetes no Ansible Galaxy .
  3. Interesse-se no SDK do operador e assine nosso boletim informativo da estrutura do operador .

Nosso aplicativo Hello World é intencionalmente simplificado, mas existem coisas que podem ajudar a torná-lo ainda mais confiável, e aqui estão algumas:

  1. Usando o SDK do operador - intencionalmente não fizemos isso em nosso exemplo para enfatizar como é fácil mudar da função Ansible para o operador. Mas é melhor ainda usar essa função com o SDK (ou seja, operator-sdk new). Além disso, você pode precisar disso nas próximas etapas.
  2. Validação - em nossa versão atual, o usuário pode criar um CR com o tamanho: abc, o que inevitavelmente levará a um erro no estágio de implantação. Portanto, é melhor detectar erros no estágio de especificação, e não após o início do trabalho.
  3. Ciclo de vida - em exemplos mais complexos, pode ser a mesma atualização de versão. Em cenários como o nosso, onde existe apenas uma versão do aplicativo Hello World, podemos determinar se a imagem de um contêiner ativo está desatualizada comparando-a com as imagens disponíveis no registro de contêiner correspondente e, se necessário, atualizar as instâncias em execução.
  4. Teste - Molécula é muito útil ao desenvolver e testar funções Ansible.
  5. O Operator Lifecycle Manager é um kit de ferramentas para gerenciar operadores. A integração com ele ajudará a instalar e atualizar nosso operador.
  6. Status - poderíamos ativar o sub-recurso de status no nosso Hello World CRD e usar o módulo k8s_status, que faz parte da imagem do Ansible Operator, para incluir informações de status no recurso personalizado.

Source: https://habr.com/ru/post/pt440188/


All Articles