Articles

Docker Run: Como criar imagens a partir de uma aplicação

Na nossa série anterior de blogs, analisámos como implementar Kubernetes e criar um cluster. Também analisámos como implantar uma aplicação no ambiente de cluster e configurar instâncias OpenStack (incluindo segurança) para o ajudar a aceder a elas. Agora vamos aprofundar o desenvolvimento de Kubernetes, analisando como criar imagens Docker para que possa implementar as suas próprias aplicações e disponibilizá-las a outras pessoas.

Como funcionam as imagens Docker

Antes de aprender a criar imagens Docker, a primeira coisa que precisamos de compreender é como funcionam as próprias imagens Docker.

A chave para uma imagem Docker é que é um sistema de ficheiros em camadas. Por outras palavras, se começar com uma imagem que é apenas o sistema operativo (digamos Windows) e depois adicionar uma aplicação (digamos Nginx), acabará com algo do género:

Como se pode ver, a diferença entre IMAGE1 e IMAGE2 é apenas a própria aplicação, e depois IMAGE4 tem as alterações feitas nas camadas 3 e 4. Assim, para criar uma imagem, está basicamente a começar com uma imagem de base e a definir as alterações a ela.

Agora, ouço-o perguntar: “Mas e se eu quiser começar do zero? Bem, vamos definir “a partir do zero” durante um minuto. É provável que queira começar com um sistema operativo limpo e ir a partir daí. Bem, na maioria dos casos há uma imagem de base para isso, por isso ainda está a começar com uma imagem de base. (Se não, pode verificar as instruções para criar uma imagem base Docker.)

Em geral, há duas maneiras de criar uma nova imagem Docker:

  • Criar uma imagem Docker a partir de um recipiente existente: Neste caso, começa com uma imagem existente, personaliza-a com as alterações desejadas, depois constrói uma nova imagem a partir dela.
  • Use um Dockerfile: Neste caso, utilize um ficheiro de instruções – o Dockerfile – para especificar a imagem de base e as alterações que deseja fazer-lhe.

Neste artigo, vamos analisar os dois métodos. Vamos começar por criar uma nova imagem a partir de um contentor existente.

Criar a partir de um contentor existente

Quando se trata do Docker, começar pode ser bastante simples. Neste exemplo, vamos começar com uma imagem que inclui o servidor de aplicações web nginx e PHP. A isso, vamos adicionar suporte à leitura de dados RSS usando um pacote de código aberto chamado SimplePie (disponível para download em GitHub). Vamos então fazer uma nova imagem a partir do contentor alterado.

Criar o contentor original Docker

A primeira coisa que precisamos de fazer é instanciar a imagem de base original, ou mandar o docker criar um contentor a partir de uma imagem.

  1. O primeiro passo é certificar-se de que o seu sistema tem o Docker instalado. Se seguiu a nossa série anterior ao executar Kubernetes no OpenStack, já tem isto tratado. Caso contrário, pode seguir as instruções aqui para apenas instalar o Docker.
  2. A seguir, terá de obter a imagem de base. No caso deste tutorial, isso é webdevops/php-nginx, que faz parte do Docker Hub, por isso, para “puxar” terá de ter uma identificação do Docker Hub. Se ainda não o tiver, vá a https://hub.docker.com e crie uma conta gratuita.
  3. Vá para a linha de comando onde tem o Docker instalado e inicie sessão no Docker Hub:
    # docker loginLogin com o seu Docker ID para empurrar e puxar imagens do Docker Hub. Se não tiver um Docker ID, vá até https://hub.docker.com para criar um.Nome de utilizador: nickchasePassword:Login Sucedido
  4. Vamos começar com a imagem de base e pedir ao Docker para iniciar um contentor. Instanciar webdevops/php-nginx:
    # docker run -dP webdevops/php-nginx

    A bandeira -dP assegura-se de que o contentor corre em fundo, e que os portos em que ouve são disponibilizados.

  5. Certifica-te de que o contentor corre:
    # docker psCONTAINER ID IMAGEM COMANDANDO PORTADORES NOMES1311034ca7dc webdevops/php-nginx "/opt/docker/bin/entr" 35 segundos atrás Até 34 segundos 0.0.0.0:32822->80/tcp, 0.0.0.0:32821->443/tcp, 0.0.0.0:32820->9000/tcp small_bassi

um par de notas aqui. Em primeiro lugar, porque não especificámos um nome específico para o contentor, Docker atribuiu um. Neste exemplo, é small_bassi. Segundo, repare que existem 3 portos que estão abertos: 80, 443, e 9000, e que foram mapeados para outros portos (neste caso 32822, 32821, e 32820, respectivamente – na sua máquina estes portos serão diferentes). Isto torna possível que vários contentores estejam “à escuta” no mesmo porto na mesma máquina anfitriã. Assim, se tentássemos aceder a uma página web hospedada por este contentor, fá-lo-íamos acedendo:

http://localhost:32822

Até agora, porém, não há páginas a aceder; vamos corrigir isso.

Criar um ficheiro no contentor

Para podermos testar este contentor, precisamos de criar um ficheiro PHP de amostra. Fá-lo-emos entrando no contentor e criando um ficheiro.

  1. Entrar no contentor
    # docker exec -it small_bassi /bin/bashroot@1311034ca7dc:/#

    Usar exec com a chave -it cria uma sessão interactiva para que possa executar comandos directamente dentro do contentor. Neste caso, estamos a executar /bin/bash, por isso podemos fazer o que mais precisarmos.

  2. A raiz do documento para o servidor nginx neste contentor está em /app, por isso vá em frente e crie o /app/index.php file:
    vi /app/index.php
  3. Adicionar uma simples rotina PHP ao ficheiro e guardá-lo:
    <?phpfor ($i; $i < 10; $i++){ echo "Item number ".$i."\n";}?>
  4. Agora saia do recipiente para voltar para a linha de comando principal:
    root@1311034ca7dc:/# exit
  5. Agora vamos testar a página. Para o fazer, executar um simples comando curl:
    # curl http://localhost:32822/index.phpItem númeroItem númeroItem número 1Item número 2Item número 3Item número 4Item número 5Item número 6Item número 7Item número 8Item número 9

p> agora é altura de ir em frente e adicionar RSS.

Faça alterações ao recipiente

Agora que sabemos que o PHP está a funcionar, podemos ir em frente e adicionar suporte RSS utilizando o pacote SimplePie. Para o fazer, vamos simplesmente descarregá-lo para o contentor e instalá-lo.

  1. O primeiro passo é voltar a entrar no contentor:
    # docker exec -it small_bassi /bin/bashroot@1311034ca7dc:/#
  2. Em seguida, vá em frente e utilize o encaracolado para descarregar o pacote, guardando-o como um ficheiro zip:
    root@1311034ca7dc:/# curl https://codeload.github.com/simplepie/simplepie/zip/1.4.3> simplepie1.4.3.zip
  3. Agora precisa de instalá-lo. Para o fazer, descomprima o pacote, crie os directórios apropriados, e copie os ficheiros necessários para os mesmos da seguinte forma:
    root@1311034ca7dc:/# unzip simplepie1.4.3.ziproot@1311034ca7dc:/# mkdir /app/phproot@1311034ca7dc:/# mkdir /app/cacheroot@1311034ca7dc:/# mkdir /app/php/libraryroot@1311034ca7dc:/# cp -r s*/library/* /app/php/library/.root@1311034ca7dc:/# cp s*/autoloader.php /app/php/.root@1311034ca7dc:/# chmod 777 /app/cache
  4. Agora só precisamos de uma página de teste para ter a certeza de que está a funcionar. Crie um novo ficheiro no directório /app:
    root@1311034ca7dc:/# vi /app/rss.php
  5. Agora adicione o conteúdo do ficheiro de amostra. (Este ficheiro é extraído do website SimplePie, mas eu cortei-o por uma questão de brevidade, uma vez que não é realmente o foco do que estamos a fazer. Por favor ver a versão original para comentários, etc.)
    <?phprequire_once('php/autoloader.php');$feed = novo SimplePie();$feed->set_feed_url("http://rss.cnn.com/rss/edition.rss");$feed->init();$feed->handle_content_type();?><html><head><title>Amostra SimplePie Page</title></head><corpo><div class="header"><h1><a href="<?php echo $feed->get_permalink(); ?>><?php echo $feed->get_title(); ?></a></h1><p><?php echo $feed->get_description(); ?></p></div>> <?php foreach ($feed->get_items() as $item): ?><div class="item"><h2><a href="<?php echo $item->get_permalink(); ?>><?php echo $item->get_title(); ?></a></h2><p><?php echo $item->get_description(); ?></p><p><pequeno>>Posto em <?php echo $item->get_date('j F Y | g:i a'); ?></pequeno></p></div><?php endforeach; ?></body></html>
  6. Saia do recipiente:
    root@1311034ca7dc:/# exit
  7. Vamos certificar-nos de que está a funcionar. Lembre-se, precisamos de aceder ao contentor no porto alternativo (verifique a doca ps para ver que portos precisa de utilizar):
    # curl http://localhost:32822/rss.php<html><head><title>Sample SimplePie Page</title></head><body><div class="header"><h1><a href="http://www.cnn.com/intl_index.html">CNN.com - Canal RSS - Página Inicial Intl - News</a></h1><p>CNN.com fornece notícias actualizadas e informações sobre as últimas notícias de topo, meteorologia, entretenimento, política e mais.</p></div>...

Agora, podemos transformá-la numa nova imagem.

Criar a nova imagem

Agora vamos ver como criar uma imagem Docker a partir do contentor. Temos um contentor a funcionar e queremos transformá-lo numa imagem e empurrá-lo para o Docker Hub para que os utilizadores da comunidade possam aceder a ele. O nome que irá usar para o seu contentor terá tipicamente três partes:

/:

Por exemplo, o meu nome de utilizador Docker Hub é nickchase, por isso vou nomear a versão 1 do meu novo contentor RSS-ificado

nickchase/rss-php-nginx:v1
  1. Se quando começámos a falar das diferenças entre camadas, começou a pensar em sistemas de controlo de versões, tem razão. O primeiro passo na criação de uma nova imagem é cometer as alterações que já fizemos, adicionando uma mensagem sobre as alterações e especificando o autor, como em:
    docker commit -m "Message" -a "Author Name" 

    So in my case, that will be:

    # docker commit -m "Added RSS" -a "Nick Chase" small_bassi nickchase/rss-php-nginx:v1sha256:148f1dbceb292b38b40ae6cb7f12f096acf95d85d85bb3ead40ead07d6b1621ad529e
  2. A seguir queremos avançar e empurrar a nova imagem para o Docker Hub para que a possamos utilizar:
    # docker push nickchase/rss-php-nginx:v1O push refere-se a um repositório 69671563c949: Pushed3e78222b8621: Pushed5b33e5939134: Pushed54798bfbf935: Pushedb8c21f8faea9: Pushed...v1: digest: sha256:48da56a77fe4ecff4917121365d8e0ce615ebbdfe31f48a996255f5592894e2b tamanho: 3667
  3. Agora, se listar as imagens que estão disponíveis, deve vê-lo na lista:
    # docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEnickchase/rss-php-nginx v1 148f1dbceb29 11 minutos atrás 677 MBnginx último abf312888d13 3 dias atrás 181.5 MBwebdevops/php-nginx o mais tardar 93037e4c8998 3 dias atrás 675.4 MBubuntu o mais tardar e4415b714b62 2 semanas atrás 128.1 MBhello-world o mais tardar c54a2cc56cbb 5 meses atrás 1.848 kB
  4. Agora vamos em frente e testá-lo. Vamos começar por parar o recipiente original para podermos remover a cópia local da imagem:
    # docker stop small_bassi# docker rm small_bassi
  5. Agora podemos remover a própria imagem:
    # docker rmi nickchase/rss-php-nginx:v1Untagged: nickchase/rss-php-nginx:v1Untagged: nickchase/rss-php-nginx@sha256:0a33c7a25a6d2db4b82517b039e9e21a77e5e2262206fdcac8b96f5afa64d96cDeleted: sha256:208c4fc237bb6b2d3ef8fa16a78e105d80d00d75fe0792e1dcc77aa0835455e3Deleted: sha256:d7de4d9c00136e2852c65e228944a3dea3712a4e7bcb477eb7393cd309be179b
  6. Se voltar a correr imagens da doca, verá que desapareceu:
    # docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEnginx último abf312888d13 3 dias atrás 181.5 MBwebdevops/php-nginx o mais tardar 93037e4c8998 3 dias atrás 675.4 MBubuntu o mais tardar e4415b714b62 2 semanas atrás 128.1 MBhello-world o mais tardar c54a2cc56cbb 5 meses atrás 1.848 kB
  7. Agora, se criar um novo contentor baseado nesta imagem, irá vê-lo descarregado a partir do Docker Hub:
    # docker run -dP nickchase/rss-php-nginx:v1
  8. Finalmente, testar o novo contentor obtendo o novo porto…
    # docker psCONTAINER ID IMAGEM COMANDANDO PORTOS DE ESTATUTO CRIADOS NOMES13a423324d80 nickchase/rss-php-nginx:v1 "/opt/docker/bin/entr" 6 segundos atrás Up 5 segundos 0.0.0.0:32825->80/tcp, 0.0.0.0.0:32824->443/tcp, 0.0.0.0:32823->9000/tcp goofy_brahmagupta
  9. … e acedendo ao ficheiro rss.php.
    curl http://localhost:32825/rss.php

