Docker para ambientes PHP

Eu venho usando Vagrant há algum tempo para criar ambientes de desenvolvimento isolados em máquinas locais. Basicamente o que Vagrant faz é gerenciar máquinas virtuais permitindo a definição de configurações para cada uma dessas máquinas de forma bem simples.
O motivo principal que me levou a usar a Vagrant, foi a possibilidade de isolar as configurações não só de sofware, mas também as de hardware em cada ambiente criado.
O problema identificado logo de cara, foi a falta de recursos existentes na máquina local para servir a cada máquina virtual dessas criadas, pois cada máquina criada é uma instalação completa de um sistema operacional, com suas necessidades de espaço em disco, memória etc. Com isso, geralmente o que eu fazia era usar uma máquina por vez, economizando recursos da máquina hospedeira, entretanto, o tempo, por exemplo, para iniciação e desligamento de cada máquina já era uma coisa chata, o que acabava me levando a juntar várias aplicações em uma mesma máquina, virando meio que um “sururu”.

A primeira vez que ouvi falar em Docker, achei a coisa tão “complicada” (leia preguiça de encarar mudanças), que fui empurrando com a barriga até os dias atuais e após encarar a verdade e tentar entender melhor o que é conteinerização, descobri que de fato o medo de mudanças deve ser encarado com mais coragem.

Basicamente, o que Docker me oferece hoje é a criação de serviços isolados com a possibilidade de relacionamento entre os mesmos. Vamos a um exemplo prático do dia a dia:

Uma aplicação básica criada em PHP, necessita de no mínimo três serviços distintos, um servidor web, um interpretador PHP e um servidor de banco de dados, por exemplo Nginx, PHP-FPM e MySQL. Normalmente, o que eu vinha fazendo era instalar o Nginx e o PHP-FPM em uma máquina com Vagrant e tinha uma segunda máquina com todos os bancos de dados servindo para outras aplicações.
Com Docker, eu tenho um serviço em cada container, sendo o relacionamento desses serviços muito mais fácil de configurar e mantendo isolado um conjunto de serviços para cada aplicação.

Você pode estar se perguntando, mas antes ele criava duas máquinas para uma aplicação, agora ele criará três?
Negativo. A diferença entre um container e uma máquina, é que o container usa apenas recursos básicos necessários para tal serviço funcionar, fazendo uso de recursos nativos do kernel do linux.

Mãos a obra!
Eu uso Ubuntu14.04 e instalei Docker seguindo esta documentação:
http://docs.docker.com.s3-website-us-east-1.amazonaws.com/engine/installation/linux/ubuntulinux/

Eu vou usar neste post o Docker Compose, que é uma ferramenta que minimiza bastante o trabalho
https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-compose-on-ubuntu-14-04#step-2-—-installing-docker-compose

Se você não usa Linux, nem tudo está perdido, existe http://boot2docker.io/, que poderá lhe ajudar com a execução de Docker.

No https://hub.docker.com/, encontramos diversas imagens já construídas que atendem inúmeras necessidades, incluindo imagens oficias como Apache, PHP, Nginx, MySQL dentre várias, contudo, acredito ser uma boa hora pra colocarmos em prática a possibilidade de construirmos a nossa própria imagem.

Crie um diretório e um subdiretório imagens/nginx, com dois arquivos: Dockerfile e start.sh

docker_imagem_nginx_1

 

No arquivo Dockerfile, vamos inserir o seguinte conteúdo:

 

FROM phusion/baseimage
MAINTAINER SEU NOME

CMD [“/sbin/my_init”]

RUN apt-get update && apt-get install -y python-software-properties
RUN add-apt-repository ppa:nginx/stable
RUN apt-get update && apt-get install -y nginx

RUN echo “daemon off;” >> /etc/nginx/nginx.conf
RUN ln -sf /dev/stdout /var/log/nginx/access.log
RUN ln -sf /dev/stderr /var/log/nginx/error.log

RUN mkdir -p /etc/service/nginx
ADD start.sh /etc/service/nginx/run
RUN chmod +x /etc/service/nginx/run

EXPOSE 80

RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

 

Dockerfile é o arquivo que registra todos os comandos que serão usados para a criação de uma imagem Docker, sugiro que você dê uma olhada em sua documentação
Vamos dar uma olhada no que cada comando faz, linha por linha:

Linha 1 – O comando FROM especifica o nome da imagem que será usada como imagem mãe da imagem que estamos criando. No nosso caso estamos usando a phufion/baseimage, que é uma imagem com Ubuntu(atualmente 16.04) com algumas ferramentas que simplificam a criação de container Docker.

Linha 2 – MAINTAINER é um comando que você usará para registrar seu nome e e-mail que serão vistos por outros desenvolvedores caso você compartilhe sua imagem em https://hub.docker.com/

Linha 3 – CMD Responsável por executar um comando embutido na imagem, nessa caso, ele executará /sbin/my_init, existente em phusion/baseimage

Linhas 4, 5 e 6 – Usa o comando RUM para instalar a ultima versão do Nginx

Linhas 7, 8 e 9 – Usar novamente o comando RUM para escrever no arquivo de configuração do Nginx e criar links simbólicos dos arquivos de logs.

Linhas 10, 11 e 12 – Copia o arquivo start.sh para o container, esse este é chamado por padrão pela imagem phusion/baseimage e, neste caso criamos um script para iniciar o Nginx.

Linha 13 – EXPOSE diz para o Docker as portas que devem ser escutadas em tempo de execução.

Linha 14 – Executa uma limpeza básica no apt e nos diretórios temporários.

Agora vamos inserir o conteúdo do arquivo start.sh

#!/usr/bin/env bash
service nginx start

Um script básico para executar o comando de iniciação do Nginx
Agora navegue até o diretório imagens/nginx e vamos executar o seguinte comando para a construção de nossa primeira imagem:

docker build -t tutorial/nginx .

 

Após diversas linhas geradas, o final deverá ser algo parecido com isso:

Processing triggers for systemd (229-4ubuntu6) ...
---> 9f1eb5866cca
Removing intermediate container b07bc3d4fbf4
Step 7 : RUN echo "daemon off;" >> /etc/nginx/nginx.conf
---> Running in 2e9e17465bee
---> 67e12eae61e0
Removing intermediate container 2e9e17465bee
Step 8 : RUN ln -sf /dev/stdout /var/log/nginx/access.log
---> Running in f1bfef1165c2
---> 0f35d25f041e
Removing intermediate container f1bfef1165c2
Step 9 : RUN ln -sf /dev/stderr /var/log/nginx/error.log
---> Running in dc6afee21aa7
---> fdbc66f4fc29
Removing intermediate container dc6afee21aa7
Step 10 : RUN mkdir -p /etc/service/nginx
---> Running in f082de625414
---> da674bf1aa6e
Removing intermediate container f082de625414
Step 11 : ADD start.sh /etc/service/nginx/run
---> 46482f2f0b3e
Removing intermediate container 5c187a026a07
Step 12 : RUN chmod +x /etc/service/nginx/run
---> Running in acdbb294f40a
---> 8fb8863aa4db
Removing intermediate container acdbb294f40a
Step 13 : EXPOSE 80
---> Running in 8abae36fc844
---> e343f9262260
Removing intermediate container 8abae36fc844
Step 14 : RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
---> Running in 154222c19d04
---> 599ea8dfdce7
Removing intermediate container 154222c19d04
Successfully built 599ea8dfdce7

 

Mas não se prenda a isso, docker nos fornece comandos para listar imagens e containers. Você deve ter observado que ao construir sua imagem, ele fez download não só da imagem base que usamos, mas também de qualquer dependência que esta imagem tenha.

Agora vamos ter a certeza de que temos as imagens necessárias, a serem criada por nós e phusion/baseimage

Execute para isso docker images

jackson@jackson:~/docker_exemplo/imagens/nginx$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
exemplo/nginx latest 599ea8dfdce7 10 minutes ago 344.8 MB
phusion/baseimage latest c39664f3d4e5 9 weeks ago 225.6 MB

 

