Flet: View e Container


Layout do Flet: View e Container

Flet: View

A palavra container do inglês é traduzida como contêiner (pt-br), plural contêineres. Para não criar confusão com a palavra técnica nós o chamaremos aqui por container, containers.

Um aplicativo do Flet abre sempre uma page que serve de container para o objeto View. Uma View é criado automaticamente quando uma nova sessão é iniciada. Ela é basicamente uma coluna (column) básica, que abriga todos os demais controles que serão inseridos na página. Dessa forma ele tem comportamento semelhante ao de uma column, e as mesmas propriedades. Uma descrição resumida será apresentada aqui. Para maiores detalhes consulte a descrição de column.

O objeto View é o componente visual de uma página Flet, responsável por renderizar os elementos da UI e gerenciar seu estado. Ele pode abrigar outros objetos como botões, campos de texto, imagens, etc, e organizá-los em uma estrutura hierárquica. Esses elementos são então renderizados na tela. O objeto View também possui métodos para lidar com eventos do usuário, como cliques em botões ou textos digitados nas caixas de texto.

Por exemplo, o código:

page.controls.append(ft.Text("Um texto na página!"))
page.update()
# ou, o que é equivalente
page.add(ft.Text("Um texto na página!"))

insere o texto na View que está diretamente criada sobre page. View possui as seguintes propriedades e métodos.

View: Propriedades

Propriedade Descrição
appbar recebe um controle AppBar para exibir na parte superior da página.
auto_scroll Booleano. True para que a barra de rolagem se mova para o final quando os filhos são atualizados. Para que scroll_to() funcione deve ser atribuído auto_scroll=False.
bgcolor Cor de fundo da página.
controls Lista de controles a serem inseridos na página. O último controle da lista pode se removido com page.controls.pop(); page.update().
fullscreen_dialog Booleano. True se a página atual é um diálogo em tela cheia.
route Rota da visualização (não usada atualmente). Pode ser usada para atualizar page.route em caso de nova visualização.
floating_action_button Recebe um controle FloatingActionButton a ser exibido no alto da página.
horizontal_alignment Alinhamento horizontal dos filhos. Default: horizontal_alignment=CrossAxisAlignment.START.
on_scroll_interval Definição do intervalo de tempo para o evento on_scrollo, em milisegundos. Default: 10.
padding Espaço entre o conteúdo do objeto e suas bordas, em pixeis. Default: 10.
scroll Habilita rolagem (scroll) vertical para a página, evitando overflow. O valor da propriedade está em um ENUM ScrollMode com as possibilidades:

  • None (padrão): nenhum scroll. Pode haver overflow.
  • AUTO: scroll habilitado, a barra só aparece quando a rolagem é necessária.
  • ADAPTIVE: scroll habilitado, a barra de rolagem visível quando aplicativo é web ou desktop.
  • ALWAYS: scroll habilitado, a barra sempre exibida.
  • HIDDEN: scroll habilitado, barra de rolagem invisível.
spacing Espaço vertical entre os controles da página, em pixeis. Default: 10. Só aplicado quando alignment = start, end, center.
vertical_alignment Alinhamento vertical dos filhos. A propriedade está em um ENUM MainAxisAlignmente com as possibilidades:

  • START (padrão)
  • END
  • CENTER
  • SPACE_BETWEEN
  • SPACE_AROUND
  • SPACE_EVENLY

Exemplos:

page.vertical_alignment = ft.MainAxisAlignment.CENTER
page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
scroll_to(offset, delta, key, duration, curve) Move a barra de scroll para uma posição absoluta ou salto relativo para chave especificada.

View: Evento

Evento Descrição
on_scroll Dispara quando a posição da barra de rolagem é alterada pelo usuário.

O controle View é útil em situações que se apresenta mais em uma visualização na mesma página e será visto mais tarde com maiores detalhes.

Flet: Container

Um objeto Container é basicamente um auxiliar de layout, um controle onde se pode inserir outros controles, permitindo a decoração de cor de fundo, borda, margem, alinhamento e preenchimento. Ele também pode responder a alguns eventos.

Como exemplo, o código abaixo:

import flet as ft

def main(page: ft.Page):
    page.title = "Contêineres com cores de fundo"

    def cor(e):
        c4 = ft.Container(content=ft.Text("Outro conteiner azul!"), bgcolor=ft.colors.BLUE, padding=5)
        page.add(c4)

    c1 = ft.Container(content=ft.ElevatedButton("Um botão \"Elevated\""),
                      bgcolor=ft.colors.YELLOW, padding=5)

    c2 = ft.Container(content=ft.ElevatedButton("Elevated Button com opacidade=0.5",
                      opacity=0.5), bgcolor=ft.colors.YELLOW, padding=5)

    c3 = ft.Container(content=ft.Text("Coloca outra área azul"),
                      bgcolor=ft.colors.YELLOW, padding=5, on_click=cor)
    page.add(c1, c2, c3)

ft.app(target=main)

gera a janela na figura 1, após 1 clique no botão c3.

Figura 1: Novo container é adicionado ao clicar em “Coloca outra área azul”.

O container c3 reage ao evento clique, adicionando um (ou mais) botão azul à janela.

Container: Propriedades

Figura 2

A figura 2 mostra o esquema de espaçamentos entre controles: a largura e altura (width, height) do container, a margem (margin) entre a caixa de decoração e o container, a borda (border) da caixa e o espaçamento interno (padding) entre o controle e a caixa.

Propriedade Descrição
alignment Alinhamento do controle filho dentro do Container para exibir na parte superior da página. Alignment é uma instância do objeto alignment.Alignment com propriedades x e y que representam a distância do centro de um retângulo.

  • x=0, y=0: o centro do retângulo,
  • x=-1, y=-1: parte superior esquerda do retângulo,
  • x=1.0, y=1.0: parte inferior direita do retângulo.
Figura 3

Constantes de alinhamento pré-definidas no módulo flet.alignment são: top_left, top_center, top_right, center_left, center, center_right, bottom_left, bottom_center, bottom_right. Por exemplo, mostrado na figura 4:

  • container_1.alignment = alignment.center
  • container_2.alignment = alignment.top_left
  • container_3.alignment = alignment.Alignment(-0.5, -0.5)

Figura 4
animate Ativa a animação predefinida do container, alterando valores de suas propriedades de modo gradual. O valor pode ser um dos seguintes tipos:

  • bool: True para ativar a animação do container com curva linear de duração de 1000 milisegundos.
  • int: ajusta tempo em milisegundos, com curva linear.
  • animation: Animation(duration: int, curve: str): ativa animação do container com duração e curva de transição especificadas.

Por exemplo:

import flet as ft

def main(page: ft.Page):

    c = ft.Container(width=200, height=200, bgcolor="red", animate=ft.animation.Animation(1000, "bounceOut"))

    def animar_container(e):
        c.width = 100 if c.width == 200 else 200
        c.height = 100 if c.height == 200 else 200
        c.bgcolor = "blue" if c.bgcolor == "red" else "red"
        c.update()

    page.add(c, ft.ElevatedButton("Animate container", on_click=animar_container))

ft.app(target=main)

O código resulta na animação mostrada abaixo, na figura 5:

Figura 5: animação

bgcolor Cor de fundo do container.
blend_mode modo de mistura (blend) de cores ou gradientes no fundo container.
blur Aplica o efeito de desfoque (blur) gaussiano sobre o container.

O valor desta propriedade pode ser um dos seguintes:

  • um número: especifica o mesmo valor para sigmas horizontais e verticais, por exemplo 10.
  • uma tupla: especifica valores separados para sigmas horizontais e verticais, por exemplo (10, 1).
  • uma instância de ft.Blur: especifica valores para sigmas horizontais e verticais, bem como tile_mode para o filtro. tile_mode é o valor de ft.BlurTileMode tendo como default ft.BlurTileMode.CLAMP.
