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:
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.