Dockerfile mkdir permission denied - bash

I am trying to build the image with:
docker build -t db-demo .
But i get
RUN mkdir -p /usr/src/app:
#5 0.512 mkdir: cannot create directory '/usr/src/app': Permission denied
The Dockerfile
FROM mcr.microsoft.com/mssql/server
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY . /usr/src/app
RUN chmod +x /usr/src/app/run-initialization.sh
ENV SA_PASSWORD bpassword
ENV ACCEPT_EULA Y
ENV MSSQL_PID Express
EXPOSE 1433
CMD /bin/bash ./entrypoint.sh
The OS is Windows.How to fix this?

If we start the mssql container with an interactive shell:
docker run -it --rm mcr.microsoft.com/mssql/server /bin/bash
and then look at the active user within the container:
mssql#ed73727870bb:/$ whoami
mssql
we see that the active user is mssql. Furthermore, if we look at the permissions for /usr/src inside the container:
mssql#ed73727870bb:/$ ls -lisa /usr | grep -i src
163853 4 drwxr-xr-x 2 root root 4096 Apr 15 2020 src
we see that only root has write-access to directory /usr/src.
Thus, if we want to create a directory /usr/src/app, so that user mssql can write to it, we will have to
create it as root and
grant the appropriate permissions to mssql.
This leads to the following Dockerfile:
FROM mcr.microsoft.com/mssql/server
# change active user to root
USER root
# create the app directory
RUN mkdir -p /usr/src/app
# set mssql as owner of the app directory
RUN chown mssql /usr/src/app
# change back to user mssql
USER mssql
WORKDIR /usr/src/app
# sanity check: try to write a file
RUN echo "Hello from user mssql" > hello.txt
if we build and run this Dockerfile:
docker build -t turing85/my-mssql -f Dockerfile .
docker run -it --rm turing85/my-mssql /bin/bash
We can now see that:
the active user is still mssql:
mssql#85e401ccc3f9:/usr/src/app$ whoami
mssql
a file /usr/src/app/hello.txt has been created, and user mssql has read-access:
mssql#85e401ccc3f9:/usr/src/app$ cat hello.txt
Hello from user mssql
user mssql has write-access to /usr/src/app:
mssql#85e401ccc3f9:/usr/src/app$ touch test.txt && ls -lisa
total 16
171538 4 drwxr-xr-x 1 mssql root 4096 Nov 6 20:13 .
171537 8 drwxr-xr-x 1 root root 4096 Nov 6 20:02 ..
171539 4 -rw-r--r-- 1 mssql root 17 Nov 6 20:02 hello.txt
171604 0 -rw-r--r-- 1 mssql root 0 Nov 6 20:13 test.txt
user mssql has no write-access to /usr/src:
mssql#85e401ccc3f9:/usr/src/app$ touch ../test2.txt
touch: cannot touch '../test2.txt': Permission denied
A comment on the Dockerfile in the post:
It seems that we try to copy an application into the mssql container. I assume this is done to start said application within the mssql container. While this is possible (with some configuration), I strongly advice against this approach. We could instead define two containers (one for the database, one for the application), e.g. through a docker-compose file.

WORKDIR creates the named directory if it doesn't exist. If your only permission problem is while trying to create the directory, you can remove the RUN mkdir line and let Docker create the directory for you.
FROM any-base-image
# Docker creates the directory if it does not exist
# You do not need to explicitly RUN mkdir
WORKDIR /usr/src/app
...
Looking further at this example, the RUN chmod ... line might also fail if the base image has a non-root user that can't access a root-owned directory. COPY will also copy the permissions from the host, so if the file is executable in the host environment you would not need to explicitly chmod +x it after it is COPYed in. That would let you delete all of the RUN lines; you'd be left with COPY and ENV instructions and runtime metadata, none of which should encounter permission problems.

Related

Add bash to Docker image [duplicate]

