Automatizando a criação de um ambiente de desenvolvimento com Docker + Bash Script + Portainer
Tags: docker, productivity, tutorial, bash
Published: 2020-08-29 15:10:22

## Introdução

Facilidade, automatização e velocidade são coisas que nós, desenvolvedores, amamos. Eu trabalho em muitos projetos, com diversas ferramentas, como MongoDb, MySQL, RabbitMQ, Redis, dentre outras e muitas vezes fica difícil gerenciar tudo isso (ao migrar de máquina, por exemplo). A ideia hoje é mostrar uma forma simples e eficiente de ter todas suas ferramentas centralizadas e organizadas utilizando **Docker** e **Bash Script** (quem me conhece sabe que eu amo Bash Script <3) e também o gerenciamento das mesmas através do **Portainer**, uma interface gráfica para o Docker. Lembrando que deixarei todos os exemplos no github ao final do artigo. E como a ideia é ser ágil, esse tutorial vai passar na velocidade da luz. Então vamos nessa!

## Pré-requisitos

- Docker
- Docker Compose

## Criando nossos serviços

Primeiramente, criaremos um arquivo do Docker Compose, que irá conter a descrição de todos os nossos serviços. Aqui utilizarei os serviços citados no inicio (Mysql, MongoDb, RabbitMQ e Redis), além do Portainer, que vai nos dar uma visão e gerenciamento de todos os serviços. Você também pode adicionar os serviços da sua preferência.

Esse será nosso arquivo de configuração:

```yml
#docker-compose.yml
version: '3.4'
x-logging:
    &default-logging
    options:
    max-size: '10m'
    max-file: '1'
    driver: json-file
services:
    portainer:
        image: portainer/portainer
        container_name: portainer
        restart: on-failure
        ports:
            - "9000:9000"
        volumes:
        - /var/run/docker.sock:/var/run/docker.sock
        - ${VOLUMES_DIR}/portainer:/data
        logging: *default-logging          
    mysql:
    image: mysql:5.7
    command: mysqld --sql_mode='NO_ENGINE_SUBSTITUTION'
    restart: on-failure
    environment:
        - MYSQL_ROOT_PASSWORD=toor
        - DEFAULT_TIME_ZONE=America/Sao_Paulo
        - TZ=America/Sao_Paulo           
    volumes:
        - ${VOLUMES_DIR}/mysql:/var/lib/mysql
    container_name: mysql
    ports:
        - 3306:3306
    logging: *default-logging
    redis:
        image: redis:latest
        container_name: redis
        ports:
        - "6379:6379"
        logging: *default-logging      
    mongo:
        image: mongo:latest
        volumes:
            - ${VOLUMES_DIR}/mongodb:/data/db
        container_name: mongo
        ports:
            - 27017:27017
        logging: *default-logging
    rabbitmq:
        image: rabbitmq:3-management
        container_name: rabbitmq
        ports:
            - "15672:15672"
            - "5672:5672"
        volumes:
            - ${VOLUMES_DIR}/rabbitmq:/var/lib/rabbitmq
        environment:
            - RABBITMQ_ERLANG_COOKIE=cookie
            - RABBITMQ_DEFAULT_USER=root
            - RABBITMQ_DEFAULT_PASS=toor
        logging: *default-logging
```

Aqui vale destacar dois pontos importantes. O primeiro é que mapeamos os volumes dos serviços utilizando uma variável que vai definir onde os dados persistentes dos containers serão armazenados na máquina **host**. Essa configuração só é necessária se você desejar persistir a informação, caso contrário, cada vez que você refizer o build ou remover a imagem, você perderá todos os dados contidos nelas.

O segundo é a utilização de uma política para definir o tamanho máximo do armazenamento de logs em cada container. É importante caso ocorra alguma situação inesperada, como um erro de algum container que fica acumulando logs, podendo levar você até mesmo a ficar sem storage na máquina.

## Rodando os serviços

Agora que já temos o nosso arquivo de configuração dos serviços, vamos automatizar as ações que iremos utilizar com Bash Script, fazendo uma pequena abstração de alguns comandos. Nosso script ficará dessa forma:

```bash
#script.sh
export VOLUMES_DIR=/var/volumes/docker

up() {
    docker-compose up --build -d $1
}

logs() {
    docker-compose logs -f $1
}

down() {
    docker-compose down
}

stop() {
    docker-compose stop $1
}

rmi() {
    docker rmi $(docker images -f dangling=true -q) --force
}

$*
```

Rodando todos os serviços:

```bash
bash script.sh up
```

Rodando um serviços específico
```bash
bash script.sh up <service name>
```

Parando todos os serviços:

```bash
bash script.sh down
```

Parando um serviço específico:

```bash
bash script.sh stop <service name>
```

Acessando os logs de todos os serviços:

```bash
bash script.sh logs
```

Acessando os logs de um serviço específico:

```bash
bash script.sh logs <service name>
```

Adicionei um comando extra muito útil também que remove todas as imagens não utilizadas (se você usa Docker no dia-a-dia e nunca fez uma limpeza, ficará surpreso com o quanto de storage será liberado ao rodar esse comando):

```bash
bash script.sh rmi
```

## Gerenciando os serviços

Bom, levando em consideração que subimos todos os serviços rodando o primeiro comando, vamos explorar um pouco o Portainer como um meio de gerenciar nossos serviços. O **Portainer** é uma interface gráfica para o Docker que permite ver containers, volumes, rodar imagens e muito mais. De acordo com nosso arquivo de instalação, ele deve estar disponível na porta 9000. Acessando 'http://localhost:9000' teremos acesso a interface do mesmo. No primeiro acesso, você deve criar uma senha para administrador.

![login](https://dev-to-uploads.s3.amazonaws.com/i/sedvr5sli3yccovszxdb.jpg)
    
Em seguida escolha a opção **Local** e clique em **connect**, para que o portainer possa se conectar aos seus containers locais.

![connect](https://dev-to-uploads.s3.amazonaws.com/i/qzvrf604bhfrp8diqeu2.jpg)
    
Acessando o nosso endpoint criado, no menu **Containers**, temos acesso aos nossos serviços (os que estão rodando e os que estão parados também).

![containers](https://dev-to-uploads.s3.amazonaws.com/i/dec48ghzephi1q4lkiok.jpg)

Clicando em um **Container**, teremos um menu com algumas opções, como logs, stats (que mostra dados sobre uso de cpu, memória, etc) e até mesmo acesso ao terminal dentro do container. É possível acessar algumas dessas opções através do menu rápido na propria tela que lista os containers.

![detail](https://dev-to-uploads.s3.amazonaws.com/i/cq467u6abdaz0lrc9qmm.jpg)

Outra opção interessante é a **App Templates**, onde você tem uma variedade enorme de serviços e é possível fazer deploy com apenas um clique.

![templates](https://dev-to-uploads.s3.amazonaws.com/i/q5pg4dlw6dni5f4bverw.jpg)

Como prometi que seria um artigo rápido, vamos ficar por aqui, mas vale muito a pena explorar outras opções, a interface é muito rica e intuitiva (merecia um artigo só pra ele). Todos os exemplos citados acima estão no github:

https://github.com/thiagomr/docker-utils

## Conclusão

Hoje vimos como é simples e rápido ter um ambiente de desenvolvimento rodando apenas um comando e também uma forma visual de gerenciar o mesmo. Se você curtiu essa dica, dá um like, star no github e me segue no twitter para novidades e deixe aqui seu comentário. Feedbacks são mais que bem-vindos.

Grande abraço e até a próxima!