Salta el contingut

Docker avançat

Informació extreta de Tutorial de Docker.

Exemple de fitxer Dockerfile

FROM node:12-alpine
RUN apk add --no-cache python g++ make
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
  • docker build -t getting-started . : Per a generar una imatge de zero amb el fitxer Dockerfile del directori actual. Al final estem iniciant una aplicació amb node que hem de tenir descomprimida al directori app dins l'actual.
  • docker run -dp 3000:3000 getting-started : Per a iniciar la imatge creant un contenidor.

Algunes comandes

Treballarem amb el hub de Docker al qual hem de tenir un usuari creat.

  • docker ps : per a veure els contenidors que tenim iniciats.

  • docker ps -a : per a veure els contenidors que tenim iniciats i els que no ho estan.

  • docker stop <container-id> : atura un contenidor.

  • docker rm <container-id> : elimina un contenidor aturat.

  • docker rm -f <container-id> : força l'eliminació d'un contenidor iniciat.

  • docker rmi <image-id> : elimina una imatge sense cap referència.

  • docker rmi -f <image-id> : força l'eliminació d'una imatge amb contenidors que el referencien. No elimina els contenidors per tant no és una bona opció.

  • docker tag getting-started <idUsuari>/getting-started : permet canviar el nom d'una imatge local.

  • docker push <usuari>/getting-started : permet pujar una imatge al nostre repositori. Abans cal haver-nos loginat.

  • docker exec <container-id> cat /data.txt : Executa la comanda que posem darrere l'identificador del contenidor. En aquest cas mostra el contingut del fitxer data.txt.

  • docker run -it ubuntu ls / : crea un contenidor, l'inicia, executa la comanda i l'atura.

Execució d'scripts al crear la màquina

Configurant la xarxa

I fins aquí... per a més consulteu Internet!

De principi a fi

Extret de Video: DOCKER 2021 - De NOVATO a PRO! (CURSO COMPLETO): 1:06:21

Totes les dependències estaran sempre dins un Contenidor (Sandbox - Entorn de proves). Docker executarà un contenidor a partir d'una imatge. Què té la imatge? - Sistema Operatiu: distribució de linix (no el kernel) - Software: - El codi de la nostra aplicació

Com genero una imatge?

A partir d'un fitxer anomenat Dockerfile. Fitxer amb instruccions que indiquen com es crea la imatge. Amb docker build generem la imatge i amb docker run l'executem.

Puc crear-me una imatge?

Sí, la imatge la podem descarregar d'internet o la podem crer nosaltres mateixos. Totes les imatges, però, estan en un registre de docker. L'oficial és DockerHub tot i que n'hi ha molts altres. Allà farem les cerques de les imatges que ens interessin. Si entrem dins l'enllaç de la imatge que ens interessa apareixerà la forma de descarregar-ho: per exemple docker pull postgres

Si la imatge no la tinc, es descarrega sola

Podem executar una imatge sense tenir-la descarregada amb docker run <imatge>. En aquest cas, abans d'executar-se, el sistema descarregarà la imatge.

Diferents versions o tags

Si la imatge té diferents versions (o tags) indicarem quina volem descaregar afegint després del nom de la imatge dos punts (:) i el nom de la versió docker run node:slim. Per defecte descarregaria la latest.

A l'executar una imatge és possible que aquesta ens demani alguns paràmetres per autoconfigurar-se.

Comandes més comuns

  • docker run <imatge>: permet executar una imatge creant el seu contenidor.

  • docker pull <imatge>: descarrega una imatge sense executar-la.

  • docker images: mostra les imatges descarregades al nostre sistema.

C:\MVD\002>docker images
REPOSITORY              TAG       IMAGE ID       CREATED       SIZE
getting-started         latest    ed59c4f4d345   5 days ago    383MB
local/getting-started   latest    ed59c4f4d345   5 days ago    383MB
<none>                  <none>    2fead90fdf6c   5 days ago    383MB
ubuntu                  latest    9873176a8ff5   4 weeks ago   72.7MB
docker/getting-started  latest    083d7564d904   5 weeks ago   28MB

De cada imatge podem veure'n el nom de la imatge, la versió/tag un identificador de la imatge la data de creació i el tamany.

  • docker ps: mostra els contenidors que s'estan executant en un moment donat.
c:\MVD\002>docker ps
CONTAINER ID   IMAGE             COMMAND                  CREATED          STATUS          PORTS     NAMES
3ff8ee26557f   getting-started   "docker-entrypoint.s…"   44 seconds ago   Up 43 seconds             vibrant_johnson
  • docker ps -a: mostra els contenidors que s'han executat darrerament.