Seems like a basic issue but couldnt find any answers so far ..
When using ADD / COPY in Dockerfile and running the image on linux, the default file permission of the file copied in the image is 644. The onwner of this file seems to be as 'root'
However, when running the image, a non-root user starts the container and any file thus copied with 644 permission cannot execute this copied/added file and if the file is executed at ENTRYPOINT it fails to start with permission denied error.
I read in one of the posts that COPY/ADD after Docker 1.17.0+ allows chown but in my case i dont know who will be the non-root user starting so i cannot set the permission as that user.
I also saw another work around to ADD/COPY files to a different location and use RUN to copy them from the temp location to actual folder like what am doing below. But this approach doesnt work as the final image doesnt have the files in /otp/scm
#Installing Bitbucket and setting variables
WORKDIR /tmp
ADD atlassian-bitbucket-${BITBUCKET_VERSION}.tar.gz .
COPY bbconfigupdater.sh .
#Copying Entrypoint script which will get executed when container starts
WORKDIR /tmp
COPY entrypoint.sh .
RUN ls -lrth /tmp
WORKDIR /opt/scm
RUN pwd && cp /tmp/bbconfigupdater.sh /opt/scm \
&& cp /tmp/entrypoint.sh /opt/scm \
&& cp -r /tmp/atlassian-bitbucket-${BITBUCKET_VERSION} /opt/scm \
&& chgrp -R 0 /opt/ \
&& chmod -R 755 /opt/ \
&& chgrp -R 0 /scm/bitbucket \
&& chmod -R 755 /scm/bitbucket \
&& ls -lrth /opt/scm && ls -lrth /scmdata
Any help is appreciated to figure out how i can get my entrypoint script copied to the desired path with execute permissions set.
The default file permission is whatever the file permission is in your build context from where you copy the file. If you control the source, then it's best to fix the permissions there to avoid a copy-on-write operation. Otherwise, if you cannot guarantee the system building the image will have the execute bit set on the files, a chmod after the copy operation will fix the permission. E.g.
COPY entrypoint.sh .
RUN chmod +x entrypoint.sh
A better option with newer versions of docker (and which didn't exist when this answer was first posted) is to use the --chmod flag (the permissions must be specified in octal at last check):
COPY --chmod=0755 entrypoint.sh .
You do not need to know who will run the container. The user inside the container is typically configured by the image creator (using USER) and doesn't depend on the user running the container from the docker host. When the user runs the container, they send a request to the docker API which does not track the calling user id.
The only time I've seen the host user matter is if you have a host volume and want to avoid permission issues. If that's your scenario, I often start the entrypoint as root, run a script called fix-perms to align the container uid with the host volume uid, and then run gosu to switch from root back to the container user.
A --chmod flag was added to ADD and COPY instructions in Docker CE 20.10. So you can now do.
COPY --chmod=0755 entrypoint.sh .
To be able to use it you need to enable BuildKit.
# enable buildkit for docker
DOCKER_BUILDKIT=1
# enable buildkit for docker-compose
COMPOSE_DOCKER_CLI_BUILD=1
Note: It seems to not be documented at this time, see this issue.

How To Docker Copy to user root ~

I'm writing a Dockerfile to run ROS on my Windows rig and I can't seem to get this COPY command to copy to the container's user root or any sub directory there. I've tried a few things, including messing with the ownership. I know file is ugly but still learning. Not really sure what the issue is here.
This file sits next to a /repos dir which has a git repo within it which can be found here (the ros-noetic branch). This is also the location from which I build and run the container from.
Overall objective is to get roscore to run (which it has been), then exec in with another terminal and get rosrun ros_essentials_cpp (node name) to actually work
# ros-noetic with other stuff added
FROM osrf/ros:noetic-desktop-full
SHELL ["/bin/bash", "-c"]
RUN apt update
RUN apt install -y git
RUN apt-get update && apt-get -y install cmake protobuf-compiler
RUN bash
RUN . /opt/ros/noetic/setup.bash && mkdir -p ~/catkin_ws/src && cd ~/catkin_ws/ && chmod 777 src && catkin_make && . devel/setup.bash
RUN cd /
RUN mkdir /repos
COPY /repos ~/catkin_ws/src
RUN echo ". /opt/ros/noetic/setup.bash" >> ~/.bashrc
Expanding tilde to home directory is a shell feature, which apparently isn't supported in Dockerfile's COPY command. You're putting the files into a directory which is literally named ~, i.e. your container image probably contains something like this:
...
dr-xr-xr-x 13 root root 0 Jun 9 00:07 sys
drwxrwxrwt 7 root root 4096 Nov 13 2020 tmp
drwxr-xr-x 13 root root 4096 Nov 13 2020 usr
drwxr-xr-x 18 root root 4096 Nov 13 2020 var
drwxr-xr-x 2 root root 4096 Jun 9 00:07 ~ <--- !!!
Since root's home directory is always /root, you can use this:
COPY /repos /root/catkin_ws/src
You need to pay attention on the docker context.
When you build docker, you are adding the path to build your image.
If you are not on the / folder, your COPY /repos command won't work.
Try to change the docker context with that:
docker build /

Cannot map a host directory with spaces to a container directory (bind mounts) - Docker Quickstart Terminal (Bash), windows 10

I am a newbie with Docker. I am following a tutorial in which I am using bind mounts and volumes, I am using windows 10 Docker quickstart terminal (bash) and Docker 19.03.1.
I am in the directory .../dockerfile-sample-2 (Note: this path contains spaces) containing:
$ ls -al
total 18
drwxr-xr-x 1 Tommaso 197121 0 mag 10 11:55 ./
drwxr-xr-x 1 Tommaso 197121 0 mag 1 19:20 ../
-rw-r--r-- 1 Tommaso 197121 410 apr 11 09:06 Dockerfile
-rw-r--r-- 1 Tommaso 197121 249 apr 11 09:06 index.html
-rw-r--r-- 1 Tommaso 197121 0 mag 10 11:55 testme.txt
Now I run and get the followings:
.../dockerfile-sample-2
$ docker container run -d --name nginx -p 80:80 -v $(pwd):/usr/share/nginx/html nginx
b8f24ee0e0b76d0b06503ce90fbd6a9e2110e40eaa4432e8c77556510c61a989
.../dockerfile-sample-2
$ docker container run -d --name nginx2 -p 8080:80 nginx
3450433e18097291936d7e62071769521eb36e92f509ad931c9e927f135df71a
Now, according to the tutorial, by accessing the IP addresses http://192.168.99.101/ and http://192.168.99.101:8080, I should be able to see, respectiverly, a custom landing page from the index.html file and the original nginx landing page.
However, I only get the original nginx landing page twice.
And more, according to my tutorial, by running
docker container exec -it nginx bash
cd /usr/share/nginx/html
ls –al
I should get the same content of the previous directory .../dockerfile-sample-2.
However, I only get
root#b8f24ee0e0b7:/usr/share/nginx/html# ls -al
total 16
drwxr-xr-x 2 root root 4096 Apr 13 19:20 .
drwxr-xr-x 3 root root 4096 Apr 13 19:20 ..
-rw-r--r-- 1 root root 494 Apr 13 15:13 50x.html
-rw-r--r-- 1 root root 612 Apr 13 15:13 index.html
and again, according to my tutorial, if I'd make a new file in my .../dockerfile-sample-2 directory, it should appear among the results of
docker container exec -it nginx bash
cd /usr/share/nginx/html
ls –al
but it does not.
What am I doing wrong?
Here you have some context:
My running containers:
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3450433e1809 nginx "/docker-entrypoint.…" 20 minutes ago Up 20 minutes 0.0.0.0:8080->80/tcp nginx2
b8f24ee0e0b7 nginx "/docker-entrypoint.…" 21 minutes ago Up 21 minutes 0.0.0.0:80->80/tcp nginx
In my Dockerfile:
# this shows how we can extend/change an existing official image from Docker Hub
FROM nginx:latest
# highly recommend you always pin versions for anything beyond dev/learn
WORKDIR /usr/share/nginx/html
# change working directory to root of nginx webhost
# using WORKDIR is preferred to using 'RUN cd /some/path'
COPY index.html index.html
# I don't have to specify EXPOSE or CMD because they're in my FROM
In my Index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Your 2nd Dockerfile worked!</title>
</head>
<body>
<h1>You just successfully ran a container with a custom file copied into the image at build time!</h1>
</body>
</html>
UPDATE:
I bet the problem is related to the fact that the current working directory contains spaces.
So I removed the nginx container and tryed run other ones.
The following commands:
docker container run -d --name nginx -p 80:80 -v "$(pwd)":/usr/share/nginx/html nginx
docker container run -d --name nginx -p 80:80 -v "/d/Files Tommaso/Programmazione/Docker/udemy-docker-mastery-main/dockerfile-sample-2:/usr/share/nginx/html" nginx
docker container run -d --name nginx -p 80:80 -v "/d/Files Tommaso/Programmazione/Docker/udemy-docker-mastery-main/dockerfile-sample-2":/usr/share/nginx/html nginx
as I try to access http://192.168.99.101/, make my browser get 403 Forbidden.
while these other commands:
docker container run -d --name nginx -p 80:80 -v $(pwd):/usr/share/nginx/html nginx
docker container run -d --name nginx -p 80:80 -v /$(pwd):/usr/share/nginx/html nginx
docker container run -d --name nginx -p 80:80 -v `pwd -W`:/usr/share/nginx/html nginx
docker container run -d --name nginx -p 80:80 -v $(pwd):/usr/share/nginx/html nginx
docker container run -d --name nginx -p 80:80 -v /d/Files Tommaso/Programmazione/Docker/udemy-docker-mastery-main/dockerfile-sample-2:/usr/share/nginx/html nginx
make my terminal respond with:
C:\Applicazioni_Tommaso\Docker Toolbox\docker.exe: invalid reference format: repository name must be lowercase.
See 'C:\Applicazioni_Tommaso\Docker Toolbox\docker.exe run --help'.
I bet this means it cannot parse spaces.
and these other commands:
docker container run -d --name nginx -p 80:80 -v %cd%:/usr/share/nginx/html nginx
make my terminal respond with:
C:\Applicazioni_Tommaso\Docker Toolbox\docker.exe: Error response from daemon: create YYYY: "YYYY" includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed. If you intended to pass a host directory, use absolute path.
Using --mount will solve the issue
docker container run -d --name nginx -p 80:80 --mount type=bind,source="$(pwd)",destination=/usr/share/nginx/html nginx
After several attempts I can assume that
on windows 10
using Docker Quickstart Terminal
Docker 19.03.1 cannot manage the use of <path containing spaces> inside -v parameter
docker container run -d --name <name> -p 80:80 -v <path containing spaces>:<destination path> <image>
The only way I found to solve this problem is to change the source volume directory to a directory in which no folder contains spaces, and running
docker container run -d --name nginx -p 80:80 -v $(pwd):/usr/share/nginx/html nginx
I ran into pretty much the same problem (given assumptions of spacing in directory causing problems) when binding directory:volume using -v.
Context: running an aws lambda function deployment package build task container using lambci/lambda:build-python3.8 image, utilising files in windowspath\build.
The following command worked for me, in the sense that files in windowspath\build were recognised and used for the following /bin/sh -c commands; therefore binding to /var/task worked as intended.
Note: after -v flag, double quotes only for the source directory (windows style pathing, supposedly would work for unix style as well), end double quotes before the colon, directory /var/task referred after colon is the docker run environment directory (unix style/WSL backend).
docker run -v "C:\windowspath\build":/var/task "lambci/lambda:build-python3.8" /bin/sh -c "pip install -r requirements.txt -t package/;cd package;zip -r ../deployment_package.zip .;zip -g ../deployment_package.zip ../lambda_function.py"

Simple method to run docker or docker-compose with the same UID/GID as parent user?

When I use docker or docker-compose with volumes I often have issues with permissions as the container user is not known on the host:
mkdir i-can-to-what-i-want
rmdir i-can-to-what-i-want
docker run -v$(pwd):/home -w/home ubuntu touch you-shall-not-delete-it
$ ls -al you-shall-not-delete-it
-rw-r--r-- 2 root root 0 2020-08-08 00:11 you-shall-not-delete-it
One solution is to always do this:
UID=$(id -u) GID=$(id -g) docker-compose up
Or
UID=$(id -u) GID=$(id -g) docker run ...
But... it is cumbersome...
Any other method?
--user will do the job, unless this is the exact cumbersome solution that you are trying to avoid:
who
neo tty7 2020-08-08 04:46 (:0)
docker run --user $UID:$GID -v$(pwd):/home -w/home ubuntu touch you-shall-delete-it
ls -la
total 12
drwxr-xr-x 3 neo neo 4096 Aug 8 02:12 .
drwxr-xr-x 34 neo neo 4096 Aug 8 02:03 ..
drwxr-xr-x 2 neo neo 4096 Aug 8 02:03 i-can-to-what-i-want
-rw-r--r-- 1 neo neo 0 Aug 8 02:12 you-shall-delete-it
In fact you don't use volume here :
docker run -v$(pwd):/home
you use bind mound.
When you use a bind mount, the resource on the host machine is mounted into a container.
Relying on the host machine’s filesystem has advantages (speed and a dynamic data source) but has also its limitations (file ownership and portability).
How I see things :
1)When you use docker-compose in dev and that you need to bind your source code that constantly changes, bind mount is unavoidable but you can simplify things by setting the user/group of the container directly in the compose.
version: '3.5'
services:
app:
user: "${UID}:${GID}"
...
Note that ${UID} and ${GID} are here shell variables.
${UID} is defined in bash, but ${GID} is not. You could export it if required or so use the user id for both : user: "${UID}:${UID}".
2)When you use docker or docker-compose in a frame where you don't need to provide the files/folders from that host at container creation time but that you can do it in the image creation, favor volume (name volume) over bind mount.

