Las respuestas existentes cubren la mayor parte de lo que cualquiera que esté viendo esta pregunta necesitaría. Así que solo cubriré algunas áreas de nicho para CMD y RUN.
CMD: se permiten duplicados pero es un desperdicio
GingerBeer hace un punto importante: no obtendrá ningún error si coloca más de un CMD, pero es un desperdicio hacerlo. Me gustaría elaborar con un ejemplo:
FROM busybox
CMD echo "Executing CMD"
CMD echo "Executing CMD 2"
Si construye esto en una imagen y ejecuta un contenedor en esta imagen, como dice GingerBeer, solo se tendrá en cuenta la última CMD. Entonces la salida de ese contenedor será:
Ejecutando CMD 2
La forma en que lo pienso es que "CMD" está configurando una única variable global para toda la imagen que se está creando, por lo que las sucesivas declaraciones "CMD" simplemente sobrescriben cualquier escritura anterior en esa variable global, y en la imagen final que se construye el último en escribir gana. Dado que un Dockerfile se ejecuta en orden de arriba a abajo, sabemos que el CMD más inferior es el que obtiene esta "escritura" final (hablando metafóricamente).
EJECUTAR: los comandos pueden no ejecutarse si las imágenes se almacenan en caché
Un punto sutil a tener en cuenta sobre RUN es que se trata como una función pura, incluso si hay efectos secundarios, y por lo tanto se almacena en caché. Lo que esto significa es que si RUN tuvo algunos efectos secundarios que no cambian la imagen resultante, y esa imagen ya ha sido almacenada en caché, el RUN no se ejecutará nuevamente y, por lo tanto, los efectos secundarios no sucederán en las construcciones posteriores. Por ejemplo, tome este Dockerfile:
FROM busybox
RUN echo "Just echo while you work"
La primera vez que lo ejecute, obtendrá un resultado como este, con diferentes ID alfanuméricos:
docker build -t example/run-echo .
Sending build context to Docker daemon 9.216kB
Step 1/2 : FROM busybox
---> be5888e67be6
Step 2/2 : RUN echo "Just echo while you work"
---> Running in ed37d558c505
Just echo while you work
Removing intermediate container ed37d558c505
---> 6f46f7a393d8
Successfully built 6f46f7a393d8
Successfully tagged example/run-echo:latest
Observe que la declaración de eco se ejecutó en lo anterior. La segunda vez que lo ejecuta, usa el caché y no verá ningún eco en la salida de la compilación:
docker build -t example/run-echo .
Sending build context to Docker daemon 9.216kB
Step 1/2 : FROM busybox
---> be5888e67be6
Step 2/2 : RUN echo "Just echo while you work"
---> Using cache
---> 6f46f7a393d8
Successfully built 6f46f7a393d8
Successfully tagged example/run-echo:latest