DEV Community

Cristiano Lemes
Cristiano Lemes

Posted on

Isolando cargas de trabalho no k8s com kata container

Introdução

Containers revolucionaram a forma como implantamos e gerenciamos aplicações, oferecendo portabilidade, escalabilidade e eficiência no uso de recursos. No entanto, apesar dessas vantagens, containers tradicionais não são projetados para fornecer isolamento total entre cargas de trabalho. Eles compartilham o kernel do sistema operacional do host, o que significa que, em cenários de ataque, vulnerabilidades no kernel ou nos próprios mecanismos de conteinerização, como namespaces e cgroups, podem ser exploradas para comprometer o ambiente do host ou outros containers.

Além disso, ataques como container escape permitem que um invasor rompa as barreiras de isolamento e obtenha acesso a recursos do host. Essa preocupação é ainda mais relevante em ambientes multi-tenant, onde múltiplas cargas de trabalho de diferentes equipes ou clientes podem estar sendo executadas lado a lado.

Por conta dessas limitações, surge a necessidade de soluções mais robustas para isolamento de cargas de trabalho. Tecnologias como Kata Containers e Firecracker oferecem maior segurança ao combinarem a leveza dos containers com o isolamento robusto de máquinas virtuais (VMs), criando uma camada adicional de proteção sem sacrificar a eficiência operacional.

Neste guia, exploraremos como integrar essas tecnologias ao Kubernetes para isolar cargas de trabalho de forma eficaz, reduzindo riscos de segurança em ambientes sensíveis.

Ferramentas Utilizadas

  • Cilium
  • Terraform
  • Ansible
  • Equinix Metal
  • Kata Container
  • Firecraker
  • Helm

Ambiente Local
Ferramentas instaladas

  • Metal Cli (Ferramenta de linha de comando da Equinix Metal)
go install github.com/equinix/metal-cli/cmd/metal@latest
Enter fullscreen mode Exit fullscreen mode
  • Ansible no Linux com pipx ou uv:
pipx install ansible-core

uvx ansible
Enter fullscreen mode Exit fullscreen mode
  • Ansible no Windows com Docker:
  • Crie os alias no seu $PROFILE
