Docker commands require keyboard interaction - docker

I'm trying to create a Docker image for ripping CDs (using abcde).
Here's the relevant portion of the Dockerfile:
FROM ubuntu:17.10
MAINTAINER Graham Nicholls <graham#rockcons.co.uk>
RUN apt update && apt -y install eject vim ruby abcde
...
Unfortunately, the package "abcde" pulls in a mail client (not sure which), and apt tries to configure that by asking what type of mail connection to configure (smarthost/relay etc).
When docker runs, it's not appearing to read from stdin, so I can't redirect into the docker process.
I've tried using --nodeps with apt (and replacing apt with apt-get); unfortunately --nodeps seems no-longer to be a supported option and returns:
E: Command line option --nodeps is not understood in combination with the other options
Someone has suggested using expect in response to a similar question, which I'd rather avoid. This seems to be a "difficult to google" problem - I can't find anything.
So, is there a way of passing in the answer to the config in apt, or of preventing apt from pulling in a mail client, which would be better - I'm not planning in sending updates to cddb.

The typical template to install apt packages in a docker container looks like:
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
eject \
vim \
ruby \
abcde \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
Running it with the "noninteractive" value removes any prompts. You don't want to set that as an ENV since that would also impact any interactive commands you run inside the container.
You also want to cleanup the package database when finished to reduce the layer size and avoid reusing a stale cached package database in a later step.
The no-install-recommends option will reduce the number of packages installed by only installing the required dependencies, not the additional recommended packages. This cuts the size of the root filesystem down by half for me.
If you need to pass a non-default configuration to a package, then use debconf. First run you install somewhere interactively and enter the options you want to save. Install debconf-utils. Then run:
debconf-get-selections | grep "${package_name}"
to view all the options you configured for that package. You can then pipe these options to debconf-set-selections in your container before running your install, e.g.:
RUN echo "postfix postfix/main_mailer_type select No configuration" \
| debconf-set-selections \
&& apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
....
or save your selections to a file that you copy in:
COPY debconf-selections /
RUN debconf-set-selections </debconf-selections \
&& apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
....

Related

Pass arguments to interactive shell in Docker Container

Currently I'm trying to create a Docker image for jitsi-meet.
I installed jitsi-meet on my test system and noticed, that I get prompted for user input. Well, this is absolutely fine, when installing jitsi manually.
However the installation process is supposed to run during the build of the image. Which means there is no way for me to manually type in the necessary data.
Is there any way to pass values as an environment variable in the Dockerfile and use the variable in the container when I get prompted to enter some additional information?
This is how my Dockerfile looks like:
FROM debian:latest
WORKDIR /opt/jitsi-meet
RUN apt-get update -y && \
apt-get upgrade -y && \
apt-get install -y ssh sudo ufw apt-utils apt-transport-https wget gnupg2 && \
wget -qO - https://download.jitsi.org/jitsi-key.gpg.key | sudo apt-key add - && \
sh -c "echo 'deb https://download.jitsi.org stable/' > /etc/apt/sources.list.d/jitsi-stable.list" && \
apt-get -y update && \
apt-get -y install jitsi-meet
EXPOSE 80 443
EXPOSE 10000/udp
Thanks in advance!
Yes you can can set ENV vars in a docker file
using 'ENV', see:
https://docs.docker.com/engine/reference/builder/#environment-replacement
To use it when you got prompted something depends on the implementation
a prompt upon container run, is not really advisable, as interactive container startup doesn't make sense in most cases.
However in bash you might be able to read redirect something to stdin using <
or send it with a pipe(|) to a command.
But how to solve that issue, depends on how it is implemented in the sourcecode
where it prompts.
In general it's best practice to skip the prompt, if an env has been set.

Install RPM package in a pre-built node image

I am writing a Node app I want to containerize using a pre-built node image (https://hub.docker.com/_/node/). I need to deploy application that I only have a RPM package for and I cannot figure out where to start finding documentation or a small example to do this.
The examples I'm looking at use yum, which I don't have (from my understanding) in the pre-built node image.
COPY src/MyApp/lib/3rdPartyApp.x86_64.rpm ./3rdPartyApp.x86_64.rpm
RUN yum localinstall 3rdPartyApp.x86_64.rpm; yum clean all && \
rm ./3rdPartyApp.x86_64.rpm
My other option is to use a CentOS docker image which has yum. But I'm running in to problems getting Node installed there trying to use NVM. But I'm also reading I shouldn't try to use NVM when building a Docker container and there is a better way.
You can use alien to convert packages from one format to another.
FROM node
RUN apt-get update && apt-get install -y alien
COPY src/MyApp/lib/3rdPartyApp.x86_64.rpm ./3rdPartyApp.x86_64.rpm
RUN alien -d -i 3rdPartyApp.x86_64.rpm
This will leave a lot of extra files in your image. You can use two step build to clear it up.
FROM node AS builder
RUN apt-get update && apt-get install -y alien
COPY src/MyApp/lib/3rdPartyApp.x86_64.rpm ./3rdPartyApp.x86_64.rpm
RUN alien -d 3rdPartyApp.x86_64.rpm
FROM node
COPY --from=builder 3rdPartyApp.x86_64.deb .
RUN dpkg -i 3rdPartyApp.x86_64.deb && rm 3rdPartyApp.x86_64.deb
FROM centos:centos7.6.1810
# Enable EPEL to install Node.js and npm
RUN rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm && \
    yum -y update && \
    yum install -y npm git && \
    yum clean all

yum -y install not assuming yes in docker build

I'm trying to simply create a dockerfile that installs wget and unzip on a centOS image. This is the file:
FROM centos:latest
EXPOSE 9000
RUN echo "proxy=http://xxx.xxx.xxx.xxx:x" >> /etc/yum.conf \
&& echo "proxy_username=username" >> /etc/yum.conf \
&& echo "proxy_password=password" >> /etc/yum.conf \
&& yum update \
&& yum -y install wget unzip
...
When I run the build it resolves the dependencies just fine but it doesn't seem to be honoring the -y flag and assuming yes for any prompts:
Total download size: 61 M
Is this ok [y/d/N]: Exiting on user command
Your transaction was saved, rerun it with:
yum load-transaction /tmp/yum_save_tx.2018-08-08.21-22.Q7f8LW.yumtx
The command '/bin/sh -c yum update && yum -y install wget unzip' returned
a non-zero code: 1
I've used the -y flag in this situation many times and have never had any trouble. It doesn't seem like this could be a caching issue but I have no idea what's going on. I also tried yum install -y wget unzip just for good measure but still no luck (as expected). I've searched stackoverflow but it seems like anyone with the same issue just wasn't using the -y flag. Any guidance would be appreciated because I don't know what could be going wrong with such a simple file.
It looks like you're missing the -y on the yum update.
Also, you should split those commands out to separate RUN commands. In this case, it doesn't make too much difference, but splitting the echos onto different lines will make it clearer.
You should keep the update and installs in the same command though
https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run

How to create the smallest possible Docker image after installing apt dependencies

I've created a Docker image using debian as the parent image. In my Dockerfile I've installed some dependencies using apt and pip.
Now, I want to get rid off everything that is not completely necessary to run my app, which of course, needs the dependencies installed.
For now I have the following lines in my Dockerfile after installing the dependencies.
RUN rm -rf /var/lib/apt/lists/* \
&& rm -Rf /usr/share/doc && rm -Rf /usr/share/man \
&& apt-get clean
I've also installed the dependencies using the --no-install-recommends option.
Anything else I can do to reduce the footprint of my Docker image?
PS: just in case, this is how I installed the dependencies:
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
sudo systemd \
build-essential libffi-dev libssl-dev \
python-pip python-dev python-setuptools python-wheel
To reduce the size of the image, you need to combine your RUN commands into one. When you create files in one layer and delete them in another, the files still exist on the drive and are shipped over the network. Their existence is just hidden when the layers of the filesystem are assembled for your container.
The Dockerfile best practices explain this in more detail: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
I'd also recommend building with docker build --rm=false --no-cache . (temporarily) and then reviewing the output of docker diff on each of the created images to see what files are created in each layer.

Silently Installing pecl modules (e.g. pecl_http) Inside a Docker Container?

I am attempting to install pecl_http inside a docker container. Currently my Dockerfile looks something like this:
FROM fun:5000/apache-php:0.1.0
# Install dependencies
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && \
apt-get -y install \
php5-dev \
libcurl4-openssl-dev && \
yes "\n" | pecl install pecl_http-1.7.6 && \
echo "extension=http.so" > /etc/php5/mods-available/http.ini && \
cd /etc/php5/apache2/conf.d/ && \
ln -s ../../mods-available/http.ini 20-http.ini && \
...
Initially I was simply using pecl install pecl_http-1.7.6 in the docker file, and the container built successfully - without pecl_http installed.
If I attach to the container, I can install pecl_http with the interactive pecl install pecl_http-1.7.6 by simply hitting enter after every prompt. I just learned about yes, and it seemed to fit my needs. Online searches indicated that many people have used it to perform unattended pecl installs, including pecl_http; however, when I attempt to use it in my docker container it fails with configure: error: could not find magic.h.
How can I perform a silent pecl_http install in Docker?
Your pecl install is asking you this question:
whether to enable response content type guessing; specify libmagic directory [no] :
And yes "\n" isn't doing what you think it is - it's actually outputting:
\n
\n
\n
\n
\n
\n
So because you're saying \n in response to the above question, the installer thinks you're telling it to look in \n for libmagic, and of course it's failing because \n is nonsense.
yes has an implicit return after each command you tell it to output, so if you want to just have it hit return and use the defaults, use yes ''.
Working Dockerfile:
FROM ubuntu:14.04
# Install dependencies
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update
RUN apt-get -y install php5-dev
RUN apt-get -y install libcurl4-openssl-dev
RUN apt-get -y install libevent-dev
RUN echo "extension=http.so" > /etc/php5/mods-available/http.ini
RUN yes "" | pecl install pecl_http-1.7.6
RUN cd /etc/php5/apache2/conf.d/
RUN ln -s ../../mods-available/http.ini 20-http.ini
...
Extra tip: Don't be afraid to split your commands out into separate RUN statements to make full use of the docker cache.

Resources