Parabéns, conseguimos criar nossa primeira imagem Docker, mas vamos lembrar que o que temos é apenas uma imagem, e nos será útil somente quando instanciarmos containers usando-as.

Antes de criar qualquer container, vamos baixar as imagens necessárias para a criação do ambiente proposto. A criação da Imagem exemplo/nginx, foi apenas para termos conhecimento da possibilidade da criação de imagens personalizadas, agora vamos baixar imagens já prontas para mysql e para p PHP-FPM, para isso,  Docker Hub é meu pastor e nada me faltará.

Vamos começar então por baixar o PHP-FPM

jackson@jackson:~/docker_exemplo/imagens/nginx$ docker pull php:7.0-fpm
7.0-fpm: Pulling from library/php

8ad8b3f87b37: Already exists
161c326a7a2d: Already exists
4f37fe44e518: Already exists
60f9ad70a554: Pull complete
bd8ea9a43d6c: Pull complete
111e9423ead8: Pull complete
0bd11255d66a: Pull complete
b207707c9544: Pull complete
ef71188aa925: Pull complete
Digest: sha256:f9147faf2ab25469f485ab70038aff0480f619d8ce53e0fe94a6606b86313794
Status: Downloaded newer image for php:7.0-fpm

 

Você pode escolher entre as versões do PHP disponíveis em https://hub.docker.com/_/php/

Agora vamos baixar a imagem do Mysql, eu estou optando pela versão 5.6, as versão podemos ser consultadas em https://hub.docker.com/_/mysql/

jackson@jackson:~/docker_exemplo/imagens/nginx$ docker pull mysql:5.6
5.6: Pulling from library/mysql

8ad8b3f87b37: Already exists
9a2674eb51d8: Already exists
b839515314a7: Already exists
0b8e3100ab50: Already exists
c9a6e2414f0a: Pull complete
62605666ff10: Pull complete
eef7cf502115: Pull complete
2b84c0dd4ca9: Pull complete
2668cb19e693: Pull complete
c1ffa5c73c3b: Pull complete
7b408f8be82c: Pull complete
Digest: sha256:31ad2efd094a1336ef1f8efaf40b88a5019778e7d9b8a8579a4f95a6be88eaba
Status: Downloaded newer image for mysql:5.6

 

Agora se executarmos docker images, veremos mais duas imagens na lista

jackson@jackson:~/docker_exemplo/imagens/nginx$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
exemplo/nginx latest 599ea8dfdce7 50 minutes ago 344.8 MB
mysql 5.6 72bb9d97fb75 2 days ago 328.9 MB
php 7.0-fpm 6a7d2279aafa 10 days ago 375.5 MB
phusion/baseimage latest c39664f3d4e5 9 weeks ago 225.6 MB

 

Temos todas as imagens necessárias para a execução de nossa aplicação, agora vamos criar a estrutura para os arquivos da mesma.

Crie a estrutura de arquivos na raiz do diretório criado anteriormente, como na imagem:

docker_imagem_nginx_2

 

O diretório src, será onde colocaremos qualquer configuração para o ambiente no futuro e src/www/public onde ficarão os arquivos da aplicação.

No arquivo index.html, eu inseri o seguinte conteúdo:

<!DOCTYPE html>
<html>
<head>
<title>Meu primeiro ambiente usando Docker</title>
</head>
<body>
<h1>Meu primeiro ambiente usando Docker</h1>
</body>
</html>

 

Vamos disponibilizar a nossa aplicação sob o domínio docker-exemplo.local, que vamos registrar em nossa máquina. Se você usa linux, aponte-o em seu /etc/hosts para o seu próprio IP.
Algo como:
192.168.0.11 docker-exemplo.local

Vamos criar um arquivo vhost para o Nginx responder para o domínio que escolhemos.

server {
listen 80;
index index.html;
server_name docker-exemplo.local;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/public;
}

 

Eu não vou entrar no mérito da configuração do Nginx, mas tenha atenção na linha root /var/www/public. Aqui é preciso ter atenção, porque precisaremos mapear o diretório da máquina hospedeira para o container.

Agora vamos de fato criar o container usando a imagem Nginx que criamos. (exemplo/nginx).

Tenha a certeza de que está na raiz do projeto, e execute o seguinte código:

docker run \
-d \
-p 8080:80 \
-v $(pwd)/src/vhost.conf:/etc/nginx/sites-enabled/vhost.conf \
-v $(pwd)/src/www:/var/www \
exemplo/nginx;

jackson@jackson:~/docker_exemplo$ docker run \
> -d \
> -p 8080:80 \
> -v $(pwd)/src/vhost.conf:/etc/nginx/sites-enabled/vhost.conf \
> -v $(pwd)/src/www:/var/www \
> exemplo/nginx;
d50cb5c634a25804a4ad28f304e0bb0cdc143a576af2733a95879c8ba3de0b10

 

Usamos a flag -d para que tudo seja executado em background.

Usamos a flag -p para mapear uma porta da máquina hospedeira para o container. Neste caso dizemos para o que entrar pela 8080 seja direcionado para a porta 80 do container. Se você olhar mais acima, verá que configuramos o container para escutar a porta 80.

Usamo a flag -v para mapear nosso arquivo vhost do nginx local com o seu local necessário no container. E mais uma vez usamos a flag -v para mapear o nosso diretório local com o container, de forma que fique disponível como configurado no vhost em root /var/www/public.

Após todos os argumentos passados para o método run, informamos finalmente o nome da imagem que deve ser usada para a criação do container, no nosso caso exemplo/nginx.

 

Você pode ter certeza de que o Nginx está funcionando corretamente executando docker logs [ID DO CONTAINER]. Para obter o id do container lembre-se de docker ps.

jackson@jackson:~/docker_exemplo$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d50cb5c634a2 exemplo/nginx "/sbin/my_init" 42 seconds ago Up 40 seconds 0.0.0.0:8080-&gt;80/tcp naughty_booth
jackson@jackson:~/docker_exemplo$ docker logs d50cb5c634a2
*** Running /etc/my_init.d/00_regen_ssh_host_keys.sh...
*** Running /etc/rc.local...
*** Booting runit daemon...
*** Runit started as PID 9
* Starting nginx nginx
Sep 10 02:40:20 d50cb5c634a2 syslog-ng[17]: syslog-ng starting up; version='3.5.6'

 

Agora é a hora da verdade, acesse o endereço http://docker-exemplo.local:8080/

docker_imagem_nginx_3

Pimba!

Docker Compose

Acredito que assim que você tenha visto as mais de cinco linhas para executar a criação do container, tenha pensado já na criação de arquivos .sh para centralizar isso. Esqueça. O Docker Compose fará todo esse trabalho para você.

Se você não pulou, provavelmente já instalou o docker compose, caso não o tenha feito, faça agora.

Basicamente, o que vamos fazer daqui pra frente será registrar os comandos necessários em um arquivo YAML.

Crie um arquivo docker-compose.yml na raiz de seu projeto

docker_imagem_nginx_4

Vamos parar o container e excluí-lo:

Use docker ps para pegar o id do container

e:

docker stop [ID DO CONTAINER]

docker rm [ID DO CONTAINER]

jackson@jackson:~/docker_exemplo$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
60b5573311c5 exemplo/nginx "/sbin/my_init" 7 minutes ago Up 7 minutes 0.0.0.0:8080-&gt;80/tcp jolly_shannon
jackson@jackson:~/docker_exemplo$ docker stop 60b5573311c5
60b5573311c5
jackson@jackson:~/docker_exemplo$ docker rm 60b5573311c5
60b5573311c5
jackson@jackson:~/docker_exemplo$

Coloque o seguinte conteúdo no arquivo docker-compose.yml

web:
image: exemplo/nginx
ports:
- "8080:80"
volumes:
- ./src/www:/var/www
- ./src/vhost.conf:/etc/nginx/sites-enabled/vhost.conf

Agora execute docker-compose up -d

jackson@jackson:~/docker_exemplo$ docker-compose up -d
Creating dockerexemplo_web_1

Acesse o endereço http://docker-exemplo.local:8080/, acabamos com a problemática da quantidade de código toda vez que tive que iniciar um container.

 

O Container Docker PHP-FPM

Vamos preparar agora o nosso container PHP-FPM, e para isso vamos inserir mais um bloco em nosso arquivo docker-composer.yml

php:
image: “php:7.0-fpm”
volumes:
– ./src/php-fpm.conf:/etc/php5/fpm/php-fpm.conf
– ./src/www:/var/www
working_dir: “/var/www/”

 

Além da inserção deste bloco, temos que dizer ao container do nginx (no bloco web), para conectar-se ao php, inserindo:

links:
– php

o Arquivo ficará assim:

web:
image: exemplo/nginx
ports:
- "8080:80"
volumes:
- ./src/www:/var/www
- ./src/vhost.conf:/etc/nginx/sites-enabled/vhost.conf
links:
- php

php:
image: "php:7.0-fpm"
volumes:
- ./src/php-fpm.conf:/etc/php5/fpm/php-fpm.conf
- ./src/www:/var/www
working_dir: "/var/www/"

Precisamos alterar o arquivo vhost.conf do nginx para que ele funcione com o PHP.

Deixe-o assim:

server {
listen 80;
index index.php index.html;
server_name docker-exemplo.local;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/public;

location / {
try_files $uri /index.php?$args;
}

location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}

agora você pode baixar este arquivo de exemplo de configuração do PHP-FPM e colocá-lo ao lado do aquivo vhost.conf em src.

Crie um arquivo em src/www/public nomeado de index.php e coloque o segundo conteúdo:

<!--?php &lt;br ?--> phpinfo();

Acesse o endereço http://docker-exemplo.local:8080/

docker_imagem_nginx_6

Pronto, agora nosso ambiente funciona corretamente com o PHP

 

O Container Docker MySQL

Para completar o nosso ambiente, vamos criar agora um container para o MySQL inserindo o seguinte bloco no docker-compose.yml:

db:
image: “mysql:5.6”
volumes:
– /var/lib/mysql
environment:
– MYSQL_ROOT_PASSWORD=exemploUser
– MYSQL_DATABASE=exemploDb
– MYSQL_USER=exemploUser
– MYSQL_PASSWORD=exemploSenha

As variáveis de ambiente definidas em environment são fornecidas pela própria imagem. Você pode pesquisar as possibilidade sempre na página da imagem do Docker Hub, neste caso usamos a imagem oficial do MySQL.

Só que agora temos que ter uma atenção especial. Vamos precisar instalar duas extensões em nossa imagem usada para o PHP, então vamos excluir todas as imagens criadas, assim como todos os containers, para isso execute:

docker rm $(docker ps -a -q)

e:

docker rmi $(docker images -q)

Pra ser sincero à você, acredito ser possível instalar a extensão apenas no container, mas por hora, vamos fazer da forma que tenhamos a certeza do sucesso.

Para instalar as extensões pdo e pdo_mysql no container do php, a imagem oficial do PHP fornece o script docker-php-ext-install que deve ser usado em um arquivo Dockerfile e para isso vamos ter que fazer uma modificação na forma de criação do container do PHP.

No diretório src, crie um diretório nomeado de php e dentro dele um arquivo nomeado de Dockerfile com o seguinte conteúdo:

FROM php:7.0-fpm
RUN docker-php-ext-install pdo pdo_mysql

A estrutura final dos diretórios ficará assim:

docker_imagem_nginx_5

Agora temos que alterar no bloco php do arquivo docker-compose.yml o atributo que indica ao Docker para usar uma imagem, ao invés disso, vamos dizer a ele para construir um container com base no arquivo Dockerfile criado. Aproveitaremos também para inserir no bloco php um índice links como fizemos entre o Nginx e o php, vamos fazer entre o PHP e o MySQL

Agora o bloco PHP em docker-compose ficará assim:

php:
build: ./src/php
volumes:
– ./src/php-fpm.conf:/etc/php5/fpm/php-fpm.conf
– ./src/www:/var/www
working_dir: “/var/www/”
links:
– db

veja que a segunda linha do arquivo foi alterada para build: ./src/php

O estado final do arquivo docker-compose.yml ficará assim:

web:
image: exemplo/nginx
ports:
- "8080:80"
volumes:
- ./src/www:/var/www
- ./src/vhost.conf:/etc/nginx/sites-enabled/vhost.conf
links:
- php

php:
build: ./src/php
volumes:
- ./src/php-fpm.conf:/etc/php5/fpm/php-fpm.conf
- ./src/www:/var/www
working_dir: "/var/www/"
links:
- db

db:
image: "mysql:5.6"
volumes:
- /var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=exemploUser
- MYSQL_DATABASE=exemploDb
- MYSQL_USER=exemploUser
- MYSQL_PASSWORD=exemploSenha

 

Execute novamente o comando docker-compose up -d

Para termos a certeza do funcionamento do PHP com o MySQL, vamos inserir um código básico de conexão com o banco de dados, que foi criado junto com o container, inserir dados e listá-los.
Deixe o arquivo index.php localizado em src/www/public com o seguinte conteúdo:

<!--?php $tabela = "mensagens"; try { $db = new PDO("mysql:dbname=exemploDb;host=db", "exemploUser", "exemploSenha" ); $db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );</p> <p> $sql="CREATE TABLE IF NOT EXISTS mensagens (<br ?--> id int(20) NOT NULL AUTO_INCREMENT,
mensagem varchar(150) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY id (id)
);
";

$data = date("Y-m-d H:i:s");

$sql = "INSERT INTO mensagens (mensagem)
VALUES (:mensagem)";

$stmt = $db->prepare($sql);
$data = array(
':mensagem' => "Mensagem inserida em {$data}",
);
$stmt->execute($data);

$consulta = $db->query("SELECT mensagem FROM mensagens;");

while ($linha = $consulta->fetch(PDO::FETCH_ASSOC)) {
echo $linha['mensagem']."
";
}

} catch(PDOException $e) {
echo $e->getMessage();//Remove or change message in production code
}

Acesse o endereço http://docker-exemplo.local:8080/ e boa sorte.

Considerações finais

Tenha bastante cautela com os dados, eu não estudei muito bem sobre o assunto, mas todos ressaltam a preocupação necessária com onde esses dados ficarão. Atualmente tenho montado o diretório /var/lib/mysql na minha máquina, algo como . /src/mysql/data:/var/lib/mysql

É possível fazer o mesmo com os diretórios de armazenamento dos logs e etc.

Inserindo novo usuário no gitolite

750px-Git-logo-jengelh.svg_

Se você não sabe como instalar o gitolite, eu criei um post Montando um servidor de repositórios git com gitolite

Gitolite faz o controle de acesso de seus usuários usando chaves SSH, para criar novos usuários basta esse novo usuário gerar uma chave ssh e entregá-la a você para que você a envie para o servidor.

Vamos fazer o seguinte, como eu tenho a chave do administrador já em minha máquina, vou movê-la para um pasta, para agir como se fosse um novo usuário, e no decorrer da postagem vamos mudando as chaves para se passar, hora por administrador, hora pelo novo usuário.

Vamos para o diretório do ssh gerar a chave para o novo usuário

jackson@localhost: ~$ cd ~/.ssh

Para gerar a chave digite o comando abaixo, lembrando de alterar o nome de usuário para o pretendido.
ssh-keygen -t rsa -f jackson

jackson@localhost: ~/.ssh$ ssh-keygen -t rsa -f jackson
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in jackson.
Your public key has been saved in jackson.pub.
The key fingerprint is:
26:cc:f1:1d:14:8a:05:58:7f:65:df:d1:c6:ba:6b:76 jackson@localhost.localdomain
The key's randomart image is:
+--[ RSA 2048]----+
| oo.. o.o o.|
| . + o o . .=|
| o o o .o.|
| o o o . . |
| + S . . |
| o . |
| . |
| + E|
| o . |
+-----------------+
jackson@localhost: ~/.ssh$