docker image run authentication required

Please help me to add credential in docker image. So if some try to enter in image it ask for credential.
Scenario -
Let say I downloaded a ubuntu image from official site, I did some changes and created a new image ubuntu-myapp.
Now no one can enter in ubuntu to copy or change my code. without provided credential
Create a Dockerfile by adding credentials to the root user and change to a different user something like this.
$ cat Dockerfile
FROM ubuntu:16.04
COPY raghu/varibale.py /root
#create password for the root user. echo "USERNAME:NEWPASSWORD" | chpasswd
RUN echo "root:raghu" | chpasswd
#create a different user for public access.
RUN useradd -ms /bin/bash raghu
#change to the new user
USER raghu
Build the docker image from the Dockerfile. This Docker image can be run by anyone but the script can be executable only by the root user.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
auth 2.0 0c15c8ef5594 7 seconds ago 112MB
Let's execute the Docker image and check if the user can access the file without the root password:
$ docker run -it auth:2.0 /bin/bash
raghu#17b003083ff7:/$ ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
raghu#17b003083ff7:/$ cd root
bash: cd: root: Permission denied
raghu#17b003083ff7:/$ su -
Password:
root#17b003083ff7:~# ls
varibale.py
root#17b003083ff7:~# pwd
/root
root#17b003083ff7:~# exit
logout
raghu#17b003083ff7:/$ exit
exit
The file cannot be executed even with privileged option unless provided with root password:
$ docker run -it --privileged auth:2.0 /bin/bash
raghu#3886fb3950f8:/$ ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
raghu#3886fb3950f8:/$ cd root
bash: cd: root: Permission denied
raghu#3886fb3950f8:/$ su -
Password:
root#3886fb3950f8:~# ls
varibale.py
root#3886fb3950f8:~# exit
logout
raghu#3886fb3950f8:/$ exit
exit
Hope this helps.
In your docker file, you need to set root user with password.
echo 'newpassword' |passwd root --stdin
and make sure that all folder just has got root access to modify any content.

Resources