The Abigail Oath

We'll call it "The Abigail Oath" and require all new sysadmins to swear it.

MySQL Binary Logs: Porque Meu HD Está Cheio?

| Comments

Se o diretório onde está alocado os arquivos data de seu MySQL está crescendo mais que o normal, possivelmente você está tendo problemas com a configuração quanto a flag que determina o uso dos binlogs.

Binlogs em sua essência são utilizados para realizar a replicação de bancos de dados e em algumas ocasiões te salvar quando algum dado é perdido, se você não realiza a replicação e tampouco se preocupa com o armazenamento dos binlogs, não existe sentido manter essa configuração.

Para desabilitar esta opção, comente a linha no seu /etc/mysql/my.cnf que diz log-bin=mysql-bin onde define que os binlogs devem ser criados e indica qual nome dos arquivos. Você ainda pode parar a geração dos binlogs on-the-fly utilizando o seguinte comando como usuario root

mysql> SET GLOBAL SQL_LOG_BIN=0;
Query OK, 0 rows affected (0.00 sec)

Este comando na verdade não desabilita o binlogs e sim, ignora INSERTs, DDLs, UPDATEs, e DELETEs, para que a alteração seja permanente você ainda terá que editar o /etc/mysql/my.cnf.

Caso você faça uso dos binlogs, você ainda pode definir um tamanho e qual a frequencia de criação destes arquivos, ajustando de acordo com a necessidade do uso, utilizando as flags:

  • max_binlog_size: que define qual tamanho maximo do arquivo em kilobytes. quando atingir este valor será criado um novo arquivo sequencial no formato nome-do-arquivo.XXXXXX

  • expire_logs_days: que define de quanto em quanto dias os binlogs serão removidos, recomenda-se utilizar o periodo minimo de 10 dias, dependendo do atraso entre o master e slave quando existir a replicação de bancos.

  • binlog-ignore-db: que especifica quais databases podem ser ignoradas pelo binlog.

  • binlog-do-db: que especifica quais databases devem ser monitoradas e os comandos salvos no binlog.

Feita a configuração, e tendo certeza que os binlogs armazenados não são mais necessários, você poderá excluir todos os binlogs através do comando

mysql> RESET MASTER;
Query OK, 0 rows affected (0.00 sec)

ou se o mysqld estiver configurado como SLAVE

mysql> RESET SLAVE;
Query OK, 0 rows affected (0.06 sec)

Você ainda poderá especificar quais binlogs devem ser removidos pela sequencia da criação dos arquivos

mysql> PURGE BINARY LOGS TO 'mysql-bin.000015';
Query OK, 0 rows affected (0.08 sec)

ou através da data de criação

mysql> PURGE BINARY LOGS BEFORE '20012-11-10 00:00:00';
Query OK, 0 rows affected (0.11 sec)

Ou mesmo utilizando o mysqladmin com o parametro flush-logs, que exclui qualquer binlog anterior a 3 dias

jazz//deadcow ~ % mysqladmin -u root flush-logs

A remoção dos binlogs devem ser realizadas através do proprio MySQL, remoções diretas podem causar efeitos inesperados no comportamento normal do serviço.

A geração de logs pelo mysqld pode ser util ao identificar problemas de performance, porém devem ser tratados com certa cautela para que uma solução não vire uma dor de cabeça. ainda existem outros fatores que podem contribuir para o aumento do uso do disco pelo mysqld e que serão abordados em outros posts no futuro.

O Mod_gzip Está Funcionando?

| Comments

Um jeito simples de verificar se seu site está realmente enviando paginas comprimidas para o cliente, sem ter que instalar um plugin no seu browser é utilizar o parametro --header do wget.

–header=header-line
Send header-line along with the rest of the headers in each HTTP request. The supplied header is sent as-is, which means it must contain name and value separated by colon, and must not contain newlines.

man wget Retirado Do Manual Pages

Passando ao parametro --header do wget Accept-Encoding: gzip é possivel baixar a página comprimida, claro se o servidor tiver esta opção

deadcow@jazz ~ $ wget --header='Accept-Encoding: gzip' \
http://www.uol.com.br -O sample.gz
--2012-10-26 18:07:56--  http://www.uol.com.br/
Resolving www.uol.com.br... 200.221.2.45, 200.147.67.142
Connecting to www.uol.com.br|200.221.2.45|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: ‘sample.gz’

    [  <=>                               ] 86,339       211KB/s   in 0.4s