Você deve ver a mesma saída que antes.

Utilizar um ficheiro Docker

Criar manualmente uma nova imagem a partir de um recipiente existente dá-lhe muito controlo, mas tem um lado negativo. Se o contentor base for actualizado, não terá necessariamente os benefícios dessas alterações.

Por exemplo, suponha que eu queria um contentor que pegasse sempre na última versão de um sistema operativo Linux, como o sistema operativo Ubuntu, e que se baseasse nisso. O método anterior não nos dá essa vantagem.

Em vez disso, podemos usar um método chamado Dockerfile, que nos permite especificar uma versão particular de uma imagem de base, ou especificar que queremos usar sempre a versão mais recente.

Por exemplo, digamos que queremos criar uma versão do contentor rss-php-nginx que começa com v1 mas serve na porta 88 (em vez da tradicional 80). Para tal, queremos basicamente executar três passos:

  1. Inicie com o recipiente base desejado.
  2. Diga Nginx para ouvir no porto 88 em vez de 80.
  3. Deixe o Docker saber que o recipiente ouve no porto 88.

Fazemos isso criando um contexto local, descarregando uma cópia local do ficheiro de configuração, actualizando-o, e criando um Dockerfile que inclui instruções para construir o novo contentor.

Vamos lá configurar isso.

  1. Crie um directório de trabalho no qual possa construir o seu novo contentor. O que lhe chama depende completamente de si. Eu chamei ao meu k8stutorial.
  2. A partir da linha de comando, No contexto local, comece por instanciar a imagem para que tenhamos algo a partir do qual possamos trabalhar:
    # docker run -dP nickchase/rss-php-nginx:v1
  3. Agora obtenha uma cópia do vhost existente.ficheiro conf. Neste recipiente em particular, pode encontrá-lo em /opt/docker/etc/nginx/vhost.conf.
    # docker cp amazing_minksy:/opt/docker/etc/nginx/vhost.conf .

    p>Nota que tenho um novo contentor chamado amazing_minsky para substituir o pequeno_bassi. Neste momento deve ter uma cópia do vhost.conf no seu directório local, por isso, no meu caso, seria ~/k8stutorial/vhost.conf.

  4. Tem agora uma cópia local do ficheiro vhost.conf. Usando um editor de texto, abra o ficheiro e especifique que nginx deve estar a ouvir na porta 88 em vez da porta 80:
    server { listen 88 default_server; listen 8000 default_server; server_name _ *.vm docker;...
  5. A seguir, queremos ir em frente e criar o ficheiro Docker. Pode fazer isto em qualquer editor de texto. O ficheiro, que deve ser chamado Dockerfile, deve começar por especificar a imagem base:
    FROM nickchase/rss-php-nginx:v1
  6. Qualquer contentor que seja instanciado a partir desta imagem vai estar à escuta na porta 80, por isso queremos avançar e sobrescrever esse ficheiro de configuração Nginx com o que editamos:
    FROM nickchase/rss-php-nginx:v1COPY vhost.conf /opt/docker/etc/nginx/vhost.conf
  7. Finalmente, precisamos de dizer ao Docker que o contentor ouve no porto 88:
    FROM nickchase/rss-php-nginx:v1COPY vhost.conf /opt/docker/etc/nginx/vhost.confEXPOSE 88
  8. Agora precisamos de construir a imagem real. Para isso, usaremos o comando docker build comando:
    # docker build -t nickchase/rss-php-nginx:v2 .Enviando contexto de construção para Docker daemon 2.048 kBStep 1 : DE nickchase/rss-php-nginx:v1 ---> 208c4fc237bbStep 2 : EXPOSIÇÃO 88 ---> Funcionando em 23408def6214 ---> 93a43c3df834Contentor intermédio removedor 23408def6214Construído com sucesso 93a43c3df834

    Notificação de que especificámos o nome da imagem, juntamente com uma nova etiqueta (pode também criar uma imagem completamente nova) e o directório onde encontrar o Dockerfile e quaisquer ficheiros de suporte.

  9. Finalmente, empurre a nova imagem para o hub:
    # docker push nickchase/rss-php-nginx:v2
  10. Teste a sua nova imagem instanciando-a e puxando para cima a página de teste. com um comando tal como docker run <image>. Por exemplo:
    # docker run -dP nickchase/rss-php-nginx:v2root@kubeclient:/home/ubuntu/tutorial# docker psCONTAINER ID IMAGEM COMANDO DE IMAGEM CREATED STATUS PORTS NAMES04f4b384e8e8e2 nickchase/rss-php-nginx:v2 "/opt/docker/bin/entr" 8 segundos atrás Up 7 segundos 0.0.0.0:32829->80/tcp, 0.0.0.0:32828->88/tcp, 0.0.0.0.0:32827->443/tcp, 0.0.0.0:32826->9000/tcp goofy_brahmagupta13a423324d80 nickchase/rss-php-nginx:v1 "/opt/docker/bin/entr" há 12 minutos Até 12 minutos 0.0.0.0:32825->80/tcp, 0.0.0.0:32824->443/tcp, 0.0.0.0:32823->9000/tcp amazing_minsky

p>Notificação de que agora tem um porto mapeado para o porto 88 que pode chamar:

curl http://localhost:32828/rss.php

Outras coisas que pode fazer com um Dockerfile

Docker define uma lista completa de coisas que pode fazer com um Dockerfile, tais como:

  • .dockerignore
  • FROM
  • MAINTAINER
  • div id=”3907832665″>RUN

  • CMD
  • EXPOSE
  • ENV
  • COPY
  • ENTRYPOINT
  • VOLUME
  • USER
  • WORKDIR
  • ARG
  • ONBUILD
  • STOPSIGNAL
  • LABEL

Como pode ver, há aqui um pouco de flexibilidade. Pode ver a documentação para mais informações, e a wsargent publicou uma boa folha de trapaça Dockerfile.

Moving forward

Criar novas imagens Docker que podem ser utilizadas por si ou por outros programadores é bastante simples. Tem a opção de criar e submeter manualmente alterações, ou de as scriptar utilizando um Dockerfile.

No nosso próximo tutorial, vamos analisar a utilização de YAML para gerir estes contentores com Kubernetes.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *