Pular para o conteúdo

User data (cloud-init)

O deploy e a reinstalação aceitam user_data: um documento do cloud-init que roda no primeiro boot de cada instalação. Use para instalar pacotes, criar arquivos, ajustar o sistema ou chamar a sua ferramenta de configuração.

  • A primeira linha é #cloud-config (YAML com um mapa de chaves, sem chaves repetidas) ou um #! de script (#!/bin/bash, #!/usr/bin/env python3…).
  • Texto UTF-8, sem caracteres nulos.
  • Até 64 KiB (65.536 bytes) depois de decodificado.
  • Em texto puro ou em base64 (alfabeto padrão; quebras de linha e espaços são ignorados), como muitas ferramentas de infraestrutura mandam.

Um documento fora dessas regras responde 400 validation_failed com o motivo em errors.user_data, por exemplo “o user data passa de 64 KiB” ou “o #cloud-config precisa ser YAML válido com um mapa de chaves (sem chaves repetidas)”. O cloud-init ignora em silêncio um cloud-config que não consegue ler; a API recusa antes.

user-data.yaml
#cloud-config
package_update: true
packages:
- nginx
- fail2ban
write_files:
- path: /etc/motd
content: |
Servidor gerenciado pelo time de infraestrutura.
runcmd:
- systemctl enable --now nginx

Mande o arquivo no deploy. Em Python, o requests cuida do JSON:

import os
import uuid
import requests
with open("user-data.yaml", encoding="utf-8") as f:
user_data = f.read()
resp = requests.post(
"https://dash.halver.com.br/api/v1/cloud/servers",
headers={
"Authorization": f"Bearer {os.environ['HALVER_API_TOKEN']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"site_id": "…",
"plan_id": "…",
"os_image_id": "…",
"hostname": "web-01",
"ssh_key_ids": ["…"],
"user_data": user_data,
},
timeout=120,
)
resp.raise_for_status()
print(resp.json()["user_data_sha256"])

No shell, mande em base64 para não brigar com aspas e quebras de linha:

Janela do terminal
UD=$(base64 -w0 user-data.yaml)
curl -X POST https://dash.halver.com.br/api/v1/cloud/servers \
-H "Authorization: Bearer $HALVER_API_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d "{\"site_id\":\"…\",\"plan_id\":\"…\",\"os_image_id\":\"…\",\"hostname\":\"web-01\",\"user_data\":\"$UD\"}"

O seu user data roda depois da configuração da plataforma, que define o login e prepara o console serial:

  • #cloud-config: o que a Halver define prevalece: o usuário de acesso, a senha (quando você pede senha), disable_root e ssh_pwauth. As suas listas (runcmd, packages, write_files, users…) são somadas às nossas, e os mapas são mesclados. O documento vai com Merge-Type: list(append)+dict(no_replace,recurse_list)+str(); um merge_how declarado no seu documento vale como você declarar.
  • Script (#!): roda depois do script de primeiro boot do sistema.
  • Hostname, chaves SSH e rede vêm dos metadados da instalação, não do user data. As suas chaves vão para o usuário de acesso do sistema (por exemplo ubuntu no Ubuntu; veja os.login_user no catálogo).

Se declarar users, inclua default na lista para manter o usuário de acesso do sistema, como manda o cloud-init:

#cloud-config
users:
- default
- name: deploy
groups: [sudo]
shell: /bin/bash
ssh_authorized_keys:
- ssh-ed25519 AAAA... deploy@ci

O user data pode ter segredos. A Halver o guarda cifrado, ligado ao servidor, e a API nunca o devolve: o servidor traz só user_data_sha256 (o SHA-256, em hexadecimal, do documento decodificado) e user_data_size (em bytes). Sem user data, user_data_sha256 é nulo e user_data_size é 0. O registro de auditoria também guarda só o hash e o tamanho.

Para conferir se o servidor tem o documento que você espera, compare o hash:

Janela do terminal
sha256sum user-data.yaml

O user data só muda numa reinstalação, que roda o documento de novo:

user_data na reinstalação Efeito
ausente ou null Mantém o do servidor e roda de novo
"" (vazio) Remove
um documento Substitui

Só os sistemas instalados por imagem (install_method: image no catálogo) rodam cloud-init. O instalador oficial do Proxmox VE (installer) e “Sem sistema” (none) não rodam: um deploy ou uma reinstalação com user data neles responde 422 cloud.user_data_unsupported.