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 exempledocker 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 terminaldocker 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 (d
etach).
Com ho apliquem al mon real?
Imaginem que tenim una aplicació en Node.Js. La descarreguem en un directori on:
- Creem un fitxer anomenat
Dockerfile
amb 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 fitxerDockerfile
. 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>
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