Ehsas
Ehsas

Reputation: 69

Dockerfile build from source in one stage and then copy and install in second stage

I'm a novice to docker and to linux.

Im running on a Alpine base image and I want to keep my image as clean and lightweight as possible. I have to build and install some packages in my Dockerfile, specifically this.

I was wondering if there was any way for me to use docker multi-stage builds and build the MariaDB connector in one stage and copy the files to the next stage and then install it there.

I've tried to build it in a separate directory and copy it to a different machine to see if it's possible, but I've run into an issue where it cannot install without a number of files that are outside the built direcory.

Upvotes: 4

Views: 4620

Answers (2)

jmaitrehenry
jmaitrehenry

Reputation: 2400

If you want to build your lib in the first stage and use it in the later stage without all the libs and tools needed to compile it, you can use a multistage build as you say.

But, when you copy the builded lib, you need to install the shared library that was linked to it (here musl and unixodbc).

You can find them by running ldd:

/build/mariadb-connector-odbc-3.1.4 # ldd /usr/lib/libmaodbc.so
    /lib/ld-musl-x86_64.so.1 (0x7fde6847b000)
    libodbcinst.so.2 => /usr/lib/libodbcinst.so.2 (0x7fde683c5000)
    libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7fde6847b000)

As musl should be already present, you only need to install back the unixodbc lib used for building the lib.

This is an example of Dockerfile for that:

FROM alpine AS build
# Add build dependencies
RUN apk add --no-cache alpine-sdk cmake unixodbc-dev mariadb-connector-c mariadb-connector-c-dev mariadb-static unixodbc
# Download the source code from github
ADD https://github.com/MariaDB/mariadb-connector-odbc/archive/3.1.4.tar.gz /build/mariadb-connector-odbc.tgz

# Build it
WORKDIR /build
RUN tar xzf mariadb-connector-odbc.tgz \
    && cd mariadb-connector-odbc-3.1.4 \
    && CFLAGS="$CFLAGS -I/usr/include/mysql" \
       cmake \
       -DCMAKE_INSTALL_PREFIX=/usr \
       -DCMAKE_INSTALL_LIBDIR=lib \
       -DBUILD_SHARED_LIBS=True \
       -DCMAKE_BUILD_TYPE=None \
       . \
    && make install

# Final stage
FROM alpine
# Add the dependencies for the lib
RUN apk add --no-cache unixodbc
# Copy it from the build image
COPY --from=build  /usr/lib/libmaodbc.so  /usr/lib/libmaodbc.so

Upvotes: 2

plswork04
plswork04

Reputation: 659

Answering just the question in the title: "Dockerfile build from source in one stage and then copy and install in second stage"

With cmake builds you can use an install prefix to create a psudo package and then merge that install directory into your final image's root. I don't know if this is good practice but it seems to work well.

A simple outline for illustration only:

build.sh

set -e # exit if error
TOP=$(pwd)
... # Fill in the blank
cmake -B./build
cd build
make -j

# Interesting part!
make DESTDIR=./install install
cp -r install "$TOP/install"

Dockerfile

FROM ubuntu:focal AS runtime-base
RUN apt-get update &&  apt-get install -y --no-install-recommends \
        libfoo \
    && rm -rf /var/lib/apt/lists/*

#------------------------------------------------

FROM runtime-base AS build
RUN apt-get update &&  apt-get install -y --no-install-recommends \
        libfoo-dev \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /root
COPY build.sh
# Makes /root/install
RUN bash ./build.sh

#------------------------------------------------

FROM runtime-base
WORKDIR /root

COPY --from=build /root/install ./install
RUN cp -RT install/usr/ /usr/ && \
    rm -r install && \
    ldconfig

cp -RT:

The -T flag stops source/file1 from being copied to destination/source/file1 instead.

Upvotes: 1

Related Questions