The json syntax of
ENTRYPOINT) pass the arguments to the kernel directly as an exec syscall. There is no separating of the command from the arguments by spaces, escaping of quotes, IO redirection, variable substitution, piping between commands, running multiple commands, etc, in the exec syscall. The syscall only takes the executable to run and list of arguments to pass to that executable, and it runs it.
$ to expand variables,
; to separate commands,
(space) to separate arguments,
|| to chain commands,
> for output redirection,
| to pipe between commands, etc, are all features of the shell and need something like
/bin/bash to interpret and implement them.
If you switch to the string syntax of
CMD, docker will run your command with a shell:
CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm
Otherwise, your second syntax does the exact same thing:
CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]
Note that I do not recommend running multiple commands this way inside of a container since there is no error handling if your first command fails, especially if it runs in the background. You also leave a shell running as pid 1 inside the container which will break signal handling, resulting in a 10 second delay and ungraceful kill of your container by docker. The signal handling can be mitigated by using the shell
CMD /etc/init.d/nullmailer start ; exec /usr/sbin/php5-fpm
However, handling processes silently failing in the background requires you switch to some kind of multi-process manager like supervisord, or preferably breakup your application into multiple containers and deploy them with something like docker-compose.