c:\MVD\002>docker ps -a
CONTAINER ID   IMAGE                    COMMAND                  CREATED              STATUS                        PORTS                               NAMES
3ff8ee26557f   getting-started          "docker-entrypoint.s…"   About a minute ago   Up About a minute                                                 vibrant_johnson
125c2219b388   ubuntu                   "bash"                   2 minutes ago        Exited (0) 2 minutes ago                                          musing_northcutt
a2c572850290   getting-started          "docker-entrypoint.s…"   5 days ago           Exited (0) 5 days ago                                             charming_ardinghelli
fae33a30db7e   docker/getting-started   "/docker-entrypoint.…"   6 days ago           Exited (255) 12 minutes ago   0.0.0.0:80->80/tcp, :::80->80/tcp   vibrant_nobel```
  • docker start <IDCONTAINER>: permet executar un contenidor que haviem aturat a partir de l'ID. Aquest contenidor s'iniciarà en background. Per veure'n els seus logs ...

  • docker logs <IDCONTAINER>: per a veure els logs d'un contenidor. Aquesta opció admet el paràmetre -f equivalent al tail de manera que es quedaria mostrant els logs nous que es generessin.

Quins logs mostra?

En realitat el que veiem és el que l'aplicació que s'executa al servidor està mostrant per la pantalla.

Sempre l'IDCONTAINER?

Podem utilitzar els noms dels contenidors que es generen de forma aleatòria. De totes maneres a l'executar el contenidor podriem haver-li posat nom amb docker run <imatge>

  • docker exec <comanda>: executa una comanda dins un contenidor en funcionament. Per exemple docker exec a2c572850290 ip a. Admet paràmetres per exemple -it el que faria seria amb -i executar una sessió interactiva i amb el -t emular una terminal. Ens pot servir per obrir una terminal docker exec -it a2c572850290 sh.

  • docker stop <IDCONTAINER>: atura un contenidor, que haviem iniciat, a partir de l'ID.

  • docker run -d <imatge>: executa una imatge en background (detach).

Com ho apliquem al mon real?

Imaginem que tenim una aplicació en Node.Js. La descarreguem en un directori on:

  • Creem un fitxer anomenat Dockerfileamb el següent contingut:
FROM node:12.22.1-alpine3.11

WORKDIR /app
COPY . .
RUN yarn install --production

CMD ["node","/app/src/index.js"]
  • La primera línia sempre serà un FROM que indica la imatge pare. Buscarem una imatge que ja tingui tot el que necessitem. Amb l'etiqueta podem veure la versió del Sistema Operatiu (buster, alpine, stretch, ...).

alpine

Sovint trobarem alpine pel poc pes que té la distribució bàsica i està pensada pels contenidors. Compte que poden haver-hi diferències entre alpine i ubuntu.

c:\MVD\002>docker images
REPOSITORY                TAG       IMAGE ID       CREATED       SIZE
ubuntu                    latest    9873176a8ff5   4 weeks ago   72.7MB
alpine                    latest    d4ff818577bc   4 weeks ago   5.6MB

  • La segona línia, WORKDIR /app indica on executarem les nostres tasques. Indiquem el directori /app que no existeix en Node però el crearà automàticament i totes les comandes s'executaran des d'aquest directori.

  • La tercera línia, COPY . . copiarà els fitxers del meu directori (màquina real) al directori del contenidor (. que és /app).

  • La següent línia, RUN yarn install --production ja és de Node i compilarà tot el que tenim al directori.

  • Finalment a la darrera línia del fitxer de Docker cal especificar la comanda que volem executar. En el nostre cas la comanda node amb l'argument del fitxer js a executar: CMD ["node","/app/src/index.js"]

Tip

Podem tenir una línia amb ENTRYPOINT que seria per a deixar oberta la comanda per a passar-li paràmetres a l'executar el docker run.

  • Creem el contenidor amb la comanda docker build .. Cal especificar el . que indica on tenim el fitxer Dockerfile. Aprofitarem per a posar-li un nom/tag

docker build -t node_exemple .

c:\MVD\002>docker build -t node_exemple .
[+] Building 103.0s (9/9) FINISHED
 => [internal] load build definition from Dockerfile                                                                                  0.1s
 => => transferring Dockerfile: 158B                                                                                                  0.0s
 => [internal] load .dockerignore                                                                                                     0.1s
 => => transferring context: 2B                                                                                                       0.0s
 => [internal] load metadata for docker.io/library/node:12.22.1-alpine3.11                                                            3.4s
 => [internal] load build context                                                                                                     0.4s
 => => transferring context: 4.63MB                                                                                                   0.4s
 => [1/4] FROM docker.io/library/node:12.22.1-alpine3.11@sha256:93b71facf11d471ac035acfaf020ecc05297f6a401781cafceae1d0561704ba4     97.7s
 => => resolve docker.io/library/node:12.22.1-alpine3.11@sha256:93b71facf11d471ac035acfaf020ecc05297f6a401781cafceae1d0561704ba4      0.0s
 => => sha256:93b71facf11d471ac035acfaf020ecc05297f6a401781cafceae1d0561704ba4 1.43kB / 1.43kB                                        0.0s
 => => sha256:5b8504e22687f25e22254d062558aa18d41d3331b64e771a6a0675e93d357e70 1.16kB / 1.16kB                                        0.0s
 => => sha256:ba59ff60c386d2dc77f7afc5f9211e410ce80e864415c1bafe0006ef76fece1c 6.53kB / 6.53kB                                        0.0s
 => => sha256:8a6a62f4b1f37fb03e07275438ef8fd27a421cd1b0790e57f7dbab0c6328f811 24.60MB / 24.60MB                                     95.2s
 => => sha256:5c72c204eb2261d221bcc8b34dbb4727d6a6625dc7dadf87425c3fa8fd8bbf36 2.24MB / 2.24MB                                        8.5s
 => => sha256:33fce3bc6102e63645ad9b969467728efd17b0cdf8b083b1f505df5af73bd627 281B / 281B                                            1.5s
 => => extracting sha256:8a6a62f4b1f37fb03e07275438ef8fd27a421cd1b0790e57f7dbab0c6328f811                                             1.6s
 => => extracting sha256:5c72c204eb2261d221bcc8b34dbb4727d6a6625dc7dadf87425c3fa8fd8bbf36                                             0.1s
 => => extracting sha256:33fce3bc6102e63645ad9b969467728efd17b0cdf8b083b1f505df5af73bd627                                             0.0s
 => [2/4] WORKDIR /app                                                                                                                0.7s
 => [3/4] COPY . .                                                                                                                    0.2s
 => [4/4] RUN yarn install --production                                                                                               0.6s
 => exporting to image                                                                                                                0.2s
 => => exporting layers                                                                                                               0.2s
 => => writing image sha256:ee9a725563ff36d8d4715b91d027b0002d21259370762ebf972892b8b2e3b099                                          0.0s
 => => naming to docker.io/library/node_exemple                                                                                       0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

Ara que tenim la imatge construida

c:\MVD\002> docker images
REPOSITORY                TAG       IMAGE ID       CREATED         SIZE
node_exemple              latest    ee9a725563ff   4 minutes ago   93.5MB

podem iniciar-la, aquesta vegada amb el nom que li hem donat.

Diferència entre RUN, CMD i ENTRYPOINT

Informació extreta de Diferencia entre RUN, CMD y ENTRYPOINT.

RUN

Executa comandes en el moment en què es construeix la imatge. La posem dins un Dockerfile per tal de poder executar comandes que acabin de crear la imatge tal i com nosaltres la volem, normalment instal·lant altres paquets.

CMD

Comanda que s'executa per defecte quan iniciem el contenidor. Aquesta comanda pot sobreescriure's si, quan executem el contenidor, li passem com a paràmeter una altra comanda. La utilitzarem per executar comandes tipus: execució de servidor web, etc. Bàsicament per a servidors.

ENTRYPOINT

Comanda que s'executa per defecte quan iniciem el contenidor. Aquesta comanda pot sobreescriure's però ja no és tan senzill.

La diferència principal és que en aquest cas podem passar paràmetres a la comanda a executar en el moment en què iniciem el contenidor. Si els paràmeters inclouen algun nom de fitxer, aquest ha d'estar dins el contenidor.

Es pot utilitzar per tenir contenidors amb diferents versions d'un llenguatge i passar-li per paràmetre el fitxer que volem executar. D'aquesta manera puc interpretar que el meu contenidor és un executable que rep paràmetres.

La Xarxa Docker

Extret de Cómo funcionan las redes en Docker.

Els contenidors de Docker s'executen en una xarxa de Docker que no està compartida amb la resta de la xarxa. Si el nostre contenidor executa un servei per un port al qual volem accedir-hi caldrà mapejar aquell port a la màquina hoste.

Podem exposar ports del contenidor a la màquina hoste en la comanda docker run amb el paràmetre -p o bé --publish especificant-li ell port i el protocol de la següent forma:

docker run -p 3000:3000 <imatge>
Per defecte treballa amb el protocol tcp.

Aquesta xarxa per defecte és del tipus bridge i tots els contenidors de la mateixa xarxa poden veure's entre ells. El problema ve quan volem accedir des d'un contenidor a un altre i no abem la IP que se'ns assignarà. En aquest cas el que caldrà serà, abans de res, crear una xarxa per a compartir entre diferents contenidors i després podrem accedir a les diferents màquines per nom.

Tipus de xarxa

Docker treballa amb diferents tipus de xarxa:

  • Bridge/NAT: La que és per defecte i la utilitzem amb un servidor de Docker que necessita que els contenidors es comuniquin entre ells.

  • Overlay: està disponible si treballem amb un cluster, és a dir més d'un servidor de Docker, i necessitem que els contenidors es comuniquin entre sí independentment del servidor on estiguin executant-se.

  • None: quan el contenidor no necessita cap connexió de xarxa.

  • Macvlan: per si volem connectar el món dockeritzat amb el món sense dockeritzar. Es tractaria d'un entorn híbrid on els contenidors tenen assignades IPs dins la xarxa del host.

Per defecte, Docker configura inicialment tres tipus de xarxes. Per veure-les podem executar la comanda:

docker network ls

que ens retornarà (els identificadors de la xarxa poden canviar)

NETWORK ID     NAME      DRIVER    SCOPE
10af278c0b34   bridge    bridge    local
f5c876012a76   host      host      local
5e9a10faea8c   none      null      local

Bridge/NAT

És el més simple i el que utilitzem si no utilitzem el paràmetre --network. Amb la comanda

docker network inspect bridge

podem veure les xarxes connectades als diferents contenidors iniciats i la seva IP. Només cal mirar l'apartat de Containers. Podem fer ping des d'un a altre contenidor però sempre a través de la IP. Per accedir per nom caldrà...

Una xarxa per compartir

docker network create <nomDeXarxa>

docker network create nomDeXarxa
00b03a1c27424140e2c3c67edc693037184498be901be5e3c7403a65af44af38

docker network ls
NETWORK ID     NAME         DRIVER    SCOPE
10af278c0b34   bridge       bridge    local
f5c876012a76   host         host      local
00b03a1c2742   nomDeXarxa   bridge    local
5e9a10faea8c   none         null      local

I creem dos contenidors que utilitzin aquesta xarxa

docker container run -dit --name container-a --network nomDeXarxa alpine ash
docker container run -dit --name container-b --network nomDeXarxa alpine ash

Ara entrarem en una de les màquines i executarem un ping cap a l'altra però per nom:

docker attach container-b
ping -c 3 container-a

Quin nom té?

Recorda que el nom accessible serà el que indiquem a l'iniciar el contenidor amb el paràmetre --name <nomDelContenidor> o bé amb el paràmetre --network-alias <nomResolIP>

Això funciona ja que Docker utilitza un servidor DNS configurat per cada contenidor que permet resoldre el nom dels altres contenidors que comparteixen la xarxa.

Puc connectar un contenidor a més d'una xarxa?

Sí, però sempre després d'haver-lo iniciat i amb la comanda docker network connect ...

Host

Aquesta xarxa elimina l'aïllament entre el host i el contenidor de manera que el contenidor NO rebrà la seva pròpia adreça IP sinó que utilitza la del host. Només funciona en Linux i no està disponible pel Docker Desktop.

docker run --rm -d --network host --name my_nginx nginx

None

Si no volem que un contenidor tingui una xarxa assignada, utilitzarem -–network none de la següent forma:

#Desabilitem la xarxa del contenidor
docker run --rm -dit --network none --name no-net-alpine alpine ash

Podem comprovar que el contenidor no té assignada cap IP amb la següent comanda

docker exec no-net-alpine ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0

Overlay

Aquesta és la xarxa que necessitem per un cluster però no entrarem en detalls.

Macvlan

El mode anomenat macvlan permet assignar IPs de la nostra xarxa a cadascun dels contenidors del host. Per això, però, cal que la targeta de xarxa del host estigui en mode promiscu. Podem configurar-la amb la segünet comanda

docker network create -d macvlan \
  --subnet=172.16.86.0/24 \
  --gateway=172.16.86.1 \
  -o parent=eth0 \
  my-macvlan-net