2012-10-26 18:07:57 (211 KB/s) - ‘sample.gz’ saved [86339]

deadcow@jazz ~ $ file sample.gz
sample.gz: gzip compressed data, from Unix
deadcow@jazz ~ $

Já se o servidor não oferece este recurso, o comando file retornará uma página html normal

deadcow@jazz ~ $ wget --header='Accept-Encoding: gzip' \
http://www.blunt.com.br -O sample.gz
--2012-10-26 18:08:17--  http://www.blunt.com.br/
Resolving www.blunt.com.br... 216.14.115.179
Connecting to www.blunt.com.br|216.14.115.179|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: ‘sample.gz’

    [     <=>                            ] 45,874      53.6KB/s   in 0.8s

2012-10-26 18:08:19 (53.6 KB/s) - ‘sample.gz’ saved [45874]

deadcow@jazz ~ $ file sample.gz
sample.gz: HTML document, ISO-8859 text, with very long lines, \
with CR, LF line terminators
deadcow@jazz ~ $

Além do Accept-Encoding: gzip, você pode passar qualquer parametro para o servidor, substituindo os valores padrões do wget, muito util para testar alguns redirecionamentos

deadcow@jazz ~ $ wget --header='Host: ig.com.br' \
http://www.uol.com.br
--2012-10-26 18:14:45--  http://www.uol.com.br/
Resolving www.uol.com.br... 200.221.2.45, 200.147.67.142
Connecting to www.uol.com.br|200.221.2.45|:80... connected.
HTTP request sent, awaiting response... 302 Found
Location: http://www.uol.com.br/ [following]
[...]
Connecting to www.uol.com.br|200.221.2.45|:80... connected.
HTTP request sent, awaiting response... 302 Found
Location: http://www.uol.com.br/ [following]
--2012-10-26 18:14:47--  http://www.uol.com.br/
Connecting to www.uol.com.br|200.221.2.45|:80... connected.
HTTP request sent, awaiting response... 302 Found
Location: http://www.uol.com.br/ [following]
20 redirections exceeded.
deadcow@jazz ~ $

Dica retirada do site nixcraft

The Abigail Oath

| Comments

I am hired because I know what I am doing, not because I will do whatever I am told is a good idea.

This might cost me bonuses, raises, promotions, and may even label me as “undesirable” by places I don’t want to work at anyway, but I don’t care.

I will not compromise my own principles and judgement without putting up a fight.

Of course, I won’t always win, and I will sometimes be forced to do things I don’t agree with. My objections will be made known.

If I am shown to be right and problems later develop, I will shout “I told you so!” repeatedly, laugh hysterically, and do a small dance or jig as appropriate to my heritage.

SSH Tips: Ssh-agent vs. Ssh_config

| Comments

Muitas vezes utilizamos chaves privadas para acessar servidores remotos via ssh, principalmente agora com a utilização de autenticações somente por chave como por exemplo a Engine Yard, que roda em cima do PaaS da amazon (AWS).

A maioria das pessoas costuma utilizar o ssh-agent como gerenciador dessas chaves, quase todos os tutoriais passo-a-passo a respeito de acesso remoto via ssh sem a utilização de senhas mencionam ele.

O problema é que nem todas as distribuições oferecem ele como pacote padrão, além disso, o ssh-agent adiciona apenas uma vez a chave a sessão, ele não vai requerer novamente a senha caso exista, isto pode ser visto como um problema de segurança.

Uma alternativa ao ssh-agent que pouca gente conhece é a associação do host destino a uma chave através do ssh_config, cada usuário tem a opção de criar um ssh_config próprio, para determinar o comportamento do cliente ssh.

Por padrão, o cliente ssh irá buscar a chave no caminho ~/.ssh/id_rsa e ~/.ssh_dsa para hosts que utilizem a versão 2 do protocolo ssh ou ~/.ssh/identity para hosts que utilizem o protocolo 1, para alterar este comportamento definindo um arquivo para cada host, edite ou crie o arquivo ~/.ssh/config adicionando as linhas:

~/.ssh/config
1
2
Host ssh.deadc.org
  IdentityFile ~/.ssh/id_rsa-deadc.org

sendo que o arquivo id_rsa-deadc.org é a nossa chave que utilizaremos para acesso o servidor remoto, além de definir uma chave para cada host, é possivel definir também para um grupo de host:

~/.ssh/config
1
2
Host *.deadc.org
  IdentityFile ~/.ssh/id_rsa-deadc.org

ou mesmo para todos os hosts:

~/.ssh/config
1
2
Host *
  IdentityFile ~/.ssh/id_rsa-deadc.org

Você poderá especificar mais de uma chave para cada host, cada chave será enviada para o servidor em sequencia, além disso, caso o ssh-agent esteja rodando e contenha alguma outra chave, ela também será enviada ao host na tentativa de se autenticar com o servidor. leia o man ssh_config para mais opções e informações a respeito.

MySQL: Binlogs Backup Full E Incremental

| Comments

Mysql binlogs são logs de todos os comandos enviados para o mysql, ele captura todos os comandos executados, desde um simples INSERT até um DROP DATABASE e insere indices atraves de datas e numeros sequenciais. É uma ferramenta muito poderosa, utilizada na replicação de banco de dados e também na realização de backups incrementais.

Por padrão, diversas distribuições linux deixam essa opção desabilitada nos pacotes tradicionais do mysql-server, se este for o caso da sua instalação, habilite o binlog no seu servidor

/etc/mysql/my.cnf
1
2
log_bin                 = /var/lib/mysql/mysql-bin.log
expire_logs_days        = 10

O expire_logs_days é a quantidade de dias que os bin-logs devem permanecer no servidor antes que sejam deletados, já na primeira linha, indica onde os bin-logs serão salvos, neste caso em /var/lib/mysql, é uma boa idéia separar a pasta onde os arquivos serão salvos caso você deseje realizar o backup incremental.

[root@jazz ~]# ls -la /var/lib/mysql/mysql-bin.*
-rw-rw---- 1 mysql mysql 27287 Jul 15 15:02 /var/lib/mysql/mysql-bin.000001
-rw-rw---- 1 mysql mysql 35873 Jul 15 15:02 /var/lib/mysql/mysql-bin.000002
-rw-rw---- 1 mysql mysql   107 Jul 15 15:03 /var/lib/mysql/mysql-bin.000003
-rw-rw---- 1 mysql mysql    57 Jul 15 15:03 /var/lib/mysql/mysql-bin.index
[root@jazz ~]#

Embora no diretorio destino exista mais de um binlog, apenas um está ativo no momento, você pode verificar qual e em qual posição o mesmo se encontra executando o seguinte comando:

deadcow@jazz ~ $ mysql -u root -e 'SHOW MASTER STATUS;'
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 |      107 |              |                  |
+------------------+----------+--------------+------------------+
deadcow@jazz ~ $

Agora iremos criar uma database para exemplificar o uso do binlog

