How to install multiple packages using apt-get via a Dockerfile - docker

So I am trying to make a basic Dockerfile, but when I run this it says
The command bin/sh -c sudo apt-get install git python-yaml python-jinja2 returned a non-zero code: 1
My question is what am I doing wrong here, and is it even allowed to do commands like 'cd' and 'source' from the Dockerfile?
FROM Ubuntu
MAINTAINER example
#install and source ansible
RUN sudo apt-get update
RUN sudo apt-get install git python-yaml python-jinja2 python-pycurl
RUN sudo git clone https://github.com/ansible/ansible.git
RUN sudo cd ansible
RUN sudo source ./hacking/env-setup

Couple of pointers / comments here:
It's ubuntu not Ubuntu
From base ubuntu (and unfortunately, a lot of images) you don't need to use sudo, the default user is root (and in ubuntu, sudo is not included anyway)
You want your apt-get update and apt-get install to be RUN as part of the same command, to prevent issues with Docker's layer cache
You need to use the -y flag to apt-get install as the Docker build process runs non-interactively
Few other points I could make about clearing up your apt-cache and other non-required artifacts after running the commands, but this should be enough to get going on
New Dockerfile (taking into account the above) would look something like:
FROM ubuntu
MAINTAINER example
#install and source ansible
RUN apt-get update && apt-get install -y \
git \
python-yaml \
python-jinja2 \
python-pycurl
RUN git clone https://github.com/ansible/ansible.git
WORKDIR ansible/hacking
RUN chmod +x env-setup; sync \
&& ./env-setup
You might also find it useful to read the Dockerfile best practises.
Edit: Larsks answer also makes some useful points about the state of the container not persisting between layers so you should go upvote him too!

When building an image you're already running as root. You don't need sudo and there's a good chance it's not installed.
Along similar lines, this will never work:
RUN sudo cd ansible
The cd command only affects the current process; this would run cd and then exit, leaving you in the same directory you started in. The Docker WORKDIR directive can be used to persistently change the working directory:
WORKDIR ansible
You can also pass a series of shell commands to the RUN directive, like this:
RUN cd ansible; source ./hacking/env-setup
But even that probably won't do what you want, because like the sudo cd ... command earlier, that would modify your environment...and then exit, leaving the current environment unchanged in any subsequent commands.
If you want to run Ansible in a container, you should probably either install it, or plan to run the env-setup script manually after starting a container from the image.

Related

Where can I find cron logs in Debian 11 by Docker

I am using a Debian 11 container in which I have installed cron tool. I am using a custom Dockerfile:
FROM debian:11-slim
RUN apt-get update && \
apt-get upgrade --yes && \
apt-get install --no-install-recommends cron -y && \
apt-get install --no-install-recommends python3 -y && \
apt install --no-install-recommends python3-pip -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
RUN service cron start
I am starting the cron service, it seems to be ok but no crontab schedule will be executed. Where can I find the cron logs? I have no /var/log/syslog
The problem with your Dockerfile above is that you put the service cron start with the RUN directive. This directive specify that the command will only run on the Dockerfile build step, not when you are executing the built image. To understand the difference between RUN, CMD, EXEC directives of docker, refer to this link.
A very simple way of collecting log from cron, which makes use of the Docker's log collecting capability is to redirect the output of cron scripts to stdout. Here is a gist that contains the solution. Basically there is two part of the solution
Specify the cron process as the entrypoint of the docker image.
Make changes to the crontab file to redirect the output of cron jobs to stdout of the main cron process.
This gist is written for the Ubuntu image, so it should work or require little modification on Debian image. However, if your ultimate goal is to run cron in your image, I recommend using alpine. See stackoverflow answer for more information for this approach.

issue in creating docker image from docker file