border Borda desenhada em torno do controle e acima da cor de fundo. Bordas são descritas por uma instância de border.BorderSide, com as propriedades: width (número) e color (string). O valor da propriedade border é instância de border.Borderclasse, descrevendo os 4 lados do retângulo. Métodos auxiliares estão disponíveis para definir estilos de borda:

  • border.all(width, color)
  • border.symmetric(vertical: BorderSide, horizontal: BorderSide)
  • border.only(left: BorderSide, top: BorderSide, right: BorderSide, bottom: BorderSide).

Por exemplo:

container_1.border = ft.border.all(10, ft.colors.PINK_600)
container_1.border = ft.border.only(bottom=ft.border.BorderSide(1, "black"))
border_radius Permite especificar (opcional) o raio de arredondamento das bordas. O raio é instância de border_radius.BorderRadius com as propriedades: top_left, top_right, bottom_left, bottom_right. Esses valores podem ser passados no construtor da instância, ou por meio de métodos auxiliares:

  • border_radius.all(value)
  • border_radius.horizontal(left: float = 0, right: float = 0)
  • border_radius.vertical(top: float = 0, bottom: float = 0)
  • border_radius.only(top_left, top_right, bottom_left, bottom_right)

Por exemplo: container_1.border_radius= ft.border_radius.all(30), fará todas as bordas do container_1 igual 1 30.

clip_behavior Opção para cortar (ou não) o conteúdo do objeto. A propriedade ClipBehavior é um ENUM com valores suportados:

  • NONE
  • ANTI_ALIAS
  • ANTI_ALIAS_WITH_SAVE_LAYER
  • HARD_EDGE

Se border_radius=None o default é ClipBehavior.ANTI_ALIAS. Caso contrário o default é ClipBehavior.HARD_EDGE.

content Define um controle filho desse container.
gradient O gradiente na cor de fundo. O valor deve ser uma instância de uma das classes: LinearGradient, RadialGradient e SweepGradient.


Uma descrição mais detalhada está em Detalhes sobre o gradiente de cores.

image_fit Descrita junto com o objeto image.
image_opacity Define a opacidade da imagem ao mesclar com um plano de fundo: valor entre 0.0 e 1.0.
image_repeat Descrita junto com o objeto image.
image_src Define imagem do plano de fundo.
image_src_base64 Define imagem codificada como string Base-64 como plano de fundo do container.
ink True para efeito de ondulação quando o usuário clica no container. Default: False.
margin Espaço vazio que envolve o controle. margin é uma instância de margin.Margin, definindo a propriedade para os 4 lados do retângulo: left, top, right e bottom. As propriedades podem ser dadas no construtor ou por meio de métodos auxiliares:

  • margin.all(value)
  • margin.symmetric(vertical, horizontal)
  • margin.only(left, top, right, bottom)

Por exemplo:

container_1.margin = margin.all(10)
container_2.margin = 20 # same as margin.all(20)
container_3.margin = margin.symmetric(vertical=10)
container_3.margin = margin.only(left=10)
padding Espaço vazio de decoração entre borda do objeto e seu container. Padding é instância da padding.Padding com propriedades definidas como padding para todos os lados do retângulo: left, top, right e bottom. As propriedades podem ser dadas no construtor ou por meio de métodos auxiliares:

  • padding.all(value: float)
  • padding.symmetric(vertical, horizontal)
  • padding.only(left, top, right, bottom)

Por exemplo:

container_1.padding = ft.padding.all(10)
container_2.padding = 20 # same as ft.padding.all(20)
container_3.padding = ft.padding.symmetric(horizontal=10)
container_4.padding=padding.only(left=10)
shadow Efeito de sombras projetadas pelo container. O valor dessa propriedade é uma instância ou uma lista de ft.BoxShadow, com as seguintes propriedades:

  • spread_radius: espalhamento, quanto a caixa será aumentada antes do desfoque. Default: 0.0.
  • blur_radius: desvio padrão da gaussiano de convolução da forma. Default: 0.0.
  • color: Cor da sombra.
  • offset: Uma instância de ft.Offsetclasse, deslocamentos da sombra, relativos à posição do elemento projetado. Os deslocamentos positivos em x e y deslocam a sombra para a direita e para baixo. Deslocamentos negativos deslocam para a esquerda e para cima. Os deslocamentos são relativos à posição do elemento que o está projetando. Default: ft.Offset(0,0).
  • blur_style: tipo de estilo, ft.BlurStyleque a ser usado na sombra. Default: ft.BlurStyle.NORMAL.

Exemplo:

ft.Container(
    shadow=ft.BoxShadow(
        spread_radius=1,
        blur_radius=15,
        color=ft.colors.BLUE_GREY_300,
        offset=ft.Offset(0, 0),
        blur_style=ft.ShadowBlurStyle.OUTER,
    )
)
shape A forma do conteiner. O valor é ENUM BoxShape: RECTANGLE (padrão), CIRCLE
theme_mode O ajuste do theme_mode redefine o tema usado no container e todos os objetos dentro dele. Se não for definido o tema em theme é válido para o container e seus filhos.
theme Ajuste o tema global e dos filhos na árvore de controle.

Segue um exemplo de uso:

import flet as ft

def main(page: ft.Page):
    page.theme = ft.Theme(color_scheme_seed=ft.colors.RED)

    b1 = ft.ElevatedButton("Botão com tema da página")
    b2 = ft.ElevatedButton("Botão com tema herdado")
    b3= ft.ElevatedButton("Botão com tema dark")

    c1 = ft.Container(
        b1,
        bgcolor=ft.colors.SURFACE_TINT,
        padding=20,
        width=300
    )
    c2 = ft.Container(
        b2,
        theme=ft.Theme(
            color_scheme=ft.ColorScheme(primary=ft.colors.PINK)
        ),
        bgcolor=ft.colors.SURFACE_VARIANT,
        padding=20,
        width=300
    )
    c3 = ft.Container(
        b3,
        theme=ft.Theme(
            color_scheme_seed=ft.colors.INDIGO
        ),
        theme_mode=ft.ThemeMode.DARK,
        bgcolor=ft.colors.SURFACE_VARIANT,
        padding=20,
        width=300
    )

    page.add(c1, c2, c3)

ft.app(main)
Figura 6: Temas

O tema principal da página é definido em page.theme, usando um seed vermelho. Os botões b1 e b2 simnplesmente herdam o tema da página. O botão b3 está no container definido com theme_mode=ft.ThemeMode.DARK, exibindo o tema escuro. O código gera a janela mostrada na figura 6.

Vale lembrar que c1 = ft.Container(b1,...) é equivalente à c1 = ft.Container(content = b1,...) sendo que o content só pode ser omitido se o conteúdo for inserido como primeiro parâmetro.urlDefine a URL a ser abertta quando o container é clicado, disparando o evento on_click.url_target

Define onde abrir URL no modo web:

  • _blank (default): em nova janela ou aba,
  • _self: na mesma janela ou aba aberta.

Container: Eventos

Evento Dispara quando
on_click o usuário clica no container.

class ft.ContainerTapEvent():
    local_x: float
    local_y: float
    global_x: float
    global_y: float

Obs.: O objeto de evento e é uma instância de ContainerTapEvent, exceto se a propriedade ink = True. Nesse caso e será apenas ControlEvent com data vazio.

Um exemplo simples de uso:

import flet as ft

def main(page: ft.Page):

    t = ft.Text()

    def clicou_aqui(e: ft.ContainerTapEvent):
        t.value = (
            f"local_x: {e.local_x}\nlocal_y: {e.local_y}"
            f"\nglobal_x: {e.global_x}\nglobal_y: {e.global_y}"
        )
        t.update()

    c1 = ft.Container(ft.Text("Clique dentro\ndo container"),
                      alignment=ft.alignment.center, bgcolor=ft.colors.TEAL_300, 
                      width=200, height=200, border_radius=10,  on_click=clicou_aqui)
    col = ft.Column([c1, t], horizontal_alignment=ft.CrossAxisAlignment.CENTER)
    page.add(col)

