I need to download and install a package directly from GitHub and I need to install some libraries I need for a build from source through pip down the line.
For that I use:
RUN apt-get update && apt-get install -y libavformat-dev libavdevice-dev libavfilter-dev libswscale-dev
and
RUN wget https://github.com/mozilla/geckodriver/releases/download/v0.30.0/geckodriver-v0.30.0-linux64.tar.gz \
&& tar -xf geckodriver-v0.30.0-linux64.tar.gz \
&& mv geckodriver /usr/local/bin/ \
&& rm geckodriver-v0.30.0-linux64.tar.gz
I want to build for different platforms with buildx:
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 .
On amd64 I do not need to install the av libraries, as pip won't need to build anything, because wheels are provided.
On arm64 and arm/v7 I need to install the libraries, and I need to download, extract and copy a different geckodriver package.
Is there a way to specify conditional statements based on CPU architecture?
Related
I am trying to rewrite a Dockerfile (https://github.com/orangefoil/rcssserver-docker/blob/master/Dockerfile) so that it uses alpine instead of ubuntu. Goal is to reduce the file size.
In the original image the robocup soccer server is built from scratch using g++, flex, bison, etc.
FROM ubuntu:18.04 AS build
ARG VERSION=16.0.0
WORKDIR /root
RUN apt update && \
apt -y install autoconf bison clang flex libboost-dev libboost-all-dev libc6-dev make wget
RUN wget https://github.com/rcsoccersim/rcssserver/archive/rcssserver-$VERSION.tar.gz && \
tar xfz rcssserver-$VERSION.tar.gz && \
cd rcssserver-rcssserver-$VERSION && \
./bootstrap && \
./configure && \
make && \
make install && \
ldconfig
I tried to do the same on alpine and had to exchange some packages:
FROM alpine:latest
ARG VERSION=16.0.0
WORKDIR /root
# Add basics first
RUN apk — no-cache update \
&& apk upgrade \
&& apk add autoconf bison clang-dev flex-dev boost-dev make wget automake libtool-dev g++ build-base
RUN wget https://github.com/rcsoccersim/rcssserver/archive/rcssserver-$VERSION.tar.gz
RUN tar xfz rcssserver-$VERSION.tar.gz
RUN cd rcssserver-rcssserver-$VERSION && \
./bootstrap && \
./configure && \
make && \
make install && \
ldconfig
Unfortunately, my version doesn't work yet. It fails with
/usr/lib/gcc/x86_64-alpine-linux-musl/9.3.0/../../../../x86_64-alpine-linux-musl/bin/ld: cannot find -lrcssclangparser
From what I found so far, this can happen, if dev packages are not installed (see ld cannot find an existing library), but I changed to dev packages where I could find them and still no luck.
So, my current assumption is that ubuntu has some package installed, that I need to add in my alpine image. I would exclude a code problem, since the ubuntu version works.
Any ideas, what could be missing? I would also be happy to understand how to compare the packages myself, but the package namings are not the same in ubuntu and alpine, so I find it pretty hard to figure this out.
You should break this up using a multi-stage build. In the image you're building now, the final image contains the C toolchain and all of the development libraries and headers that those -dev packages install; you don't need any of those to actually run the built application. The basic idea is to build the application exactly as you have it now, but then COPY only the built application into a new image with fewer dependencies.
This would look something like this (untested):
FROM ubuntu:18.04 AS build
# ... exactly what's in the original question ...
FROM ubuntu:18.04
# Install the shared libraries you need to run the application,
# but not -dev headers or the full C toolchain. You may need to
# run `ldd` on the built binary to see what exactly it needs.
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \
apt-get install --assume-yes --no-install-recommends \
libboost-atomic1.65.1 \
libboost-chrono1.65.1 \
# ... more libboost-* libraries as required ...
# Get the built application out of the original image.
# Autoconf's default is to install into /usr/local, and in a
# typical Docker base image nothing else will be installed there.
COPY --from=build /usr/local /usr/local
RUN ldconfig
# Describe how to run a container.
EXPOSE 12345
CMD ["/usr/local/bin/rcssserver"]
Compared to the size of the C toolchain, header files, and build-time libraries, the difference between an Alpine and Ubuntu image is pretty small, and Alpine has well-documented library compatibility issues with its minimal libc implementation.
I've got a small Dockerfile where I'm trying to get to a point where I can RUN pip3 bdist_wheel successfully. That is, without getting this error:
unknown command "bdist_wheel" - maybe you meant "wheel"
I've tried installing everything mentioned in this answer, but no luck.
Minimal repro Dockerfile and docker build output:
FROM ubuntu:18.04
RUN apt-get update \
&& apt-get install -qyy -o APT::Install-Recommends=false -o APT::Install-Suggests=false \
file \
gcc \
python3 \
python3-dev \
python3-pip \
python3-setuptools \
python3-venv \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN pip3 install --cache-dir=/tmp/pipcache --upgrade pip && rm -rf /tmp/pipcache
RUN pip install --cache-dir=/tmp/pipcache poetry && rm -rf /tmp/pipcache
WORKDIR /src/app
RUN poetry new .
RUN poetry add gevent
The most relevant part of the output is of course
error: invalid command 'bdist_wheel'
First, some notes to the error: invalid command 'bdist_wheel' output. When running pip install <pkgname>, pip will try to find a prebuilt wheel that matches your target platform. If it doesn't find one, it tries to build a wheel itself -- the source dist is downloaded and pip wheel is run to produce the wheel. On success, the built wheel is installed. On any failure (the wheel package not installed, python setup.py bdist_wheel failed or whatever), pip will fallback to the second option, which is the distutils installation method: running python setup.py install over the unpacked source dist. This is what you can observe in the log you posted:
Failed building wheel for gevent
...
Running setup.py install for gevent: started
Only when the setup.py install also fails, the installation is failed unconditionally. So while pip can't indeed build the wheel b/c the wheel package is not installed, it is not an issue for the failing installation. You can fix this by adding wheel to development packages:
RUN poetry add --dev wheel
RUN poetry add gevent
but this is an optional thing and won't affect the build result.
Now, to the real error:
Running '(cd "/tmp/pip-build-ek9pxyw2/gevent/deps/libev" && sh ./configure -C > configure-output.txt )' in /tmp/pip-build-ek9pxyw2/gevent
config.status: error: in `/tmp/pip-build-ek9pxyw2/gevent/deps/libev':
config.status: error: Something went wrong bootstrapping makefile fragments
for automatic dependency tracking. Try re-running configure with the
'--disable-dependency-tracking' option to at least be able to build
the package (albeit without support for automatic dependency tracking).
See `config.log' for more details
Something went wrong bootstrapping makefile fragments usually means that you're missing make. Install it in addition to the rest:
RUN apt install -y make
After doing that and rerunning the build, I've got the last error
error: src/gevent/libev/corecext.c: No such file or directory
This is because gevent needs Cython for generating the C extension sources. Install it before installing gevent:
RUN poetry add --dev cython
RUN poetry add gevent
The complete Dockerfile for reference, changes in bold:
FROM ubuntu:18.04
RUN apt-get update \
&& apt-get install -qyy -o APT::Install-Recommends=false -o APT::Install-Suggests=false \
file \
gcc \
python3 \
python3-dev \
python3-pip \
python3-setuptools \
python3-venv \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN pip3 install --cache-dir=/tmp/pipcache --upgrade pip && rm -rf /tmp/pipcache
RUN pip install --cache-dir=/tmp/pipcache poetry && rm -rf /tmp/pipcache
WORKDIR /src/app
RUN poetry new .
RUN apt update
RUN apt install -y make
RUN poetry add --dev wheel cython
RUN poetry add gevent
Neither wheel nor cython are required to actually run gevent, so they can be safely uninstalled afterwards to reduce the image size.
This dockerfile works as expected on my laptop. But it fails if I use automated builds on docker hub.
FROM ubuntu
# Install required software via apt and pip
RUN apt-get -y update && \
apt-get install -y \
awscli \
python \
python-pip \
software-properties-common \
&& add-apt-repository ppa:ubuntugis/ppa \
&& apt-get -y update \
&& apt-get install -y \
gdal-bin \
&& pip install boto3
# Copy Build Thumbnail script to Docker image and add execute permissions
COPY build-thumbnails.py build-thumbnails.py
RUN chmod +x build-thumbnails.py
The error is:
Step 6/7 : COPY build-thumbnails.py build-thumbnails.py
COPY failed: stat /var/lib/docker/tmp/docker-builder259560514/build-thumbnails.py: no such file or directory
The repo is here...
https://github.com/shantanuo/docker/blob/master/batch/Dockerfile
Why would copy or add command not work for automated builds?
Seems like other people have had the same issue see here:
https://forums.docker.com/t/docker-build-failing-on-docker-hub/76191/2
The solution is to set the build context appropriately so that the relative path >in the Dockerfile COPY is correct.
In your Docker Hub repository go to “Builds” and click on “Configure Automated >Builds”. There you can set the “Build Context” for each build rule.
Check the last answer on this page too:
https://github.com/docker/hub-feedback/issues/811
Let me know if that helps!
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.
Our Dockerfile invokes a python script which copies a binary from S3 to /usr/bin. This works fine the first time. But from then on "docker-compose build" does nothing because everything is cached. This is a problem if the binary has changed.
Short of building with --no-cache, what is the best way to make sure "docker-compose build" will always pick up the new binary if there is one. We don't mind if it unnecessarily downloads the binary even if unchanged, so long as it does work then the binary has changed.
Seems like we want a Dockerfile step that always executes?
FROM ubuntu:trusty
RUN apt-get update
RUN apt-get -y install software-properties-common
RUN apt-get -y install --reinstall ca-certificates
RUN add-apt-repository ppa:fkrull/deadsnakes
RUN apt-get update && apt-get install -y \
curl \
wget \
vim \
git \
python3.5 \
python3-pip \
python3-setuptools \
libpcap0.8-dev
RUN ln -sf /usr/bin/python3.5 /usr/bin/python3
ADD . /app
WORKDIR /app
# Install Python Requirements
RUN pip3 install -r etc/python/requirements.txt
# Download/Install processor and associated libs
RUN python3 setup_processor.py
RUN mkdir -p /logs
ENTRYPOINT ["/app/entrypoint.sh"]
Where setup_processor.py downloads directly from S3 to /usr/bin.
So as of now there is no direct feature like this. But there is a workaround to your solution.
Add Build argument before your download step
ARG BUILD_ON=now
# Download/Install processor and associated libs
RUN python3 setup_processor.py
While building the image use below
docker build --build-arg BUILD_ON=$(date) ....
This will always make sure that you get a change in the ARG step and all steps cache after that will be invalidated
A feature has already been requested and being worked out on below thread
https://github.com/moby/moby/issues/1996