Ponència Ujilliurex 2020: Be docker, my friend

Podeu consultar esta ponència i totes les ponències a http://ujilliurex.uji.es/videos.php

Abans d’explicar què és docker, farem una comparativa amb la realitat. Nosaltres, com a persones, som dependents d’objectes que necessitem per a fer certes faenes. Per exemple, necessitem culleres per al caldo, forquetes per a l’ensalada… Imaginem que se’n anem a passar un mes fora de casa, allà on Sant Pere va pedre la sabata. Allí sols hi ha quatre parets i un teulat, ni sofà, ni cuina… I et preguntes, paga la pena anar? I si pogueres embolicar totes les dependències/ferramentes necessàries per a desenvolupar la teua vida allí amb normalitat i foren portables? Doncs açò és docker.

No obstant, no podem començar la casa per la teulada, cal posar èmfasi amb diversos conceptes envers als contenidors. Per tant, a continuació s’expliquen els conceptes bàsics.

Imatges

Una imatge és un paquet, en el qual es troba una aplicació o servei i tot el necessari (codi, executables, llibreries, configuració, etc) perquè esta aplicació puga funcionar.

Però, aleshores, per què estem parlant d’imatges i no de contenidors? D’acord amb el diccionari, una imatge és una «idea o representació mental del que es percep pels sentits». Què té a vore una imatge ací? Doncs bé, un contenidor no és més que una instància d’una imatge, és a dir, una imatge en funcionament. També podem fer un símil entre imatge i un programa executable. Si ens fixem, quan executem un programa, este es transforma en un procés (una instància del programa). Si el tornem a executar obtenim una segona instància. Aleshores, podem dir que les imatges són com els programes executables i els contenidors com els processos en execució.

Contenidors

Com explicàvem abans, un contenidor no és més que una instància d’esta imatge que té tot el necessari perquè la nostra aplicació funcione adequadament. Però, el contenidor té una característica realment interessant. El contenidor utilitza i comparteix el sistema operatiu de la màquina en la qual s’està executant, amb altres aplicacions i per descomptat, amb altres contenidors.

Això és precisament el que ho diferencia d’una màquina virtual. Les màquines virtuals alcen un sistema operatiu complet, mentre que els contenidors tenen el mínim imprescindible per al funcionament de l’aplicació o servei, és a dir, minimitza les aplicacions i programes bàsics per al funcionament d’una aplicació o programa concret.

Imatges i contenidors

La diferència entre el paral·lelisme, que feiem abans entre les instàncies dels programes i els contenidors, radica en el fet que quan acaba l’execució d’una instància de l’aplicació esta desapareix, en canvi, en detindre un contenidor este queda enmagatzemat en el nostre equip. Per què? La raó perquè el contenidor quede en el nostre equip és, d’una banda per poder iniciar-lo de nou, i en segon lloc, perquè és possible que a l’interior d’este tinguem arxius que ens siguen d’utilitat. Si en acabar l’execució del contenidor, s’esborrara de manera automàtica, segur que en més d’una ocasió, s’emportaríem un disgust.

Instal·lació de l’entorn

Podem trobar les instruccions d’instal·lació del docker al web oficial: https://docs.docker.com/get-docker/

Com som sabeu, al Lliurex 19 podem instal·lar el docker emprant el Zero-Center o per comandaments. Ací, ho farem per consola.

Preparació dels repositoris

# Actualitzar i instal·lar paquets per permetre l’ús d’apt via https
$ sudo apt-get update

$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

# Afegir clau GPG
 $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# Afegir repositori
 $ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

Instalar docker i docker-compose

# Actualitzar i instal·lar docker Community Edition
 $ sudo apt-get update
 $ sudo apt-get install docker-ce docker-ce-cli containerd.io
# Afegir docker al nostre grup, així no cal emprar sudo
 $ sudo usermod -aG docker $USER
# Instal·lar docker-compose
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose

Test: Hola món

# Hola món
 $ docker run hello-world

Com tots els programes, el primer és fer el Hola món.
Com qualsevol contenidor, es necessita d’una imatge per poder generar una instància. Esta imatge és diu hello-world.
Normalment, les imatges estan allotjades a https://hub.docker.com. Es una plataforma on podem penjar les nostres imatges i seran públiques per a les demés persones.
Què fa «docker run hello-world» comandament? Al intentar posar en funcionament la imatge hello-world, el que fem es buscar si ja tenim una imatge anomenada «hello-world» al nostre equip, en cas contrari, la descarrega del repositori, crea i arranca un contenidor al nostre ordinador.

Comandaments docker

Llistar imatges i contenidors

Per a saber de quines imatges disposem localment, podem emprar docker image ls o docker images. Per obtindre els contenidors que tenim executant-se actualment emprarem docker container ls. Si volem llistar tots els contenidors docker container ls -a.

Arrancar un contenidor i executar la consola

Una vegada posem en marxa un contenidor amb docker run [nom_imatge], este passa a execució. Podem executar comandaments dins del contenidor. Per exemple, podem emprar la consola d’eixe contenidor. Per a fer-ho, abans hem d’intentificar el nom del contenidor, el seu CONTAINER ID. Per tant, executem docker container ls i copiem l’identificador corresponent. També podem quedar-nos amb els primers caracters alfanumèrics. Per exemple, si tenim un contenidor amb id 2d09865a0635 podem emprar docker exec -ti 2d0 sh. Amb este comandament estem executant sh en el contenidor 2d09865a0635 amb dues opcions: -t li estem dient que emprarem una pseudoterminal i amb -i serà interactiva. Tan propte com executem el comandament entrarem en la consola del contenidor i podrem navegar i executar comandaments dins d’este. Per aquest motiu, no cal usar SSH per interactuar amb els contenidors.

Parar i esborrar un contenidor

Si ja hem acabat amb el contenidor i volem tombar-lo, el primer que hem de fer es parar l’execució amb docker stop 2d0 (també podem polsar ctrl + C en el terminal on hem llançat el contenidor). Si el que volem es esborrar els contenidors, perquè ja no els necessitem i ocupen espai, emprarem docker container rm 2d0.

Docker-compose

Una vegada hem vist com llançar i manejar els contenidors i les imatges, passarem a les opcions per a emprar volums, exposar serveis, mapejar ports… Però en compte d’emprar directament docker, emprarem una ferramenta que ens ajuda a configurar, alçar, parar i moltes més coses, els nostres contenidors. Esta ferramenta es diu docker-compose. Per a aprendre de forma simple com s’empra esta ferramenta, anem a fer-ho de forma pràctica. Abans, un poc de context.
Moltes vegades, quan treballem com a coordinadores TIC als centres, ens trobem que hem de solucionar infinites incidències, totes sabeu de què parle… Doncs una forma de centralizar-les és emprar un formulari accessible dins del centre, on les docents poden emplenar les seues incidències i les coordinadores planificar-se per resoldre-les o donar instruccions de com es poden solventar. A més, podem emprar el mateix sistema que s’usa per a les incidències que col·loquem al SAI, el sistema OTRS.
Aleshores, anem a la faena. Per emprar la ferramenta docker-compose, necessitem crear un fitxer anomenat docker-compose.yml. Afortunadament, no som els únics que hem pensat en «dockeritzar» OTRS, una simple cerca al web ens duu a un repositori a GitHub anomenat complemento/docker.otrs. A més, ens dona ja un fitxer docker-compose.yml. Crearem una carpeta local (p.e. $ mkdir docker-otrs) i dins d’esta executem $ wget https://raw.githubusercontent.com/complemento/docker.otrs/master/docker-compose.yaml En este moment, ja podem analitzar les opcions de les que fa ús este fitxer. Este fitxer empra el format yml. De forma resumida, la formatació que empra és:

  • Cada opció depén de forma jeràrquica de la seua superior.
  • Cada opció ha de ser identada de forma correcta per a especificar a qui pertany.
  • Si una opció té diverses entrades podem emprar el guionet (-)

Al web https://docs.docker.com/compose/compose-file/compose-file-v2/ podem trobar totes les opcions de què disposa este fitxer.

El fitxer docker-compose.yml

version: '2'

services:
  otrs:
    image: ligero/otrs
    restart: unless-stopped
    volumes:
      - ./data/otrs:/opt/otrs
      - /etc/localtime:/etc/localtime:ro
      - ./otrs_addons:/opt/otrs_addons
    environment:
      - MYSQL_HOSTNAME=mysql
      - MYSQL_USERNAME=root
      - MYSQL_PASSWORD=ligero
      - CUSTOMER_ID=ligero
      - OTRS_SYSTEM_ID=10
      - OTRS_DEFAULT_LANGUAGE=en
      - OTRS_FQDN=myotrs.ligero.online
      - INSTALL=1
#      - DONT_INSTALL_LIGERO_ADDONS=1
    depends_on:
      - mysql
    expose:
      - 80
    # ports:
    #   - 80:80
  mysql:
    image: mysql:5.7
    restart: unless-stopped
    volumes:
      - ./data/mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=ligero
    command:
      - --max_allowed_packet=65737518
      - --innodb_log_file_size=269331648
      - --query_cache_size=36737518
      - --character_set_server=utf8
      - --bind-address=0.0.0.0