ft.app(target=main)
Figura 8: posição do click.

As propriedades e.local_x e e.local_y se referem à posição dentro do container c1, enquanto e.global_x e e.global_y se referem à posição global, dentro da página.

on_hover o cursor do mouse entra ou abandona a área do container. A propriedade data do evento contém um string (não um booleano) e.data = "true" quando o cursor entra na área, e e.data = "false" quando ele sai.

Um exemplo de um container que altera sua cor de fundo quando o mouse corre sobre ele:

import flet as ft

def main(page: ft.Page):
    def on_hover(e):
        e.control.bgcolor = "blue" if e.data == "true" else "red"
        e.control.update()

    c1 = ft.Container(width=100, height=100, bgcolor="red",
                      ink=False, on_hover=on_hover)
    page.add(c1)

ft.app(target=main)
on_long_press quando o container recebe um click longo (pressionado por um certo tempo).

Detalhes sobre o gradiente de cores

O gradiente na cor de fundo admite como valor uma instância de uma das classes: LinearGradient, RadialGradient e SweepGradient.

Um exmplo de uso está no código abaixo:

import flet as ft
import math

def main(page: ft.Page):
    c1 = ft.Container(
        gradient=ft.LinearGradient(
        begin=ft.alignment.top_center,
        end=ft.alignment.bottom_center,
        colors=[ft.colors.AMBER_900, ft.colors.BLUE],),
        width=150, height=150, border_radius=5,)

    c2 = ft.Container(
         gradient=ft.RadialGradient(colors=[ft.colors.GREY, ft.colors.CYAN_900],),
         width=150, height=150, border_radius=5,)

    c3 = ft.Container(
         gradient=ft.SweepGradient(center=ft.alignment.center,
         start_angle=0.0, end_angle=math.pi * 2,
         colors=[ft.colors.DEEP_PURPLE_800, ft.colors.DEEP_ORANGE_400],),
         width=150, height=150, border_radius=5,)
    
    page.add(ft.Row([c1, c2, c3]))

ft.app(target=main)

O código acima gera as imagens na figura 9:

Figura 9: LinearGradient, a segundo com RadialGradient e a última com SweepGradient

A primeira imagem é gerada com LinearGradient, a segunda com RadialGradient e a última com SweepGradient.

São propriedades da classe LinearGradient:

begin instância de Alignment. Posicionamento inicial (0.0) do gradiente.
end instância de Alignment. Posicionamento final (1.0) do gradiente.
colors cores assumidas pelo gradiente a cada parada. Essa lista deve ter o mesmo tamanho que stops se a lista for não nula. A lista deve ter pelo menos duas cores.
stops lista de valores de 0.0 a 1.0 marcando posições ao longo do gradiente. Se não nula essa lista deve ter o mesmo comprimento que colors. Se o primeiro valor não for 0.0 fica implícita uma parada em 0,0 com cor igual à primeira cor em colors. Se o último valor não for 1.0 fica implícita uma parada em 1.0 e uma cor igual à última cor em colors.
tile_mode como o gradiente deve preencher (tile) a região antes de begin depois de end. O valor é um ENUM GradientTileMode com valores: CLAMP (padrão), DECAL, MIRROR, REPEATED.
rotation rotação do gradiente em radianos, em torno do ponto central de sua caixa container.

Mais Informações:

Gradiente linear na documentação do Flutter.
Unidade de medida de radianos na Wikipedia.

São propriedades da classe RadialGradient:

colors, stops, tile_mode, rotation propriedades idênticas às de LinearGradient.
center instância de Alignment. O centro do gradiente em relação ao objeto que recebe o gradiente. Por exemplo, alinhamento de (0.0, 0.0) coloca o centro do gradiente radial no centro da caixa.
radius raio do gradiente, dado como fração do lado mais curto da caixa. Supondo uma caixa com largura = 100 e altura = 200 pixeis, um raio de 1 no gradiente radial colocará uma parada de 1,0 afastado 100,0 pixeis do centro.
focal ponto focal do gradiente. Se especificado, o gradiente parecerá focado ao longo do vetor do centro até esse ponto focal.
focal_radius raio do ponto focal do gradiente, dado como fração do lado mais curto da caixa. Ex.: um gradiente radial desenhado sobre uma caixa com largura = 100,0 e altura = 200,0 (pixeis), um raio de 1,0 colocará uma parada de 1,0 a 100,0 pixels do ponto focal.

São propriedades da classe SweepGradient:

colors, stops, tile_mode, rotation propriedades idênticas às de LinearGradient.
center centro do gradiente em relação ao objeto que recebe o gradiente. Por exemplo, alinhamento de (0.0, 0.0) coloca o centro do gradiente no centro da caixa.
start_angle ângulo em radianos onde será colocada a parada 0.0 do gradiente. Default: 0.0.
end_angle ângulo em radianos onde será colocada a parada 1.0 do gradiente. Default: math.pi * 2.

Graus e radianos

Figura 10: graus e radianos.

A maiora das medidas angulares na programação do flet (e do python em geral) é dada em radianos. Segue uma breve imagem explicativa do uso de radianos.

Bibiografia


Controles do Flet: Row e Column

Containers e Docker


Um histórico sobre containers

Embora exista a palavra contêiner, (plural: contêineres) nos dicionários de português do Brasil, manterei nesse texto a terminologia container (plural: containers) para me referir aos objetos de software tratado neste texto.

Uma máquina virtual, ou uma VM (Virtual Machine) é uma simulação em software de um computador, incluindo CPU, memória, área de armazenamento de arquivos e conexão com à internet. Um aplicativo como o VMware, VirtualBox ou Gnome Boxes cria um arquivo no computador (a imagem) que se comporta como sendo outro computador, no sistema operacional escolhido. Essa imagem se torna um novo ambiente que pode ser isolado ou ter suas interações bem definidas com o computador hospedeiro. Máquinas virtuais foram a primeira resposta dada para o problema de executar diversos aplicativos simultaneamente e em isolamento nos servidores.

Containers são pacotes de software que contém um ambiente completo para a execução de um aplicativo. Isso inclui suas dependências, bibliotecas de sistemas, configurações e outros binários, além dos arquivos de configuração necessários para essa operação. Eles estão disponíveis no Linux e Windows e são extremamente úteis para executar da mesma forma os aplicativos, independentemente do ambiente usado. Eles são especialmente usados na fase de desenvolvimento, reduzindo os conflitos entre as equipes de TI por favorecerem a montagem de ambiente idêntico para todos os envolvidos no projeto. Elem disso facilitam a portabilidade de um para outro sistema operacional, ou mesmo entre diferentes modelos de arquitetura de hardware.

Nas máquinas virtuais um pacote de software inclui, além do aplicativo que se quer executar, um sistema operacional inteiro. No caso dos containers o kernel (o núcleo) do sistema operacional é compartilhado com outros containers que, por isso, usam menos recursos do que as máquinas virtuais. Um servidor físico executando três máquinas virtuais, por exemplo, teria que rodar três sistemas operacionais separados. O mesmo servidor executando três aplicativos em containers roda em um único sistema operacional, sendo que cada container tem acesso ao núcleo do sistema operacional hospedeiro. Dessa forma a máquina pode rodar um número muito superior de containers. Além disso aplicativos de container são iniciados mais rápido, porque não precisam inicializar todo o sistema operacional, e podem liberar recursos que não estão em uso.

Outro problema que os containers buscam resolver é questão dos diversos aplicativos instalados em uma máquina que partilham bibliotecas comuns. Não é raro que um dos aplicativos necessite de versão diferente da biblioteca, o que pode fazer com que partes do software instalado deixe de funcionar. Containers são, portanto, úteis para o desenvolvimento, a distribuição e instalação, e uso em produção de softwares.

