When using Docker, what is the difference between the 'command' in docker-compose, and the manual execution of commands after entering the container?

Viewed 33

The docker-compose startup file 'docker-compose.yml' is as follows (some information is omitted):

version: '2'
services:
  container_1:
    image: ...
    ports: ...
    command: /worker/bin/init.sh
    volumes: ...
    extra_hosts: ...
    restart: always
    network: ...
    cap_add:
      - SYS_ADMIN
      - SYS_PTRACE

Then I start the container using below command:

docker-compose -f docker-compose.yml up -d

The second way to get into the container to execute commands is actually based on docker-compose, since I need to specify a lot of port mappings and file mappings, it's complicated to start using the command line. I modified the command in the above yml file to (in order to keep the container running):

command: vim tmpfile

Starting the container using the same method, and use the following method to enter the container:

docker exec -ti container_1 bash

Finally execute the script (/worker/bin/init.sh) manually.

When using the first method, I encountered a strange problem. After executing the 'init.sh' script, the permissions of some files in the container were modified, and the read permissions of these files were removed. But after executing the same script using method 2, nothing has changed.

Has anyone encountered a similar problem? thank you for your reply.

1 Answers

A Docker container normally only runs one process. That's specified by the entrypoint and command when you start the container. That process has process ID 1 within the container, which is special in a couple of ways.

If you launch a debugging shell or other debugging command with docker exec it creates an additional process in the container. It's not process ID 1 (and won't inherit zombie processes for example). This debugging command won't run via the container's entrypoint, which occasionally causes some inconsistencies (especially if the entrypoint sets up environment variables).

In normal operation you should not need to "get into the container to execute commands". Any changes you make, say by running init.sh here, won't be visible by the main container process at startup and will be lost as soon as the container exits. Set up the container to be able to initialize itself, maybe using an entrypoint wrapper script.

... I need to specify a lot of port mappings and file mappings ...

One option here is to docker-compose run a secondary container. This takes most of the settings from the docker-compose.yml file, but ignores ports: and overrides the command:. For example, a good way to manually run database migrations in a Python/Django application could be

docker-compose run django \
  python manage.py migrate

which will pick up the Compose networks and environment-variable configuration, but still can run next to the main application.

The other thing to consider is just reducing the amount of deploy-time configuration if possible. COPY some of the files into your Docker image if possible; set a CMD in the Dockerfile instead of the Compose command:; set up a DNS server instead of the fragile extra_hosts: configuration. That might make it easier to translate the image into a different setup.

Related