I want to run a multiline command when starting a container in docker compose:
services:
foo:
image: alpine:edge
entrypoint: ["/bin/sh", "-c"]
command: >
apk add --no-cache curl
Running docker compose up
gives me the following errors:
[+] Running 2/0
✔ Network tmps6nvvhf0ms_default Created 0.1s
✔ Container tmps6nvvhf0ms-foo-1 Created 0.0s
Attaching to foo-1
foo-1 | apk-tools 2.14.0, compiled for aarch64.
foo-1 |
foo-1 | usage: apk [<OPTIONS>...] COMMAND [<ARGUMENTS>...]
foo-1 |
foo-1 | Package installation and removal:
foo-1 | add Add packages to WORLD and commit changes
foo-1 | del Remove packages from WORLD and commit changes
...
...
It’s clear that only the first word apk
was passed to docker compose
. I tried with other commands and they have the same results.
docker version
:
Client: Docker Engine - Community
Version: 24.0.7
API version: 1.43
Go version: go1.21.3
Git commit: afdd53b4e3
Built: Thu Oct 26 07:06:42 2023
OS/Arch: darwin/arm64
Context: colima
Server: Docker Engine - Community
Engine:
Version: 24.0.7
API version: 1.43 (minimum version 1.12)
Go version: go1.20.10
Git commit: 311b9ff
Built: Thu Oct 26 09:08:29 2023
OS/Arch: linux/arm64
Experimental: false
containerd:
Version: 1.6.25
GitCommit: d8f198a4ed8892c764191ef7b3b06d8a2eeb5c7f
runc:
Version: 1.1.10
GitCommit: v1.1.10-0-g18a0cb0
docker-init:
Version: 0.19.0
GitCommit: de40ad0
docker compose version
Docker Compose version 2.23.3
3
Answers
Because you specify the command as a string, it is subjected to shell splitting. Given the fragment in your question, you end up with the following invocation:
Whereas you meant:
One way to accomplish that is by specifying an array for
command
, which disables shell splitting:As @Botje indicates in their answer, Compose splits a multi-word
command:
into separate words for you, butsh -c
only expects a single word as its input.I’d address this by just deleting the
entrypoint:
override. The YAML block scalar (multiline string) syntax isn’t special here.Note that the
command:
gets repeated every time you start the container. It’s not usually a good practice to install software inside a running container, since that will be lost as soon as the container exits. A better approach is to do the installation once as part of building a custom image. The Compose file becomes even simplerand in the same directory, a Dockerfile
This also has the advantage of it being easy to have multiple
RUN
lines, which run in order, and of theRUN
lines actually being processed by a shell.Alternatively, this form is convenient: