A preparação e configuração de um cluster Kubernetes exige a execução de comandos idênticos em múltiplos nós simultaneamente (como instalação de pacotes, configurações de kernel e ajustes de rede).
Para otimizar esse processo e evitar erros de digitação, utilizaremos o multi-ssh-tmux, um script que cria uma sessão do tmux com múltiplos painéis SSH conectados aos nós do cluster, permitindo que o que você digita em um terminal seja replicado instantaneamente para todos os outros.
O tmux é um multiplexador de terminal que permite gerenciar múltiplas sessões e painéis em um único terminal. É essencial para o script multi-ssh-tmux funcionar.
sudo apt update
sudo apt install tmux
Verifique a instalação:
tmux -V
O tmux vem com configurações padrão, mas podemos melhorar significativamente a experiência do usuário com um arquivo .tmux.conf customizado. Este arquivo define cores, atalhos e comportamentos do tmux.
Crie ou edite o arquivo ~/.tmux.conf:
nano ~/.tmux.conf
Cole o seguinte conteúdo:
# ====================== PALETA DE CORES ====================== #
# Paleta de cores consistente com o tema do terminal
color_dark="colour236" # #2E3137 - fundo escuro
color_text="colour245" # #7E8187 - texto principal
color_accent="colour39" # #159BEE - azul (destaque)
color_warning="colour166" # #F4A623 - laranja/amarelo
color_success="colour76" # #76C893 - verde
color_secondary="colour134" # #A24BCF - roxo
# ================== ESTILOS BÁSICOS ================== #
# Bordas dos painéis com cores diferenciadas
# Painéis inativos: texto em cor clara
# Painéis ativos: borda em laranja/amarelo em negrito
set -g pane-border-style "fg=$color_text,bg=default"
set -g pane-active-border-style "fg=$color_warning,bg=default,bold"
# Estilo geral da barra de status (localizada no topo)
set -g status-position top
set -g status-style "fg=$color_text,bg=$color_dark"
# ================== BARRA DE STATUS ================== #
# Lado esquerdo: Exibe o nome da sessão (em verde) seguido de um separador visual
set -g status-left-length 30
set -g status-left "#[bold,fg=$color_success]#S #[fg=$color_text]⟩ "
# Centro: Exibe as janelas abertas na sessão
# Janelas inativas: formato simples "ID:Nome"
# Janela ativa: formato em laranja/amarelo em negrito
set -g status-justify centre
set -g window-status-format " #I:#W "
set -g window-status-current-format "#[bold,fg=$color_warning]#I:#W "
# Lado direito: Exibe informações do sistema
# Componentes: usuário@hostname, número do painel ativo, data e hora
set -g status-right "#[fg=$color_secondary]#{client_user}@#h #[fg=$color_text]⟨ #[fg=$color_accent]#P/#{window_panes} #[fg=$color_text]⟨ #[fg=$color_success]%d-%m-%Y %H:%M"
# ================== ATALHOS CUSTOMIZADOS ================== #
# Atalho 'S' (Shift+s) para ativar/desativar sincronização de painéis
# Quando ativado, o mesmo comando é enviado para todos os painéis da janela ativa
# Muito útil para executar comandos em múltiplas máquinas simultaneamente
bind-key S set-window-option synchronize-panes\; display-message -F "#[fg=green]sync #{?pane_synchronized,ON,OFF}"
# Dica: Para ajuda interna do tmux, pressione Prefix (Ctrl+b) e depois ?
Recarregue a configuração do tmux (sem precisar reiniciar as sessões ativas):
tmux source-file ~/.tmux.conf
Ou, se já estiver dentro de uma sessão tmux, pressione Ctrl+b e depois :source-file ~/.tmux.conf e Enter.
Paleta de Cores: Define uma paleta consistente com o tema do terminal, facilitando a leitura e reduzindo fadiga visual.
Bordas dos Painéis: Painéis inativos têm bordas em cor clara, enquanto o painel ativo (aquele onde você está digitando) é destacado em laranja/amarelo em negrito, deixando claro qual painel receberá seus comandos.
Barra de Status: Posicionada no topo para melhor visibilidade. O lado esquerdo mostra o nome da sessão (útil quando você tem múltiplas sessões), o centro mostra as janelas abertas, e o lado direito mostra informações de contexto (usuário, hostname, data/hora).
Atalho de Sincronização: O atalho Shift+s permite ativar/desativar rapidamente a sincronização de painéis. Quando ativado, qualquer texto que você digita é enviado para todos os painéis simultaneamente. Quando desativado, você digita apenas no painel ativo. Isso é essencial para situações onde você precisa digitar uma senha diferente em um nó específico.
multi-ssh-tmuxEste script é robusto, valida as entradas, suporta layouts diferentes e lida bem com a criação dinâmica de painéis.
Crie o arquivo no diretório de binários locais para que fique acessível globalmente:
sudo nano /usr/local/bin/multi-ssh-tmux
Cole o conteúdo abaixo:
#!/bin/bash
################################################################################
# multi-ssh-tmux - Gerenciador de Conexões SSH Múltiplas com tmux
# Versão: 1.0.1 (com correção de criação de painéis)
################################################################################
#
# Descrição:
# Script para criar sessões tmux com múltiplas conexões SSH simultâneas.
# Oferece sincronização de comandos, diferentes layouts e gerenciamento
# flexível de hosts através de linha de comando ou arquivo.
#
# Dependências:
# - bash (versão 4.0+)
# - tmux (versão 2.0+)
# - ssh (OpenSSH)
################################################################################
set -euo pipefail
# ============================================================================
# Definições de Cores
# ============================================================================
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly NC='\033[0m'
# ============================================================================
# Constantes Globais
# ============================================================================
readonly MAX_HOSTS=32
readonly VALID_LAYOUTS=("tiled" "even-horizontal" "even-vertical" "main-horizontal" "main-vertical")
# ============================================================================
# Funções de Log
# ============================================================================
_info() { echo -e "${BLUE}[INFO]${NC} $*"; }
_warn() { echo -e "${YELLOW}[WARN]${NC} $*" >&2; }
_error() { echo -e "${RED}[ERRO]${NC} $*" >&2; }
_success() { echo -e "${GREEN}[SUCESSO]${NC} $*"; }
# ============================================================================
# Funções de Validação
# ============================================================================
_validar_host() {
local host="$1"
local hostname="${host##*@}"
if [[ ! "$hostname" =~ ^[a-zA-Z0-9][a-zA-Z0-9._-]*$ ]] || [ ${#hostname} -gt 253 ]; then
return 1
fi
return 0
}
_validar_opcao_ssh() {
local option="$1"
if [[ ! "$option" =~ ^-[a-zA-Z][a-zA-Z0-9]*= ]]; then
return 1
fi
return 0
}
_validar_layout() {
local layout="$1"
for valid_layout in "${VALID_LAYOUTS[@]}"; do
if [ "$layout" = "$valid_layout" ]; then
return 0
fi
done
return 1
}
# ============================================================================
# Funções Auxiliares
# ============================================================================
_escapar_para_tmux() {
local string="$1"
string="${string//\\'/\\'\\\\\\'\\'}"
echo "'$string'"
}
command_exists() {
command -v "$1" &>/dev/null
}
# ============================================================================
# Função de Ajuda
# ============================================================================
mostrar_ajuda() {
cat << 'EOF'
Uso: multi-ssh-tmux [OPÇÕES] [USUARIO@]HOST1 [[USUARIO@]HOST2 ...]
Opções:
--sync Ativa modo sincronizado (comandos replicados em todos os painéis)
-s, --session NOME Define um nome para a sessão tmux (padrão: multi-ssh-tmux)
-u, --user USUARIO Define um usuário padrão para hosts sem usuário
-o, --ssh-option Passa opções específicas para o SSH (ex: -StrictHostKeyChecking=no)
-l, --layout LAYOUT Define o layout tmux (padrão: tiled)
-d, --detach Cria a sessão mas não anexa
-c, --command CMD Executa comando em todos os hosts após conexão
-f, --file ARQUIVO Lê hosts de um arquivo (um por linha)
--list Lista todas as sessões tmux existentes
-h, --help Mostra esta ajuda
EOF
}
# ============================================================================
# Função Principal
# ============================================================================
main() {
local sync_mode=false
local hosts=()
local session_name="multi-ssh-tmux"
local default_user="${SSH_DEFAULT_USER:-$USER}"
local ssh_options=()
local layout="tiled"
local attach=true
local initial_command=""
local hosts_file=""
while [[ $# -gt 0 ]]; do
case $1 in
--sync) sync_mode=true; shift ;;
-s|--session) session_name="$2"; shift 2 ;;
-u|--user) default_user="$2"; shift 2 ;;
-o|--ssh-option) ssh_options+=("-$2"); shift 2 ;;
-l|--layout) layout="$2"; shift 2 ;;
-d|--detach) attach=false; shift ;;
-c|--command) initial_command="$2"; shift 2 ;;
-f|--file) hosts_file="$2"; shift 2 ;;
--list) tmux list-sessions 2>/dev/null || _info "Nenhuma sessão tmux ativa"; return 0 ;;
-h|--help) mostrar_ajuda; return 0 ;;
-*) _error "Opção desconhecida: $1"; return 1 ;;
*)
if [[ "$1" != *"@"* ]]; then
hosts+=("${default_user}@$1")
else
hosts+=("$1")
fi
shift
;;
esac
done
if [ -n "$hosts_file" ]; then
if [ ! -f "$hosts_file" ]; then
_error "Arquivo não encontrado: $hosts_file"
return 1
fi
while IFS= read -r host; do
[ -z "$host" ] && continue
[[ "$host" =~ ^[[:space:]]*# ]] && continue
host=$(echo "$host" | xargs)
if [[ "$host" != *"@"* ]]; then
hosts+=("${default_user}@$host")
else
hosts+=("$host")
fi
done < "$hosts_file"
fi
if [ ${#hosts[@]} -eq 0 ]; then
_error "Nenhum host especificado"
return 1
fi
if [ ${#hosts[@]} -gt $MAX_HOSTS ]; then
_error "Máximo de hosts permitido: $MAX_HOSTS"
return 1
fi
if ! command_exists tmux; then
_error "tmux não está instalado. Execute: sudo apt install tmux"
return 1
fi
if tmux has-session -t "$session_name" 2>/dev/null; then
_error "Já existe uma sessão tmux com o nome '$session_name'"
return 1
fi
local ssh_cmd="ssh"
for option in "${ssh_options[@]}"; do
ssh_cmd+=" $option"
done
trap 'tmux kill-session -t "$session_name" 2>/dev/null' RETURN
local first_host_escaped=$(_escapar_para_tmux "${hosts[0]}")
if ! tmux new-session -d -s "$session_name" "$ssh_cmd $first_host_escaped" 2>/dev/null; then
_error "Falha ao conectar ao host ${hosts[0]}"
return 1
fi
for host in "${hosts[@]:1}"; do
local host_escaped=$(_escapar_para_tmux "$host")
if ! tmux split-window -t "$session_name" "$ssh_cmd $host_escaped" 2>/dev/null; then
_warn "Falha ao criar painel para $host"
continue
fi
tmux select-layout -t "$session_name" tiled 2>/dev/null
done
tmux select-layout -t "$session_name" "$layout" 2>/dev/null
if [ -n "$initial_command" ]; then
tmux send-keys -t "$session_name" "$initial_command" Enter
sleep 0.5
fi
if [ "$sync_mode" = true ]; then
tmux set-window-option -t "$session_name" synchronize-panes on
_success "Sessão '$session_name' criada com modo sincronizado ativado"
else
_success "Sessão '$session_name' criada com ${#hosts[@]} painéis"
fi
trap - RETURN
if [ "$attach" = true ]; then
tmux attach-session -t "$session_name"
fi
}
main "$@"
Torne o script executável:
sudo chmod +x /usr/local/bin/multi-ssh-tmux
Para executar comandos em todos os 6 nós do cluster simultaneamente (ideal para atualizar pacotes, desativar swap, carregar módulos do kernel):
# Usando IPs diretos e ativando a sincronização (--sync)
multi-ssh-tmux --sync \
suporte@10.48.9.2 suporte@10.48.9.3 suporte@10.48.9.4 \
suporte@10.48.9.20 suporte@10.48.9.21 suporte@10.48.9.22
Ou, se o DNS já estiver funcionando perfeitamente a partir do seu gateway/bastion:
multi-ssh-tmux --sync -u suporte \
kube-ctrl-01 kube-ctrl-02 kube-ctrl-03 \
kube-worker-01 kube-worker-02 kube-worker-03
Quando precisar instalar algo específico apenas nos workers:
multi-ssh-tmux --sync -s k8s-workers \
suporte@10.48.9.20 suporte@10.48.9.21 suporte@10.48.9.22
Quando precisar gerenciar o etcd ou componentes da API:
multi-ssh-tmux --sync -s k8s-ctrl \
suporte@10.48.9.2 suporte@10.48.9.3 suporte@10.48.9.4
Quando estiver dentro da sessão sincronizada, lembre-se destes atalhos importantes (assumindo que o prefixo padrão do tmux seja Ctrl+b):
Ctrl+b, solte, e digite :setw synchronize-panes (útil se precisar digitar uma senha diferente em apenas um nó).Ctrl+b e as setas direcionais.Ctrl+b e depois d (detach).exit nos terminais (como a sincronização está ativa, fechará todos de uma vez).Para reconectar a uma sessão que ficou em background:
tmux attach -t multi-ssh-tmux