Archive for the 'Dicas' Category

Criando DNS dinâmicos com sua conta no DreamHost

Sou cliente do DreamHost já faz um tempo e acho o serviço deles sensacional.

Uma feature que eu ainda não tinha usado é a API que eles disponibilizam para todos os clientes. Bem bacana e flexível.

Como em casa eu tenho IP dinâmico e vez por outra ele muda justamente quando preciso acessar de volta resolvi aproveitar e fiz um shell script quick’n dirty pra usar esse recurso bacana.

Sei que existem diversos serviços de DNS dinâmico por ai, mas preferi essa alternativa que pode ser útil pra mais alguém com uma necessidade parecida. ;)

Tá aqui o script.

Túnel SSH reverso

Dica rápida e muito útil:

Se você já precisou acessar um servidor Linux atrás de um NAT sobre qual você não tem controle sabe como seria bom poder iniciar a conexão do lado do servidor conectando de volta em você.

Isso é possível com um túnel SSH reverso. A idéia é que o servidor que você deseja acessar inicia a conexão do lado dele, conecta-se na sua máquina e disponibiliza, via túnel SSH uma porta de volta pra ele.

Eu uso isso como um acesso rápido de casa para a empresa naqueles casos onde preciso só acessar rapidamente alguma coisa vinha linha de comando. Tenho acesso VPN se precisar de email, Terminal Services, etc. Seria possível fazer tudo via túnel, mas ai o desempenho não fica grandes coisas e nem é tão conveniente.

O comando (a ser executado do servidor atrás do NAT) é:

ssh -nNT -R 2222:localhost:22 username@suamaquina

Uma vez estabelecido o túnel você pode conectar de volta à partir da sua máquina utilizando:

ssh -p 2222 username@localhost

Como é possível que a conexão caia, o processo trave ou sei lá o que mais, recomendo os seguintes truques:

  • Use chaves públicas para autenticação, assim não precisa de senha
  • Rode a sessão inicial dentro do screen, isso evita perder o console
  • Rode o túnel dentro de um loop while, pro processo poder ser restaurado caso morra
  • Pra evitar alguém te sacanear crie um usuário dedicado pra essa conexão e aponte o shell dele para /bin/false

Multi Master Replication Manager (MMM)

UPDATE: Acho que arrumei a formatação. Deve estar legível agora.
!!!ATENÇÃO – A visualização de algumas sessões pode estar truncando conteúdo! Pelo jeito a tag <pre> tá quebrada. Preciso olhar isso, mas preguiça, né? Dá pra ler direitinho usando o RSS !!!!

Mesmo com a a infra-estrutura toda virtualizada e clusterizada nos ESXi fazer um cluster de MySQL ainda é uma boa idéia.

Não só você pode colocar as duas máquinas em storages diferentes e eliminar mais um ponto de falha mas também você pode dedicar uma (ou mais) VM(s) para read-only.

Isso quer dizer que seus usuários rodando reports e chamando estatísticas/gráficos no meio do dia não vão afetar o desempenho de quem está entrando operações em produção.

Isso dito entra em cena o MySQL Multi Master Replication Manager (MMM): Um conjunto de scripts Perl que facilita a replicação e gerenciamento do seu cluster MySQL.

Abaixo os passos que utilizei para criar um cluster de 2 máquinas CentOS 5.5. Vou assumir que você já tem as máquinas em pé com MySQL devidamente instalado.

Além das máquinas rodando o MySQL você vai precisar de uma terceira, que é o monitor. É esse cara que vai manter os olhos no cluster, decidir quando uma máquina morreu e gerenciar os papéis de cada uma.

Nem idéia ainda dos requisitos mínimos desse servidor, visto que apenas fiz um teste pequeno aqui. Mas tá rodando sem reclamar em 1 processador e 512 de RAM.

Cenário:

IP Leitura/Gravação MySQL -> 10.0.0.1

IP Somente Leitura MySQL -> 10.0.0.100

IP Servidor MySQL 1 (hostname master) -> 10.0.0.2

IP Servidor MySQL 2 (hostname master2) -> 10.0.0.3

IP Monitor (hostname mon) -> 10.0.0.10

Editando a configuração do MySQL:

Em cada um dos servidores adicione as seguintes linhas embaixo da sessão [mysqld] do /etc/my.cnf:

#MMM
read-only
replicate-ignore-db = mysql
binlog-ignore-db = mysql
log-bin=master-binary
relay-log=master-relay
server-id=2
Atenção!! master (ali no log-bin e relay-bin) é o HOSTNAME da máquina em questão. Então no meu caso no outro servidor o arquivo receberá as linhas:
#MMM
read-only
replicate-ignore-db = mysql
binlog-ignore-db = mysql
log-bin=master2-binary
relay-log=master2-relay
server-id=2
Isso vai evitar que mudanças sejam feitas no banco de dados mysql e também define um nome único para os logs que vamos usar mais tarde.
Não esqueça do restart no serviço.

Instalando o MMM:

Não sei vocês, mas já passei da idade de compilar pacote na mão. Eu instalo a EPEL e já era.
Nos servidores MySQL:

rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm
yum -y install perl-Algorithm-Diff perl-Class-Singleton perl-DBD-MySQL perl-Log-Log4perl perl-Log-Dispatch perl-Proc-Daemon perl-MailTools
yum install mysql-mmm.noarch mysql-mmm-agent.noarch mysql-mmm-tools.noarch

Configurando os Usuários:

Dentro de cada servidor precisamos criar 3 usuários: replication, agent e monitor. Abra seu console do MySQL e mande:

GRANT REPLICATION CLIENT                 ON *.* TO 'mmm_monitor'@'10.0.0.%' IDENTIFIED BY 'monitor_password';
GRANT SUPER, REPLICATION CLIENT, PROCESS ON *.* TO 'mmm_agent'@'10.0.0.%'   IDENTIFIED BY 'agent_password';
GRANT REPLICATION SLAVE                  ON *.* TO 'replication'@'10.0.0.%' IDENTIFIED BY 'replication_password';
FLUSH PRIVILEGES;
FLUSH TABLES WITH READ LOCK;

Abra duas sessões (uma em cada MySQL) e não as feche depois de rodar os comandos acima. Com eles executados faça a seguir:

SHOW MASTER STATUS;

E o resultado vai ser algo como:

mysql> SHOW MASTER STATUS;
+-----------------------+----------+--------------+------------------+
| File                  | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-----------------------+----------+--------------+------------------+
| master2-binary.000003 |       98 |              | mysql            |
+-----------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
mysql>

Você vai usar essa informação nos comandos abaixo. Note que você deve utilizar o output da execução em uma máquina no input da outra, de forma que crie uma cross-reference entre elas:

change master to master_host = '10.0.0.3', master_user='replication', master_password='replication_password', master_log_file='master2-binary.000001', master_log_pos=98;

A seguir vamos editar o /etc/mysql-mmm/mmm_common.conf:

active_master_role      writer

<host default>
    cluster_interface       eth1
    pid_path                /var/run/mysql-mmm/mmm_agentd.pid
    bin_path                /usr/libexec/mysql-mmm/
    replication_user        replication
    replication_password    replication_password
    agent_user              mmm_agent
    agent_password          agent_password
</host>

<host master>
    ip      10.0.0.2
    mode    master
    peer    master2
</host>

<host master2>
    ip      10.0.0.3
    mode    master
    peer    master
</host>

<role writer>
    hosts   master,master2
    ips     10.0.0.1
    mode    exclusive
</role>

<role reader>
    hosts   master,master2
    ips     10.0.0.100
    mode    balanced
</role>

Este arquivo deve ser exatamente o mesmo nos dois lados do cluster!

E só fica faltando agora editar o /etc/mysql-mmm/mmm_agent.conf:

include mmm_common.conf
this master
A variável “this” indica o hostname. Portanto no meu caso o outro servidor vai ter um “this master2″

Com tudo isso pronto vamos no servidor de monitoramento e fazemos:

rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm
yum install mysql-mmm-monitor.noarch

Copiamos nele também o /etc/mysql-mmm/mmm_common.conf.

E depois editamos o /etc/mysql-mmm/mmm_mon.conf:

<monitor>
    ip                  127.0.0.1
    pid_path            /var/run/mysql-mmm/mmm_mond.pid
    bin_path            /usr/libexec/mysql-mmm
    status_path         /var/lib/mysql-mmm/mmm_mond.status
    ping_ips            10.0.0.1,10.0.0.2,10.0.0.3,10.0.0.100
    auto_set_online     60

    # The kill_host_bin does not exist by default, though the monitor will
    # throw a warning about it missing.  See the section 5.10 "Kill Host
    # Functionality" in the PDF documentation.
    #
    # kill_host_bin     /usr/libexec/mysql-mmm/monitor/kill_host
    #
</monitor>

<host default>
    monitor_user        mmm_monitor
    monitor_password    monitor_password
</host>

debug 0

Iniciando os serviços:

Nos servidores MySQL:

service mysql-mmm-agent start
chkconfig mysql-mmm-agent on

No servidor de monitoração:

service mysql-mmm-monitor start
chkconfig mysql-mmm-monitor on

Se tudo correu bem em alguns segundos você vai ter os serviços rodando e pode ver o status deles à partir do servidor de monitoração com o seguinte comando:

[root@mon ~]# mmm_control show
  master(10.0.0.2) master/ONLINE. Roles: writer(10.0.0.1)
  master2(10.0.0.3) master/ONLINE. Roles: reader(10.0.0.100)
Agora é só aprender mais sobre as opções do mmm_control e correr pro abraço.

Referências:

http://www.packtpub.com/article/install-manage-use-mmm-for-mysql-high-availability

http://www.packtpub.com/article/setting-up-mysql-replication-for-high-availability?utm_source=rk_mysql_cb_abr2_0510&utm_medium=content&utm_campaign=ramsai

http://fedoraproject.org/wiki/EPEL/FAQ#What_is_EPEL.3F

http://mysql-mmm.org/mmm2:guide

Restingindo acesso com rbash

Como sysadmins vez por outra a gente precisa dar acesso a clientes, parceiros ou outro tipo de usuário temporário/untrusted aos servidores. Apesar de criar um jail root completo ser a melhor solução muitas vezes é mais trabalho do que o necessário e começa a entrar naquele cenário em que a segurança atrapalha a usabilidade e os negócios.

Uma forma simples de conseguir uma segurança bacana é utilizar o modo restrito do bash. Com isso habilitado o shell irá desabilitar as seguintes funções:

  • Mudar o diretório (cd)
  • Mudar o valor das variáveis SHELL, PATH, ENV, or BASH_ENV
  • Comandos que incluem /
  • Especificar um arquivo que contenha / como fonte para o comando “.”
  • Usar redirecionamento de output (>, >>, |)
  • etc (man bash para todas as features)

Colocando para rodar:

Crie um link do bash para o rbash e adicione o mesmo em /etc/shells:

ln -s /bin/bash /bin/rbash
echo /bin/rbash >> /etc/shells

Depois é só mudar o shell do usuário a ser restringido para usar o rbash:

usermod -s /bin/rbash username

Combinando isso com traps (do CTRL+C, por exemplo) você consegue criar um ambiente seguro o suficiente para fornecer serviços e acessos aos seus servidores e ainda assim dormir à noite.

Como diria o SuSE: Have a lot of fun!

Não reinvente a roda você também


Preâmbulo:

Recentemente coloquei no ar o FollowUpTime, que como já disse em outros posts é um sistema de monitoração para redes e servidores.

Como podem imaginar, um bocado de linhas de código está envolvida num sistema assim e a conta só do engine principal passa das 90 mil linhas. Isso sem incluir templates, javascripts, etc.

O sistema é composto de duas partes: Uma que roda num servidor principal gerenciando a maior parte das tarefas e as “probes”. As probes são pequenos scripts que recebem instruções sobre hosts a serem testados e respondem para o servidor principal com o tempo de resposta, um OK ou um FAIL. Simples assim.

São essas probes que temos espalhados por vários cantos do planeta.

Porém quando recebi a probe dos desenvolvedores me vi com um pequeno, mas incoveniente problema. Os desenvolvedores realmente optaram pelo princípio KISS. Eles me entregaram uma excelente probe que fazia o que era necessário. E nada mais. Eu tinha nas mãos um daemon que rodava em foreground e jogava mensagens para stdout e stderr e nada mais.

Eu não me demorei e ataquei o problema da forma errada, pensando como um programador e não como um administrador Unix. E acabei reinventado a roda.

Introdução – O problema

Quando percebi o que eu tinha nas mãos logo pensei nos problemas que eu precisava resolver:

  • Preciso iniciar o daemon sempre que der boot na máquina
  • Preciso ser capaz de rodar em daemon em background, ou vai me zoar a seqüencia de boot
  • Posso precisar parar/reiniciar/iniciar manualmente este daemon
  • Se o processo morrer eu tenho que ser notificado e que, de preferência, ele seja reiniciado automaticamente
  • E sim, esse processo não deve rodar como root

Já velhaco de Linux logo pensei num script para ser colocado em /etc/init.d/ que ia resolver boa parte dos meus problemas. Com uma combinação bonita de bash scripting, várias ferramentas e comandos Linux que só se conhece depois de muito tempo de casa (como nohup, pidof, &) e gambiarras na crontab eu consegui. Consegui reinventar a roda. Não vou entrar em detalhes da solução que fiz, pois apesar de 100% funcional não era nem de perto tão bonita quanto:

A solução – Daemontools

Nosso caro amigo D.J.B, autor do famoso Qmail também já passou por um problema parecido com o meu, mas ao invés de criar um solução simples para resolver um problema pontual ele foi mais longe. Ele criou uma solução global que atende o problema dele, o meu e provavelmente também o seu.

Na página oficial do daemontools tem uma tabela, que traduzo abaixo, comparando a ferramenta dele com outras abordagens (incluindo a minha, que utilizava init.d):

Funcionalidade inittab ttys init.d rc.local /service
Fácil instalação e remoção de serviços Não Não Sim Não Sim
Simples startup inicial Não Não Não Não Sim
Reinicializações confiáveis Sim Sim Não Não Sim
Sinalização simples e confiável Não Não Não Não Sim
Estado de processo limpo Sim Sim Não Não Sim
Portabilidade Não Não Não Não Sim

Dá para perceber que o cara pensou em tudo e não tem porquê reinventar a roda. Vamos utilizar o daemontools!

Continue reading ‘Não reinvente a roda você também’

Nested variables no Bash

Não sei ao certo como é o nome em português. Variáveis aninhadas? :-P

Me deparei com um problema assim hoje: Eu tinha uma função num script shell que recebia um parâmetro de sucesso ou erro. Eu executava algumas coisas e depois tinha que jogar uns dados no arquivo respectivo.

Então inicialmente tinha setado uma variável com os paths dos caminhos:

1
2
ARQUIVO_SUCESSO=/tmp/sucesso
ARQUIVO_ERRO=/tmp/erro

Minha função recebia o status como o primeiro argumento ($1) e por isso depois de processar eu precisaria de algo assim:

1
echo "batatinha" >> $ARQUIVO_$1

Mas logo percebi que isso não funciona. A solução, no entanto, é simples:

1
echo "batatinha" >>  $(eval echo \$ARQUIVO_$1)

Anotem ai na caixa de truques do Bash.

Truques no Bash

Alguns truques para facilitar o seu dia-a-dia na linha de comando:

!$

Representa a última parte do último comando executado. Exemplo:

$ grep macarrao comidas.txt
macarrao
$  cat !$
cat comidas.txt
arroz
feijao
batata frita
macarrao

Expansão automática

Expande automaticamente os valores entre chaves. Uma mão na roda para loops:

$ for i in {1..4}; do echo "i vale $i"; done
i vale 1
i vale 2
i vale 3
i vale 4

Também funciona com letras:

$ for i in {a..d}; do echo "i vale $i"; done
i vale a
i vale b
i vale c
i vale d

E pode ser útil em situações assim:

$ mkdir -p diretorio{a..c}/sub-diretorio{w..z}
$ find .
.
./diretorioc
./diretorioc/sub-diretoriow
./diretorioc/sub-diretoriox
./diretorioc/sub-diretorioz
./diretorioc/sub-diretorioy
./diretoriob
./diretoriob/sub-diretoriow
./diretoriob/sub-diretoriox
./diretoriob/sub-diretorioz
./diretoriob/sub-diretorioy
./diretorioa
./diretorioa/sub-diretoriow
./diretorioa/sub-diretoriox
./diretorioa/sub-diretorioz
./diretorioa/sub-diretorioy

^antigo^novo

Executa o último comando substituindo o valor antigo pelo novo. Exemplo:

$ cat /etb/lsb-release
cat: /etb/lsb-release: No such file or directory
$ ^b^c
cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=8.10
DISTRIB_CODENAME=intrepid
DISTRIB_DESCRIPTION="Ubuntu 8.10"

!!

Reexecuta o último comando. Útil quando você esqueceu algo, como o sudo na frente do comando. Exemplo:

$ whoami
user
$ sudo !!
sudo whoami
root

Mais truques e dicas aqui.

Lighttpd como proxy

Esses dias me deparei com a seguinte situação: Precisava implementar um serviço baseado em web. Esse serviço vai acumular bastante informações sobre a infra-estrutura da empresa e por isso precisa de autenticação para garantir que apenas as pessoas corretas tenham acesso a essas informações.

Mas por motivos que nem vale a pena citar, afinal não quero uma gastrite, o bagulho não aceita autenticação.

A forma que eu arranjei para resolver isso foi simples: A porta do serviço original é bloqueada via iptables e instalei o lighttpd para servir como proxy, já me aproveitando das features de autenticação dele.

Caso precise fazer algo parecido com isso um dia, segue abaixo como fiz:

Na sessão server.modules adicione:

            "mod_proxy",

E logo depois dessa sessão adicione:

auth.backend = "htpasswd"
auth.backend.htpasswd.userfile = "/etc/lighttpd/.htpasswd"
auth.require = ( "/" =>
  (
    "method"  => "basic",
    "realm"   => "status",
    "require" => "valid-user"
  )
)

$HTTP["remoteip"] == "192.168.0.0/24" {
          proxy.server  = ( "" => (
          ( "host" => "127.0.0.1", "port" => 8080 )
           )
      )
}

Onde:

192.168.0.0/24 = Rede que poderá acessar a aplicação

“host” => “127.0.0.1″, “port” => 8080 = IP e porta originais da sua aplicação.

Utilizando o VIM como IDE para o Bash

Como já devem saber eu sou da turminha do vi. Nada contra o Emacs, lógico, mas vi é vi.
O relacionamento com ele nunca começa bem. Lembro-me que a primeira vez que abri o vi, num SCO Unix, o único jeito que consegui sair do editor foi rebootando a máquina. Eu não tinha nem idéia de que bastava um ESC:q! para cumprir a tarefa. Mas passados 11 anos ou mais deste início traumático, posso dizer que me dou bem com o editor hoje em dia, utilizando-o inclusive para escrever posts no meu blog, como neste momento o faço.

Às vezes o que sentia falta era de alguma coisa para facilitar minha vida quando estava fazendo meus scripts. Alguns pedaços de código você usa de novo, de novo e de novo. E é um saco ficar redigitando.
Importar para dentro do arquivo atual (ESC:r /path/arquivo) ajuda, mas não resolve.

A solução

Pesquisando achei o sensacional BASH-IDE para vim. Resolveu todos os meus problemas, exceto a falta de competência como programador.
Utilizando o BASH-IDE podemos configurar um template para novos arquivos, de forma que sempre que abro um novo arquivo .sh no vim ele já adiciona o cabeçalho com informação sobre o autor, data, tag $id$ pro cvs e algumas variáveis e funções que eu coloco em todos os meus script.

O autor do BASH-IDE foi cuidadoso para facilitar a documentação de forma que vários atalhos já são auto-documentados.
Uma nova função criada utilizando o BASH-IDE automaticamente terá o seguinte aspecto:

function teste ()
{

}    # ----------  end of function teste  ----------

E ao chamar o atalho para documentação de função você recebe este template:

#===  FUNCTION  ================================================================
#          NAME:
#   DESCRIPTION:
#    PARAMETERS:
#       RETURNS:
#===============================================================================

Como tudo é baseado em arquivos texto, as customizações só dependem da sua boa vontade. E ainda vem com um uma cheat sheet em pdf pronta para imprimir e pendurar na sua baia! :)

Boa diversão

Morre!

Uma funçãozinha muito útil do Perl é a “die”. Fica fácil gerar mensagens de erro e já abortar a execução numa tacada só.

Segue a versão primo-pobre para bash:

function die () { echo "$progname: $1"; exit ${2:-1}  ; }

Exemplos de uso:

[ ! -f /tmp/teste.txt ] && die "Arquivo não existe"

ou

[ "$A" -ne 0 ] && die "Nao encontrei o zero" 99