# A Dockerfile for Composer (a dependency manager for PHP)

I recently built a Docker image for Composer. I'd love to get a review of the image, the Bash based wrapper script, its recommended use, and the repository structure.

Here's the Dockerfile for the latest tag:

FROM alpine:edge

MAINTAINER Samuel Parkinson <sam@graze.com>

RUN echo "http://dl-4.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
ca-certificates \
git \
mercurial \
subversion \
php7 \
php7-curl \
php7-json \
php7-openssl \
php7-phar \
php7-posix

RUN /usr/bin/php7 -r "readfile('https://getcomposer.org/installer');" | \
/usr/bin/php7 -- --install-dir=/usr/local/bin --filename=composer

COPY ./composer-wrapper /usr/local/bin/composer-wrapper

VOLUME ["/usr/src/app", "/root/.composer"]

WORKDIR /usr/src/app

ENTRYPOINT ["/usr/local/bin/composer-wrapper"]


The wrapper script, which adds the --ignore-platform-reqs flag for supported commands, so that users don't have to do it themselves as the image doesn't contain many of the common php extensions library's require:

#!/bin/sh

# Loop over each argument.
for argument in "$@"; do case "$argument" in
# Append the argument if the command matches one we need to use --ignore-platform-reqs with.
# Found using the following search: https://github.com/composer/composer/search?q=ignore-platform-reqs+path%3Asrc%2FComposer%2FCommand%2F
# Uses set to update the arguments, see https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html.
create-project|install|remove|require|update) set -- --ignore-platform-reqs "$@";; # Otherwise just pass it on. *) ;; esac done # Call composer with the updated arguments. exec /usr/bin/php7 /usr/local/bin/composer "$@"


The recommended way to use the image, mounting the source and composer user folder, and read only mounting the users ssh key for use when using git based dependencies:

docker run --rm -it \
-v $(pwd):/usr/src/app \ -v ~/.composer:/root/.composer \ -v ~/.ssh:/root/.ssh:ro \ graze/composer  And finally the repository itself (which includes tests of the image!): https://github.com/graze/docker-composer I'm no expert at bash, and pretty new to Docker too so I'd love to know if there's anything I'm missing, or anything I'm doing that's unconventional. • Some points I'm thinking about are creating and running under a different user, volume for /root/.composer, docker-entrypoint.sh rather than composer-wrapper, and just read only mounting all of ~/.ssh. – Sam Parkinson Feb 19 '16 at 0:40 ## 1 Answer In the wrapper script, I don't understand why you need to loop over each argument. Wouldn't it be enough to use a case "$1" in ... without looping at all?

If you really do need to loop, for example to make it work even if the command you want to match is not in the first position sometimes, then I think you want to break out of the loop after finding a match. That is:

# Loop over each argument.
for argument in "$@"; do case "$argument" in
# Append the argument if the command matches one we need to use --ignore-platform-reqs with.
# Found using the following search: https://github.com/composer/composer/search?q=ignore-platform-reqs+path%3Asrc%2FComposer%2FCommand%2F
# Uses set to update the arguments, see https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html.
create-project|install|remove|require|update) set -- --ignore-platform-reqs "\$@"
break
;;

# Otherwise just pass it on.
*) ;;
esac
done


Another small thing, at the top of the Dockerfile, I find the echo ... >> /etc/apk/repositories && apk add ... a bit curious. Under what circumstances might that appending with echo fail? And why not check the exit code of the other commands that follow? It seems that either all commands should be chained with &&, or none of them.

Lastly, I have very minimal experience with Docker, but I'm wondering if instead of multiple RUN commands, wouldn't it be better to put them in a single shell script, and RUN that script instead. (That's not a recommendation, just a general wondering...)

• Great point on the wrapper script, there's no guarantee where the command will be, but I should be breaking out once it's found! For you second point, I'm using && to chain a bunch of work together, rather than using separate RUN commands that create more layers in the final image. Looking at it now, the second RUN I think should be merge in. Finally, I could well do, but I can't see a convention of it yet. Having the instructions in the file makes them more accessible in Docker Hub though. Thanks! – Sam Parkinson Feb 21 '16 at 10:44
• Good to know that about RUN, I learned something, thanks! – janos Feb 21 '16 at 10:46