Agora basta esse usuário lhe entregar o arquivo NOME_DO_USUÁRIO.pub, que no meu caso ficou como jackson.pub.

Você deve colocar esse arquivo no diretório keydir daquele repositório chamado gitolite-admin que clonamos no post anterior

Lembre-se de após colocar o arquivo em seu local correto, devemos adicioná-lo, fazer um commit e empurrar para o servidor onde estão hospedados os repositórios.

jackson@localhost: ~/.ssh$ cd ~/gitolite-admin/
jackson@localhost: ~/gitolite-admin (master *)$ ls conf keydir
git.pub jackson.pub
jackson@localhost: ~/gitolite-admin (master *)$ git status
On branch master
Your branch is up-to-date with 'origin/master'.

Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)

modified: keydir/jackson.pub

no changes added to commit (use "git add" and/or "git commit -a")
jackson@localhost: ~/gitolite-admin (master *)$ git add .
jackson@localhost: ~/gitolite-admin (master +)$ git commit -m "Inserindo usuário jackson"
[master 7518a48] Inserindo usuário jackson
1 file changed, 1 insertion(+), 1 deletion(-)
rewrite keydir/jackson.pub (93%)
jackson@localhost: ~/gitolite-admin (master)$ git push

Counting objects: 7, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 707 bytes | 0 bytes/s, done.
Total 4 (delta 0), reused 0 (delta 0)
To git@192.168.0.17:gitolite-admin
d9bffaa..7518a48 master -> master
jackson@localhost: ~/gitolite-admin (master)$

Sua saída do git será diferente sobre a linha modified: keydir/jackson.pub.
A questão aí é que eu já possuía uma chave jackson.pub e ela foi modificada, mas no seu caso geralmente será um novo arquivo.

Lembre-se que apenas criamos o usuário, ele ainda não tem nenhuma permissão no servidor:

Nós temos dois repositórios publicados, o gitolite-admin e um nomeado testing criado automaticamente peli gitolite para testes

jackson@localhost: ~$ ssh jackson@192.168.0.17
jackson@192.168.0.17's password:
Welcome to Ubuntu 12.04.4 LTS (GNU/Linux 3.11.0-20-generic x86_64)

* Documentation: https://help.ubuntu.com/

System information as of Wed May 7 17:41:00 BRT 2014

System load: 0.0 Processes: 72
Usage of /: 45.4% of 3.11GB Users logged in: 0
Memory usage: 11% IP address for eth0: 192.168.0.17
Swap usage: 0%

Graph this data and manage this system at:
https://landscape.canonical.com/

Last login: Sun May 4 22:11:54 2014 from 192.168.0.15

jackson@ubuntu12:~$ sudo su - git

git@ubuntu12:~$ ls
bin gitolite git.pub projects.list repositories
git@ubuntu12:~$ cd repositories/
git@ubuntu12:~/repositories$ ls
gitolite-admin.git testing.git
git@ubuntu12:~/repositories$
git@ubuntu12:~/repositories$ logout
jackson@ubuntu12:~$ exit
sair
Connection to 192.168.0.17 closed.
jackson@localhost: ~$

Vamos tentar clonar esse repositório de testes criado pelo gitolite usando o novo usuário criado.

É importante que a chave nomeada como git não esteja no diretório ssh para termos a certeza que o sistema irá usar o usuário jackson (no meu caso) e não o git.
Como eu tenho as duas na minha máquina eu a movi para um diretório criado (gitolite-admin-key) para criar este tutorial.

jackson@localhost: ~$ ls -a ~/.ssh/
. .. gitolite-admin-key jackson jackson.pub known_hosts
jackson@localhost: ~$ ls -a ~/.ssh/gitolite-admin-key/
. .. git git.pub
jackson@localhost: ~$

O que me causava dúvidas era sempre se eu tinha que colocar o nome do usuário na frente do domínio ou do ip, a resposta é NÃO, sempre deve ser usado git@ENDERECO_DO_SERVIDOR:NOME_DO_REPOSITORIO

jackson@localhost: ~$ git clone git@192.168.0.17:testing
Cloning into 'testing'...
warning: You appear to have cloned an empty repository.
Checking connectivity... done.

Está aí um repositório clonado pelo usuário jackson.

Você pode estar se perguntando, mas ele disse que não tínhamos ainda dado permissões a nenhum usuário.

É isso mesmo, só que como esse repositório foi um repositório criado pelo próprio gitolite
ele já o criou com configurações de permissões no arquivo conf/gitolite.conf

jackson@localhost: ~$ cat gitolite-admin/conf/gitolite.conf
repo gitolite-admin
RW+ = git

repo testing
RW+ = @all
jackson@localhost: ~$

Eu vou criar uma postagem sobre criação de repositórios e permissões, mas veja que para o repositório gitolite-admin só o usuário git tem permissões para escrita e leitura

repo gitolite-admin
RW+ = git

Já no testing, a permissão foi dada para um grupo @all
repo testing
RW+ = @all

Até a próxima!

Montando um servidor de repositórios git com gitolite

Captura de tela de 2014-05-04 22:40:23

Trabalho com git já algum tempo, porém, antes de eu entrar para a Seven Soluções em julho de 2012 não tinha passado pela experiência de usá-lo em equipe. No início para sanar apenas a necessidade de mais de uma pessoa usar o mesmo repositório remoto, criamos um diretório na minha máquina (a mesma usada como estação de desenvolvimento), e passei minha senha de usuário para os outros desenvolvedores usarem com ssh. A pior gambiarra, é a gambiarra consciente, naquele momento eu sabia que estava fazendo a coisa errada, e saí em busca de alguma solução para aquela necessidade.

Além de vários usuários para o mesmo repositório, eu precisava de algo que possibilitasse gerenciar permissões de acesso a repositórios e a branches, pois tínhamos projetos, como por exemplo,  uma espécie de cms que estava sempre em desenvolvimento e ao mesmo tempo em produção para a criação dos projetos do dia a dia, então, era preciso permissão apenas de leitura neste repositório para alguns usuários e leitura e escrita para outros.

Depois de ascender algumas velas para São Google, encontrei então o Gitolite.

Para seguir este tutorial acredito ser necessário:

  • Ter noções de git
  • Ter noções de ssh
  • Se você não usa uma distribuição linux, será mais difícil, não tenho conhecimento sobre a utilização do gitolite no windows.

Usando ssh, logue-se no servidor onde irá criar os repositórios

Captura de tela de 2014-05-04 19:53:15

Para instalar o git no ubuntu digite:

sudo apt-get install git

jackson@localhost: ~$ sudo apt-get install git

 

Agora precisamos criar um usuário no sistema que armazenará os repositórios e só permitir acesso a este usuário usando uma chave ssh pública.

Vamos criar um usuário chamado git com o seguinte comando:

sudo adduser \

–system \
–shell /bin/bash \
–gecos ‘git version control’ \
–group \
–disabled-password \
–home /home/git git

jackson@ubuntu12:~$ sudo adduser \
> --system \
> --shell /bin/bash \
> --gecos 'git version control \
> --group \
> --disabled-password \
> --home /home/git git
Adicionando usuário de sistema 'git' (UID 106) ...
Adicionando novo grupo `git' (GID 113) ...
Adicionando novo usuário `git' (UID 106) ao grupo `git' ...
chfn: name with non-ASCII characters: 'Controlador de acesso a repositórios git'
Criando diretório pessoal `/home/git' ...
jackson@ubuntu12:~$

 

Vamos aproveitar que estamos logado no servidor e baixar o gitolite de seu repositório no github.

Lembrando que acabamos de criar um usuário para que todo processo aconteça no diretório do mesmo, neste caso  /home/git. Para ficar mais fácil vamos passar para o usuário git digitando:

sudo su – git

jackson@ubuntu12:~$ sudo su - git
git@ubuntu12:~$

 

Para clonar o repositório do gitolite no servidor digite:

git clone git://github.com/sitaramc/gitolite

git@ubuntu12:~$ git clone git://github.com/sitaramc/gitolite
Cloning into 'gitolite'...
remote: Reusing existing pack: 8457, done.
remote: Counting objects: 16, done.
remote: Compressing objects: 100% (15/15), done.
remote: Total 8473 (delta 2), reused 0 (delta 0)
Receiving objects: 100% (8473/8473), 3.55 MiB | 583 KiB/s, done.
Resolving deltas: 100% (4778/4778), done.
git@ubuntu12:~$ ls
gitolite
git@ubuntu12:~$

 

Atenção! Apenas clonamos o repositório para o servidor, ainda não o instalamos.
Vamos criar um diretório para instalá-lo:
mkdir bin

git@ubuntu12:~$ mkdir bin
git@ubuntu12:~$ ls
bin gitolite
git@ubuntu12:~$

 

Agora sim vamos instalá-lo com:
gitolite/install -to /home/gitolite/bin

git@ubuntu12:~$ gitolite/install -to /home/git/bin
git@ubuntu12:~$ ls bin/
commands gitolite gitolite-shell lib syntactic-sugar triggers VERSION VREF
git@ubuntu12:~$

 

Vamos voltar em nossa estação de desenvolvimento para criar nossa chave ssh

git@ubuntu12:~$ exit
sair
jackson@ubuntu12:~$ exit
sair
Connection to 192.168.0.17 closed.
jackson@localhost: ~$

Vá para o diretório ~/.ssh

jackson@localhost: ~$ cd ~/.ssh
jackson@localhost: ~/.ssh$

Gerando a nossa chave:
ssh-keygen -t rsa -f git

jackson@localhost: ~/.ssh$ ssh-keygen -t rsa -f git
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in git.
Your public key has been saved in git.pub.
The key fingerprint is:
39:ed:8e:37:c3:7c:fc:90:b5:42:55:1f:1a:55:23:22 jackson@localhost.localdomain
The key's randomart image is:
+--[ RSA 2048]----+
| E . o.++|
| . . +.+|
| .. .|
| o . |
| S . . . |
| o . o . |
| o..+ . |
| o* oo |
| ...+ .. |
+-----------------+
jackson@localhost: ~/.ssh$

 

Agora precisamos enviar a chave gerada para o servidor, para isso vamos usar scp:

scp ~/.ssh/git.pub jackson@192.168.0.17:

jackson@localhost: ~/.ssh$ scp ~/.ssh/git.pub jackson@192.168.0.17:
jackson@192.168.0.17's password:
git.pub 100% 411 0.4KB/s 00:00
jackson@localhost: ~/.ssh$

 

Vamos agora voltar ao servidor para colocar a chave para o usuário git em seu diretório e configurar o gitolite para usar esta chave para o seu repositório principal.

ssh 192.168.0.17

jackson@localhost: ~/.ssh$ ssh 192.168.0.17
jackson@192.168.0.17's password:
Welcome to Ubuntu 12.04.4 LTS (GNU/Linux 3.11.0-20-generic x86_64)

* Documentation: https://help.ubuntu.com/

System information as of Sun May 4 22:11:54 BRT 2014

System load: 0.0 Processes: 74
Usage of /: 45.3% of 3.11GB Users logged in: 1
Memory usage: 16% IP address for eth0: 192.168.0.17
Swap usage: 0%

Graph this data and manage this system at:
https://landscape.canonical.com/

Last login: Sun May 4 19:20:34 2014 from 192.168.0.15
jackson@ubuntu12:~$

 

Duas ações importantes devem ser cometidas agora, sendo a primeira mover a chave enviada por scp para o diretório do usuário git e tornar o usuário git proprietário desta chave.

Para mover a chave use:

sudo mv git.pub /home/git/

jackson@ubuntu12:~$ sudo mv git.pub /home/git/
[sudo] password for jackson:
jackson@ubuntu12:~$

 

E para tornar o usuário git seu proprietário:

sudo chown git:git /home/git/git.pub

jackson@ubuntu12:~$ sudo chown git:git /home/git/git.pub
jackson@ubuntu12:~$

 

Passando a ser o usuário git

sudo su – git

jackson@ubuntu12:~$ sudo su - git
git@ubuntu12:~$

 

Vamos agora finalmente configurar o gitolite para trabalhar inicialmente com a chave que geramos:

/home/git/bin/gitolite setup -pk git.pub

git@ubuntu12:~$ /home/git/bin/gitolite setup -pk git.pub
Initialized empty Git repository in /home/git/repositories/gitolite-admin.git/
Initialized empty Git repository in /home/git/repositories/testing.git/
WARNING: /home/git/.ssh missing; creating a new one
WARNING: /home/git/.ssh/authorized_keys missing; creating a new one
git@ubuntu12:~$

 

Vamos sair do servidor e voltar a nossa estação de desenvolvimento:

git@ubuntu12:~$ exit
sair
jackson@ubuntu12:~$ exit
sair
Connection to 192.168.0.17 closed.
jackson@localhost: ~/.ssh$

 

Agora vamos tentar clonar o repositório mais importante que teremos em nosso servidor. O gitolite-admin.

Lembre-se de sair do diretório ~/.ssh

Para clonar o repositório use:

git clone git@192.168.0.17:gitolite-admin

jackson@localhost: ~$ git clone git@192.168.0.17:gitolite-admin
Cloning into 'gitolite-admin'...
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (6/6), done.
Checking connectivity... done.
jackson@localhost: ~$

Observe que não fará diferença quem está acessando o servidor, sempre será git@IP_DO_SERVIDOR:NOME_DO_REPOSITORIO. É claro que veremos em outro post a instalação de novos usuários e a criação de novos repositórios

Quer inserir novos usuários? eu criei um post  Inserindo novo usuário no gitolite

 

 

Usando Twitter-bootstrap no meu blog

De fato o trabalho com gems no rails é fantástico. Poder modularizar até assets em um projeto de forma simples como farei aqui é um alívio pra quem já trabalhou em projetos que tinham inúmeras linhas fazendo referências a arquivos javascripts e css.

Eu vou usar uma gem chamada twitter-bootstrap-rails, que fará o trabalho pesado para mim.

Para isto, basta inserir no arquivo Gemfile a seguinte linha:

gem "twitter-bootstrap-rails"

 

Salvamos o arquivo e pedimos ao bundle para instalar a gem em questão:

jackson@jackson:~/www/app_rails/blog
master$ bundle install

 

Agora eu peço a gem para que gere os assets necessários para mim:

jackson@jackson:~/www/app_rails/blog
master$ rails generate bootstrap:install static

 

Agora vamos criar a página layout application para que funcione com a gem

jackson@jackson:~/www/app_rails/blog
master$ rails g bootstrap:layout application fluid
conflict app/views/layouts/application.html.erb
Overwrite /var/www/app_rails/blog/app/views/layouts/application.html.erb? (enter "h" for help) [Ynaqdh] y
force app/views/layouts/application.html.erb
jackson@jackson:~/www/app_rails/blog

 

Agora é só eu iniciar o servidor e acessar a aplicação pelo navegador para ver a mágica:

Captura de tela de 2014-01-20 00:52:05

Janela maximizada

Captura de tela de 2014-01-20 00:52:48

Janela restaurada

 

 

Criando a minha página home no Rails

O melhor lugar para começar é sempre pelo início, então vou criar a página inicial do meu blog, mas antes disso vamos entender como fazemos para levantar um servidor que entenda ruby e nos permita acessar o blog pelo nosso navegador.

Dá até medo né!? Que nada, entre no diretório do blog e execute o comando rails server.

jackson@jackson:~$ cd www/app_rails/blog/
jackson@jackson:~/www/app_rails/blog
master$ rails server
=> Booting WEBrick
=> Rails 4.0.0 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
[2014-01-09 20:43:08] INFO WEBrick 1.3.1
[2014-01-09 20:43:08] INFO ruby 2.0.0 (2013-11-22) [x86_64-linux]
[2014-01-09 20:43:08] INFO WEBrick::HTTPServer#start: pid=3074 port=3000

Agora acesse em seu navegador o endereço: http://0.0.0.0:3000 e se tudo estiver certo você verá uma página de boas vindas oferecida pelo Rails:

Welcome aboard

A página é muito bonitinha mas não é o que eu quero, o que eu preciso é criar uma página inicial que eu possa customizá-la no futuro.

Então vamos lá:

Em seu terminal, pressione [CTRL] + c para parar o servidor.

Eu quero minha página principal sem conexão direta com banco de dados para que eu possa obter dados de qualquer outra “área” existente na plicação, como por exemplo posts, comentários e etc.

Então vamos criar apenas uma view e um controlador.

Rails possui um comando chamado generate que tem a capacidade de geral um monte de coisas, e de forma bastante inteligente.

Pediremos a ele aqui que nos ajude apenas com a criação de um controlador chamado home e que este controlador possua um método nomeado de index. Rails nos dará uma colher de chá e criará uma view para este método index.

jackson@jackson:~/www/app_rails/blog
master$ rails generate controller home index
create app/controllers/home_controller.rb
route get "home/index"
invoke erb
create app/views/home
create app/views/home/index.html.erb
invoke test_unit
create test/controllers/home_controller_test.rb
invoke helper
create app/helpers/home_helper.rb
invoke test_unit
create test/helpers/home_helper_test.rb
invoke assets
invoke coffee
create app/assets/javascripts/home.js.coffee
invoke scss
create app/assets/stylesheets/home.css.scss
jackson@jackson:~/www/app_rails/blog
master$

Não vamos nos prender agora a todas as linhas geradas com o comando acima, mas para mim é importante saber que foi gerado um controlador com um método chamado index, um diretório em views chamado home com o arquivo index.html.erb. E que Rails também escreveu no arquivo config/routes.rb a linha:

get “home/index”

Blog::Application.routes.draw do
get "home/index"
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".

# You can have the root of your site routed with "root"
# root 'welcome#index'

...

Agora mais uma vez vamos executar o comando rails server, ou se preferir rails s e acesse novamente o endereço http://0.0.0.0:3000

Frustrado porque nada mudou? Insira no endereço /home/index de forma que fique assim:

http://0.0.0.0:3000/home/index

Eu também acho que não tem nada a ver para acessar o endereço principal do blog ter que digitar tudo isso. Para arrumarmos, abra o arquivo config/routes.rb e diga para o Rails que você quer que seu endereço principal (o endereço root) seja /home/index inserindo a linha:

root “home/index”

Blog::Application.routes.draw do
get "home/index"
root "home#index"
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".

Aí está minha página principal acessada pelo endereço principal da aplicação. De lambuja ela ainda me diz onde encontro o arquivo da view. 😉

Captura de tela de 2014-01-09 22:09:43

 

Conectando um repositório de trabalho local a um repositório remoto no github

Para continuar o desenvolvimento do blog, como eu prometi no post anterior vamos conectar o repositório local (de trabalho), com o criado no github (bare).

Vá para o diretório do blog

jackson@jackson:~$ cd www/app_rails/blog

jackson@jackson:~/www/app_rails/blog
master$

Para adicionar o repositório criado no github:

jackson@jackson:~/www/app_rails/blog
master$ git remote add origin https://github.com/jacksonbicalho/blog.git

master$

Atenção para alterar o nome do usuário para o seu nome. Você conseguirá o endereço correto na página do repositório.

Captura de tela de 2013-12-19 21:56:20

 

 

 

 

 

 

Agora vamos empurrar os arquivos locais para o repositório remoto

master$ git push origin master
Username for 'https://github.com': jacksonbicalho
Password for 'https://jacksonbicalho@github.com':
To https://github.com/jacksonbicalho/blog.git
* [new branch] master -&gt; master
jackson@jackson:~/www/app_rails/blog
master$

Se correu tudo certo, os arquivos podem ser vistos na página de seu repositório

Captura de tela de 2013-12-19 22:04:43

 

 

 

 

 

 

 

Até a próxima!

Criando meu blog em rails

O que mais tem pela net é tutorial de criação de blogs usando Ruby on Rails. Eu vou partilhar com vocês a criação do meu blog, mostrar os erros quando ocorrer, procurar ajuda e corrigir. Vai ser meu diário de bordo durante o desenvolvimento do blog que rodará sob este domínio.

 

A Aplicação

Vamos voltar para o diretório app_rails

jackson@jackson:~$ cd www/app_rails
jackson@jackson:~/www/app_rails$

 

Agora usamos o comando new acompanhado da palavra blog, para pedir ao rails que crie uma nova aplicação com o nome de blog. Aguarde, esta ação pode demorar um pouco.

jackson@jackson:~$ cd www/app_rails
jackson@jackson:~/www/app_rails$ rails new blog
create
create README.rdoc
create Rakefile
create config.ru
create .gitignore
create Gemfile
create app
create app/assets/javascripts/application.js
create app/assets/stylesheets/application.css
create app/controllers/application_controller.rb
create app/helpers/application_helper.rb
create app/views/layouts/application.html.erb
create app/assets/images/.keep
create app/mailers/.keep
create app/models/.keep
create app/controllers/concerns/.keep
create app/models/concerns/.keep
create bin
create bin/bundle
create bin/rails
create bin/rake
create config
create config/routes.rb
create config/application.rb
create config/environment.rb
create config/environments
create config/environments/development.rb
create config/environments/production.rb
create config/environments/test.rb
create config/initializers
create config/initializers/backtrace_silencers.rb
create config/initializers/filter_parameter_logging.rb
create config/initializers/inflections.rb
create config/initializers/mime_types.rb
create config/initializers/secret_token.rb
create config/initializers/session_store.rb
create config/initializers/wrap_parameters.rb
create config/locales
create config/locales/en.yml
create config/boot.rb
create config/database.yml
create db
create db/seeds.rb
create lib
create lib/tasks
create lib/tasks/.keep
create lib/assets
create lib/assets/.keep
create log
create log/.keep
create public
create public/404.html
create public/422.html
create public/500.html
create public/favicon.ico
create public/robots.txt
create test/fixtures
create test/fixtures/.keep
create test/controllers
create test/controllers/.keep
create test/mailers
create test/mailers/.keep
create test/models
create test/models/.keep
create test/helpers
create test/helpers/.keep
create test/integration
create test/integration/.keep
create test/test_helper.rb
create tmp/cache
create tmp/cache/assets
create vendor/assets/javascripts
create vendor/assets/javascripts/.keep
create vendor/assets/stylesheets
create vendor/assets/stylesheets/.keep
run bundle install
Fetching gem metadata from https://rubygems.org/..........
Fetching gem metadata from https://rubygems.org/..
Resolving dependencies...
Using rake (10.1.0)
Using i18n (0.6.5)
Using minitest (4.7.5)
Using multi_json (1.8.2)
Using atomic (1.1.14)
Using thread_safe (0.1.3)
Using tzinfo (0.3.38)
Using activesupport (4.0.0)
Using builder (3.1.4)
Using erubis (2.7.0)
Using rack (1.5.2)
Using rack-test (0.6.2)
Using actionpack (4.0.0)
Using mime-types (1.25)
Using polyglot (0.3.3)
Using treetop (1.4.15)
Using mail (2.5.4)
Using actionmailer (4.0.0)
Using activemodel (4.0.0)
Using activerecord-deprecated_finders (1.0.3)
Using arel (4.0.1)
Using activerecord (4.0.0)
Using bundler (1.3.5)
Using coffee-script-source (1.6.3)
Using execjs (2.0.2)
Using coffee-script (2.2.0)
Using thor (0.18.1)
Using railties (4.0.0)
Using coffee-rails (4.0.1)
Using hike (1.2.3)
Using jbuilder (1.5.2)
Using jquery-rails (3.0.4)
Using json (1.8.1)
Using tilt (1.4.1)
Using sprockets (2.10.0)
Using sprockets-rails (2.0.1)
Using rails (4.0.0)
Using rdoc (3.12.2)
Using sass (3.2.12)
Using sass-rails (4.0.1)
Using sdoc (0.3.20)
Using sqlite3 (1.3.8)
Using turbolinks (1.3.0)
Using uglifier (2.3.0)
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.
jackson@jackson:~/www/app_rails$

 

O versionamento

Captura de tela de 2013-10-28 22:56:06

Como eu não consigo mais trabalhar sem o uso do git, não tem porque  eu esconder  o uso dele.

A primeira coisa a fazer, será a criação de um repositório, decidindo se o blog será proprietário ou livre, eu decidi pela segunda opção, ele será livre. Sendo assim não tenho porque deixar de criar esse repositório no github.

Vamos lá, com o git instalado  em minha máquina, vou no diretório de minha aplicação, e inicio um repositório.

 

 

jackson@jackson:~/www/app_rails$ cd blog
jackson@jackson:~/www/app_rails/blog$ git init
Initialized empty Git repository in /var/www/app_rails/blog/.git/
jackson@jackson:~/www/app_rails/blog
master$

Este comando fará com que o git crie em nosso diretório (blog) um subdiretório chamado .git onde serão armazenadas todas as informações sobre o nosso repositório a partir de agora.

 

O primeiro comando a usarmos será o git add [http://git-scm.com/docs/git-add]

Este comando fará com que o git coloque todos os arquivos contidos no diretório blog em seu índice.

Para adicionar tudo use [ . ]  (ponto)

jackson@jackson:~/www/app_rails/blog
master$ git add .
jackson@jackson:~/www/app_rails/blog
master$

 

O próximo passo, é efetuar o git commit [http://git-scm.com/docs/git-commit]  de tudo que está no índice, para de fato ser versionado, o bacana nisso é que ainda podemos colocar um nome amigável a versão passando uma mensagem para o commit (usando o parâmetro m), aqui vamos nomear nossa primeira versão de “Primeiro commit”, que será a aplicação depois de gerada pelo rails, sem mexermos em nada.

jackson@jackson:~/www/app_rails/blog
master$ git commit -m "Primeiro commit"
[master (root-commit) 8a55878] Primeiro commit
36 files changed, 821 insertions(+)
create mode 100644 .gitignore
create mode 100644 Gemfile
create mode 100644 Gemfile.lock
create mode 100644 README.rdoc
create mode 100644 Rakefile
create mode 100644 app/assets/images/.keep
create mode 100644 app/assets/javascripts/application.js
create mode 100644 app/assets/stylesheets/application.css
create mode 100644 app/controllers/application_controller.rb
create mode 100644 app/controllers/concerns/.keep
create mode 100644 app/helpers/application_helper.rb
create mode 100644 app/mailers/.keep
create mode 100644 app/models/.keep
create mode 100644 app/models/concerns/.keep
create mode 100644 app/views/layouts/application.html.erb
create mode 100755 bin/bundle
create mode 100755 bin/rails
create mode 100755 bin/rake
create mode 100644 config.ru
create mode 100644 config/application.rb
create mode 100644 config/boot.rb
create mode 100644 config/database.yml
create mode 100644 config/environment.rb
create mode 100644 config/environments/development.rb
create mode 100644 config/environments/production.rb
create mode 100644 config/environments/test.rb
create mode 100644 config/initializers/backtrace_silencers.rb
create mode 100644 config/initializers/filter_parameter_logging.rb
create mode 100644 config/initializers/inflections.rb
create mode 100644 config/initializers/mime_types.rb
create mode 100644 config/initializers/secret_token.rb
create mode 100644 config/initializers/session_store.rb
create mode 100644 config/initializers/wrap_parameters.rb
create mode 100644 config/locales/en.yml
create mode 100644 config/routes.rb
create mode 100644 db/seeds.rb
create mode 100644 lib/assets/.keep
create mode 100644 lib/tasks/.keep
create mode 100644 log/.keep
create mode 100644 public/404.html
create mode 100644 public/422.html
create mode 100644 public/500.html
create mode 100644 public/favicon.ico
create mode 100644 public/robots.txt
create mode 100644 test/controllers/.keep
create mode 100644 test/fixtures/.keep
create mode 100644 test/helpers/.keep
create mode 100644 test/integration/.keep
create mode 100644 test/mailers/.keep
create mode 100644 test/models/.keep
create mode 100644 test/test_helper.rb
create mode 100644 vendor/assets/javascripts/.keep
create mode 100644 vendor/assets/stylesheets/.keep
jackson@jackson:~/www/app_rails/blog
master$

Até aí, tenho uma aplicação iniciada, um repositório git nesta aplicação, já com  a primeira versão de meu projeto. E já criei também um repositório on line no github. Amanhã, eu vou ligar esses dois repositórios (O criado em minha máquina e o criado no github) e vou definir as características básicas que o blog terá em sua primeira versão.

Até!

 

 

 

 

 

 

O que rails tem a ver com DRY (Don’t repeat yourself)

O conceito DRY (Don’t repeat yourself)  “Não se repita” é levado a sério pelo rails, por exemplo, no CakePHP temos dois arquivos de visualização, um para editar e um para adicionar, sendo que a unica coisa que muda de uma para o outro é que no editar é inserido mais um input com a chave estrangeira do registro a ser editado. Até aí nada de mais, entre aspas, porque se você inserir ou remover atributos para o objeto em si, você terá que fazer isso no formulário usado para editar e no  usado para adicionar.

No Rails de fato nós temos um arquivo a mais, que geralmente é o _form.html.erb, que é usado aí para centralizar dados que na maioria das vezes não vão ser diferentes. Esses arquivos usados para renderizar seu conteúdo em outra view, são chamados no rails de partials guardando os dados inerentes ao formulário de inserção e o atualização. Não se preocupe, nós temos que fixar mais essa ideia, o que eu acho importante olhar neste momento é qual o conceito usado no uso de partials? Para mim, ler isso foi o suficiente http://www.artima.com/intv/dry3.html. Atenção para duas páginas anteriores.

 

Iniciando com rails

Só de olhar para a sintaxe de Ruby, quem gosta de códigos elegantes se apaixona.

Eu não vou nem um pouco, tentar me passar por especialista, nem em Ruby, nem em Rails. O propósito aqui é documentar cada descoberta e cada criação com ambos durante meu aprendizado.

 

Vamos lá, porque eu deveria investir tempo para dominar uma nova linguagem?

A questão não é apenas o investimento de tempo, que não podemos dispensar, ele é valioso, mas acredito que se olharmos para os benefícios obtidos com a utilização de algo como rails, a balança tende a baixar para o lado de cá.

 

Sintaxe mais clara e simples

No início deste ano, falou-se em crianças a partir dos cinco anos de idade em escolas da Inglaterra estarem aprendendo linguagem de programação no ensino primário.

A grande sacada aí, é que já está mais do que claro que a informatização vai se tornar cada vez mais inerente a tudo. Talvez a competição seja o fator “carro chefe”.

Não vivemos mais a época onde códigos de programação só eram entendidos por quem os programavam. Grandes softwares foram desenvolvidos sob licenças totalmente públicas e livres. Vivemos a era da colaboração, onde diversos desenvolvedores expõe suas lógicas e descobertas.

Ruby é Semanticamente correto, rapidamente se entende o que se vê pela pela frente, muitas vezes intuitivamente se escreve um código que funciona sem tê-lo visto antes.

A defesa aqui com a simplicidade da linguagem não pode ofuscar o esclarecimentos sobre as  qualidades:

 

Tudo em Ruby é um objeto

Pra entender a frase: Tudo em Ruby é um objeto, basta ter em mente que Tudo em Ruby é um objeto.

Isso pode não parecer tão relevante para aquele que ainda pensa que existe a possibilidade de se trabalhar sem ser orientado a objeto, é claro que eu me refiro a projetos para atender essa louca demanda de “coisas”  que alguns clientes nem conseguem ainda enxergar o que realmente quer.

Projetos só perpetuam quando são bem desenvolvidos e criados com foco em atualizações e padrões sérios. Coso contrário, eles sobrevivem na Web durante algum tempo, até que seu mantenedor caia na real que a “coisa” não passa de um peso e ele ou deixa de lado ou manda “cortar”.

Pra finalizar, tratar objetos é muito mais simples que tratar banco de dados.

 

Agilidade

A possibilidade de ter uma aplicação realmente modulada se faz muito mais próxima para mim com rails do que com cake. Além de mesmo dentro da aplicação os objetos ficarem bem distintos, a possibilidade de trabalhar com as famosas Gems, que agora, neste momento que escrevo, exibe em seu site a existência de 64,726 gems, imagine uma ferramenta que pode ser usada quase como um plataforma para a criação de sistemas que funcionam como “camada base”, a internet.

O reaproveitamento de código fica claro sabendo da existência e funcionamento das Gems, parece que a criação de gems é uma ótima solução para funcionalidades completas e independentes compartilhadas entre sistemas.

 

Rails não é uma árvore de natal

Acho que uma grande dificuldade encontrada em projetos open source é o inchaço descontrolado. Projetos onde começam a surgir ideias onde satisfazem necessidades que não são inerentes a todos os projetos, onde algumas ficam esquecidas e olha que já vi caso de “um amigo meu” hehehe… desenvolver algo que tinha investido tempo no desenvolvimento da mesma funcionalidade.

A impressão que rails passa é que ele quer nele apenas o que é usado como base.

Montando a minha estação de trabalho

Vamos começar então a por a mão na massa?

Eu espero que você use um sistema unix, como alguma distribuição Linux ou Mac, caso contrário continue aí, tem vários tutoriais sobre Ruby e Ruby on Rails para windows, mas a arquitetura aqui usada é Ubuntu 12.4, servidor Apache 2.2.22  Ruby 1.9.3-p448, Rails 4.0.0

Existe um projeto chamado RVM que entre outras coisas ele disponibiliza no ambiente de usuário uma versão ruby definida por você em gems, ou seja o ambiente de desenvolvimento “montado” na máquina é inerente ao usuário e não ao sistema como um todo. Na verdade, não vejo muita utilidade olhando para por este âmbito, mas se olharmos para a possibilidade de alteração de uma versão ruby a qualquer momento, a coisa já muda de figura para as minhas necessidades.

 

Tutorial de instalação do RVM

 

Se você seguiu o tutorial até o final, você já tem rodando em sua máquina uma aplicação rails, mas digamos que você não seguiu até o fim e só deixou tudo instaladinho como precisamos.

Crie no diretório usado pelo seu servidor como raiz um diretório com o nome de app_rails

Esse diretório ao que parece, poderia ficar em qualquer lugar, mas eu gosto de centralizar, não foi a toa que os objetos me fascinaram. 🙂

No meu caso:

jackson@jackson:~$ mkdir /var/www/app_rails

 

Agora vamos criar nossa primeira aplicação usando Rails

jackson@jackson:~$ cd /var/www/app_rails
jackson@jackson:/var/www/app_rails$ rails new MeuSite
create
create README.rdoc
create Rakefile
create config.ru
create .gitignore
create Gemfile
create app
create app/assets/javascripts/application.js
create app/assets/stylesheets/application.css
create app/controllers/application_controller.rb
create app/helpers/application_helper.rb
create app/views/layouts/application.html.erb
create app/assets/images/.keep
create app/mailers/.keep
create app/models/.keep
create app/controllers/concerns/.keep
create app/models/concerns/.keep
create bin
create bin/bundle
create bin/rails
create bin/rake
create config
create config/routes.rb
create config/application.rb
create config/environment.rb
create config/environments
create config/environments/development.rb
create config/environments/production.rb
create config/environments/test.rb
create config/initializers
create config/initializers/backtrace_silencers.rb
create config/initializers/filter_parameter_logging.rb
create config/initializers/inflections.rb
create config/initializers/mime_types.rb
create config/initializers/secret_token.rb
create config/initializers/session_store.rb
create config/initializers/wrap_parameters.rb
create config/locales
create config/locales/en.yml
create config/boot.rb
create config/database.yml
create db
create db/seeds.rb
create lib
create lib/tasks
create lib/tasks/.keep
create lib/assets
create lib/assets/.keep
create log
create log/.keep
create public
create public/404.html
create public/422.html
create public/500.html
create public/favicon.ico
create public/robots.txt
create test/fixtures
create test/fixtures/.keep
create test/controllers
create test/controllers/.keep
create test/mailers
create test/mailers/.keep
create test/models
create test/models/.keep
create test/helpers
create test/helpers/.keep
create test/integration
create test/integration/.keep
create test/test_helper.rb
create tmp/cache
create tmp/cache/assets
create vendor/assets/javascripts
create vendor/assets/javascripts/.keep
create vendor/assets/stylesheets
create vendor/assets/stylesheets/.keep
run bundle install
Fetching gem metadata from https://rubygems.org/..........
Fetching gem metadata from https://rubygems.org/..
Resolving dependencies...
Using rake (10.1.0)
Using i18n (0.6.5)
Using minitest (4.7.5)
Using multi_json (1.8.2)
Using atomic (1.1.14)
Using thread_safe (0.1.3)
Using tzinfo (0.3.38)
Using activesupport (4.0.0)
Using builder (3.1.4)
Using erubis (2.7.0)
Using rack (1.5.2)
Using rack-test (0.6.2)
Using actionpack (4.0.0)
Using mime-types (1.25)
Using polyglot (0.3.3)
Using treetop (1.4.15)
Using mail (2.5.4)
Using actionmailer (4.0.0)
Using activemodel (4.0.0)
Using activerecord-deprecated_finders (1.0.3)
Using arel (4.0.1)
Using activerecord (4.0.0)
Using bundler (1.3.5)
Using coffee-script-source (1.6.3)
Using execjs (2.0.2)
Using coffee-script (2.2.0)
Using thor (0.18.1)
Using railties (4.0.0)
Using coffee-rails (4.0.1)
Using hike (1.2.3)
Using jbuilder (1.5.2)
Using jquery-rails (3.0.4)
Using json (1.8.1)
Using tilt (1.4.1)
Using sprockets (2.10.0)
Using sprockets-rails (2.0.1)
Using rails (4.0.0)
Using rdoc (3.12.2)
Using sass (3.2.12)
Using sass-rails (4.0.1)
Using sdoc (0.3.20)
Using sqlite3 (1.3.8)
Using turbolinks (1.3.0)
Using uglifier (2.2.1)
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.
jackson@jackson:/var/www/app_rails$

A primeira vista, confesso que tomei um susto quando vi a quantidade de diretórios e arquivos, mas logo cai na real que eu já tinha desenvolvido projetos que de cara dava pra ver que posuia um volume igual ou maior.

O que Rails cria aí quando pedimos a ele uma nova aplicação, é uma espécie de chassi se não estaria rebaixando Rails, pois ele por si próprio já é uma aplicação possível de reunir funcionalidades em instantes formando um novo site simples ou até mesmo um sistema mais complexo. O legal aí é que após a criação da aplicação, ele com base nessa aplicação gerada, coloca em uso para aplicação todas as bibliotecas externas que aplicação gerada depende, no nosso caso MeuSite.

Captura de tela de 2013-10-24 00:29:29

A estrutura MVC dentro do diretório app deixa clara a separação da lógica do sistema em si das visualizações.

Basicamente separamos nossa aplicação em modelos onde especificamos regras de inserção de dados como validações e alterações de valores antes e após as inserções ou filtragens.

Os controladores são os responsáveis por receber parâmetros vindos geralmente de uma view, com base nesses parâmetros, solicitar ao modelo dados ou entregar dados a ele. Da mesma forma que o controlador recebe parâmetros de uma view, ele disponibiliza variáveis de instância acessíveis na view.

O diretório config fala por si só.

O diretório db é onde fica toda a  estrutura do banco de dados da aplicação.

Os outros vamos vendo aos poucos com o tempo.

 

 

 

Se consegue editar qualquer arquivo da aplicação, sua estação de trabalho está pronta. É claro que temos preferências por editores e etc, mas com isso aí já dá pra gente seguir em frente.

 

 

Top