- Use staged container builds to improve caching and reduce size (#727)

* - Use staged container builds to improve caching and reduce size
- Image size reduced from 8 GB to 1.6ish
- Switched from Make to Ninja for faster builds that do not hog processor
- Removed unneded dependencies
- Added to .dockerignore
- Readme for docker stuff

- Staged Builds
    - Docker's overlay FS means that `rm`ing files does not reduce size
    - Once build artifacts are build, the build dependencies are no longer needed
    - Both of these can be solved by building in a temporary image and copying
    only the needed libraries in
    - Leverages DESTDIR to generate a directory structure that can be just
    copied onto the `/` of the filesystem
    - Similarly, the data files (like models) can be downloaded ahead of time
    into their own image and copied in. This saves on network IO.
    - Anything in a RUN directive that is non-deterministic (e.g. downloading
    a file from a link, the content of that link changes) does not cause a cache
    miss, so if you need to update something RUN uses, either modify the
    dockerfile or build with `--no-cache` to force a rebuild
- Switch to Ninja
    - cmake can generate many types of build systems
    - Ninja builds faster than GNU Make
    - `make -j` has a tendency to lock up my system when building locally
    - Do not need to tell ninja how many jobs to run
- .dockerignore
    - Paths in .dockerignore are basically invisible to dockerd, so when dockerd
    zips up the build context, all of the cruft can be ignored
    - it is beneficial to docker build speed to add any large, unnecssary files
    and directories to .dockerignore.
    - Just remember they cannot be seen by dockerd

* removing cruft and some format fixes

* updated dockerfile to opencv 4.1.0
This commit is contained in:
Mike McDermott
2019-07-04 03:13:48 -04:00
committed by Tadas Baltrusaitis
parent 397a58d2e8
commit b802889ef0
8 changed files with 206 additions and 78 deletions

View File

@@ -1,3 +1,5 @@
.git
docker-compose.yml
build
matlab_runners
matlab_version
@@ -5,4 +7,4 @@ python_scripts
test-dump
samples
model_training
gui
gui

6
.env Normal file
View File

@@ -0,0 +1,6 @@
## This is read by docker-compose. You can overwrite these at runtime, e.g.:
## DOCKERUSER=bobfoo docker-compose build
DOCKERUSER=openface
DOCKERTAG=latest
DATA_MOUNT=/tmp/openface

5
.gitignore vendored
View File

@@ -1,3 +1,5 @@
lib/local/LandmarkDetector/model/patch_experts/cen_patches_*.dat
matlab_version/experiments_menpo/out_semifrontal/
/x64/Release/
/x64/Debug/
@@ -100,3 +102,6 @@ lib/local/Utilities/Debug/
lib/3rdParty/CameraEnumerator/Debug/
lib/local/CppInerop/Debug/
*.user
# IDE-generated folders
.idea

View File

@@ -138,7 +138,7 @@ endforeach()
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if (GCC_VERSION VERSION_LESS 8.0)
MESSAGE(FATAL_ERROR "Need a 8.0 or newer GCC compiler ${GCC_VERSION}")
MESSAGE(FATAL_ERROR "Need a 8.0 or newer GCC compiler. Current GCC: ${GCC_VERSION}")
else ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse -msse2 -msse3")
endif ()

View File

@@ -1,76 +0,0 @@
FROM ubuntu:16.04 as build
LABEL maintainer="Edgar Aroutiounian <edgar.factorial@gmail.com>"
ARG DEBIAN_FRONTEND=noninteractive
ARG BUILD_DIR=/home/build-dep
ARG OPENFACE_DIR=/home/openface-build
RUN mkdir ${OPENFACE_DIR}
WORKDIR ${OPENFACE_DIR}
COPY ./CMakeLists.txt ${OPENFACE_DIR}
COPY ./cmake ${OPENFACE_DIR}/cmake
COPY ./exe ${OPENFACE_DIR}/exe
COPY ./lib ${OPENFACE_DIR}/lib
ADD https://www.dropbox.com/s/7na5qsjzz8yfoer/cen_patches_0.25_of.dat?dl=1 \
${OPENFACE_DIR}/lib/local/LandmarkDetector/model/patch_experts/cen_patches_0.25_of.dat
ADD https://www.dropbox.com/s/k7bj804cyiu474t/cen_patches_0.35_of.dat?dl=1 \
${OPENFACE_DIR}/lib/local/LandmarkDetector/model/patch_experts/cen_patches_0.35_of.dat
ADD https://www.dropbox.com/s/ixt4vkbmxgab1iu/cen_patches_0.50_of.dat?dl=1 \
${OPENFACE_DIR}/lib/local/LandmarkDetector/model/patch_experts/cen_patches_0.50_of.dat
ADD https://www.dropbox.com/s/2t5t1sdpshzfhpj/cen_patches_1.00_of.dat?dl=1 \
${OPENFACE_DIR}/lib/local/LandmarkDetector/model/patch_experts/cen_patches_1.00_of.dat
RUN mkdir ${BUILD_DIR}
ADD https://github.com/opencv/opencv/archive/3.4.0.zip ${BUILD_DIR}
RUN apt-get update && apt-get install -qq -y \
curl build-essential llvm clang-3.7 libc++-dev python3 python3-pip\
libc++abi-dev cmake libopenblas-dev liblapack-dev git libgtk2.0-dev \
pkg-config libavcodec-dev libavformat-dev libswscale-dev \
python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev \
libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev checkinstall \
libboost-all-dev wget unzip && \
rm -rf /var/lib/apt/lists/*
RUN pip3 install setuptools
RUN cd ${BUILD_DIR} && unzip 3.4.0.zip && \
cd opencv-3.4.0 && \
mkdir -p build && \
cd build && \
cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D WITH_TBB=ON -D WITH_CUDA=OFF \
-D BUILD_SHARED_LIBS=OFF .. && \
make -j4 && \
make install
RUN wget http://dlib.net/files/dlib-19.13.tar.bz2 && \
tar xvf dlib-19.13.tar.bz2 && \
cd dlib-19.13/ && \
mkdir build && \
cd build && \
cmake .. && \
cmake --build . --config Release && \
make install && \
ldconfig && \
cd ..
RUN cd ${OPENFACE_DIR} && mkdir -p build && cd build && \
cmake -D CMAKE_BUILD_TYPE=RELEASE .. && \
make -j4
RUN ln /dev/null /dev/raw1394
ENTRYPOINT ["/bin/bash"]

24
docker-compose.yml Normal file
View File

@@ -0,0 +1,24 @@
---
# Variables can be set from the shell: `DOCKERTAG=foo docker-compose build`
# or from a .env file. See docker-compose documentation for details
# Variable DOCKERUSER should be set to your dockerhub user
# Alternatively, use a docker registry url as the image name
version: '3.7'
services:
## Image runtime service
## This can be used to add volume mounts or pass environment variables
## Todo: make a service which can use the container interactively
openface:
container_name: openface
build:
context: .
dockerfile: docker/Dockerfile
image: "${DOCKERUSER}/openface:${DOCKERTAG}"
tty: true
volumes:
- "${DATA_MOUNT}:${DATA_MOUNT}"
environment:
DATA_MOUNT: "${DATA_MOUNT}"
command: ["bash"]
...

110
docker/Dockerfile Normal file
View File

@@ -0,0 +1,110 @@
# ==================== Building Model Layer ===========================
# This is a little trick to improve caching and minimize rebuild time
# and bandwidth. Note that RUN commands only cache-miss if the prior layers
# miss, or the dockerfile changes prior to this step.
# To update these patch files, be sure to run build with --no-cache
FROM alpine as model_data
RUN apk --no-cache --update-cache add wget
WORKDIR /data/patch_experts
RUN wget -q https://www.dropbox.com/s/7na5qsjzz8yfoer/cen_patches_0.25_of.dat &&\
wget -q https://www.dropbox.com/s/k7bj804cyiu474t/cen_patches_0.35_of.dat &&\
wget -q https://www.dropbox.com/s/ixt4vkbmxgab1iu/cen_patches_0.50_of.dat &&\
wget -q https://www.dropbox.com/s/2t5t1sdpshzfhpj/cen_patches_1.00_of.dat
## ==================== Install Ubuntu Base libs ===========================
## This will be our base image for OpenFace, and also the base for the compiler
## image. We only need packages which are linked
FROM ubuntu:18.04 as ubuntu_base
LABEL maintainer="Michael McDermott <mikemcdermott23@gmail.com>"
ARG DEBIAN_FRONTEND=noninteractive
# todo: minimize this even more
RUN apt-get update -qq &&\
apt-get install -qq curl &&\
apt-get install -qq --no-install-recommends \
libopenblas-dev liblapack-dev \
libavcodec-dev libavformat-dev libswscale-dev \
libtbb2 libtbb-dev libjpeg-dev \
libpng-dev libtiff-dev &&\
rm -rf /var/lib/apt/lists/*
## ==================== Build-time dependency libs ======================
## This will build and install opencv and dlib into an additional dummy
## directory, /root/diff, so we can later copy in these artifacts,
## minimizing docker layer size
## Protip: ninja is faster than `make -j` and less likely to lock up system
FROM ubuntu_base as cv_deps
WORKDIR /root/build-dep
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update -qq && apt-get install -qq -y \
cmake ninja-build pkg-config build-essential checkinstall\
g++-8 &&\
rm -rf /var/lib/apt/lists/* &&\
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8
## llvm clang-3.7 libc++-dev libc++abi-dev \
## ==================== Building dlib ===========================
RUN curl http://dlib.net/files/dlib-19.13.tar.bz2 -LO &&\
tar xf dlib-19.13.tar.bz2 && \
rm dlib-19.13.tar.bz2 &&\
mv dlib-19.13 dlib &&\
mkdir -p dlib/build &&\
cd dlib/build &&\
cmake -DCMAKE_BUILD_TYPE=Release -G Ninja .. &&\
ninja && \
ninja install && \
DESTDIR=/root/diff ninja install &&\
ldconfig
## ==================== Building OpenCV ======================
ENV OPENCV_VERSION=4.1.0
RUN curl https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.tar.gz -LO &&\
tar xf ${OPENCV_VERSION}.tar.gz && \
rm ${OPENCV_VERSION}.tar.gz &&\
mv opencv-${OPENCV_VERSION} opencv && \
mkdir -p opencv/build && \
cd opencv/build && \
cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D WITH_TBB=ON -D WITH_CUDA=OFF \
-DWITH_QT=OFF -DWITH_GTK=OFF\
-G Ninja .. && \
ninja && \
ninja install &&\
DESTDIR=/root/diff ninja install
## ==================== Building OpenFace ===========================
FROM cv_deps as openface
WORKDIR /root/openface
COPY ./ ./
COPY --from=model_data /data/patch_experts/* \
/root/openface/lib/local/LandmarkDetector/model/patch_experts/
RUN mkdir -p build && cd build && \
cmake -D CMAKE_BUILD_TYPE=RELEASE -G Ninja .. && \
ninja &&\
DESTDIR=/root/diff ninja install
## ==================== Streamline container ===========================
## Clean up - start fresh and only copy in necessary stuff
## This shrinks the image from ~8 GB to ~1.6 GB
FROM ubuntu_base as final
WORKDIR /root
# Copy in only necessary libraries
COPY --from=openface /root/diff /
# Since we "imported" the build artifacts, we need to reconfigure ld
RUN ldconfig

57
docker/README.md Normal file
View File

@@ -0,0 +1,57 @@
# Docker building instructions
This image can be build with just `docker`, but it is highly recommend to use
`docker-compose` as this greatly simplifies and improves the process.
## Quick start
To start with the container hosted by the repo maintainer, run
`docker run -it --rm --name openface algebr/openface:latest`
This will drop you into a shell with binaries such as FaceLandmarkImg. For example,
try this code (in the container):
```bash
curl -o tesla.jpg https://upload.wikimedia.org/wikipedia/commons/thumb/b/b7/Nicola_Tesla_LCCN2014684845.jpg/559px-Nicola_Tesla_LCCN2014684845.jpg
FaceLandmarkImg -f tesla.jpg
```
Then, copy the output to the host system (from host terminal):
```bash
docker cp openface:/root/processed /tmp/
cd /tmp/processed
```
Tip: On Ubuntu and other *nixes with X running, you can open a file directly
like this:
```bash
xdg-open /tmp/processed/tesla.jpg
```
## Building
In repo root, run `docker-compose build` to automatically build and tag.
There are two variables which can be used to modify the tag, `$DOCKERUSER` and
`$DOCKERTAG`. DC will automatically tag image as
`${DOCKERUSER}/openface:${DOCKERTAG}`
## OpenFace service (in progress)
To run OpenFace like a service, you can start the container with bind mounts
in order to pass data into and out of the container easily.
`$DATA_MOUNT` by default is set to `/tmp/openface`. This can be overridden by
modifying `.env` file, setting it in your shell environment, or passing in
before `docker-compose` at runtime. Note: output will be `root` owner.
```bash
export DATA_MOUNT=/tmp/openface
mkdir -p $DATA_MOUNT/tesla # this is just to ensure this is writable by user
docker-compose up -d openface && sync # sync is to wait till service starts
curl -o $DATA_MOUNT/tesla.jpg \
https://upload.wikimedia.org/wikipedia/commons/thumb/b/b7/Nicola_Tesla_LCCN2014684845.jpg/559px-Nicola_Tesla_LCCN2014684845.jpg
docker exec -it openface FaceLandmarkImg -f $DATA_MOUNT/tesla.jpg -out_dir $DATA_MOUNT/tesla
docker exec -it openface chown -R $UID:$UID $DATA_MOUNT # chown to current user
docker-compose down # stop service if you wish
```