function runansible { 
  docker run -ti --rm `
    -v "$HOME\.ssh:/root/.ssh" `
    -v "$HOME\.aws:/root/.aws" `
    -v "${PWD}:/apps" `
    -w /apps `
    alpine/ansible ansible @args
}  
New-Alias -Name ansible -Value runansible

function playbook {
  docker run -ti --rm `
    -v "$HOME\.ssh:/root/.ssh" `
    -v "$HOME\.aws:/root/.aws" `
    -v "${PWD}:/apps" `
    -w /apps alpine/ansible `
   bash -c `
   "chmod -R 700 /root/.ssh && ansible-playbook $($args -join ' ')"
}
New-Alias -Name ansible-playbook -Value playbook
Enter fullscreen mode Exit fullscreen mode
  • Terraform siga a instalação para sua plataforma

Parte 1: Criando servidores

Nessa guia eu vou usar a Equinix Metal para o ambiente de servidores, você também pode usar seu provedor de Bare metal preferido, ou ambiente de virtualização local se seu ambiente suportar virtualização aninhada (Nested VT-x/AMD-V).
os requisitos são mínimo 2 servidores com 2CPU e 4GB de Ram .

Criando ambiente na Equinix Metal

1. Crie uma conta na Equinix Metal , ou caso já tenha faça login.

  • No momento eles estão oferendo um crédito de $250,00 para testar a plataforma, o suficiente para seguir esse tutorial. O uso é cobrado por hora em instancias on demand, com cobrança mínima de 1 hora (Não adianta desligar depois de 1 minuto, vai cobrar 1 hora).

2. Crie uma chave de API para acessar a Equinix.

  • No console da equinix, selecione o projeto em qual você vai criar suas maquinas, vá em project settings, e em api keys, adicione uma chave com permissão readwrite.

Api Equinix

Criando scripts Terraform para a implantação das máquinas

Siga as instruções abaixo para criar os arquivos e configurar a infraestrutura.

1. Estrutura de Arquivos

📂 k8s-metal-fire/
├── 📂 terraform/
│ ├── 📄 main.tf
│ ├── 📄 output.tf
│ ├── 📄 providers.tf
│ ├── 📄 terraform.tfvars
│ ├── 📄 variables.tf
│ └── 📝 inventory.sh
├── 📂 ansible/
....

Crie a estrutura de pastas e arquivos. Use os comandos abaixo:

mkdir -p k8s-metal-fire/terraform
mkdir -p k8s-metal-fire/ansible/{build,inventory,scripts/devmapper}

touch k8s-metal-fire/terraform/{main.tf,output.tf,providers.tf,terraform.tfvars,variables.tf}
touch k8s-metal-fire/ansible/{build/firecracker,inventory/hosts.yml,scripts/devmapper/{create.sh,reload.sh}}
touch k8s-metal-fire/{cluster_bootstrap.yml,k8s_environment.yml,k8s_firecracker.yml,main.yml}
Enter fullscreen mode Exit fullscreen mode

2. Crie o arquivo main.tf

Esse arquivo define os recursos que serão provisionados no Equinix Metal.

Conteúdo:

resource "equinix_metal_device" "k8s_master" {
  count            = var.k8s_master.num_instances
  hostname         = "k8s-master-${count.index + 1}"
  plan             = var.k8s_master.plan
  metro            = var.em_region
  operating_system = var.k8s_master.operating_system
  billing_cycle    = var.billing_cycle
  project_id       = var.em_project_id

  tags = ["kubernetes", "master"]
}

resource "equinix_metal_device" "k8s_worker" {
  count            = var.k8s_nodes.num_instances
  hostname         = "k8s-worker-${count.index + 1}"
  plan             = var.k8s_nodes.plan
  metro            = var.em_region
  operating_system = var.k8s_nodes.operating_system
  billing_cycle    = var.billing_cycle
  project_id       = var.em_project_id

  tags = ["kubernetes", "worker"]
}
Enter fullscreen mode Exit fullscreen mode

O que faz:

  • Define dois tipos de máquinas:
    • Masters: Controlam o cluster Kubernetes.
    • Workers: Executam os workloads (cargas de trabalho).

3. Crie o arquivo output.tf

Esse arquivo define as saídas dos recursos provisionados.

Conteúdo:

output "master_ips" {
  value = {
    for device in equinix_metal_device.k8s_master :
    device.hostname => {
      "public_ip"  = device.access_public_ipv4
      "private_ip" = device.access_private_ipv4
    }
  }
  description = "IP addresses of master nodes"
}

output "worker_ips" {
  value = {
    for device in equinix_metal_device.k8s_worker :
    device.hostname => {
      "public_ip"  = device.access_public_ipv4
      "private_ip" = device.access_private_ipv4
    }
  }
  description = "IP addresses of worker nodes"
}
Enter fullscreen mode Exit fullscreen mode

O que faz:

  • Mostra os IPs públicos e privados dos masters e workers após a execução do Terraform.

4. Crie o arquivo providers.tf

Esse arquivo configura o provedor do Terraform.

Conteúdo:

terraform {
  required_providers {
    equinix = {
      source  = "equinix/equinix"
      version = "2.11.0"
    }
  }
  # backend "gcs" {
  #   bucket = "cslemes-terraform"
  #}
}

provider "equinix" {
  auth_token = var.em_api_token
}
Enter fullscreen mode Exit fullscreen mode

O que faz:

  • Configura o provedor Equinix Metal para gerenciar os recursos.
  • Inclui um exemplo comentado de backend remoto para armazenar o estado do Terraform.

5. Crie o arquivo terraform.tfvars

Esse arquivo define os valores das variáveis.

Conteúdo:

em_api_token  = "xxxxxxxxxxxxxxxxxxxxxxxxx"
em_project_id = "xxxxxxxxxxxxxxxxxxxxxxxxxx"
em_region     = "da"

billing_cycle = "hourly"

k8s_master = {
  plan             = "c3.small.x86"
  ipxe_script_url  = ""
  operating_system = "ubuntu_24_04"
  num_instances    = 3
  tags             = ["k8s_master"]
}

k8s_nodes = {
  plan             = "c3.small.x86"
  ipxe_script_url  = ""
  operating_system = "ubuntu_24_04"
  num_instances    = 2
  tags             = ["k8s-nodes"]
}
Enter fullscreen mode Exit fullscreen mode

O que faz:

  • Define as credenciais (API token e ID do projeto).
  • Configura os planos e características das máquinas para os masters e workers.

6. Crie o arquivo variables.tf

Esse arquivo declara as variáveis usadas no projeto.

Conteúdo:

variable "em_api_token" {
  description = "Equinix Metal API Key"
  type        = string
}

variable "em_project_id" {
  description = "Equinix Metal Project ID"
  type        = string
}

variable "em_region" {
  description = "Equinix Metal region to use"
  type        = string
}

variable "billing_cycle" {
  description = "value of billing cycle"
  type        = string
}

variable "k8s_master" {
  description = "k8s master"
  type = object({
    plan             = string
    ipxe_script_url  = optional(string)
    operating_system = string
    num_instances    = number
    tags             = optional(list(string), [])
  })
}

variable "k8s_nodes" {
  description = "k8s nodes"
  type = object({
    plan             = string
    ipxe_script_url  = optional(string)
    operating_system = string
    num_instances    = number
    tags             = optional(list(string), [])
  })
}
Enter fullscreen mode Exit fullscreen mode

O que faz:

  • Declara as variáveis obrigatórias, como token, projeto, região, e configurações dos nós.

Com esses arquivos criados, você pode iniciar a implantação executando os seguintes comandos no diretório terraform:

terraform init      # Inicializa o projeto
terraform plan      # Exibe o plano de execução
terraform apply     # Aplica as configurações e provisiona os recursos
Enter fullscreen mode Exit fullscreen mode

7. Crie o arquivo inventory.sh

  • Esse script vai pegar o output do terraform e gerar o arquivo de inventory para o ansible.
terraform output -json | jq -r '
  .master_ips.value as $masters |
  .worker_ips.value as $workers |
  {
    all: {
      children: {
        k8s_master: {
          hosts: (
            $masters | to_entries | map({
              (.key): {
                ansible_host: .value.public_ip,
                ansible_user: "root"
              }
            }) | add
          )
        },
        k8s_workers: {
          hosts: (
            $workers | to_entries | map({
              (.key): {
                ansible_host: .value.public_ip,
                ansible_user: "root"
              }
            }) | add
          )
        }
      }
    }
  }
' | yq -P > ../ansible/hosts.yaml
Enter fullscreen mode Exit fullscreen mode

Criando manifestos Ansible para configuração do cluster Kubernetes

Você pode criar os arquivos necessários para o Ansible em uma estrutura organizada. Aqui está um guia passo a passo para criar e organizar os arquivos mencionados:


1. Estrutura de diretórios

Crie os seguintes diretórios e arquivos no seu projeto:

📂 ansible/
├── 📂 group_vars/
├── 📂 host_vars/
├── 📂 roles/
│ ├── 📂 k8s_environment/
│ │ ├── 📂 scripts/
│ │ │ ├── 📂 devmapper/
│ │ │ │ ├── 📄 create.sh
│ │ │ │ └── 📄 reload.sh
│ │ │ └── 📄 devmapper_reload.service
│ │ ├── 📂 tasks/
│ │ │ └── 📄 main.yml
│ ├── 📂 k8s_bootstrap/
│ │ ├── 📂 build/
│ │ │ └── 📄 firecraker
│ │ ├── 📂 tasks/
│ │ │ └── 📄 main.yml
│ ├── 📂 k8s_firecracker/
│ │ ├── 📂 tasks/
│ │ │ └── 📄 main.yml
│ ├── 📂 apply_kata/
│ │ ├── 📂 tasks/
│ │ │ └── 📄 main.yml
├── 📄 hosts.yml
└── 📄 playbook.yml

2. Arquivo hosts.yml

Define os grupos de hosts (master e workers), vamos cria-lo a partir do output do terraform aqui é um exemplo:

all:
  children:
    k8s_master:
      hosts:
        node1:
          ansible_host: 147.75.45.67
          ansible_user: root
    workers:
      hosts:
        node:
          ansible_host: 147.28.197.223
          ansible_user: root

Enter fullscreen mode Exit fullscreen mode

3. Arquivo playbook.yml

O ponto de entrada principal do Ansible:

- name: Setup Kubernetes cluster
  hosts: all
  become: yes
  tasks:
    - name: Install Kubernetes dependencies
      import_role:
        name: k8s_environment

- name: Configure Firecracker
  hosts: all
  become: yes
  tasks:
    - name: Configure Firecracker
      import_role:
        name: k8s_firecracker

- name: Add kube-vip
  hosts: k8s_master
  become: yes
  tasks:
    - name: Generate kube-vip manifest
      include_tasks: kube-vip.yaml

- name: Bootstrap Kubernetes cluster
  hosts: k8s_master
  become: yes
  tasks:
    - name: Bootstrap cluster
      import_role:
        name: k8s_bootstrap

- name: Apply Kata manifests
  hosts: k8s_master
  become: yes
  tasks:
    - name: Apply Kata
      import_role:
        name: apply_kata

- name: Join worker nodes
  hosts: k8s_workers
  become: yes
  tasks:
    - name: Join cluster
      command: "{{ hostvars[groups['k8s_master'][0]]['join_command'] }}"
      args:
        creates: /etc/kubernetes/kubelet.conf
Enter fullscreen mode Exit fullscreen mode

4. Arquivo roles/k8s_environment/tasks/main.yml

Responsável por configurar o ambiente do Kubernetes:

---
- name: Update apt cache
  ansible.builtin.apt:
    update_cache: yes

- name: Install required packages
  ansible.builtin.apt:
    name:
      - apt-transport-https
      - ca-certificates
      - curl
      - gnupg
      - lsb-release
      - thin-provisioning-tools
      - lvm2
      - bc
    state: present

- name: Install Container runtime
  ansible.builtin.apt:
    name:
      - containerd
    state: present

- name: Enable and start container runtime
  ansible.builtin.systemd:
    name: containerd
    state: started
    enabled: yes

- name: Create Containerd Directory
  ansible.builtin.file:
    path: /etc/containerd
    state: directory
    mode: "0755"

- name: Configure containerd default
  ansible.builtin.shell: |
    mkdir -p /etc/containerd
    containerd config default > /etc/containerd/config.toml
    sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml

- name: Reload containerd
  ansible.builtin.systemd:
    name: containerd
    state: started

- name: Download Kubernetes GPG key
  ansible.builtin.get_url:
    url: https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key
    dest: /tmp/kubernetes-release.key

- name: Crege keyring directory
  ansible.builtin.file:
    path: /etc/apt/keyrings
    state: directory

- name: Convert and move Kubernetes GPG key
  ansible.builtin.command:
    cmd: gpg --yes --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg /tmp/kubernetes-release.key

- name: Add Kubernetes repository
  ansible.builtin.lineinfile:
    path: /etc/apt/sources.list.d/kubernetes.list
    line: "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.31/deb/ /"
    create: yes

- name: Update apt cache
  apt:
    update_cache: yes

- name: Install Kubernetes packages
  apt:
    name:
      - kubelet
      - kubeadm
      - kubectl
    state: present

- name: Hold Kubernetes packages
  dpkg_selections:
    name: "{{ item }}"
    selection: hold
  loop:
    - kubelet
    - kubeadm
    - kubectl

- name: Disable swap
  command: swapoff -a
  when: ansible_swaptotal_mb > 0

- name: Remove swap from /etc/fstab
  lineinfile:
    path: /etc/fstab
    regexp: '^[^#].*\sswap\s.*'
    state: absent

- name: Enable kernel modules
  modprobe:
    name: "{{ item }}"
    state: present
  loop:
    - overlay
    - br_netfilter

- name: Add kernel modules to load on boot
  copy:
    dest: /etc/modules-load.d/k8s.conf
    content: |
      overlay
      br_netfilter

- name: Set kernel parameters for Kubernetes
  sysctl:
    name: "{{ item.name }}"
    value: "{{ item.value }}"
    state: present
    reload: yes
  loop:
    - { name: "net.bridge.bridge-nf-call-iptables", value: "1" }
    - { name: "net.bridge.bridge-nf-call-ip6tables", value: "1" }
    - { name: "net.ipv4.ip_forward", value: "1" }

- name: Set extra args for kubelet
  ansible.builtin.lineinfile:
    path: /etc/default/kubelet
    regexp: "^KUBELET_EXTRA_ARGS="
    line: 'KUBELET_EXTRA_ARGS="--cloud-provider=external"'
    state: present
Enter fullscreen mode Exit fullscreen mode

5. Arquivo roles/k8s_bootstrap/tasks/main.yml

Responsável pelo bootstrap do cluster Kubernetes:

---
- name: Get the IP address of the master node
  set_fact:
    advertise_address: "{{ ansible_default_ipv4.address }}"
    # advertise_address: "10.70.191.131"
- name: Initialize Kubernetes cluster
  command: kubeadm init --skip-phases=addon/kube-proxy --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address {{ advertise_address }}
  register: kubeadm_init
  args:
    creates: /etc/kubernetes/admin.conf
- name: Create .kube directory
  file:
    path: /root/.kube
    state: directory
    mode: "0755"
- name: Copy admin.conf to root's kube config
  copy:
    src: /etc/kubernetes/admin.conf
    dest: /root/.kube/config
    remote_src: yes
    owner: root
    group: root
    mode: "0644"
- name: Deploy Calico
  command: kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.29.1/manifests/calico.yaml
- name: Get join command
  command: kubeadm token create --print-join-command
  register: join_command
- name: Store join command
  set_fact:
    join_command: "{{ join_command.stdout }}"
Enter fullscreen mode Exit fullscreen mode

6. Arquivo roles/k8s_firecracker/tasks/main.yml

Configura o Firecracker:

---
- name: Copy Firecracker binary
  copy:
    src: build/firecracker
    dest: /usr/local/bin/firecracker
    mode: "0755"

- name: Create DevMapper directories
  ansible.builtin.file:
    path: /var/lib/containerd/io.containerd.snapshotter.v1.devmapper
    state: directory
    mode: "0755"

- name: Move and set permissions for DevMapper scripts
  copy:
    src: "{{ item.src }}"
    dest: "{{ item.dest }}"
    mode: "0755"
  with_items:
    - {
        src: scripts/devmapper/create.sh,
        dest: /usr/local/bin/devmapper-create.sh,
      }
    - {
        src: scripts/devmapper/reload.sh,
        dest: /usr/local/bin/devmapper-reload.sh,
      }

- name: Run initial DevMapper creation script
  ansible.builtin.command: /usr/local/bin/devmapper-create.sh
  ignore_errors: yes

- name: Containerd Configuration Firecracker
  ansible.builtin.shell: |
    CONFIG_FILE="/etc/containerd/config.toml"
    sudo cp "$CONFIG_FILE" "${CONFIG_FILE}.bak"

    sudo sed -i '/\[plugins."io.containerd.snapshotter.v1.devmapper"\]/,/^$/d' "$CONFIG_FILE"
    sudo sed -i '/\[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata-fc\]/,/^$/d' "$CONFIG_FILE"

    cat <<EOF >> /etc/containerd/config.toml
    [plugins."io.containerd.snapshotter.v1.devmapper"]
    pool_name = "devpool"
    root_path = "/var/lib/containerd/io.containerd.snapshotter.v1.devmapper"
    base_image_size = "40GB"

    [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata-fc]
    snapshotter = "devmapper"
    runtime_type = "io.containerd.kata-fc.v2"
    EOF

- name: Create DevMapper reload systemd service
  copy:
    dest: /lib/systemd/system/devmapper-reload.service
    content: |
      [Unit]
      Description=Devmapper reload script
      After=network.target

      [Service]
      Type=oneshot
      ExecStart=/usr/local/bin/devmapper-reload.sh
      RemainAfterExit=yes

      [Install]
      WantedBy=multi-user.target

- name: Enable and reload systemd daemon
  systemd:
    name: devmapper-reload.service
    enabled: yes
    daemon_reload: yes

- name: Restart containerd
  systemd:
    name: containerd.service
    state: restarted

Enter fullscreen mode Exit fullscreen mode

7. Arquivo roles/apply_kata/tasks/main.yml

Aplica os manifestos Kata:

---
- name: Install Kata RBAC
  ansible.builtin.command: kubectl apply -f https://raw.githubusercontent.com/kata-containers/kata-containers/main/tools/packaging/kata-deploy/kata-rbac/base/kata-rbac.yaml
- name: Install Kata Deploy
  ansible.builtin.command: kubectl apply -f https://raw.githubusercontent.com/kata-containers/kata-containers/main/tools/packaging/kata-deploy/kata-deploy/base/kata-deploy.yaml
- name: Install Kata Runtime
  ansible.builtin.command: kubectl apply -f https://raw.githubusercontent.com/kata-containers/kata-containers/main/tools/packaging/kata-deploy/runtimeclasses/kata-runtimeClasses.yaml
- name: Install Rke LocalPath
  ansible.builtin.command: kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.30/deploy/local-path-storage.yaml
Enter fullscreen mode Exit fullscreen mode

8. Executando o Ansible

Com tudo configurado, execute o seguinte comando para aplicar o playbook:

ansible-playbook -i hosts.yml playbook.yml
Enter fullscreen mode Exit fullscreen mode

  • Estrutura de diretórios: Usamos roles para separar as responsabilidades.
  • Playbook: Importa os roles para configurar diferentes partes do cluster.
  • Hosts: Define os grupos de servidores para os nós mestres e trabalhadores.
  • Execução: O comando ansible-playbook aplica todas as tarefas nos servidores.

Rodando tudo junto

  1. Crie um arquivo make file.
.PHONY: all init plan apply destroy ansible-lint terraform-lint ansible-deploy help

# Directories
TERRAFORM_DIR := terraform
ANSIBLE_DIR := ansible

# Default target
all: init plan apply create-inventory ansible-deploy
    @echo "Complete deployment finished successfully!"

help:
    @echo "Available targets:"
    @echo "  init           - Initialize Terraform"
    @echo "  plan           - Create Terraform plan"
    @echo "  apply          - Apply Terraform changes"
    @echo "  destroy        - Destroy Terraform infrastructure"
    @echo "  create-inventory - Generate Ansible inventory from Terraform outputs"
    @echo "  ansible-lint   - Run Ansible linter"
    @echo "  ansible-deploy - Run Ansible playbook"
    @echo "  terraform-lint - Run Terraform formatting and validation"
    @echo
    @echo "Example usage:"
    @echo "  make all       - Runs init, plan, apply, inventory, and ansible-deploy"

# Terraform targets
init:
    cd $(TERRAFORM_DIR) && terraform init

plan:
    cd $(TERRAFORM_DIR) && terraform plan

apply:
    cd $(TERRAFORM_DIR) && terraform apply -auto-approve

destroy:
    cd $(TERRAFORM_DIR) && terraform destroy -auto-approve

# Generate Ansible inventory
create-inventory:
    cd $(TERRAFORM_DIR) && ./inventory.sh

# Ansible targets
ansible-lint:
    ansible-lint $(ANSIBLE_DIR)/

ansible-deploy:
    ansible-playbook -i $(ANSIBLE_DIR)/hosts.yml $(ANSIBLE_DIR)/playbook.yml

# Terraform linting and validation
terraform-lint:
    cd $(TERRAFORM_DIR) && terraform fmt -check && terraform validate

Enter fullscreen mode Exit fullscreen mode

Este Makefile automatiza o processo de gerenciamento de infraestrutura com Terraform e Ansible, organizando os comandos em alvos específicos para facilitar o uso e manutenção. Aqui está um resumo das principais funcionalidades:

  1. Alvo Principal (all):

    Executa todo o pipeline, incluindo init, plan, apply, criação do inventário (create-inventory) e a execução do playbook Ansible.

  2. Gerenciamento com Terraform:

    • init: Inicializa o Terraform.
    • plan: Gera o plano de execução.
    • apply: Aplica as alterações na infraestrutura.
    • destroy: Destroi a infraestrutura provisionada.
  3. Inventário Dinâmico:

    • create-inventory: Gera o inventário do Ansible com base na saída do Terraform.
  4. Ansible:

    • ansible-lint: Executa o linter para validar os playbooks.
    • ansible-deploy: Executa o playbook principal (playbook.yml).
  5. Linting e Validação de Terraform:

    • terraform-lint: Valida a formatação e os arquivos de configuração do Terraform.
  6. Ajuda (help):

    Exibe os alvos disponíveis e um exemplo de uso.

    Teste

  7. Crie um manifesto para um nginx

  8. Adicione runtimeClassName: kata-fc em specs.

   apiVersion: v1
   kind: Pod
   metadata:
     creationTimestamp: null
     labels:
       run: nginx1
     name: nginx1
   spec:
     runtimeClassName: kata-fc
     containers:
     - image: nginx
       name: nginx1
       resources: {}
     dnsPolicy: ClusterFirst
     restartPolicy: Always
   status: {}
Enter fullscreen mode Exit fullscreen mode
  1. Verifique a versão do kernel do container
   $ k exec -it nginx1 -- bash -c "uname -a"
   Linux nginx1 6.1.62 #1 SMP Fri Nov 15 11:22:02 UTC 2024 x86_64 GNU/Linux
Enter fullscreen mode Exit fullscreen mode
  1. E o kernel do host
   root@k8s-master-1:~# uname -a
    Linux k8s-master-1 6.8.0-49-generic #49-Ubuntu SMP PREEMPT_DYNAMIC Mon      Nov  4 02:06:24 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
Enter fullscreen mode Exit fullscreen mode

Referências

Repositório do Projeto
Aws Firecracker Kata Containers

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (0)

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up