Finalmente, containers introduzem um nível adicional de segurança aos computadores. Sabemos que existem programas deliberadamente projetados para atacar, invadir, roubar dados e tempo de máquina no computador hospedeiro. Mesmo programas bem-intencionados podem conter bugs perigosos para o sistema e usuário. Um programa rodando em um container só tem acesso ao seu próprio ambiente, a menos que tenha sido projetado de outra forma.

Todas essas caraterísticas tornam os containers especialmente úteis para a implementação de aplicativos e serviços na nuvem, usando ambientes tais como o Azure, AWS, Google Cloud, etc.

Docker

Docker é o formato de implementação de container mais conhecido. Ele foi desenvolvido primeiro para o uso no Linux, depois levado até plataformas com MacOS e Windows. Associado ao uso de docker temos o Kubernetes, um projeto de código aberto do Google que serve como orquestrador de aplicativos em container. Ele é um dos gerenciadores de containers e imagens do docker disponíveis.

O projeto é open-source e mantido pela empresa Docker Inc., EUA. Empresas e indivíduos contribuem para o projeto que é construído sobre uma arquitetura de plug-ins, onde componentes podem ser acrescentados ou removidos. A Open Container Iniciative, OCI, é um conselho fundado para zelar pela manutenção e observância de padrões, e é mantida pela Linux Foundation com a colaboração de Docker Inc. e outras.

Atualmente (em 2022) o docker roda nativamente no Linux. Para MacOs e Windows ele instala uma única máquina virtual que pode executar todos os containers. Em sistemas modernos é possível rodar dentro de containers aplicativos do Windows e macOS. Docker não é uma linguagem de programação nem um ambiente de desenvolvimento mas sim uma ferramenta de comando de linha que ajuda na solução de diversos problemas comuns ao processo de desenvolvimento, tais como a construção de projetos, sua distribuição, instalação, remoção, atualização e execução. Existem hoje diversos aplicativos GUI (com interfaces gráficas) para o gerenciamento do Docker.

Resumindo

Podemos pensar um container como uma caixa que contém aplicações. Dentro dela existe tudo o que é necessário para a execução das aplicações e o container se assemelha a um computador, com seu próprio nome de máquina, endereço de IP address e até seus próprios discos, todos eles virtuais e criados pelo docker.

O aplicativo dentro do container não tem contato com nada fora dele, exceto o que for explicitamente indicado. Um exemplo disso seriam os casos de interação com o usuário via teclado, ou o acesso do aplicativo a um banco de dados externo.

Terminologia

Images (imagens do Docker) contêm o código-fonte do aplicativo executável, junto com as ferramentas, bibliotecas e dependências que o código precisa para ser executado. Elas podem ser construídas pelo desenvolvedor ou baixadas prontas de repositórios como o Docker Hub. Geralmente uma imagem é composta de várias outras imagens base que são empilhadas em camadas. Vários containers podem ser criados a partir de uma imagem.

Containers são as instâncias ativas e em execução das imagens. Enquanto imagens são arquivos de leitura somente (read-only) os containers são processos ativos que podem interagir com outros processos. Administradores podem ajustar suas configurações e condições usando comandos do Docker.

Dockerfiles (arquivos Docker) são arquivos de texto com as instruções sobre como criar imagens. Um Dockerfile automatiza o processo de criação de containers, contendo todos os passos na sequência que devem ser executados para a construção da imagem. Ele é similar a um script, declarando qual é a imagem base inicial a usar e com instruções para instalar os demais programas necessários, em camadas posteriores.

Build é a ação de criar de uma imagem usando as informações fornecidas pelo Dockerfile, desde que os arquivos adicionais estejam disponíveis no diretório onde a imagem é criada.

Tag (marcação) é uma marca ou rótulo aplicado em imagens para diferenciar versões. As tags podem ser usadas para, por exemplo, baixar uma imagem em versão específica.

Layers (camadas) são modificações aplicadas à uma imagem por meio de instruções do dockerfile. Por exemplo, dentro de uma imagem do ubuntu, que está na primeira camada, pode-se instalar outro aplicativo qualquer que será construído em uma segunda camada. Layers são identificadas por ids (hashes) que são usados para identificá-las.

Repository (repositório) é uma coleção de imagens do Docker rotuladas com marcação (tags) que indicam a versão da imagem. Podem conter imagem de versões diversas diferenciadas por tags, e variantes para as diversas plataformas.

Docker Hub é o repositório público padrão de imagens do Docker considerado a “maior biblioteca para imagens de containers”. Ele contém mais de 100.000 imagens de containers provenientes de fornecedores de software comercial ou de código aberto, e desenvolvedores individuais. Usuários do Docker Hub podem compartilhar suas imagens livremente ou baixar imagens base para usar no desenvolvimento de outros projetos. Existem outros repositórios, como o GitHub. Acesse o site Docker Hub.

Registro do Docker é um sistema de armazenamento e distribuição de imagens do Docker. Ele permite rastrear versões de imagens em repositórios usando o git, uma ferramenta de controle de versão. O registro padrão para imagens mais frequentemente usado é o Docker Hub (propriedade da Docker como uma organização).

Daemon Docker é um serviço que cria e gerencia imagens Docker usando os comandos do cliente. Ele serve como central de controle da implementação do Docker. O servidor onde o daemon é executado é chamado de host do Docker, que pode ser o computador local ou um serviço em nuvem.

Docker Desktop é um aplicativo que facilita a criação e compartilhamento de aplicativos e microsserviços em containers. Junto com o Desktop são instaladas ferramentas como Kubernetes, Docker Compose, BuildKit e verificação de vulnerabilidades. Inicialmente disponível apenas para Windows e MacOS, foi disponibilizado para desenvolvedores no Linux em Maio de 2022. Docker Desktop também inclui extensões do Docker para facilitar a integração com ferramentas de outros desenvolvedores da equipe ou de terceiros.

Docker Dashboard é um aplicativo GUI para gerenciamento de imagens, containers e volumes do Docker. Ele é um aplicativo WEB que roda em Node, abrindo uma página no navegador e pode ser usado para gerenciar visualmente os recursos de container.

Docker Compose é uma ferramenta utilizada na definição e compartilhamento de aplicações multi-container. Com Compose podemos criar um arquivo YAML para definir os serviços usados. Dessa forma um aplicativo pode ser iniciado ou finalizado com um único comando. Ele também facilita a colaboração entre desenvolvedores.

Instalando o Docker


Existem duas versões disponíveis para instalação:

  • Community Edition (CE), edição da comunidade,
  • Enterprise Edition (EE), edição comercial.

Docker CE é gratuita. Docker EE é o mesmo pacote de software, mas com suporte técnico e acesso à outros produtos da empresa.

Instalação: Fedora Linux, Ubuntu Linux, Archlinux, Mac, Windows.

Como exemplo, listamos o procedimento de instalação no Fedora Linux:

# Primeiro habilitamos o repositório    
$ sudo dnf -y install dnf-plugins-core

$ sudo dnf config-manager \
     --add-repo \
     https://download.docker.com/linux/fedora/docker-ce.repo

# instalamos o docker engine
$ sudo dnf install docker-ce docker-ce-cli containerd.io docker-compose-plugin

Para iniciar o serviço do docker via systemctl usamos start docker. Depois podemos testar se a instalação foi bem sucedida verificando a versão instalada e o status do serviço.

# para iniciar o Docker
sudo systemctl start docker

# para verificar a versão instalada
$ docker --version
  Docker version 20.10.17, build 100c701

# verificando o status do serviço
$ sudo service docker status
Redirecting to /bin/systemctl status docker.service
● docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
     Active: active (running) since Fri 2022-08-12 18:52:19 -03; 1min 10s ago
