sexta-feira, 15 de março de 2019

Administração de conteiners com Docker - Parte 1

O que é um conteiner?


Conteiner, ou jaula, é um forma de executar um sistema de forma isolada do resto do sistema operacional. Esse isolamento permite maior segurança tanto para a aplicação quanto para o sistema operacional. Diferente da virtualização, o aplicativo que roda no conteiner precisa ser compatível com o sistema operacinal do servidor hospedeiro, usando os mesmo recursos, como CPU, Ram e disco. 

Docker é uma plataforma de administração de conteiners livre desenvolvida pela Google e que pode ser integrada com os principais núvens públicas, como Amazon, Azure e Google Cloud. O Docker foi construído usando o conceito de DevOPS e tecnologias ágeis.

Instalação do Docker


Para instalar o Docker, no Debian, use o seguinte comando:
# apt-get install docker-ce

Veja se o Docker está instalado.
# docker --versionDocker version 18.09.0, build 4d60db4

Para que o usuário possa executar o docker é necessário que ele faça parte do grupo docker.
# usermod -G docker -a <usuario>

Verifique se o Docker está rodando.
# service docker status
[ ok ] Docker is running.

Comandos básicos

Agora que temos o Docker instalado podemos pesquisar o que existe de pronto nos repositórios. Por exemplo, podemos ver quais imagens temos disponíveis para o Wordpress.

$ docker search wordpress
NAME                          DESCRIPTION  STARS         OFFICIAL            AUTOMATED
wordpress                     The WordPress rich content management system…   2839   [OK]
bitnami/wordpress       Bitnami Docker Image for WordPress     102                         [OK]
appcontainers/wordpress Centos/Debian Based Customizable Wordpress C… 34    [OK]
etopian/alpine-php-wordpress Alpine WordPress Nginx PHP-FPM WP-CLI   20     [OK]
centurylink/wordpress             Wordpress image with MySQL removed.         14      [OK]
raulr/nginx-wordpress             Nginx front-end for the official wordpress:f… 12      [OK]
arm32v7/wordpress                 The WordPress rich content management system…   8
dalareo/wordpress-ldap   Wordpress images with LDAP support automatic…   6     [OK]
wodby/wordpress-nginx          Nginx for WordPress                             3                    [OK]
wodby/wordpress-php             PHP for WordPress                                3                    [OK]
dsteinkopf/wordpress              wordpress clone plus some php extensions     1          [OK]
owncloud/wordpress               Wordpress image for ownCloud websites           1
itherz/wordpress                      Wordpress                                              0                    [OK]

Imagens são bases de onde criaremos os conteiners. Podemos ter vários conteiners baseados numa mesma imagem. Você verá imagens, oficiais ou não, do Windows, FreeBSD, diversos sabores de Linux, e vários outros sistemas.

Vamos baixar a imagem do Wordpress para teste.
$ docker pull wordpress
Using default tag: latest
latest: Pulling from library/wordpress
6ae821421a7d: Pull complete
08f3d19635b0: Pull complete
dc8a54b8000b: Pull complete
b2c1d103db99: Pull complete
edfa752aa38a: Pull complete
583d37cbf2f0: Pull complete
c7846a240c1d: Pull complete
d8f9f0fd02fe: Pull complete
01d43e56770d: Pull complete
d7028d09ed0d: Pull complete
e7ada57130df: Pull complete
f8e18fc0e759: Pull complete
84b31f19dee2: Pull complete
5c0a2578817b: Pull complete
2fc1807539b8: Pull complete
62fcf2f6ca7b: Pull complete
64fda3ba2679: Pull complete
7500be78bfbe: Pull complete
Digest: sha256:37f9b9ba391302990b349daefe9fbf4691f79d4aa87e1af5f3617a3750e9678c
Status: Downloaded newer image for wordpress:latest
Agora podemos ver que temos uma imagem do Wordpress.
$ docker images
REPOSITORY   TAG               IMAGE ID           CREATED         SIZE
wordpress           latest              523eaf9f0ced        2 days ago          422MB

Apesar de termos uma imagem, ainda não temos nenhum conteiner rodando.
$ docker ps
CONTAINER ID  IMAGE COMMAND  CREATED  STATUS     PORTS         NAMES

Agora podemos subir o primeiro conteiner do Wordpress.
$ docker run wordpress
WordPress not found in /var/www/html - copying now...
Complete! WordPress has been successfully copied to /var/www/html

Agora podemos ver que temos um conteiner rodando o Wordpress.
$ docker ps
CONTAINER ID IMAGE     COMMAND        CREATED   STATUS PORTS  NAMES
d746d4cd238c wordpress "docker-entrypoint.s…"About an hour agoUp 3 seconds 80/tcp dazzling_diffie

Reparem que o ID do conteiner é d746d4cd238c. Se você executar outro comando "docker run wordpress" outro conteiner será criado com outro id. Para parar um conteiner você deve executar o seguinte.
$ docker stop d746d4cd238c
d746d4cd238c

Vemos agora que nunhum conteiner está rodando.
$ docker ps
CONTAINER ID   IMAGE        COMMAND   CREATED STATUS  PORTS   NAMES

Se quisermos ver todos os conteiner, inclusive os que estão parados, digite:
$ docker ps -a
CONTAINER ID IMAGE      COMMAND     CREATED STATUS        PORTS NAMES
d746d4cd238c wordpress "docker-entrypoint.s…" 20 hours ago Exited (0) 34 seconds ago        dazzling_diffie

Para executarmos o conteiner novamente digitamos:
$ docker start d746d4cd238c
d746d4cd238c
$ docker ps
CONTAINER ID  IMAGE        COMMAND      CREATED STATUS  PORTS   NAMES
d746d4cd238c wordpress "docker-entrypoint.s…" About an hour ago Up 1 second 80/tcp        dazzling_diffie

Podemos usar também o comando "docker kill" para matar o conteiner. Isso poderá gerar inconsistências nos dados. Por isso, só o use em último caso. Kill não apaga o conteiner.

Podemos notar na saída do comando "docker ps" que o coteiner está ouvindo a pora 80 TCP. O Docker cria por padrão uma interface virtual na rede 172.17.0.0/16.
$ ip addr show dev docker0
6: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:00:e8:b2:2d brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:ff:fee8:b22d/64 scope link
       valid_lft forever preferred_lft forever

O primeiro conteiner terá o próximo IP disponível nesta rede, e o seu gateway será o IP 172.17.0.1, que é o IP da interface virtual do hospedeiro.
$ ping -c 1 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.094 ms
--- 172.17.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.094/0.094/0.094/0.000 ms

Você pode acessar a página do Wordpress digitando na barra do navegador:
http://172.17.0.2

Podemos apagar o conteiner com o comando:
$ docker rm d746d4cd238c
d746d4cd238c

Esse comando não apaga os volumes associados ao conteiner. Para apagar todos os volumes, digite:
$ docker rm -v d746d4cd238c
d746d4cd238c

Se quisermos apagar todos os conteiners, podemos usar o seguinte comando:
$ docker rm -v `docker ps -aq`

A opção -aq mostra somente os IDs dos conteiners, e isso será passado para o rm.

O mesmo pode ser feito para excluir as imagens. Lembre-se de que, para excluir uma imagen, deve-se excluir primeiro todos os conteiners que a usam.
$ docker rmi `docker images -q`
Untagged: wordpress:latest
Untagged: wordpress@sha256:37f9b9ba391302990b349daefe9fbf4691f79d4aa87e1af5f3617a3750e9678c


Nomeando conteiners


É interessante nomear um conteiner antes de criá-lo.
$ docker run -ti --name Olonca -d debian /bin/bash
9538911a284e0ca1df0b64202e46e5856b764a256d9b41879c230eaa467ce993

A opção -ti permite que entremos no conteiner no modo interativo. Com esse comando criamos um conteiner chamado Olonca derivado da imagem debian.
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
debian                        latest                d508d16c64cd       3 weeks ago           101MB
$ docker ps
CONTAINER ID IMAGE        COMMAND      CREATED  STATUS  PORTS   NAMES
9538911a284e      debian           "/bin/bash"         40 seconds ago Up    37 seconds Olonca

Podemos entrar no conteiner com a opção -ti.
$ docker exec -ti 9538911a284e /bin/bash

Se preferir, podemos executar um comando dentro do conteiner.
$ docker exec -ti 9538911a284e hostname
9538911a284e


Trocando arquivos com o conteiner


Podemos copiar arquivos de/para o conteiner.

$ docker ps
CONTAINER ID  IMAGE         COMMAND  CREATED  STATUS   PORTS    NAMES
90b9504cb87a debian   "/bin/bash" 41 minutes ago Up 39 minutes                  Limit_ram2
bdbd7f583122 debian   "/bin/bash" 42 minutes ago Up 31 minutes                  Limit_ram
9538911a284e  debian        "/bin/bash"   2 hours ago  Up 40 minutes               Olonca
$ docker exec 90b9504cb87a ls /tmp 
$ docker cp tmp/20190301.txt 90b9504cb87a:/tmp
$ docker exec 90b9504cb87a ls /tmp
20190301.txt

Em algumas situações, o conteiner deverá utilizar uma pasta no host como se fosse nele. Podemos fazer isso com o parâmetro -v. Por exemplo, vamos montar a pasta /home/ricardo/tmp/ftp na pasta /home/ftp do conteiner.
$ mkdir /home/ricardo/tmp/ftp
$ docker run -ti --name FTP -v /home/ricardo/tmp/ftp:/home/ftp debian /bin/bash
root@5b348f6bb9b1:/# exit
exit
$ docker ps -a
CONTAINER ID IMAGE       COMMAND   CREATED STATUS        PORTS  NAMES
5b348f6bb9b1  debian   "/bin/bash"  14 seconds ago Exited (0) 7 seconds ago            FTP
9538911a284e  debian   "/bin/bash" 3 hours ago    Up About an hour                 Olonca
$ docker start 5b348f6bb9b1
5b348f6bb9b1 
$ docker ps 
CONTAINER ID IMAGE        COMMAND      CREATED  STATUS  PORTS   NAMES
5b348f6bb9b1   debian          "/bin/bash" 25 seconds ago Up 2 seconds                       FTP
9538911a284e   debian       "/bin/bash"    3 hours ago    Up About an hour              Olonca
$ docker exec 5b348f6bb9b1 ls /home/ftp 
$ touch /home/ricardo/tmp/ftp/teste 
$ docker exec 5b348f6bb9b1 ls /home/ftp
teste
Podemos montar um volume somente como leitura.

$ docker run -ti --name FTP2 -v /home/ricardo/tmp/cd:/mnt/cdrom:ro debian /bin/bash

Para ver os mapeamentos digite o seguinte:
$ docker inspect -f {{.Mounts}} FTP
[{bind  /home/ricardo/tmp/ftp /home/ftp   true rprivate}]
$ docker inspect -f {{.Mounts}} FTP2
[{bind  /home/ricardo/tmp/cd /mnt/cdrom  ro false rprivate}]

Você pode criar uma pasta no conteiner que poderá ser compartilhada com outros conteiners.
$ docker run -ti -v /home --name dados debian /bin/bashroot@38a438db1903:/# exit
exit 
$ docker start 38a438db1903
38a438db1903 
$ docker inspect -f {{.Mounts}} dados
[{volume 7bc9d12f3fdc7d6527052d7ac488cdadd17b811f37680d8cff201da9b86d4fb1 /var/lib/docker/volumes/7bc9d12f3fdc7d6527052d7ac488cdadd17b811f37680d8cff201da9b86d4fb1/_data /home local  true }]

E agora podemos montar esse volume em um novo conteiner.
$ docker run -ti --volumes-from dados centos /bin/bash
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
a02a4930cb5d: Pull complete
Digest: sha256:184e5f35598e333bfa7de10d8fb1cebb5ee4df5bc0f970bf2b1e7c7345136426
Status: Downloaded newer image for centos:latest 
[root@bb85fcc8b5f0 /]# exit
exit 
$ docker inspect -f {{.Mounts}} dados
[{volume 7bc9d12f3fdc7d6527052d7ac488cdadd17b811f37680d8cff201da9b86d4fb1 /var/lib/docker/volumes/7bc9d12f3fdc7d6527052d7ac488cdadd17b811f37680d8cff201da9b86d4fb1/_data /home local  true }] 
$ docker ps -a
CONTAINER ID IMAGE    COMMAND CREATED STATUS            PORTS   NAMES
bb85fcc8b5f0 centos "/bin/bash" 39 minutes ago Exited (0) About a minute ago eager_lumiere
38a438db1903 debian "/bin/bash"  43 minutes ago Up 43 minutes                            dados
247f457f6d81  debian  "/bin/bash" About an hour ago   Up About an hour                FTP2
5b348f6bb9b1  debian "/bin/bash"  2 hours ago       Up 2 hours                                  FTP
90b9504cb87a debian "/bin/bash" 3 hours ago  Exited (0) 2 hours ago            Limit_ram2
bdbd7f583122 debian "/bin/bash" 3 hours ago  Up 3 hours                                Limit_ram
9538911a284e debian  "/bin/bash"  5 hours ago   Up 3 hours                                  Olonca 
$ docker start bb85fcc8b5f0
bb85fcc8b5f0 
$ docker ps
CONTAINER ID IMAGE        COMMAND      CREATED  STATUS  PORTS   NAMES
bb85fcc8b5f0 centos   "/bin/bash" 40 minutes ago Up 2 seconds                  eager_lumiere
38a438db1903 debian       "/bin/bash"   43 minutes ago Up 43 minutes                     dados
247f457f6d81  debian       "/bin/bash"   About an hour ago  Up About an hour          FTP2
5b348f6bb9b1 debian       "/bin/bash"   2 hours ago       Up 2 hours                             FTP
bdbd7f583122 debian      "/bin/bash" 3 hours ago  Up 3 hours                           Limit_ram
9538911a284e debian       "/bin/bash"   5 hours ago     Up 3 hours                           Olonca
$ docker inspect -f {{.Mounts}} eager_lumiere
[{volume 7bc9d12f3fdc7d6527052d7ac488cdadd17b811f37680d8cff201da9b86d4fb1 /var/lib/docker/volumes/7bc9d12f3fdc7d6527052d7ac488cdadd17b811f37680d8cff201da9b86d4fb1/_data /home local  true }] 
$ docker inspect -f {{.Mounts}} dados
[{volume 7bc9d12f3fdc7d6527052d7ac488cdadd17b811f37680d8cff201da9b86d4fb1 /var/lib/docker/volumes/7bc9d12f3fdc7d6527052d7ac488cdadd17b811f37680d8cff201da9b86d4fb1/_data /home local  true }]

Trabalhando com rede


Podemos levantar um conteiner e mapear uma porta TCP para ser espelhada no hospedeiro. Com isso não é necessário criar um NAT para esse serviço.
$ docker run -ti --name Drupal -p 80:80 -d drupal /bin/bash

$ docker exec -ti 471f35e0eb01 /bin/bash 
rro@471f35e0eb01:/var/www/html# /etc/init.d/apache2 start
[....] Starting Apache httpd web server: apache2AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3. Set the 'ServerName' directive globally to suppress this message
. ok  
root@471f35e0eb01# exit
exit 
$ docker ps 
CONTAINER ID IMAGE        COMMAND       CREATED STATUS  PORTS   NAMES
471f35e0eb01 drupal "docker-php-entrypoi…" 4 minutes ago Up 4 minutes 0.0.0.0:80->80/tcp Drupal
9538911a284e debian   "/bin/bash"         6 days ago     Up 3 hours                          Olonca

Agora acesse o site pelo endereço http://localhost


Criando images


Você também pode criar imagens personalizadas. Para isso crie um arquivo chamado Dockerfile com o seguinte conteúdo.
    FROM <imagem>
    ENV <variavel=valor>
    RUN <comandos>
    COPY <origem> <destino>
  
FROM é o modelo que você vai usar, como "debian".
ENV define variáveis de ambiente que serão usadas na imagem personalizada.
RUN são os comandos que você quer executar na imagem.
COPY pode ser usado para copiar arquivos da máquina hospedeira para a imagem.

Agora rode o comando:

$ docker build -t <nome> .

Por exemplo, vamos criar uma imagem baseada em Debian só com o iptables.
$ cat Dockerfile
FROM debian
RUN apt-get update
RUN apt-get install -y apt-utils
RUN apt-get install -y iptables
RUN apt-get upgrade -y
$ docker build -t firewall .
Sending build context to Docker daemon  1.721MB
Step 1/5 : FROM debian
 ---> d508d16c64cd
Step 2/5 : RUN apt-get update
 ---> Running in c653b4fcf3b8
Get:3 http://security-cdn.debian.org/debian-security stretch/updates InRelease [94.3 kB]
Ign:1 http://cdn-fastly.deb.debian.org/debian stretch InRelease
Get:2 http://cdn-fastly.deb.debian.org/debian stretch-updates InRelease [91.0 kB]
...
Removing intermediate container c653b4fcf3b8
 ---> 1fb31b2efe4d
Step 3/5 : RUN apt-get install -y apt-utils
 ---> Running in 022f86a9d7cb
Reading package lists...
Building dependency tree...
Reading state information...
The following additional packages will be installed:
  libapt-inst2.0
The following NEW packages will be installed:
  apt-utils libapt-inst2.0
0 upgraded, 2 newly installed, 0 to remove and 7 not upgraded.
Need to get 602 kB of archives.
After this operation, 1607 kB of additional disk space will be used.
...
Removing intermediate container 022f86a9d7cb
 ---> 09974d670efb
Step 4/5 : RUN apt-get install -y iptables
 ---> Running in 2b2a14386488
Reading package lists...
Building dependency tree...
Reading state information...
The following additional packages will be installed:
  libip4tc0 libip6tc0 libiptc0 libnetfilter-conntrack3 libnfnetlink0
  libxtables12
Suggested packages:
  kmod
The following NEW packages will be installed:
  iptables libip4tc0 libip6tc0 libiptc0 libnetfilter-conntrack3 libnfnetlink0
  libxtables12
0 upgraded, 7 newly installed, 0 to remove and 7 not upgraded.
Need to get 609 kB of archives.
After this operation, 2222 kB of additional disk space will be used.
Get:1 http://cdn-fastly.deb.debian.org/debian stretch/main amd64 libnfnetlink0 amd64 1.0.1-3 [13.5 kB]
Get:2 http://cdn-fastly.deb.debian.org/debian stretch/main amd64 libip4tc0 amd64 1.6.0+snapshot20161117-6 [67.8 kB]
...
Removing intermediate container 2b2a14386488
 ---> 520d7a44e5d4
Step 5/5 : RUN apt-get upgrade -y
 ---> Running in b062393ac802
Reading package lists...
Building dependency tree...
Reading state information...
Calculating upgrade...
The following packages will be upgraded:
  base-files gpgv libc-bin libc6 libsystemd0 libudev1 multiarch-support
7 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 4631 kB of archives.
After this operation, 4096 B of additional disk space will be used.
Get:1 http://security-cdn.debian.org/debian-security stretch/updates/main amd64 libsystemd0 amd64 232-25+deb9u9 [281 kB]
Get:2 http://security-cdn.debian.org/debian-security stretch/updates/main amd64 libudev1 amd64 232-25+deb9u9 [126 kB]
...
Removing intermediate container b062393ac802
 ---> da1e417ebd51
Successfully built da1e417ebd51
Successfully tagged firewall:latest

Agora temos uma imagem do Debian chamada firewall que já possui o iptables.
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
firewall            latest              da1e417ebd51        About an hour ago   140MB
wordpress        latest              4771adb1849c        3 days ago                421MB
drupal              latest              47a58c95e8e4         3 days ago                446MB
debian              latest              d508d16c64cd        4 weeks ago             101MB
centos              latest              1e1148e4cc2c         3 months ago            202MB 
$ docker run -ti -d firewall /bin/bash
47c616dc4a45b0468a7b67f10a689eed303db1d95358def850807d78331ddef7 
$ docker ps
CONTAINER ID IMAGE        COMMAND      CREATED STATUS  PORTS    NAMES
47c616dc4a45 firewall "/bin/bash" 13 seconds ago Up 3 seconds         pedantic_elbakyan
471f35e0eb01 drupal "docker-php-entrypoi…" 24 hours ago Up 6 hours 0.0.0.0:80->80/tcp Drupal
$ docker exec -ti 47c616dc4a45 iptables -nL
iptables v1.6.0: can't initialize iptables table `filter': Permission denied (you must be root)
Perhaps iptables or your kernel needs to be upgraded.
Com isso já dá para ir brincando com o Docker. 

Nenhum comentário:

Postar um comentário