1
2
3
4
5
6
7
8
CREATE DATABASE `bk_test`;
USE `bk_test`;
CREATE TABLE `bk_test_t1` (
    `id` INT NOT NULL AUTO_INCREMENT,
    `test_field` VARCHAR(30) NOT NULL,
    `time_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB;

e então inserir algumas entradas

1
2
3
4
USE `bk_test`;
INSERT into `bk_test_t1` (test_field) VALUES ('val1');
INSERT into `bk_test_t1` (test_field) VALUES ('val2');
INSERT into `bk_test_t1` (test_field) VALUES ('val3');

Agora temos um banco de dados ativo com entradas validas para a realização de um backup, primeiro iremos realizar um full backup em nosso banco

mysqldump -uroot -p --all-databases --single-transaction --flush-logs \
--master-data=2 > full_backup.sql

A flag –flush-logs é utilizada para que o binlog ativo seja fechado e um novo seja criado, –master-data=2 adiciona comentários no dump com os indices do binlog, já a flag –single-transaction é utilizada para a realização consistente de dumps de bancos InnoDB, para quem não está familiarizado, uma forma simples de explicar uma transaction é dizer que é um unico comando, caso alguma entrada falhe, o comando inteiro será descartado e nenhuma alteração será feita no banco.

[root@jazz ~]# ls -la /var/lib/mysql/mysql-bin.*
-rw-rw---- 1 mysql mysql 27287 Jul 15 15:02 /var/lib/mysql/mysql-bin.000001
-rw-rw---- 1 mysql mysql 35873 Jul 15 15:02 /var/lib/mysql/mysql-bin.000002
-rw-rw---- 1 mysql mysql  1208 Jul 15 15:13 /var/lib/mysql/mysql-bin.000003
-rw-rw---- 1 mysql mysql    57 Jul 15 15:03 /var/lib/mysql/mysql-bin.index
[root@jazz ~]# mysqldump -uroot -p --all-databases --single-transaction \
> --flush-logs --master-data=2 > full_backup.sql
Enter password:
[root@jazz ~]# ls -la /var/lib/mysql/mysql-bin.*
-rw-rw---- 1 mysql mysql 27287 Jul 15 15:02 /var/lib/mysql/mysql-bin.000001
-rw-rw---- 1 mysql mysql 35873 Jul 15 15:02 /var/lib/mysql/mysql-bin.000002
-rw-rw---- 1 mysql mysql  1251 Jul 15 15:26 /var/lib/mysql/mysql-bin.000003
-rw-rw---- 1 mysql mysql   107 Jul 15 15:26 /var/lib/mysql/mysql-bin.000004
-rw-rw---- 1 mysql mysql    76 Jul 15 15:26 /var/lib/mysql/mysql-bin.index
[root@jazz ~]#

Agora iremos adicionar algumas entradas novas ao banco para exemplificar o backup incremental

1
2
3
4
USE `bk_test`;
INSERT into `bk_test_t1` (test_field) VALUES ('val4');
INSERT into `bk_test_t1` (test_field) VALUES ('val5');
INSERT into `bk_test_t1` (test_field) VALUES ('val6');

Como realizamos o flush-logs no backup full, as novas entradas devem estar no arquivo mysql-bin.000004, para realizarmos o backup incremental de forma consistente, precisamos iniciar um novo binlog e copiar o arquivo (ou arquivos) para outra localidade, para iniciar um novo binlog execute

[root@jazz ~]# mysqladmin -uroot -p flush-logs
[root@jazz ~]# ls -la /var/lib/mysql/mysql-bin.*
-rw-rw---- 1 mysql mysql 27287 Jul 15 15:02 /var/lib/mysql/mysql-bin.000001
-rw-rw---- 1 mysql mysql 35873 Jul 15 15:02 /var/lib/mysql/mysql-bin.000002
-rw-rw---- 1 mysql mysql  1251 Jul 15 15:26 /var/lib/mysql/mysql-bin.000003
-rw-rw---- 1 mysql mysql   885 Jul 15 15:38 /var/lib/mysql/mysql-bin.000004
-rw-rw---- 1 mysql mysql   107 Jul 15 15:38 /var/lib/mysql/mysql-bin.000005
-rw-rw---- 1 mysql mysql    95 Jul 15 15:38 /var/lib/mysql/mysql-bin.index
[root@jazz ~]#

Agora temos os componentes para realizar um restore a partir de um backup full e um incremental, nosso banco agora está desta forma

mysql> USER bk_test;
Database changed

mysql> SHOW TABLES;
+-------------------+
| Tables_in_bk_test |
+-------------------+
| bk_test_t1        |
+-------------------+
1 row in set (0.00 sec)

mysql> SELECT * FROM bk_test_t1;
+----+------------+---------------------+
| id | test_field | time_created        |
+----+------------+---------------------+
| 1  | val1       | 2012-07-15 15:13:53 |
| 2  | val2       | 2012-07-15 15:13:53 |
| 3  | val3       | 2012-07-15 15:13:54 |
| 4  | val4       | 2012-07-15 15:33:50 |
| 5  | val5       | 2012-07-15 15:33:50 |
| 6  | val6       | 2012-07-15 15:33:52 |
+----+------------+---------------------+
6 rows in set (0.00 sec)

mysql>

Digamos agora que acidentalmente a database que utilizamos foi completamente removida

mysql> DROP DATABASE bk_test;
Query OK, 1 row affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.00 sec)

mysql>

Tudo bem! temos o backup full e estamos a salvo certo?!

deadcow@jazz ~ $ mysql -u root < full_backup.sql
deadcow@jazz ~ $ mysql -u root
mysql> use bk_test;
Database changed

mysql> SELECT * FROM bk_test_t1;
+----+------------+---------------------+
| id | test_field | time_created        |
+----+------------+---------------------+
| 1  | val1       | 2012-07-15 15:13:53 |
| 2  | val2       | 2012-07-15 15:13:53 |
| 3  | val3       | 2012-07-15 15:13:54 |
+----+------------+---------------------+
3 rows in set (0.00 sec)

mysql>

Este backup não está completo, havia 6 entradas e agora só existem 3, mas ainda temos o backup incremental de um periodo posterior ao backup full, vamos aplica-lo

[root@jazz ~]# cd /var/lib/mysql/
[root@jazz mysql]# mysqlbinlog mysql-bin.000004 | mysql -u root bk_test
[root@jazz mysql]# mysql -u root bk_test

mysql> SELECT * FROM bk_test_t1;
+----+------------+---------------------+
| id | test_field | time_created        |
+----+------------+---------------------+
| 1  | val1       | 2012-07-15 15:13:53 |
| 2  | val2       | 2012-07-15 15:13:53 |
| 3  | val3       | 2012-07-15 15:13:54 |
| 4  | val4       | 2012-07-15 15:33:50 |
| 5  | val5       | 2012-07-15 15:33:50 |
| 6  | val6       | 2012-07-15 15:33:52 |
+----+------------+---------------------+
6 rows in set (0.00 sec)

mysql>

E tudo está recuperado, sem dores de cabeça. a ferramenta mysqlbinlog acompanha o pacote de instalação do mysql-server, ela retorna os comandos do binlog em plaintext e através dela é possivel recuperar o banco de dados, também pode se redirecionar a saida do programa para um arquivo e então editá-lo para excluir queries destrutivas antes de executar no mysql.

Além disso é possivel passar como parametro um periodo especifico de tempo para o mysqlbinlog, é muito util para recuperar pequenas quantidades de entradas perdidas em um banco de dados, desde que se conheca o periodo.

mysqlbinlog --start-datetime="2012-07-15 15:13:53" \ 
--stop-datetime="2012-07-15 15:13:54" mysql-bin.000004|mysql -uroot bk_test

Existem outras dezenas de possibilidades no MySQL que poucas pessoas conhecem, procure blogs, assine feeds e procure crescer profissionalmente através do seu conhecimento, facilite sua vida e a da sua empresa!

Referencias:

Ruby / DL: Acessando Funções Externas

| Comments

Eu estava precisando acessar uma DLL especifica no Windows para automatizar um processo no serviço, eu (ainda!) não domino muito a linguagem ruby, mas por conta de todos meus colegas de trabalho fazerem uso, inclusive do RoR meio que fui absorvido por essa linguagem que, depois de python virou uma das minhas preferidas.

Pois bem, depois de algumas tentativas frustradas na sexta-feira, resolvi no sábado pesquisar melhor como em ruby, acessar funções externas de dll’s e lib’s. meu maior problema na sexta era a falta de compatibilidade de versões do ruby, eu escrevia um código pra ruby 1.9.2 e tentava rodar em uma versão anterior, 1.8.7 (Windows em produção).

Em casa, consegui escrever 2 scripts para versões distintas e finalmente criar o script para acessar a DLL, o script é tão simples que cheguei seriamente a pensar em não publicar isso, mas como pode ser util para alguém, segue ai!

dlopen18.rb
1
2
3
4
5
require dl

dl = DL.dlopen(libcurl.so)
mycall = dl["curl_version",'S']
puts mycall.call

E a versão para Ruby 1.9.2, que é um pouquinho diferente, mas tão facil quanto:

dlopen19.rb
1
2
3
4
5
6
require dl
require fiddle

dl = DL.dlopen(libcurl.so)
mycall = Fiddle::Function.new(dl['curl_version'], [], Fiddle::TYPE_VOIDP)
puts mycall.call

Lembrando que por conta do uso do Fiddle, este exemplo só funciona no Ruby 1.9.3 ou superior, para ser 100% compativel com 1.9 você deve fazer as modificações necessárias.

Explicando: no primeiro script onde se lê “curl_version” é aonde vai o nome da função externa, que a lib ou dll contém, no segundo campo, é o tipo de entrada da função mais o tipo de retorno, se a função recebesse algum argumento como por exemplo do tipo String e retornasse um Inteiro, ficaria assim:

1
2
mycall = dl["funcao",'SI']
puts mycall.call(string)

no segundo script isso fica mais claro já que, o retorno fica no final, enquanto os argumentos dentro de um array, que neste caso está vazio já que a função não necessita de nenhum parametro. Mais referencias de como usar e sobre os tipos possiveis de entrada nas funções RTFM

uma dica para quem usa linux e quer saber quais funções determinada lib possui e não tem o código-fonte, é utilizar o comando nm:

deadcow@stack ~ $ nm –defined-only -D /usr/lib/libcurl.so|grep easy
00000000000297d0 T Curl_easy_addmulti
0000000000029b40 T Curl_easy_initHandleData
00000000000319c0 T Curl_multi_rmeasy
0000000000040270 T Curl_pp_easy_statemach
0000000000029e30 T curl_easy_cleanup
0000000000029c00 T curl_easy_duphandle
0000000000022de0 T curl_easy_escape
0000000000029e00 T curl_easy_getinfo
000000000002a0d0 T curl_easy_init
00000000000299b0 T curl_easy_pause
0000000000029e50 T curl_easy_perform
0000000000029930 T curl_easy_recv
0000000000029b60 T curl_easy_reset
0000000000029880 T curl_easy_send
0000000000029f40 T curl_easy_setopt
0000000000034e30 T curl_easy_strerror
0000000000022cb0 T curl_easy_unescape
deadcow@stack ~ $

obviamente consultando o oráculo depois para saber mais sobre a função!

MySQL Tips: Economizando Espaço E Tempo

| Comments

Quando faltar espaço em HD ou a transferência de dados de um ponto ao outro não ser 100/100mbit, voce pode realizar a migração do seu banco de dados da seguinte maneira:

deadcow@jazz ~ $ mysqldump -u root database | gzip > database.sql.gz

e para subir o banco após voce ter transferido para a nova maquina:

deadcow@jazz ~ $ gunzip < database.sql.gz | mysql -u root database

isto além de economizar o espaço em disco, aumenta a velocidade na transferência do arquivo já que ele vai ser pelo menos 40% menor que o tamanho original.

RVM Install REE/Ruby 1.8.7 With GCC 4.7

| Comments

Na instalação do ree/ruby 1.8.7 pelo RVM nas versões mais novas do gcc (estou utilizando a versão 4.7.2), o seguinte erro é apresentado quando você tenta rodar gem install bundler (não somente este comando, mas alguns outros também):

1
2
3
deadcow@jazz ~ $ gem install bundler
/home/deadcow/.rvm/rubies/ree-1.8.7-2012.02/lib/ruby/1.8/timeout.rb:60: [BUG] Segmentation fault
ruby 1.8.7 (2012-02-08 MBARI 8/0x6770 on patchlevel 358) [x86_64-linux], MBARI 0x6770, Ruby Enterprise Edition 2012.02

para resolver é muito simples, faça o seguinte procedimento:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
deadcow@jazz ~ $ rvm remove ree
Removing /home/deadcow/.rvm/src/ree-1.8.7-2012.02...
Removing /home/deadcow/.rvm/rubies/ree-1.8.7-2012.02...
Removing ree-1.8.7-2012.02 aliases...
Removing ree-1.8.7-2012.02 wrappers...
Removing ree-1.8.7-2012.02 environments...
Removing ree-1.8.7-2012.02 binaries...
deadcow@jazz ~ $ export CFLAGS="-O2 -fno-tree-dce -fno-optimize-sibling-calls"
deadcow@jazz ~ $ rvm install ree
Installing Ruby Enterprise Edition from source to: /home/deadcow/.rvm/rubies/ree-1.8.7-2012.02
ree-1.8.7-2012.02 - #fetching (ruby-enterprise-1.8.7-2012.02)
ree-1.8.7-2012.02 - #extracting ruby-enterprise-1.8.7-2012.02 to /home/deadcow/.rvm/src/ree-1.8.7-2012.02
Applying patch 'tcmalloc' (located at /home/deadcow/.rvm/patches/ree/1.8.7/tcmalloc.patch)
Applying patch 'stdout-rouge-fix' (located at /home/deadcow/.rvm/patches/ree/1.8.7/stdout-rouge-fix.patch)
Applying patch 'no_sslv2' (located at /home/deadcow/.rvm/patches/ree/1.8.7/no_sslv2.diff)
Applying patch 'lib64' (located at /home/deadcow/.rvm/patches/ree/lib64.patch)
ree-1.8.7-2012.02 - #installing
Removing old Rubygems files...
Installing rubygems-1.8.24 for ree-1.8.7-2012.02 ...
Installation of rubygems completed successfully.
ree-1.8.7-2012.02 - #importing default gemsets (/home/deadcow/.rvm/gemsets/)
deadcow@jazz ~ $ gem install bundler
Fetching: bundler-1.2.1.gem (100%)
Successfully installed bundler-1.2.1
1 gem installed
Installing ri documentation for bundler-1.2.1...
Installing RDoc documentation for bundler-1.2.1...
deadcow@jazz ~ $

e é isso