Hi,
When I have volumes:
directive set in docker-compose.yml, the ownership of the logs
directory is root:root
. If I get rid of volumes:
directive then the ownership of the logs
directory is root:www-data
which is what I want but this time I won't be able share logs with my local OS. How can I make this possible? So all I need is, own /usr/local/apache2/logs
as root:www-data
and see the logs in local OS. That's all!
Thanks
$ docker-compose -v
docker-compose version 1.17.0, build ac53b73
$ docker -v
Docker version 17.09.0-ce, build afdb6d4
docker-compose.yml
version: '3'
services:
apache_img:
container_name: apache_con
build: ./apache
volumes:
- ../logs/apache:/usr/local/apache2/logs
apache/Dockerfile
FROM httpd:2.4
RUN chown -R root:www-data /usr/local/apache2/logs
Result from having volumes:
directive
$ docker exec -it apache_con bash
root@6063c694ef2b:/usr/local/apache2# ls -l
...
drwxr-sr-x 1 root www-data 4096 Dec 23 09:40 conf
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 htdocs
drwxr-xr-x 2 root root 4096 Dec 23 09:40 logs
root@6063c694ef2b:/usr/local/apache2# ls -l logs/
...
-rw-r--r-- 1 root root 0 Dec 23 09:47 access.log
-rw-r--r-- 1 root root 0 Dec 23 09:47 error.log
Result from not having volumes:
directive
ubuntu@linux:~/hello-world$ docker exec -it apache_con bash
root@9a5da32a0557:/usr/local/apache2# ls -l
...
drwxr-sr-x 1 root www-data 4096 Dec 23 09:47 conf
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 htdocs
drwxr-sr-x 1 root www-data 4096 Dec 23 09:47 logs
root@9a5da32a0557:/usr/local/apache2# ls -l logs/
...
-rw-r--r-- 1 root www-data 0 Dec 23 09:47 access.log
-rw-r--r-- 1 root www-data 0 Dec 23 09:47 error.log
This is a bit of a combination of issues.
I'll try to explain the "permissions" issue first.
When using the <host-path>:<container-path>
for a volume, this is actually not a "volume", but a bind-mounted host-directory (a "bind mount" for short).
Bind mounts are a way to express that you allow a container to have access to a path on the host, and (in case the host-path is a directory) all the files that are in there, and with the permissions and ownership of those files on the host (they're _literally_ the same files as the files on the host, mounted into the container). So what you're seeing is not a change in permissions of the actual files in the container, but the permissions and ownership of the files/directories on the host, and that are mounted in the container.
Here's where the problem is; somewhere in the docker history, a feature was added to automatically _create_ the host path if the path didn't exist ("let's make this easier to use"). In hindsight, this was a bad idea for various reasons;
./apache.conf:/some/path/apache.conf
), and the file doesn't exist, docker will create a _directory_ named apache.conf
and try to bind-mount that (causing hard-to-find issues).root
)The last one is the issue you're running into:
logs/apache
directory didn't exist before you started the containerroot:root
)To make sure the bind-mounted directory has the correct permissions;
Inside the container, find out the UID/GID of the www-data
user;
$ id www-data
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Exit the container, and remove the compose stack;
$ docker-compose down
Stopping apache_con ... done
Removing apache_con ... done
Removing network repro5507_default
Create the host-directory, and change its permissions;
$ mkdir -p logs/apache
$ sudo chown -R 0:33 logs/apache
Start your docker compose stack
$ docker-compose up -d
...
Creating network "repro5507_default" with the default driver
Creating apache_con ... done
And you'll see that the permissions/ownership matches what's on the host;
$ docker exec apache_con ls -la
total 48
drwxr-sr-x 1 www-data www-data 4096 Dec 12 04:59 .
drwxrwsr-x 1 root staff 4096 Dec 12 04:57 ..
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 bin
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 build
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 cgi-bin
drwxr-sr-x 4 root www-data 4096 Dec 12 04:59 conf
drwxr-sr-x 3 root www-data 4096 Dec 12 04:59 error
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 htdocs
drwxr-sr-x 3 root www-data 4096 Dec 12 04:59 icons
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 include
drwxr-xr-x 2 root www-data 4096 Dec 25 14:25 logs
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 modules
Having explained the permissions issue above, your question is also around _logging_. When using containers, the recommended approach is to have your container's process not log to _files_, but to stdout
and stderr
, and use Docker's logging drivers to capture the logs.
If you look at the Dockerfile for the httpd image, you'll find these lines;
sed -ri \
-e 's!^(\s*CustomLog)\s+\S+!\1 /proc/self/fd/1!g' \
-e 's!^(\s*ErrorLog)\s+\S+!\1 /proc/self/fd/2!g' \
"$HTTPD_PREFIX/conf/httpd.conf"; \
These lines configure Apache to send logs to /proc/self/fd/1
and /proc/self/fs/2
, which are stdout
and stderr
. This means that logs are not sent to a file.
If you run a httpd (Apache) container, the output of stdout
and stderr
are caught by Docker's logging driver, and you can view those logs using the docker container logs
command (or, with Docker Compose; docker-compose logs <service name>
)
$ docker-compose logs apache_img
Attaching to apache_con
apache_con | AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.18.0.2. Set the 'ServerName' directive globally to suppress this message
apache_con | AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.18.0.2. Set the 'ServerName' directive globally to suppress this message
apache_con | [Mon Dec 25 14:25:45.740722 2017] [mpm_event:notice] [pid 1:tid 140131754698624] AH00489: Apache/2.4.29 (Unix) configured -- resuming normal operations
apache_con | [Mon Dec 25 14:25:45.740900 2017] [core:notice] [pid 1:tid 140131754698624] AH00094: Command line: 'httpd -D FOREGROUND'
This means that you should _not_ create a volume for that directory, but have docker handle the logs.
More information on logging can be found in the userguide; https://docs.docker.com/engine/admin/logging/view_container_logs/
First of all thanks for the detailed explanation!
Whether I manually create folders or not and grand specific permissions before running docker-compose
command, sadly my settings don't remain intact. They become root:root
again so docker doesn't obey anything. Let's ignore it for a minute because I tried this in many different combinations so far.
If I was docker, this is how I would behave:
volumes
directive_)docker-compose
command_) owner of the folders, not the root
.because I don't like seeing root
all over the place.
This is how temporarily solved the problem but I don't consider this as a concrete solution. Docker should handle this. Although the config below is for PHP, same thing applies to apache too so just showing as an example.
Dockerfile
...
RUN usermod -u 1000 www-data \
&& groupmod -g 1000 www-data
build.sh
#!/bin/bash
set -e
docker-compose up -d
docker exec php_container chown -R root:www-data /usr/local/etc/logs
Based on above, folders and files are owned as shown below - owner:group.
Container:
/usr/local/etc/logs: www-data www-data
/usr/local/etc/logs/error.log: www-data www-data
Local:
logs/php: ubuntu ubuntu
logs/php/error.log: ubuntu ubuntu
Whether I manually create folders or not and grand specific permissions before running docker-compose command, sadly my settings don't remain intact
What platform / setup are you running on? Are you running on OS X? Using Docker for Mac, or Docker Toolbox? If so, the situation is slightly different, because your local directory is not what's being shared with the container.
Create folders and make the current host OS user (the one who runs the docker-compose command
The daemon (which is what creates the directory/host path) has no knowledge about that. The only connection between docker-compose and the daemon is the remote API, which does not carry "who made the API call"
I am on Ubuntu 16.04, no Toolbox. Everything is as native as they get. Plain docker, plain compose, plain Ubuntu.
I'm not able to reproduce that problem; here's the steps I took (based on your _first_ description at the top of this issue), running on an Ubuntu 16.04 machine;
First create directories, docker-compose file and Dockerfile;
mkdir -p repro-5507 && cd repro-5507
mkdir -p compose/apache logs/apache
cat > compose/apache/Dockerfile <<EOF
FROM httpd:2.4
RUN chown -R root:www-data /usr/local/apache2/logs
EOF
cat > compose/docker-compose.yml <<EOF
version: '3'
services:
apache_img:
container_name: apache_con
build: ./apache
volumes:
- ../logs/apache:/usr/local/apache2/logs
EOF
Which should now look like this;
ubuntu@ubuntu-2gb-ams3-01:~/repro-5507$ tree
.
โโโ compose
โย ย โโโ apache
โย ย โย ย โโโ Dockerfile
โย ย โโโ docker-compose.yml
โโโ logs
โโโ apache
4 directories, 2 files
And permissions for the logs/apache directory;
ubuntu@ubuntu-2gb-ams3-01:~/repro-5507$ ls -la logs/
total 12
drwxrwxr-x 3 ubuntu ubuntu 4096 Dec 29 10:41 .
drwxrwxr-x 4 ubuntu ubuntu 4096 Dec 29 10:41 ..
drwxrwxr-x 2 ubuntu ubuntu 4096 Dec 29 10:41 apache
Now, change to the compose
directory
ubuntu@ubuntu-2gb-ams3-01:~/repro-5507$ cd compose/
And bring up the compose stack;
ubuntu@ubuntu-2gb-ams3-01:~/repro-5507/compose$ docker-compose up -d
Creating network "compose_default" with the default driver
Building apache_img
Step 1/2 : FROM httpd:2.4
2.4: Pulling from library/httpd
f49cf87b52c1: Pull complete
02ca099fb6cd: Pull complete
de7acb18da57: Pull complete
770c8edb393d: Pull complete
0e252730aeae: Pull complete
6e6ca341873f: Pull complete
2daffd0a6144: Pull complete
Digest: sha256:b5f21641a9d7bbb59dc94fb6a663c43fbf3f56270ce7c7d51801ac74d2e70046
Status: Downloaded newer image for httpd:2.4
---> 7239615c0645
Step 2/2 : RUN chown -R root:www-data /usr/local/apache2/logs
---> Running in 8467f222adc3
Removing intermediate container 8467f222adc3
---> 77f46ced55fa
Successfully built 77f46ced55fa
Successfully tagged compose_apache_img:latest
WARNING: Image for service apache_img was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating apache_con ... done
Check permissions of the logs
directory inside the container (1000:1000
matches the uid:gid
of the "ubuntu" user on the host);
ubuntu@ubuntu-2gb-ams3-01:~/repro-5507/compose$ docker exec apache_con ls -l /usr/local/apache2/
total 40
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 bin
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 build
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 cgi-bin
drwxr-sr-x 4 root www-data 4096 Dec 12 04:59 conf
drwxr-sr-x 3 root www-data 4096 Dec 12 04:59 error
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 htdocs
drwxr-sr-x 3 root www-data 4096 Dec 12 04:59 icons
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 include
drwxrwxr-x 2 1000 1000 4096 Dec 29 10:47 logs
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 modules
Change permissions of the logs directory on the host to ubuntu:www-data
(uid/gid: 1000:33
);
ubuntu@ubuntu-2gb-ams3-01:~/repro-5507/compose$ sudo chown -R 1000:33 ../logs/apache/
Check permissions again inside the container;
root@ubuntu-2gb-ams3-01:/home/ubuntu/repro-5507/compose# docker exec apache_con ls -l /usr/local/apache2/
total 40
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 bin
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 build
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 cgi-bin
drwxr-sr-x 4 root www-data 4096 Dec 12 04:59 conf
drwxr-sr-x 3 root www-data 4096 Dec 12 04:59 error
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 htdocs
drwxr-sr-x 3 root www-data 4096 Dec 12 04:59 icons
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 include
drwxrwxr-x 2 1000 www-data 4096 Dec 29 10:53 logs
drwxr-sr-x 2 root www-data 4096 Dec 12 04:59 modules
I think I got lost in too many things I tried and probably gave you a wrong impression. I've just did what you did above and the result is same. I'll have to go with your solution because not having local folder messes up everything so I shall manually create logs
folder and get on with it. Thanks for taking all that time to answer my question.
Good to hear my input helped you. While the documentation around this was improved recently, I think we can still use some additional information to explain the differences (in "semantics" and "behaviour") between "volumes" and "bind mounts" a bit more in-depth; https://docs.docker.com/engine/admin/volumes/bind-mounts/ (and https://docs.docker.com/engine/admin/volumes/).
I have not found the time to work on that, but it may be good to open an issue in the documentation issue tracker (perhaps you can open one? https://github.com/docker/docker.github.io/issues)
@thaJeztah I've just created one and hope that it makes sense or addresses what you meant. Please let me know if it needs specific update to make it clearer.
Thanks! I'll try to have a look soon (but don't hesitate to "ping" me if I don't get round to it :innocent:)
Hi. I see this issue is pretty old but not closed yet. I am currently having strange issue. I am using docker-compose to create and spawn a locally running application I am developing. The idea here is that if I modify any file this is bind-mounted to the docker image and the changes are available to it without the need of restarting it. I.e., I change a JS file, hit refresh in my browser and the change is present.
My docker-compose.yaml
looks like this:
volumes:
- ..:/var/www/my-app
- /tmp
The reason for ..
is that my docker-compose.yaml
is inside of /var/www/my-app/docker
folder.
Now the problem I am facing is that all files have 0644
permission set and the owner is myuser:my-domain
which lets me edit the files without a problem. But if I run from within my app root
docker-compose -f docker/docker-compose.yaml my-app-dev up
all my files user owner is changed to www-data
. Inside the image, there is a supervisor
process which runs nginx
and php-fpm
processes beneath. They both are using www-data
user and group.
Since the user owner of all my files changes to www-data
(keeping the my-domain
group) and the permissions are 0644
, I am unable to edit the files anymore until running sudo chown -R my-user:my-domain
./`. The owner remains changed even if after I stop the container.
Is this expected behavior? Or am I doing something wrong? I cannot change the permission of the files to 0755
or 0777
as doing so would require to commit them all to Git which is definitely not desired.
If this is all setup and behaving correctly, then I do not have other choice than to build the images manually and for each change during the development re-build and restart the docker image, which is also not desired.
Many thanks for your help!
Hi. I see this issue is pretty old but not closed yet.
Well.. it's closed, but not "locked"
all my files user owner is changed to www-data. Inside the image, there is a supervisor process which runs nginx and php-fpm processes beneath. They both are using www-data user and group.
Note that docker itself won't change permissions of files that are bind-mounted from the host. Is there perhaps an (entrypoint-)script in your container that sets permissions?
Is this expected behavior? Or am I doing something wrong?
It's not expected if docker would do this, but (as mentioned) perhaps it's something in your container that's setup to set permissions?
Please keep in mind that the GitHub issue tracker is not intended as a general support forum,
but for reporting bugs and feature requests. For other type of questions, consider using one of;
Most helpful comment
This is a bit of a combination of issues.
I'll try to explain the "permissions" issue first.
When using the
<host-path>:<container-path>
for a volume, this is actually not a "volume", but a bind-mounted host-directory (a "bind mount" for short).Bind mounts are a way to express that you allow a container to have access to a path on the host, and (in case the host-path is a directory) all the files that are in there, and with the permissions and ownership of those files on the host (they're _literally_ the same files as the files on the host, mounted into the container). So what you're seeing is not a change in permissions of the actual files in the container, but the permissions and ownership of the files/directories on the host, and that are mounted in the container.
Here's where the problem is; somewhere in the docker history, a feature was added to automatically _create_ the host path if the path didn't exist ("let's make this easier to use"). In hindsight, this was a bad idea for various reasons;
./apache.conf:/some/path/apache.conf
), and the file doesn't exist, docker will create a _directory_ namedapache.conf
and try to bind-mount that (causing hard-to-find issues).root
)The last one is the issue you're running into:
logs/apache
directory didn't exist before you started the containerroot:root
)To make sure the bind-mounted directory has the correct permissions;
Inside the container, find out the UID/GID of the
www-data
user;Exit the container, and remove the compose stack;
Create the host-directory, and change its permissions;
Start your docker compose stack
And you'll see that the permissions/ownership matches what's on the host;
Specific to logging
Having explained the permissions issue above, your question is also around _logging_. When using containers, the recommended approach is to have your container's process not log to _files_, but to
stdout
andstderr
, and use Docker's logging drivers to capture the logs.If you look at the Dockerfile for the httpd image, you'll find these lines;
These lines configure Apache to send logs to
/proc/self/fd/1
and/proc/self/fs/2
, which arestdout
andstderr
. This means that logs are not sent to a file.If you run a httpd (Apache) container, the output of
stdout
andstderr
are caught by Docker's logging driver, and you can view those logs using thedocker container logs
command (or, with Docker Compose;docker-compose logs <service name>
)This means that you should _not_ create a volume for that directory, but have docker handle the logs.
More information on logging can be found in the userguide; https://docs.docker.com/engine/admin/logging/view_container_logs/