Al nostre fitxer, el primer que trobem és «version». Amb esta opció, especifiquem quina versió del «compose-file» estem usant. En el nostre cas, la 2 (s’especifica entre cometa simple). A continuació, trobem la secció de «services» on especifiquem els nostres serveis o contenidors que emprarem. En el nostre cas, emprem dos contenidors, un per al servei web (otrs) i altre per a emmagatzemar la informació, un sistema gestor de bases de dades (MySQL). Cada servei té les seues pròpies opcions. En primer lloc, el contenidor «otrs» empra com a imatge «ligero/otrs». Amb l’opció «restart: unless-stopped» indiquem que el contenidor torne a execució sempre que nosaltres no el parem. Per exemple, si l’ordinador s’apaga, quan es torne a encendre el contenidor també es posarà en funcionament. La següent opció que trobem és «volumes». Amb esta opció mapegem els directoris locals amb els de l’interior del contenidor. Així, dintre del directori que hem creat tindrem dos directoris (el punt (.) indica que l’ha de crear dins del directori actual:

  • ./data/otrs contindrà tot el que conté /opt/otrs
  • ./otrs_addons contindrà tot el que conté /opt/otrs_addons

A més, també li propocionem al contenidor la nostra configuració d’ús horari, la data i l’hora amb /etc/localtime:/etc/localtime:ro. :ro significa read only, sols lectura. Continuant amb les opcions, trobem «environment» on idiquem les variables d’entorn que emprarà el nostre contenidor. Trobem, doncs, les següents variables:

  • MYSQL_HOSTNAME=mysql. Indiquem que la direcció de l’equip que disposa de MySQL és el contenidor «mysql». També podríem indicar-li altres direccions, com localhost, exemple.com…
  • MYSQL_USERNAME=root i MYSQL_PASSWORD=ligero, on idiquem l’usuari i la contrasenya per autenticar-nos contra la base de dades.
  • CUSTOMER_ID=ligero, OTRS_SYSTEM_ID=10, OTRS_DEFAULT_LANGUAGE=en, OTRS_FQDN=myotrs.ligero.online, INSTALL=1 són variables que empra el OTRS.

Amb l’opció «depends_on» indiquem que el contenidor «otrs» depén de «mysql», per tant, per a iniciar-se s’ha d’iniciar primer el contenidor corresponent. Per defecte, cap contenidor exposa cap servei (port). Com sabeu, el port habitual del protocol HTTP és el 80. Per tant, hem d’exposar el port 80 del contenidor «otrs». Però, exposar-lo no significa que siga accessible a través de la xarxa, significa que podem fer una petició a l’IP que tinga assignada el contenidor i obtindre el servei solicitat. Per això, tenim a la nostra disposició l’opció «ports» on podem mapejar els ports del contenidor amb la nostra màquina. Per exemple, -ports: 80:80, per tant, tota petició rebuda a la nostra màquina pel port 80 serà redirigida al port 80 del contenidor. Així, dins del centre podríem accedir a l’OTRS amb 10.0.1.1:80. Per altre costat, el contenidor «mysql» compta amb opcions molt paregudes a les del contenidor anterior. D’estes, remarcarem la contrasenya del MYSQL que ha de ser la mateixa que la del contenidor anterior. Finalment, trobem l’opció «commands» on especifiquem els comandaments que ha d’executar el nostre contenidor.

Desplegar serveis

Donades per explicades les configuracions bàsiques que podem especificar al fitxer «docker-compose.yml», en este moment ja podem desplegar els nostres serveis (contenidors). Per a fer-ho, comptem amb el comandament docker-compose up i si volem que s’execute en «backgroud» o com a dimoni (daemon), emprarem docker-compose up -d.

Consultar logs

Per a llegir els logs que generen els nostres contenidors emprarem «docker-compose logs». Si volem llegir a mesura que van generant-se «docker-compose logs -f». Si sols volem llegir els d’un contenidor en concret «docker-compose logs -f mysql».

Entrar al terminal del contenidor

Com féiem amb «docker», també podem accedir dins del contenidor amb «docker-compose exec mysql bash».

Reiniciar contenidors

Per altra banda, podem reiniciar els contenidors amb «docker-compose restart» o sols un contenidor «docker-compose restart mysql». També podem parar-los amb «docker-compose down»..

Llistar les imatges i contenidors del projecte

Podem mostrar quins contenidors tenim executant-se amb «docker-compose ps». Llistar les imatges ho faríem amb «docker-compose images».

Esborrar contenidors

Esborrar els contenidors amb «docker-compose rm» o si sols volem fer-ho sobre un «docker-compose rm mysql».

Dockerfile: Muntant la nostra pròpia imatge

Ja que estem treballant sobre el projecte https://github.com/complemento/docker.otrs farem ús del seu Dockerfile. Una cosa que encara no hem explicat és que les imatges docker es construeixen mitjançant capes. Una capa es crea quan es treballa sobre la imatge, és a dir, quan s’executa una instrucció o comandament.

FROM ubuntu:16.04
MAINTAINER Complemento 

# Definitions
ENV OTRS_VERSION=6.0.10
ENV LIGERO_REPOSITORY=6.0.0

RUN apt-get update && \
    apt-get install -y supervisor \
    apt-utils \
    libterm-readline-perl-perl && \
    apt-get install -y locales && \
    locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

RUN apt-get install -y apache2 git bash-completion cron sendmail curl vim wget mysql-client

# CREATE OTRS USER
RUN useradd -d /opt/otrs -c 'OTRS user' otrs && \
    usermod -a -G www-data otrs && \
    usermod -a -G otrs www-data

RUN mkdir /opt/src && \
    cd /opt/src/ && \
    chown otrs:www-data /opt/src && \
    su -c "git clone -b rel-$(echo $OTRS_VERSION | sed --expression='s/\./_/g') \
    --single-branch https://github.com/OTRS/otrs.git" -s /bin/bash otrs

RUN sed -i -e "s/6.0.x git/${OTRS_VERSION}/g" /opt/src/otrs/RELEASE

COPY link.pl /opt/src/

RUN chmod 755 /opt/src/link.pl && \
    mkdir /opt/otrs && \
    chown otrs:www-data /opt/otrs

# perl modules
RUN apt-get install -y  libarchive-zip-perl \
                        libcrypt-eksblowfish-perl \
                        libcrypt-ssleay-perl \
                        libtimedate-perl \
                        libdatetime-perl \
                        libdbi-perl \
                        libdbd-mysql-perl \
                        libdbd-odbc-perl \
                        libdbd-pg-perl \
                        libencode-hanextra-perl \
                        libio-socket-ssl-perl \
                        libjson-xs-perl \
                        libmail-imapclient-perl \
                        libio-socket-ssl-perl \
                        libauthen-sasl-perl \
                        libauthen-ntlm-perl \
                        libapache2-mod-perl2 \
                        libnet-dns-perl \
                        libnet-ldap-perl \
                        libtemplate-perl \
                        libtemplate-perl \
                        libtext-csv-xs-perl \
                        libxml-libxml-perl \
                        libxml-libxslt-perl \
                        libxml-parser-perl \
                        libyaml-libyaml-perl


RUN /opt/src/otrs/bin/otrs.SetPermissions.pl --web-group=www-data

RUN ln -s /opt/src/otrs/scripts/apache2-httpd.include.conf /etc/apache2/sites-available/otrs.conf && \
    a2ensite otrs && \
    a2dismod mpm_event && \
    a2enmod mpm_prefork && \
    a2enmod headers

# Supervisor
RUN mkdir -p /var/log/supervisor
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

# Setup a cron for checking when OTRS is already installed, then start otrs Cron
COPY daemonstarter.sh /opt/src/
RUN chmod +x /opt/src/daemonstarter.sh
RUN echo "* * * * * /opt/src/daemonstarter.sh" | crontab -

COPY otrs.sh /opt/src/
RUN chmod 755 /opt/src/otrs.sh

RUN mkdir /opt/ligero_addons/ && chown otrs:www-data /opt/ligero_addons

ADD https://addons.ligerosmart.com/AddOns/6.0/Community/LigeroRepository/LigeroRepository-${LIGERO_REPOSITORY}.opm /opt/ligero_addons/

RUN chown otrs:www-data /opt/ligero_addons -R

EXPOSE 80

CMD ["/opt/src/otrs.sh"]

Per tant, quan comencem a confeccionar una nova imatge docker podem partir d’una imatge anterior (sentència FROM). Com vegem, la imatge docker.otrs parteix d’una imatge d’Ubuntu versió 16.04. A continuació, podem especificar el mantenidor d’eixa imatge amb «MAINTAINER». També podem configurar variables d’entorn amb «ENV». Per a executar programes o aplicacions, emprarem «RUN». Amb una sentència «RUN» podem instal·lar paquets (apt), cambiar permisos (chown), crear directoris (mkdir)… També disposem d’una sentencia «COPY» que copia fitxers/directoris locals dins de les imatges. La sentència «ADD», passant-li com a primer paràmetre una URL, descarregarà el contingut en el fitxer/directori destí. Amb la sentència «EXPOSE» obrim el port o ports que empra la nostra aplicació. Finalment, amb la sentència «CMD» indiquem quin o quins comandaments ha d’executar una vegada ha arrancat el nostre contenidor.

Per a més informació, podem consultar https://docs.docker.com/engine/reference/builder/

Per a crear la nostra imatge tan sols hem d’executar «docker build .».

Conclusions

En esta sessió hem explicat els conceptes relatius als contenidors, com són les imatges i els contenidors. Hem vist que una imatge és un concepte de programari estàtic, és a dir, que especifica de què es conforma un contenidor. Per altra banda, un contenidor és una imatge en funcionament, en execució. Quan treballem sobre els contenidors, normalment es guarda l’estat d’execució anterior. Així podem consultar les dades en les quals treballa.
Els contenidors els podem emprar per a desplegar aplicacions complexes que requereixen de diverses dependències especifiques per al correcte funcionament d’una aplicació en concret. D’esta forma fem les nostres aplicacions portables i fàcilment distribuibles. A més, no s’hem de preocupar de configurar el context en el qual s’executa la nostra aplicació (falta de llibreries, programari obsolet, interacció entre aplicacions…).

Per a manejar els contenidors comptem amb la ferramenta «docker». Amb ella podem gestionar les imatges, els contenidors… També comptem amb una ferramenta que ens permet gestionar un projecte d’una forma més fàcil i intuitiva, «docker-compose».

Finalment, hem vist com crear una imatge basant-se amb un altra i configurar-la al nostre gust.

Deixa un comentari

L'adreça electrònica no es publicarà. Els camps necessaris estan marcats amb *

four × 4 =

"edutictac.es