Differenze tra RUN CMD e ENTRYPOINT

Differenze tra RUN CMD e ENTRYPOINT: uno degli argomenti peggiori quando si tratta di avere a che fare con Docker. Oggi sfatiamo qualche mito e facciamo chiarezza su queste tre istruzioni.

 

Introduzione

 

Alcune istruzioni di Docker come quelle sopracitate sembrano molto simili e causano confusione tra gli utilizzatori che hanno appena iniziato a lavorare con Docker o lo fanno in modo discontinuo.

 

Versione breve

  • RUN esegue i comandi in un nuovo layer e crea una nuova immagine, spesso definita intermedia. Questo comando viene spesso utilizzato per l’installazione di pacchetti tramite i vari package manager.
  • CMD definisce il comando e/o i parametri predefiniti, che possono essere sovrascritti dalla riga di comando durante l’esecuzione del container Docker.
  • ENTRYPOINT configura un container che verrà eseguito come eseguibile.

 

Versione lunga

 

Quando Docker esegue un container, esegue un’immagine al suo interno. Questa immagine viene solitamente creata eseguendo le istruzioni definire nel Dockerfile, che aggiungono livelli (o layer) sopra l’immagine esistente.

 

La prima istruzione rappresenta la distribuzione scelta -solitamente un sistema operativo con qualche pacchetto- e ogni livello aggiuntivo crea una nuova immagine.

 

L’immagine finale di Docker ricorda una cipolla con il sistema operativo all’interno e diversi livelli sopra questo primo strato. Ad esempio, la tua immagine può essere creata installando diversi pacchetti tramite apt e la tua applicazione può quindi basarsi su una versione minificata di Ubuntu 20.04.

 

Architettura Docker come una cipolla
Architettura Docker come una cipolla

 

Modalità diretta vs. modalità shell

 

Alcuni di questi comandi possono essere eseguiti in due modalità, diretta e shell: nel primo caso, la sintassi è del tipo:

 

$ RUN [“apt”, “install”, “python3”]

 

Nel secondo caso invece, la sintassi è la seguente:

 

$ RUN apt install python3

 

Quando l’istruzione viene eseguita con la modalità diretta, viene chiamato l’eseguibile e l’elaborazione della shell non avviene. Cosa vuol dire?

 

Vuol dire che il seguente comando inserito all’interno di un Dockerfile non riuscirebbe a valorizzare la variabile e produrrebbe un risultato pari a “Hello $name”:

 

ENTRYPOINT ["/bin/echo", "Hello $name"]

 

In questo altro caso, l’output sarebbe corretto:

 

ENV name John Doe

ENTRYPOINT ["/bin/bash", "-c", "echo Hello $name"]


$ Hello John Doe

 

 

Comando RUN

 

Abbiamo detto che il comando RUN esegue i comandi in un nuovo layer creando una nuova immagine. Quando usato per installare pacchetti software, fa sì che venga creata un’immagine intermedia che poi viene scartata una volta terminata l’esecuzione dell’attività richiesta.

 

Può essere eseguito in entrambe le modalità.

 

Esempi

 

$ RUN npm install python3

$ RUN apt update && apt install -y \

  git \

  xz\

  unzip

 

Comando CMD

 

L’istruzione CMD consente di impostare un comando predefinito, che verrà eseguito solo quando si esegue il container senza specificare un comando. Se il container Docker viene eseguito con un comando, il comando predefinito verrà ignorato.

 

Se Dockerfile ha più di un’istruzione CMD, tutte le istruzioni CMD tranne l’ultima vengono ignorate.

 

Può essere eseguito in entrambe le modalità.

 

Esempi

 

$ CMD echo “Hello world”

$ CMD node server.js

 

 

Comando ENTRYPOINT

 

L’istruzione ENTRYPOINT consente di configurare un container che verrà eseguito come eseguibile. È simile all’istruzione CMD, perché consente anche di specificare un comando con dei parametri, ma a differenza è che i parametri non verranno ignorati quando il container Docker viene eseguito con i parametri passati tramite riga di comando.

 

Esempi

 

FROM ubuntu:trusty

ENTRYPOINT ["/bin/ping","-c","3"]

CMD ["localhost"]


ENTRYPOINT /bin/echo "Welcome, $name"


COPY entrypoint.sh /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

 

Esempi di utilizzo

Airflow

 

FROM python:3.8-alpine


ENV AIRFLOW_VERSION=1.10.11

ENV AIRFLOW_EXTRAS=async,all_dbs,celery,crypto,devel_hadoop,jdbc,ldap,password,redis,s3,samba,ssh,statsd

ENV AIRFLOW_HOME=/opt/airflow

ENV AIRFLOW_CONFIG=/opt/airflow/airflow.cfg


RUN set -xe \

    && apk add --no-cache \

        build-base \

        cyrus-sasl-dev \

        freetds \

        freetds-dev \

        krb5-dev \

        libffi-dev \

        mariadb-dev \

        postgresql-dev \

        python3-dev \

    && pip install --no-cache-dir cython numpy psycopg2-binary \

    && pip install --no-cache-dir apache-airflow[${AIRFLOW_EXTRAS}]==${AIRFLOW_VERSION} \

    && apk del \

        build-base \

        cyrus-sasl-dev \

        freetds-dev \

        krb5-dev \

        libffi-dev \

        mariadb-dev \

        postgresql-dev \

        python3-dev \

    && rm -rf /root/.cache/pip


WORKDIR ${AIRFLOW_HOME}

VOLUME ${AIRFLOW_HOME}


EXPOSE 8080


ENTRYPOINT ["airflow"]

CMD ["--help"]

 

Django CMS

FROM vimagick/python:2

WORKDIR /app

RUN set -xe \

    && apk add -U py-pillow tzdata \

    && pip install --no-cache-dir djangocms-installer \

    && mkdir -p data \

    && djangocms --db sqlite://localhost/data/project.db \

                 --filer \

                 --languages en \

                 --no-input \

                 --parent-dir . \

                 --skip-empty-check \

                 --utc \

                 mysite

VOLUME /app/data

EXPOSE 80

CMD ["python", "manage.py", "runserver", "0.0.0.0:80"]

 

 

MariaDB

FROM alpine

RUN set -xe \

    && apk add -U bash \

                  mariadb \

                  mariadb-client \

                  tzdata \

    && mkdir -p /run/mysqld \

    && chown mysql:mysql /run/mysqld \

    && sed -Ei -e 's/^(bind-address|log)/#&/' \

               -e 's/^\[mysqld\]$/&\nskip-host-cache\nskip-name-resolve\nuser=mysql/' /etc/mysql/my.cnf \

    && rm -rf /var/cache/apk/*

COPY docker-entrypoint.sh /

VOLUME /var/lib/mysql

ENTRYPOINT ["/docker-entrypoint.sh"]

EXPOSE 3306

CMD ["mysqld"]

 

 

Tomcat

FROM tomcat:8.0-alpine

ADD sample.war /usr/local/tomcat/webapps/

EXPOSE 8080

CMD ["catalina.sh", "run"]

 

Se ancora non fossero chiare le differenze, prova a dare un’occhiata tra le risorse utili per trovare ispirazione!

 

Risorse utili

 

Condividi la tua opinione