Created a Docker file in oreder to install Tomcat server from Unix as bashe os
My Dockerfile:
FROM ubuntu
RUN apt-get update && apt-get upgrade -y #to update os
RUN apt-get dist-upgrade
RUN apt-get install build-essential
RUN apt-get install openjdk-8-jdk # to install java 8
RUN apt-get wget -y #to install wget package
RUN apt-get wget https://mirrors.estointernet.in/apache/tomcat/tomcat-9/v9.0.37/bin/apache-tomcat-9.0.37.tar.gz #to download tomcat
RUN tar -xvzf apache-tomcat-9.0.37 # unzipping the tomcat
RUN mkdir tomcat # craeting tomacat directory
RUN cp apache-tomcat-9.0.37/* tomcat # copying tomact files to tomact directory
Command to create Docker Image from Docker file:
docker build -t [img name] -f [file name] .
On execution, while installing java package am getting like this:
'''After this operation, 242 MB of additional disk space will be used.
Do you want to continue? [Y/n] Y'''
You are getting the prompt because the command is awaiting user input for whether or not to install a package. The -y flag you're using for a few of them (like wget) allows bash to assume a yes. Add this flag to all your installation commands.
By the way, there's quite a few potential issues with the Dockerfile you posted.
For example, you have RUN apt-get wget ...
Are you sure that is what you want to do, and not just RUN wget ...? Unless wget is a command that apt-get takes, which it isn't, it will cause unexpected behavior.
You also seem to be missing the command to start the Tomcat server, which can make it so that nothing happens when you attempt to run the image.
I think you should add DEBIAN_FRONTEND=noninteractive when running the apt-get commands, something like this:
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install build-essential -y
Also, it's considered bad practice to use multiple RUN steps which could be consolidated into one. More about Dockerfile best practices can be found here.

Jenkins not starting in docker (Dockerfile included)

I am attempting to build a simple app with Jenkins in a docker container. I have the following Dockerfile:
FROM ubuntu:trusty
# Install dependencies for Flask app.
RUN sudo apt-get update
RUN sudo apt-get install -y vim
RUN sudo apt-get install -y curl
RUN sudo apt-get install -y python3-pip
RUN pip3 install flask
# Install dependencies for Jenkins (Java).
# Install Java 1.8.
RUN sudo apt-get install -y python-software-properties debconf-utils
RUN sudo apt-get install -y software-properties-common
RUN sudo add-apt-repository -y ppa:webupd8team/java
RUN sudo apt-get update
RUN echo "oracle-java8-installer shared/accepted-oracle-license-v1-1 select true" | sudo debconf-set-selections
RUN sudo apt-get install -y oracle-java8-installer
# Install, start Jenkins.
RUN sudo apt-get install -y wget
RUN wget -q -O - https://pkg.jenkins.io/debian/jenkins-ci.org.key | apt-key add -
RUN echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list
RUN sudo apt-get update
RUN sudo apt-get install -y jenkins
RUN sudo /etc/init.d/jenkins start
COPY ./app /app
CMD ["python3","/app/main.py"]
I run this container with the following:
docker build -t jenkins_test .
docker run --name jenkins_test_container -tid -p 5000:5000 -p 8080:8080 jenkins_test:latest
I am able to start flask and install Jenkins, however, when running, Jenkins is not running. curl localhost:8080 is not successful.
In the log output, I am able to see:
Correct java version found
* Starting Jenkins Automation Server jenkins [ OK ]
However, it's still not running.
I can ssh into the container and manually run sudo /etc/init.d/jenkins start to start it, but I want it to start on docker run or docker build.
I have also tried putting sudo /etc/init.d/jenkins start in the CMD portion of the Docker file:
CMD python3 /app/main.py; sudo /etc/init.d/jenkins start
With this, I am able to curl Flask, but still not Jenkins.
How can I get Jenkins to start automatically?
You have some points that you need to be aware of:
No need to use sudo as the default user is root already.
In order to run multiple service in the same container you need to use any kind of service manager like Supervisord. Jenkins is not running because the CMD is the main entry point for your container so only flask should be running. Check the following link in order to know how to start multiple service in docker.
RUN will be executed only during the build process unlike CMD which will be executed each time you start a container from that image.
Combine all the RUN lines together as possible in order to minimize the build layers which lead to a smaller docker image.
Regarding the usage of this:
CMD python3 /app/main.py; sudo /etc/init.d/jenkins start
It does not work for you because this command python3 /app/main.py is not running as a background process so this command sudo /etc/init.d/jenkins start wont run until the previous command is done.
I was only able to get this to work by starting Jenkins in the CMD portion, but needed to start Jenkins before Flask since Flask would continuously run and the next command would never execute:
Did not work:
CMD python3 /app/main.py; sudo /etc/init.d/jenkins start
This did work:
CMD sudo /etc/init.d/jenkins start; python3 /app/main.py
EDIT:
I believe putting it in the RUN portion would not work because container would build but not save the any running services. I'm not sure if containers can be saved and loaded with running processes like that but I might be wrong. Would appreciate clarification if so.
It seems like a thing that should be in RUN so if anyone knows why that didn't work or some best practices, would also appreciate the info.

Use STDIN during docker build from a Dockerfile

I'm trying to install Miniconda in a docker image as a first step, right now this is what I have:
FROM ubuntu:14.04
RUN apt-get update && apt-get install wget
RUN wget *miniconda download URL* && bash file_downloaded.sh
When I try to build the image, it goes well until it starts popping the following message continously:
>>> Please answer 'yes' or 'no'
At that point I need to stop docker build. How can I fix it? Should I include something in the dockerfile?
You can't attach interactive tty during image build. If it is asking for 'yes' or 'no' during package installation, wget in your case, you can replace the corresponding line with RUN apt-get update -qq && apt-get install -y wget. If it is bash file_downloaded.sh, check if file_downloaded.sh accepts 'yes' or 'no' as a command line argument.
If file_downloaded.sh doesn't have that option, create a container from ubuntu:14.04 image, install wget and run your commands manually there. Then, you can make an image of the container by committing your changes like: docker commit <cotainer_id> <image_name>.
I believe you can pass -b flag to miniconda shell script to avoid manual answering
Installs Miniconda3 4.0.5
-b run install in batch mode (without manual intervention),
it is expected the license terms are agreed upon
-f no error if install prefix already exists
-h print this help message and exit
-p PREFIX install prefix, defaults to $PREFIX
something like that:
RUN wget http://......-x86_64.sh -O miniconda.sh
RUN chmod +x miniconda.sh \
&& bash ./miniconda.sh -b

How to make sure commands are not repeated in docker

I am learning about build image using docker file.
short description of what I have done
step 1
For making testing I have started on build image using below docker file
FROM centos:6.8
MAINTAINER Bilal Usean "xxxxx#xxx.xxx"
RUN yum install -y httpd; yum -y clean all
after that I have run the below command
docker build -t httpd/centos:6.8 .
it is successfully install apache in httpd/centos:6.8 image
step 2
Next I am trying to install jdk in the same existing newly created image
FROM centos:6.8
MAINTAINER Bilal Usean "xxxxxx#xxx#xx"
RUN yum install -y httpd; yum -y clean all
yum install java-1.6.0-openjdk-devel; yum -y clean all
after that I have run the below command
docker build -t httpd/centos:6.8 .
But It will start from again httpd install, I expected it will skip that httpd step for already install.
I think it is not a good practice to make docker file.I have 20 RUN command in docker file, that is download heavy size file from net so I want to make sure about it each command success. otherwise it will fail intermediately and again it will charge more MB.
note: If I am in the wrong way, please describe the best way to deal with image and docker file.
It repeats here because you did not add another RUN command, but appended (and changed) the previous command (docker detects this change, and runs the new command).
What you should be writing is:
FROM centos:6.8
MAINTAINER Bilal Usean "xxxxxxxx#xxx.xxx"
RUN yum install -y httpd; yum -y clean all
RUN yum install java-1.6.0-openjdk-devel; yum -y clean all

Resources