TriggeredBy: ● docker.socket
       Docs: https://docs.docker.com
   Main PID: 32787 (dockerd)
      Tasks: 13
     Memory: 111.8M
        CPU: 344ms     # (saída truncada)

Nessa instalação é criado um grupo de usuários que podem rodar o Docker. Por default o Docker exige privilégios de root para rodar containers, o que pode ser problemático para a segurança do sistema. Para rodar o Docker sem necessidade de emitir comandos como superuser adicionamos um usuário ao grupo do Docker.

$ sudo usermod -aG docker <nome_usuario>
# verificando
$ cat /etc/group | grep docker
  docker:x:973:nome_usuario

Temos dois componentes principais com a instalação do docker: o cliente e o docker daemon (também chamado de docker engine). Uma versão alternativa de docker version (sem os hífens) fornece mais dados sobre a instalação:

$ docker version
  Client: Docker Engine - Community
   Version:           20.10.17
   API version:       1.41
   Go version:        go1.17.11
   Git commit:        100c701
   Built:             Mon Jun  6 23:03:59 2022
   OS/Arch:           linux/amd64
   Context:           default
   Experimental:      true

Server: Docker Engine - Community (saída truncada)

Para instalar e verificar o docker-compose usamos:

# instalar o docker
$ sudo dnf install docker-compose  # (no fedora) ou
$ sudo apt install docker-compose  # (no ubuntu)

# Para verificar a instalação
$ docker-compose version 
  docker-compose version 1.29.2, build unknown
  docker-py version: 5.0.3
  CPython version: 3.10.5
  OpenSSL version: OpenSSL 3.0.5 5 Jul 2022

Desinstalação e atualização: Para atualizar o docker é necessário remover os pacotes antigos e realizar uma nova instalação.

As desinstalações podem ser feitas da seguinte maneira:

# para desinstalar o docker
$ sudo dnf remove docker-desktop

# para desinstalar Docker Engine, CLI, containerd, e Docker Compose
$ sudo dnf remove docker-ce docker-ce-cli containerd.io docker-compose-plugin

Docker Desktop

Docker Desktop é um aplicativo (disponível para Mac, Linux ou Windows) que permite criar, compartilhar e executar aplicativos e microsserviços em containers. Ele fornece uma GUI (interface gráfica do usuário) simples que permite gerenciar seus containers, aplicativos e imagens diretamente de sua máquina.

Para instalar o Docker desktop faça o download do pacote mais recente: Docker desktop e o instale, por exemplo com o comando dnf. Isso criará um ícone no desktop que pode ser clicado para iniciar o aplicativo.


$ sudo dnf install ./docker-desktop--.rpm

# para iniciar o docker-desktop clique no ícone no desktop ou
# alternativamente use, para iniciar e finalizar o docker-desktop
$ systemctl --user start docker-desktop
$ systemctl --user stop docker-desktop

O Docker-desktop é iniciado dando as alternativas de criação de uma conta no Docker, de login em contas já criadas, ou de prosseguir sem esse login.

Docker Dashboard (GUI)

Um aplicativo web pode ser usado com Docker Dashboard. O Dashboard roda com Node.js que, portanto, precisa estar instalado em seu sistema. Depois você deve clonar um repositório do Github.

# clone repositório
$ git clone git@github.com:rakibtg/docker-web-gui.git

# mude para o novo directório criado
$ cd ./docker-web-gui

# execute o app app.js usando o node. Essa ação instalará os módulos necessários ainda não instalados.
$ node app.js

# agora você pode abrir no navegador a página http://localhost:3230/

O navegador abrirá uma página exibindo as imagens instaladas, containers em execução ou parados, visualização dos logs, criação e vizualização de grupos de containers.

Para baixar o código do aplicativo usando git clone git@github.com:rakibtg/docker-web-gui.git, você deve ter uma conta do GitHub com chaves certificadas de ssh. Instruções em Connecting to GitHub with ssh. Alternativamente você pode entrar no site do GitHub para esse aplicativo, baixar e instalar o código.

Imagens do Docker

Uma imagem do docker é um objeto que contém um aplicativo e arquivos de sistema, suficientes para rodar esse aplicativo. Essas imagens podem ser construídas pelo desenvolvedor ou baixadas pela internet de algum repositório, onde outros desenvolvedores as disponibilizaram. Por default as imagens são procuradas no GitHub. Um exemplo simples pode ser dado com a imagem de hello_world. Digitamos no prompt de comando do terminal:

# o primeiro passo é baixar uma imagem
$ docker pull hello-world
# o container pode ser agora executado
$ docker run hello-world
  Hello from Docker!
  This message shows that your installation appears to be working correctly.
  (saída truncada)


O uso de docker pull <imagem> não é estritamente necessário. O comando docker run procura primeiro a imagem na máquina local e, se ela não foi previamente baixada, ele a procura em Docker Hub. Se a imagem for encontrada ele a baixa e constroi um container à partir dela. No caso desse exemplo a imagem contém um aplicativo simples de demonstração que imprime a mensagem listada (que foi aqui truncada) no console. A cada execução de run um novo container é criado e seu aplicativo subjacente é rodado. Imagens baixadas são previamente compiladas (built).

Se você está com o Docker-Desktop aberto a imagem baixada aparecerá no painel do aplicativo.

O comando docker image ls permite ver quais são as imagens já baixadas:

$ docker image ls
  REPOSITORY                   TAG       IMAGE ID       CREATED        SIZE
  hello-world                  latest    feb5d9fea6a5   9 months ago   13.3kB

A tag latest indica que a última versão disponível foi baixada. Em outros casos, a tag é a versão da imagem. A imagem hello-world foi preparada para teste dos iniciantes e contém instruções interessantes. Para apagar um imagem baixada usamos docker rm imagem ou cicando no painels do Docker-Desktop. Mesmo sem a imagem baixada podemos rodar o container. O output da execução será em inglês (para essa imagem) mas a exibiremos aqui com partes traduzidas.

# para apagar a imagem
$ docker rm hello-world

# para rodar novamente essa imagem
$ docker container run hello-world

  Hello from Docker!
  Essa messagem mostra que sua instalação parece estar funcionando corretamente.
  
  Para gerar essa mensagem Docker seguiu os seguintes passos:
   1. O cliente Docker fez contato com o Docker daemon.
   2. O Docker daemon baixou (pulled) a imagem "hello-world" do Docker Hub. (amd64)
   3. O Docker daemon criou um novo container à partir dessa imagem. O container
      executou código que produziu o presente output.
   4. O Docker daemon transmitiu esse output para o Docker client, que o enviou para
      o terminal.
  
  Você pode tentar algo mais ambicioso, por ex. rodando o container do Ubuntu usando:
   $ docker run -it ubuntu bash
  
  Partilhe imagens, fluxos de trabalho automatizados e mais coisas usando um Docker ID gratuito:
    https://hub.docker.com/
  
  Para ver mais exemplos e ideias visite:
        https://docs.docker.com/get-started/

Aproveite a oportunidade para entrar no Docker Hub e criar uma conta.

Comandos do Docker

Recapitulando, podemos baixar uma imagem do docker usando pull.

$ docker pull <nome_imagem>:latest

Como vimos latest significa que baixamos a última e mais atualizada versão da imagem. Outra versão pode ser especificada se necessário como, por exemplo, fazendo $ docker pull <nome_imagem>:8.0. Para executar essa imagem usamos:

$ docker run -d --name=<nome_alternativo> -p m:n -<nome_imagem>

Além do comando run para criar e rodar um container usamos os parâmetros:

  • --name: para dar um nome alternativo para o container criado,
  • -p: para tornar a porta do docker visível fora do container,
  • <nome_imagem>: especifica a imagem a ser executada,
  • m:n: mapeia portas do container em portas do host. (porta_host:porta_container)

