Many Docker users encounter confusion when trying to execute multiple commands in their containers. The initial approach might look like this:
CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]
This doesn't work because Docker's CMD
directive in JSON/exec format doesn't interpret shell operators like semicolons. The container fails to start because it's trying to execute the entire array as a single command with literal semicolons as arguments.
Docker supports two formats for CMD
:
# Shell format (processed by shell)
CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm
# Exec format (direct execution)
CMD ["/usr/sbin/php5-fpm"]
The working solution uses the exec format but explicitly invokes a shell to interpret the commands:
CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]
Here are some common patterns for running multiple commands:
# Using shell to chain commands
CMD ["sh", "-c", "command1 && command2"]
# Background process with follow-up command
CMD ["sh", "-c", "service nginx start & service php-fpm start"]
# Environment variable substitution
CMD ["sh", "-c", "echo $HOME && ls -la"]
When dealing with multiple services in a container:
- Consider using a process manager like supervisord
- For complex setups, split into multiple containers
- Always test your CMD syntax with
docker run
before building the final image
The same principle applies to docker-compose.yml
:
services:
app:
command: sh -c "/etc/init.d/nullmailer start && /usr/sbin/php5-fpm"
Remember that while it's possible to run multiple commands, Docker's philosophy favors single-process containers for better isolation and scalability.
When trying to run multiple commands in a Docker container, many developers encounter unexpected behavior. The natural approach might be:
CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]
But this fails because Docker interprets the semicolon as a literal argument rather than a shell operator.
Docker's CMD directive has two fundamental formats:
1. JSON array format (exec form):
CMD ["executable","param1","param2"]
This directly executes the binary without shell processing, meaning:
- No environment variable expansion
- No shell operators (;, &, |, etc.)
- No command substitution
2. Shell format:
CMD command param1 param2
To execute multiple commands, you have several proper approaches:
Solution 1: Explicit shell invocation
CMD ["sh", "-c", "/etc/init.d/nullmailer start && /usr/sbin/php5-fpm"]
Solution 2: Using a shell script
# Dockerfile
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
CMD ["/entrypoint.sh"]
Solution 3: For complex scenarios
CMD ["sh", "-c", "service nullmailer start && \
/usr/sbin/php5-fpm --nodaemonize"]
Example 1: Database initialization
CMD ["sh", "-c", "mysqld_safe & \
while ! mysqladmin ping --silent; do sleep 1; done \
&& mysql -uroot -e 'CREATE DATABASE IF NOT EXISTS app'"]
Example 2: Multiple services in one container
CMD ["sh", "-c", "nginx && php-fpm7"]
- Always prefer explicit shell invocation over assuming shell behavior
- For production, consider using proper process managers (supervisord, s6)
- Remember that shell-form CMD runs under /bin/sh -c
- Debug with:
docker run -it --entrypoint sh yourimage