Add bash to Docker image [duplicate] - bash

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.

Related

Attempting to use a volume in my docker container (windows) and when I run docker run it does not appear to work

A simple bash script whereby a user can search through a folder and organise their files by type. For this I need to give my container access to my C drive and navigate to the right directory where the code is executed and where the folders are.
Since it s windows I know I need to use winpty and use \ rather than / when navigating.
winpty docker run -it -v basic-vol:/C:\Users\XYZ\dev\repos\filefind filefind:latest
I am not sure why this is not working. Here is my Dockerfile too:
FROM ubuntu
RUN chmod 700 .
WORKDIR /app
COPY . .
VOLUME [ "/c/Users/XYZ/dev/repos/"]
#when conatiner starts what is the executable
ENTRYPOINT ["/bin/bash", "file-find.sh"]
Would love your help here folks

Where should I put input file in docker environment?

I am a newbie in Docker. I introduced the Docker environment in WSL2 (Windows10Home). I do not wish to use the VSCode for simpler implementation. I would like to rather use the Ubuntu terminal. When I try to compile my LaTeX file (my_input.tex) with a Docker image (https://hub.docker.com/r/weichuntsai/texlive-small), but it complains that there is no such a tex file.
docker run --name mylatex -dt -v /home/myname:/home weichuntsai/texlive-small:1.1.0
When I send the following command in the terminal, he complains of no corresponding file.
txrun my_input.tex xelex, although I created this tex file in the home
(~, or home/myname) directory.
Sending ls returns tex.mf only without showing my_input.tex unfortunately.
Sending pwd returns root with some reasons. I have no idea why it returns root, not home/myname.
It may be due to my insufficient understanding of Docker, but I appreciate your kind advice on
that question.
N.B. I became to know that Docker images are located in /var/lib/docker.
To change this directory, one must stop the Docker daemon with
sudo service docker stop. Then one must edit /etc/docker/daemon.json.
{
"data-root": "/to/some/path"
}
Checking Dockerfile of your image shows that working directory is root https://hub.docker.com/r/weichuntsai/texlive-small/dockerfile
Just mount your home to container root:
docker run --name mylatex -dt -v /home/myname:/root weichuntsai/texlive-small:1.1.0
OR inside container change to home by cd /home
Checking Dockerfile of your image shows that working directory is root https://hub.docker.com/r/weichuntsai/texlive-small/dockerfile
Just mount your home to container root:
docker run --name mylatex -dt -v "/home/me":"/file" weichuntsai/texlive-small:1.1.0
OR inside container change to home by cd /home
and then you access your file like
docker exec -it mylatex bash
cd /file
ls

Permission Denied for cp command on Bitnami Nginx Docker Image

I want to serve a static website using Bitnami's Nginx base image. I have a multi-stage Dockerfile as follows:
# build stage
FROM node:lts-alpine as build-stage
COPY ./ /app
WORKDIR /app
COPY .npmrc .npmrc
RUN npm install && npm run build
# Production stage
FROM bitnami/nginx:1.16 as production-stage
COPY --from=build-stage --chown=1001 /app/dist /app
COPY nginx.conf /opt/bitnami/nginx/conf/nginx.conf
COPY --chown=1001 entrypoint.sh /
RUN chmod +w /entrypoint.sh
CMD ["/entrypoint.sh"]
I use that entrypoint.sh to replace some file content with environment variables like:
#!/bin/bash
function join_by { local IFS="$1"; shift; echo "$*"; }
vars=$(env | grep VUE_APP_ | awk -F = '{print "$"$1}')
vars=$(join_by ' ' $vars)
for file in /app/js/app.*;
do
### T H I S L I N E T H R O W S E R R O R ###
cp $file $file.tmpl
envsubst "$vars" < $file.tmpl > $file
rm $file.tmpl
done
exec "$#"
On cp command it throws an error:
cp: cannot create regular file '/app/js/app.042ea3b0.js.tmpl': Permission denied
As you see, I have copied both the dist files and the entrypoint.sh with --chown=1001 (The default user in the Bitnami image), but no benefits.
Is it because the image folder app is exposed by a volume by default? How can I copy and modify that file I have moved into the image?
P.S: It runs in an OpenShift environment.
The Bitnami image performs some actions in the postunpack.sh script, this script is called from the Dokerfile. One of the actions perfomed by the script is related to configure the permissions due to the user running nginx is a non-root user. You can try implementing something similar with your needs.
It turned out to be a result of Openshift's behavior stated here:
How can I enable an image to run as a set user ID?:
When an application is deployed it will run as a user ID unique to the project it is running in. This overrides the user ID which the application image defines it wants to be run as.
...
The best solution is to build the application image so it can be run as an arbitrary user ID.
So, instead of copying the files and modifying the owner of them (chown), the access levels (chmod) of the files must be set appropriately.

executable file not found in $PATH Dockerfile

I am building a Dockerfile for an application. I want to execute a bash script with parameters when the container starts to run, so I have made it an entry point. However, Docker cannot find the directory in which my script is located. Thi script is located in the Intellij Idea project folder and the path practically looks like this: /home/user/Documents/folder1/folder2/folder3/Projectname/runapp.sh
I have tried to mount this directory as volume, but while running built image an error occurred:
docker: Error response from daemon: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: \"runapp.sh\": executable file not found in $PATH": unknown.
What may be the reason of such behavior? How else can I reach this bash script from Dockerfile?
Here is how the Dockerfile looks like:
FROM java:8
ENV SCALA_VERSION 2.11.8
ENV SBT_VERSION 1.1.1
ENV SPARK_VERSION 2.2.0
ENV SPARK_DIST spark-$SPARK_VERSION-bin-hadoop2.6
ENV SPARK_ARCH $SPARK_DIST.tgz
ENV NEO4J_CONFIG default
ENV BENCHMARK_NAME default
WORKDIR /opt
# Install Scala
RUN \
cd /root && \
curl -o scala-$SCALA_VERSION.tgz http://downloads.typesafe.com/scala/$SCALA_VERSION/scala-$SCALA_VERSION.tgz && \
tar -xf scala-$SCALA_VERSION.tgz && \
rm scala-$SCALA_VERSION.tgz && \
echo >> /root/.bashrc && \
echo 'export PATH=~/scala-$SCALA_VERSION/bin:$PATH' >> /root/.bashrc
# Install SBT
RUN \
curl -L -o sbt-$SBT_VERSION.deb https://dl.bintray.com/sbt/debian/sbt-$SBT_VERSION.deb && \
dpkg -i sbt-$SBT_VERSION.deb && \
rm sbt-$SBT_VERSION.deb
# Install Spark
RUN \
cd /opt && \
curl -o $SPARK_ARCH http://d3kbcqa49mib13.cloudfront.net/$SPARK_ARCH && \
tar xvfz $SPARK_ARCH && \
rm $SPARK_ARCH && \
echo 'export PATH=$SPARK_DIST/bin:$PATH' >> /root/.bashrc
EXPOSE 9851 9852 4040 7474 7687 7473
VOLUME /home/user/Documents/folder1/folder2/folder3/Projectname /workdir1
WORKDIR /workdir1
ENTRYPOINT ["runapp.sh"]
CMD ["$NEO4J_CONFIG", "$BENCHMARK_NAME"]
You misunderstood volumes in Docker I think. (see What is the purpose of VOLUME in Dockerfile)
I'm citing #VonC answer:
A volume is a persistent data stored in /var/lib/docker/volumes/...
You can either declare it in a Dockerfile, which means each time a container is stated from the image, the volume is created (empty), even if you don't have any -v option.
You can declare it on runtime docker run -v [host-dir:]container-dir.
combining the two (VOLUME + docker run -v) means that you can mount the content of a host folder into your volume persisted by the container in /var/lib/docker/volumes/....
docker volume create creates a volume without having to define a Dockerfile and build an image and run a container. It is used to quickly allow other containers to mount said volume.
So you should use docker run -v /home/user/Documents/folder1/folder2/folder3/Projectname:/workdir1 when starting the container
And your Dockerfile volume declaration should be:
VOLUME /workdir1
That being said, you define both Entrypoint and CMD. What is the CMD being for ? You will never use your image without using runapp.sh ? I prefer using only CMD for development since you can still do docker run -it my_container bash for debugging purpose with this syntax.
This time I'm using #Daishi answer from What is the difference between CMD and ENTRYPOINT in a Dockerfile?
The ENTRYPOINT specifies a command that will always be executed when the container starts.
The CMD specifies arguments that will be fed to the ENTRYPOINT.
If you want to make an image dedicated to a specific command you will use ENTRYPOINT ["/path/dedicated_command"]
Otherwise, if you want to make an image for general purpose, you can leave ENTRYPOINT unspecified and use CMD ["/path/dedicated_command"] as you will be able to override the setting by supplying arguments to docker run
Moreover, runapp.sh isn't in your $PATH and you call it without absolute path, so it will not find the file even if the volume is mounted correctly.
You could just use:
CMD /workdir1/runapp.sh "$NEO4J_CONFIG" "$BENCHMARK_NAME"
Now be careful, on your host you mention that the shell script is named script.sh and you call runapp.sh in your Dockerfile, I hope it's a typo. By the way your script needs to be executable.

Default user for files and directories created in bash under sudo

I'm writing a bash script that creates directories and copy files under Mac OSX. Some of these directories and files need to be placed in folders owned by the system such as /Library/Audio/Plug-Ins, and so I run the script under sudo. Such script might look like:
copy-plugins.sh:
#!/usr/bin/env bash
mkdir -p /Library/Audio/Plug-Ins/My-Plugins
cp plugin-A.dylib /Library/Audio/Plug-Ins/My-Plugins
cp plugin-B.dylib /Library/Audio/Plug-Ins/My-Plugins
and called:
$ sudo ./copy-plugins.sh
However when running under sudo, all created directories and copied files are owned by root.
I would like to be able to run the script under sudo and have the files be owned by my user.
I could call chown after each file/directory is created or copied
copy-plugins-cumbersome.sh:
#!/usr/bin/env bash
mkdir -p /Library/Audio/Plug-Ins/My-Plugins
chown 501:501 /Library/Audio/Plug-Ins/My-Plugins
cp plugin-A.dylib /Library/Audio/Plug-Ins/My-Plugins
chown 501:501 /Library/Audio/Plug-Ins/My-Plugins/plugin-A.dylib
cp plugin-B.dylib /Library/Audio/Plug-Ins/My-Plugins
chown 501:501 /Library/Audio/Plug-Ins/My-Plugins/plugin-B.dylib
but I'm hoping for a more general solution.
As far as I can tell there is no setuid for bash.
Use cp -p option to preserve file attributes.
Note this will preserve user, group permissions and the modification and access times of the files.
As you need sudo to copy to the directories you are copying to in script, it means you need to be root to copy anything in those directories.
When you do sudo you are root for that particular command or script, so whatever will be created or executed will have root permissions. Till the time you specify.
The possible ways to come out of it without changing anything:
The one you are using, and
Other one to use -p or -a with cp
rsync -go <source file> <destination file>
-g for preserving group and
-o for preserving ownership.
Note If you do a chown out of script, you will have to specifically do sudo chown since files you would be touching belong to root.

Resources