Podemos ver quais são os containers em execução:

docker ps
container ID  IMAGE               COMMAND                 CREATED         STATUS                 
642881d63879  mysql/mysql-server  "/entrypoint.sh mysq…"  16 minutes ago  Up 16 minutes (healthy)

PORTS                                                       NAMES
0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060-33061/tcp  mysql1

Para encerrar a execução, e remover o container usamos, respectivamente:

# encerrar
$ docker stop <nome_imagem>
# remover container
$ docker rm <nome_imagem>

No linux, os arquivos de configuração do docker e as imagens baixadas ficam no diretório /var/lib/docker. No Windows o endereço desses arquivos varia, de acordo com o modo de instalação. Esses arquivos nunca devem ser manipulados diretamente pelo usuário.

Uma página de ajuda é exibida com docker help, sobre a sintaxe de docker. Uma lista completa da saída do help pode ser vista na seção Docker Help.

# ajuda geral
$ docker help

# ajuda sobre um comando específico
$ docker <comando> help
# por exemplo, para o comando cp (copy)
$ docker cp help

Podemos ver todas as imagens baixadas no computador e apagá-las, se assim for desejado.

# para listar as imagens
$ docker image ls
REPOSITORY                   TAG       IMAGE ID       CREATED         SIZE
mysql/mysql-server           latest    5a9594052aec   3 months ago    438MB
hello-world                  latest    feb5d9fea6a5   10 months ago   13.3kB

# para apagar as imagens usamos os primeiros caracteres do id para identificá-las
$ docker image rm -f 5a
$ docker image rm -f fe

#alternativamente, o seguinte comando lista todos os containers
$ docker container ls --all --quiet

# podemos apagar todos os containers usando (veja descrição abaixo)
$ docker container rm --force $(docker container ls --all --quiet)

A sintaxe $(), usada no último comando, faz com que a saída de um comando seja enviada para o comando externo. Nesse caso o comando interno gera uma lista de containers instalado, que é enviada para o comando de apagamento forçado. A chave –force (ou -f) força o apagamento mesmo que exista uma imagem desse container em execução. Esse comando deve ser usado com cautela pois a remoção é feita sem nenhuma confirmação.

Várias dessas operações, como inicializar o docker, apagar imagens, visualizar status e rodar uma imagem, podem ser executadas através do aplicativo gui, Docker Desktop. Você encontra mais ajuda no site do docker.

Imagem do MySQL

Como um exemplo mais completo e útil vamos carregar e executar uma imagem contendo o mysql. Começamos por baixar (pull) a imagem.


# baixar a imagem
$ docker pull mysql/mysql-server:latest
# um outpup  é exibido:
   What's Next?
     1. Sign in to your Docker account → docker login
     2. View a summary of image vulnerabilities and recommendations → docker scout quickview mysql/mysql-server:latest

A mensagem (aqui truncada) sugere o login na conta do docker ou a visualização de recomendações. O login também pode ser feito na janela do Docker Desktop.

Como vimos, latest significa que baixamos a última e mais atualizada versão do mysql. Outra versão pode ser especificada se necessário, como em $ docker pull mysql/mysql-server:8.0. Para executar essa imagem usamos:

# executar a imagem do mysql
$ docker run --name=mysql1 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=meupassword -d mysql/mysql-server
# um id é exibido

Pode ocorrer que a porta designada esteja ocupada por outro serviço do computador host, o que provoca a emissão de uma mensagem de erro. Nesse caso podemos usar outra porta, tal como docker run --name=mysql1 -p 8080:3306....

Além do comando run para criar e rodar um container usamos os parâmetros:

  • --name: para dar um nome alternativo para o container criado,
  • -p: para tornar a porta do docker visível fora do container,
  • -e: para inserir um password de gerenciamento do mysql,
  • mysql/mysql-server: especifica a imagem a ser executada,
  • 3306:3306: mapeia portas do container em portas do host, (porta_host:porta_container).

Podemos ver quais são os containers em execução:

docker ps
container ID  IMAGE               COMMAND                 CREATED         STATUS                 
642881d63879  mysql/mysql-server  "/entrypoint.sh mysq…"  16 minutes ago  Up 16 minutes (healthy)

PORTS                                                       NAMES
0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060-33061/tcp  mysql1

A linha foi quebrada para facilitar a visualização. Para conectar com o servidor do mysql executamos:

$ docker exec -it mysql1 mysql -uroot -p
Enter password: meupassword

Welcome to the MySQL monitor.  ... (saída truncada)
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> 


Um prompt de comandos fica aberto para receber comandos do mysql. Operações usuais sobre o banco de dados ficam disponíveis. Você pode encontrar mais informações sobre a sintaxe básica do SQL no artigo Linguagem de Consulta SQL.

Por exemplo, no caso abaixo criamos um banco de dados, uma tabela, inserimos valores, fazemos uma consulta, finalizando depois o uso do MySQL.

# cria um banco de dados
mysql> CREATE DATABASE teste;
# use esse BD
mysql> USE teste;
# cria uma tabela 
mysql> CREATE TABLE cidades(nome varchar(60),id varchar(4));

# insere valores na tabela
mysql> INSERT INTO cidades SET nome='Belo Horizonte', id='1';
mysql> INSERT INTO cidades SET nome='Salvador', id='2';
mysql> INSERT INTO cidades SET nome='Curitiba', id='3';

mysql> SELECT * FROM cidades;
+----------------+------+
| nome           | id   |
+----------------+------+
| Belo Horizonte | 1    |
| Salvador       | 2    |
| Curitiba       | 3    |
+----------------+------+
3 rows in set (0.00 sec)

# para abandonar o programa
mysql> exit

Para encerrar a execução, e remover o container usamos, respectivamente:

# encerrar    
$ docker stop mysql1
# remover container
$ docker rm mysql1

Conectando com o container

A interação com um container se dá de modo similar à execução de comandos em um computador remoto. Para mostrar isso executaremos uma imagem do docker chamada diamol/base, criada e disponibilizada no Dockerhub por E. Stoneman para exemplificar um trecho de seu livro (veja bibliografia). Para interagir com o aplicativo em execução usamos as flags –interactive e –tty (ou simplesmente -i e -t) para fazer essa interação através do terminal. O primeiro comando abaixo baixa a imagem e a executa, criando um container que expõe um prompt de terminal para o usuário. Os comandos aceitos no prompt dependem do sistema operacional. Por exemplo, no linux usamos ls para listar os arquivos do diretório atual; no Windows usamos dir.

# para baixar e rodar a imagem    
$ docker container run --interactive --tty diamol/base
  Unable to find image 'diamol/base:latest' locally
  latest: Pulling from diamol/base
  31603596830f: Pull complete 
  792f5419a843: Pull complete 
  Digest: sha256:787fe221a14f46b55e224ea0436aca77d345c3ded400aaf6cd40125e247f35c7
  Status: Downloaded newer image for diamol/base:latest

# O aplicativo expõe o prompt do terminal (usando os sinais / ⧣ para indicar o prompt)
/ ⧣
# no linux podemos listar os arquivos na pasta ativa
/ ⧣ ls
  bin    etc    lib    mnt    proc   run    srv    tmp    var
  dev    home   media  opt    root   sbin   sys    usr

# o nome da máquina em execução é o mesmo que o id da imagem
/ ⧣ hostname
2c33c99fcaf7

# para ver a data
/ ⧣ date
Sat Aug  6 15:38:21 UTC 2022

# uma lista de comandos disponíveis pode ser vista com help
/ # help
Built-in commands:
------------------
	. : [ [[ alias bg break cd chdir command continue echo eval exec
	exit export false fg getopts hash help history jobs kill let
	local printf pwd read readonly return set shift source test times
	trap true type ulimit umask unalias unset wait

# para terminar a execução
/ ⧣ exit

Mantendo esse terminal aberto, podemos abrir outro terminal e listar detalhes dos containers em execução:

$ docker container ls
container ID  IMAGE        COMMAND    CREATED        STATUS       PORTS  NAMES
2c33c99fcaf7  diamol/base  "/bin/sh"  3 minutes ago  Up 3 minutes        strange_lehmann

# para listar os processos dentro desse container (notando que 2c são os primeiros dígitos do container ID)
$ docker container top 2c
UID      PID      PPID      C    STIME    TTY     TIME      CMD
root     13436    13410     0    12:36    pts/0   00:00:00  /bin/sh

# para listar as ações (log) executadas nesse container
$ docker container logs 2c
# ls
bin    etc    lib    mnt    proc   run    srv    tmp    var
dev    home   media  opt    root   sbin   sys    usr

(retorna uma lista de comandos já utilizados no container, aqui truncada)

# inspect retorna uma descrição detalhada do container
$ docker container inspect 2c
  [
    {
        "Id": "2c33c99fcaf7fb94393ce1e7e31ce05ab6f5bcc914fc5eac8c90e600cf711995",
        "Created": "2022-08-06T15:36:14.327115583Z",
        "Path": "/bin/sh",
        "Args": [],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,                        ... (saída truncada)
        },
    }
]        

Os comandos usam o atalho 2c para se referir ao ID do container 2c33c99fcaf7. inspect retorna dados no formato JSON, aqui truncados, incluindo informações sobre caminhos usados pelo filesystem virtual e muitos outros.

Podemos ver uma lista de imagens instaladas usando docker image list ou docker image ls, e apagar uma imagem que não será mais necessária com docker image rm <id>, onde <id> é o id listado no passo anterior. No nosso caso, se usamos:

# para listar imagens baixadas
$ docker image list
  REPOSITORY                   TAG       IMAGE ID       CREATED         SIZE
  mysql/mysql-server           latest    5a9594052aec   3 months ago    438MB
  hello-world                  latest    feb5d9fea6a5   10 months ago   13.3kB
  diamol/base                  latest    9fc3f74c8b53   17 months ago   7.13MB

# para apagar a imagem referente à diamol/base (a imagem está em uso no container 5f73d74675a7)
$ docker image rm 9fc3f74c8b53
  Error response from daemon: conflict: unable to delete 9fc3f74c8b53 (must be forced)
  - image is being used by stopped container 5f73d74675a7

# para forçar a interrupção desse container e apagar a imagem
$ docker image rm -f 9fc3f74c8b53
  Deleted: sha256:9fc3f74c8b533bed2ac40ccfc6a5235ebb626a26a230dc3731fcdf926d984106

# lista todos os containers (em execução ou não)
$ docker container ls --all
  container ID   IMAGE               COMMAND                  CREATED        STATUS                  PORTS    NAMES
  5f73d74675a7   9fc3f74c8b53        "/bin/sh"                3 hours ago    Exited (0) 2 hours ago            intelligent_wescoff
  2c33c99fcaf7   9fc3f74c8b53        "/bin/sh"                6 hours ago    Exited (0) 3 hours ago            strange_lehmann
  e0ca567900b9   nginx               "/docker-entrypoint.…"   25 hours ago   Created                           webserver
  5ccc8d7d5ff3   hello-world         "/hello"                 32 hours ago   Exited (0) 32 hours ago           hopeful_banach
  fb9dc473c7f5   hello-world         "/hello"                 32 hours ago   Exited (0) 32 hours ago           loving_swartz
  5e5c65bb00c4   hello-world         "/hello"                 32 hours ago   Exited (0) 32 hours ago           cool_cannon
  (... saída truncada)

Como nenhum container está ativo (no meu caso) eles têm o status Exited. Quando um container está em execução o mesmo ocorre com o aplicativo que ele contém. Quando o processo é terminado o container entra no estado de encerrado (Exited). Containers encerrados não usam recursos de memória nem tempo de CPU do computador mas são mantidos em disco e ocupam espaço. Containers não desaparecem quando são terminados mas continuam a existir e podem ser executados novamente. Nesse estado eles retêm logs e arquivos no sistema de arquivos. Para remover containers encerrados você deve emitir o controle específico para tal.

Outros comandos associados:

$ docker ps -a                  # Lista containers, informando a imagem que os gerou

$ docker images                 # Lista imagens 

$ docker rm <container_id>      # Remove um container interrompido (não em execução)

$ docker rm -f <container_id>   # Força a remoção de um container mesmo que em execução

$ docker rmi <image_id>         # Remove uma imagem que não esteja
                                # associada um container em execução

$ docker rmi -f <image_id>      # Força a remoção da imagem mesmo que esteja em uso

$ docker system prune -a        # remove: todos os containers parados,
                                # todas as redes não utilizadas 
                                # todas as imagens não ativas
                                # todo o cache de docker                           


Claro que o comando docker system prune -a deve ser usada com bastante cuidado.
Uma lista de comandos está listada na seção Docker Help.

Rodando um webserver



Outro bom exemplo de funcionamento do docker consiste em rodar um container preparado para fins educacioanis pelo DockerHub, que roda um tutorial interativo para iniciantes. Outras instruções podem ser encontradas em Docker Docs: Getting started.

$ docker run -d -p 8080:80 docker/getting-started

# as flags podem ser unidas
docker run -dp 8080:80 docker/getting-started

# para acessar o tutorial abra o navegador em http://localhost:8080. 

As flags ou chaves significam o seguinte:

  • -d: execute o container em mode destacado (detached ou em background).
  • -p 8080:80: associa a porta 8080 do host à porta 80 do container. Se a porta 8080 já estiver em uso especifica outra porta, como 80 ou 3000.
  • docker/getting-started especifica o nome da imagem a ser usada.

Como já vimos, a imagem é baixada (se não estiver no computador) e rodada. Ela cria uma seção de um servidor que pode ser acessado em http://localhost:8080, contendo um tutorial de uso do docker com instruções iniciais para seu uso, preparada por seus desenvolvedores.

Se iniciarmos uma imagem em segundo plano e quisermos um terminal interativo podemos executar

$ docker exec -it <container> bash

Rodando Oracle Linux


Mostraremos outro exemplo rodando um container com Oracle Linux.

Verificamos primeiro o status do docker:

$ service docker status
  Redirecting to /bin/systemctl status docker.service
  ○ docker.service - Docker Application Container Engine
       Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
       Active: inactive (dead)
  TriggeredBy: ○ docker.socket
       Docs: https://docs.docker.com

Vemos que o docker está inativo, como exibido em Active: inactive (dead). Então reiniciamos o serviço:

$ sudo service docker start
  [sudo] password for guilherme: 
  Redirecting to /bin/systemctl start docker.service

$ service docker status
  Redirecting to /bin/systemctl status docker.service
  ● docker.service - Docker Application Container Engine
       Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
       Active: active (running) since Mon 2022-08-15 16:32:32 -03; 2s ago
       (saída truncada)

Podemos terminar um comando no prompt do bash usamos CTRL-C.
Para baixar a imagem do Oracle Linux usamos pull oraclelinux:9, sendo 9 a versão mais atual, na data em que esse texto foi escrito. Caso seja necessária uma versão anterior usamos pull oraclelinux:8 (ou a versão necessária). No caso do Oracle Linux a tag latest foi removida, como se pode ver na página docker: oraclelinux.

$ sudo docker pull oraclelinux:9
  9: Pulling from library/oraclelinux
  16c5055e8b97: Pull complete 
  Digest: sha256:93514816e192d51fbb34c008a479c789c43fb1fe0c2f91bd5be1ba7919dafa77
  Status: Downloaded newer image for oraclelinux:9
  docker.io/library/oraclelinux:9

# para visualizar as imagens baixadas
$ docker images
REPOSITORY               TAG       IMAGE ID       CREATED        SIZE
docker/getting-started   latest    cb90f98fd791   4 months ago   28.8MB
oraclelinux              9         61a922496eee   16 hours ago   236MB


Podemos rodar essa imagem, gerando um container, com o comando docker run <nome_imagem>. Por default a imagem é criada, se já não existe, e roda em primeiro plano (attached mode). Para rodá-la no segundo plano (em background ou dettached mode) usamos o marcador (flag) -d. Para usar o terminal de modo interativo use as opções –i, –t. As flags podem ser juntas, como em –dit. A flag –rm serve para apagar o container quando ele for encerrado. A opção --name é usada para dar um nome para a imagem sendo rodada. Esse nome deve ser único (não pode ter o mesmo nome de um que já está rodando).

# para rodar a imagem em primeiro plano (attached mode)    
$ sudo docker run  <nome_imagem>
    
# para rodar a imagem em segundo plano ou background (dettached mode)
$ sudo docker run -d  <nome_imagem>

No caso de nossa imagem para o oracle linux usaremos run com as flags já descritas. Um terminal é apresentado, onde podem ser digitados comandos apropriados.

$ docker run -i -t  --rm --name oraclelinux oraclelinux:9
  [root@723e7c1a71ea /]#
# se executado em outro terminal (para não fechar o terminal do oraclelinux)
# podemos ver que temos uma imagem rodando. 
$ docker images
  REPOSITORY    TAG       IMAGE ID       CREATED      SIZE
  oraclelinux   9         a0ad236ea4f0   6 days ago   218MB

# no prompt do Oracle digitamos comandos. Por exemplo:
[root@723e7c1a71ea /]# cat /etc/oracle-release
  Oracle Linux Server release 9.0

[root@03d35e4c35b1 teste_oracle]# cat /etc/os-release
  NAME="Oracle Linux Server"
  VERSION="9.0"
  <saída truncada>

O comando cat é usado para ler, concatenar e escrever em arquivos, para o output padrão. Outros comandos usuais do linux podem ser executados no prompt:

[root@723e7c1a71ea /]# mkdir teste_oracle      # cria um novo diretório
[root@723e7c1a71ea /]# cd teste_oracle         # move cursor para o novo diretório

# envia texto para arquivo.txt
[root@723e7c1a71ea teste_oracle]# echo "teste de docker no oraclelinux" > arquivo.txt
# exibe conteúdo do arquivo.txt
[root@723e7c1a71ea teste_oracle]# cat arquivo.txt
  teste de docker no oraclelinux
  
# para interromper a execução usamos exit [root@723e7c1a71ea teste_oracle]# exit # retornamos ao prompt do sistema hospedeiro $

Uma vez rodando o Oracle Linux todas as operações válidas no sistema podem ser executadas. Mais detalhes sobre o Oracle Linux 9 pode ser lido no site da Oracle.

O Docker é normalmente usado para rodar aplicativos em segundo plano e programas CLI (command-line interface). Mas ele também pode ser usado para executar programas com interface gráfico, desde que você faça o setup necessário. Informações podem ser vistas por exemplo em Baeldung.com: Running GUI Applications in a Linux Docker Container.

Docker Help

A execução de docker help resulta em uma lista de comandos e parâmetros, mostrados na tabela.
Para ajuda sobre comando específico digite docker COMMAND --help. Para mais informações visite Docker Guides.

O Docker é executado como a seguinte sintaxe:
docker [OPÇÕES] COMANDO

 Comandos comuns:
run Cria e executa um novo container de uma imagem
exec Executa comando em container em execução
ps Lista containers
build Cria imagem de um Dockerfile
pull Download imagem de um repositório
push Upload imagem para repositório
images Lista imagens
login Login no repositório
logout Logout do repositório
search Pesquisa imagens no Docker Hub
version Exibe informações de versão do Docker
info Exibe informações gerais de sistema
 Comandos de gerenciamento:
builder Gerencia builds
buildx* Docker Buildx
compose* Docker Compose
container Gerencia containers
context Gerencia contexts
debug* Abre uma shell dentro de qualquer imagem ou container
dev* Ambiente de Docker Dev
extension* Gerencia extensões do Docker
feedback* Fornece feedback direto no terminal
imagem Gerencia imagens
init* Cria arquivos de inicialização do Docker para o projeto
manifest Gerencia manifestos de imagem e lists do Docker
network Gerencia networks
plugin Gerencia plugins
sbom* Visualiza Software Bill Of Materials (SBOM) de uma imagem
scout* Docker Scout
system Gerencia Docker
trust Gerencia confiança sobre imagens do Docker
volume Gerencia volumes
 Comandos de grupo:
attach Anexa entrada, saída e mensagens de erro padrões local a container em execução
commit Cria nova imagem após alteração em container
cp Copia arquivos/pastas entre um container e sistema local
create Cria novo container
diff Inspeciona alterações em arquivos e pastas no container
events Recebe eventos no servidor em tempo real
export Exporta aqruivos de sistema em um container para arquivo tar
history Exibe o histórico de uma imagem
import Importa conteúdo de tarball para criat sistema na imagem
inspect Retorna informação de baixo nível sobre objetos do Docker
kill Extingue um ou mais containersem execução
load Carrega uma imagem de arquivo tar ou STDIN
logs Captura os logs de um container
pause Pausa todos os processos dentro de um ou mais containers
port Lista mapeamento de portas para o container
rename Renomeia um container
restart Reinicia um ou mais containers
rm Remove um ou mais containers
rmi Remove uma ou mais imagems
save Grava uma ou mais imagems para arquivo tar (para STDOUT, por default)
start Inicializa um ou mais containers parados
stats Exibe estísticas de containers em tempo real
stop Para um ou mais containers em execução
tag Cria uma tag TARGET_IMAGE em referência à SOURCE_IMAGE
top Exibe os processos ativos de um container
unpause Recomeça todos os processos dentro de um ou mais containers
update Atualiza a configuração de um ou mais containers
wait Paraliza a execução até que um ou mais containers são interrompidos, depois exibe códigos de saída
 Opções globais:
–config string Local dos arquivos de configuração do cliente (default “/home/usuario/.docker”)
-c, –context string Nome do contexto a ser usado para conectar com o daemon (sobrescreve DOCKER_HOST e ajusta default para “docker context use”)
-D, –debug Liga modo de debug
-H, –host list Daemon socket a conectar
-l, –log-level string Ajusta nível de logging (“debug”, “info”, “warn”, “error”, “fatal”) (default é “info”)
–tls Usa TLS; implícito por –tlsverify
–tlscacert string Aceita apenas certificados assinado por esse CA (default “/home/usuario/.docker/ca.pem”)
–tlscert string Caminho para arquivo de certificado (default “/home/usuario/.docker/cert.pem”)
–tlskey string Caminho para arquivo de chave (default “/home/guilherme/.docker/key.pem”)
–tlsverify Use TLS e verifique o remoto
-v, –version Exibe informação de versão e termina

: Na tabela usamos a expressão repositório no lugar de registry. O Registry é a implementação de código aberto para armazenamento e distribuição de imagens de containers e outros conteúdos. A implementação do registro Docker Hub é baseada em Distribuição. Docker Hub implementa especificação de distribuição OCI versão 1.0.1. Mais informações em Docker Hub Registry.

Bibliografia


Livros:

  • Ashley, David: Foundation Dynamic Web Pages with Python, Apress, 2020,
  • Miel, Ian: Sayers, Aidan H.: Docker in Practice, 2 Ed., Manning, 2019,
  • Nickoloff, Jeff; Kuenzli, Stephen: Docker in Action, 2 Ed., Manning, 2019,
  • Poulton, Nigel: Docker Deep Dive, disponível em Leanpub.com, 2018,
  • Stoneman, Elton: Learn Docker in a Month of Lunches, Manning, 2020,
  • Vohra, Deepak: Pro Docker, Apress, 2016.

Sites: