From 7b0c20e373e394524d8086683e791122d26294df Mon Sep 17 00:00:00 2001 From: Patrick Durand Date: Wed, 12 Jul 2017 16:33:31 +0200 Subject: [PATCH] add Docker support for Alpine Linux --- docker/Dockerfile.alpine | 98 +++++++++++++ docker/Dockerfile.alpine-compiler | 64 +++++++++ docker/README.md | 39 ++++++ docker/build.sh | 223 ++++++++++++++++++++++++++++++ 4 files changed, 424 insertions(+) create mode 100644 docker/Dockerfile.alpine create mode 100644 docker/Dockerfile.alpine-compiler create mode 100644 docker/README.md create mode 100755 docker/build.sh diff --git a/docker/Dockerfile.alpine b/docker/Dockerfile.alpine new file mode 100644 index 0000000..08b6703 --- /dev/null +++ b/docker/Dockerfile.alpine @@ -0,0 +1,98 @@ +######################################################################################### +# +# P R O D U C T I O N R E A D Y +# +# Docker container fully based on Alpine Linux: contained PLAST software compiled +# using native Alpine c/c++ tools. +# +######################################################################################### +# +# == Docker build command: +# +# docker build -f Dockerfile.alpine -t plast_alpine_machine . +# +# == Running a PLAST job +# +# docker run --rm -i -t plast_alpine_machine +# +# where are the PLAST command-line arguments. +# See https://plast.inria.fr/user-guide/plast-command-line-arguments/ +# +# == Sample PLAST job with provided data +# +# docker run --rm -i -t -v $PWD:/tmp plast_alpine_machine -p plastp -i /opt/plastbinary/db/query.fa -d /opt/plastbinary/db/query.fa -o /tmp/test.out -a 4 +# +# -> you should have a 'test.out' file when PLAST job is done. +# +# This command-line line explained: +# +# docker run [1] +# --rm [2] +# -i -t [3] +# -v $PWD:/tmp [4] +# plast_machine [5] +# -p plastp [6] +# -i /opt/plastbinary/db/query.fa [7] +# -d /opt/plastbinary/db/tursiops.fa [8] +# -o /tmp/test.out [9] +# -a 4 [10] +# +# [1]-[5]: Docker arguments +# [6]-[10]: PLAST arguments +# +# [1]: start Docker container +# [2]: destroy container when Docker finishes +# (it does NOT delete the 'plast_machine' image) +# [3]: start an interactive job +# (for instance, you'll see messages on stdout, if any) +# [4]: mount a volume. This is required to get the results from PLAST. +# Here, we say that current local directory will be viewed as '/tmp' +# from the inside of the container. +# [5]: tell Docker which image to start: the 'plast_machine' of course. +# [6]: run a plastp job, i.e. protein query vs. protein reference bank +# [7]: the query; this file is provided inside the container. +# [8]: the reference bank; this file is provided inside the container. +# [9]: the result file. +# Created within the '/tmp' directory inside the container, this file +# will be available in the current local directory, thanks to argument [4]. +# [10]: request to use up to 4 threads +# (adapt the value to your computer!) +# +######################################################################################### + +FROM alpine:3.6 +# (image size after: 4Mb) + +# who to blame? +MAINTAINER Patrick Durand patrick.durand@inria.fr + +# ### +# Package installation and configuration +# +RUN apk update && \ + apk add --no-cache libstdc++ && \ + mkdir -p /opt +# (image size after: 6.5Mb) + +# ### +# PLAST tarball is supposed to be located in this directory. +# +ENV PLAST_VERSION=2.3.2 +ENV PLAST_PACKAGE=plastbinary_v${PLAST_VERSION}-Alpine +COPY ${PLAST_PACKAGE}.tar.gz /opt + +# ### +# PLAST installation. +# +RUN cd /opt \ + && gunzip ${PLAST_PACKAGE}.tar.gz \ + && tar -xf ${PLAST_PACKAGE}.tar \ + && rm -f ${PLAST_PACKAGE}.tar \ + && mv ${PLAST_PACKAGE} plastbinary +# (image size after: 9.6Mb) + +# ### +# Start a GATB-Tool. See "run-tool.sh" header for more information. +# +ENTRYPOINT ["/opt/plastbinary/plast"] + diff --git a/docker/Dockerfile.alpine-compiler b/docker/Dockerfile.alpine-compiler new file mode 100644 index 0000000..3f0f18c --- /dev/null +++ b/docker/Dockerfile.alpine-compiler @@ -0,0 +1,64 @@ +######################################################################################### +# +# P R O D U C T I O N R E A D Y +# +# Docker container based on Alpine Linux. It aims at compiling PLAST software using +# Alpine c/c++ compiler. +# +######################################################################################### +# +# == Docker build command: +# +# docker build -f Dockerfile.alpine-compiler -t plast_alpine_compiler . +# +# == Docker run command: +# +# see companion scripts "build.sh" to review how to use this Alpine c/c++ complier. +# +######################################################################################### + +# Base image to compile PLAST using an Alpine Linux OS. +# JDK is required since PLAST contains JNI interface, natively. +# JDK is required to compile PLAST source code... however, it is not to run PLAST binary. +# Alpine/JDK8 Docker from: https://hub.docker.com/r/frolvlad/alpine-oraclejdk8/ +FROM frolvlad/alpine-oraclejdk8:full + +# who to blame? +MAINTAINER Patrick Durand patrick.durand@inria.fr + +# ### +# +# Package installation and configuration: +# +# 1. We need libc and libc++ to compile PLAST +# 2. We also need cmake, make and c/c++ compiler +# 3. We need perl (used by cmake to get current build date) +# 4. We need bash (compile script) and curl (to get tarballs from Github) +# +RUN apk update && \ + apk add --no-cache \ + bash \ + curl \ + perl \ + cmake make g++ + #make cmake gcc g++ libstdc++ libgcc + +# Add the build script +COPY build.sh /usr/bin + +# Fix: ensure script has exec permission +RUN chmod +x /usr/bin/build.sh + +# Run this container as non-root +# testing machine: use pdurand account +# production machine: use Jenkins account +RUN adduser -D -H -u 502 pdurand +RUN adduser -D -H -u 1000 ci +# Note: we do not use Docker 'USER' command here. Instead, use "--user xxx" +# with "docker run" command. + +# ### +# Start to make a PLAST Tool. See "build.sh" header for more information. +# +ENTRYPOINT ["/usr/bin/build.sh"] + diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..b61f038 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,39 @@ +# Introduction + +This directory contains Docker material aims at creating a PLAST Docker container. + +# CentOS container + +Genscale Team uses a CentOS 6 Linux system to compile and to test the PLAST software. + +As a consequence, we first designed a Dockerfile relying on that OS. + +You simply create the Docker image as follows: + + docker build -f Dockerfile -t plast_machine . + +Image size is 230 Mb. + +Then to run PLAST jobs using that container, refer to the header of Dockerfile. + +# Alpine Linux container + +In order to provide a more compact version of the PLAST Docker container, we designed another Dockerfile to use the compact Alpine Linux system. + +For that purpose, we actually made two Dockerfiles: + +* Dockerfile.alpine-compiler: use to compile PLAST source code into Alpine-based binary +* Dockerfile.alpine: use to package the previous binary into a ready-to-use PLAST job machine + +So, you create the PLAST machine as follows: + + docker build -f Dockerfile.alpine-compiler -t plast_alpine_compiler . + docker run --rm -i -t -v $PWD:/tmp plast_alpine_compiler \ + "plast-library;plastbinary;plast_source;2.3.2" + docker build -f Dockerfile.alpine -t plast_alpine_machine . + +You'll end up with a very, very compact PLAST machine sizing only 9.6 Mb! + +To use that Docker container, please refer to the header of Dockerfile.alpine + + diff --git a/docker/build.sh b/docker/build.sh new file mode 100755 index 0000000..632ce80 --- /dev/null +++ b/docker/build.sh @@ -0,0 +1,223 @@ +#!/bin/bash + +######################################################################################### +# +# Companion file to be used with Dockerfile.alpine-compiler +# +# This script is embedded within the container: it is responsible for compiling +# PLAST tool. +# +######################################################################################### +# +# A shell script to compile PLAST using Alpine system: c/c++ libs and compiler. +# +# Use: build.sh "name1;name2;name3;version" +# (see below for a description of this single string-based argument) +# +# It works as follows: +# a. get a PLAST Source bundle from Github/PLAST-software/plast-library +# b. compile the source within an Alpine Docker Container +# c. make the binary bundle for 'Alpine' +# d. run PLAST tool test +# e. archive the Alpine Binary bundle +# +# Declaration of a PLAST description is done using a single string-based argument +# within double quotes. This argument is formated as: +# +# "name1;name2;name3;version" +# +# where: +# [0]:name1: PLAST github project name +# [1]:name2: PLAST name of the binary tarball +# [2]:name3: PLAST name of the source tarball +# [3]:version: PLAST version to retrieve and compile (without prefix 'v') +# +# Caution: - ';' is the field separator +# - do not add space chars in between fields and ';' +# - do not forget to enclose string within " (otherwise cmd-line won't work) +# +# +# Author: Patrick G. Durand, Inria, July 2017 +# +######################################################################################### + +# Here is ready-to-use description to compile PLAST from its official release: +# +# "plast-library;plastbinary;plast_source;2.3.2" +# +# Simple use: +# +# docker run --rm -i -t -v $PWD:/tmp plast_alpine_compiler "plast-library;plastbinary;plast_source;2.3.2" +# +# where '$PWD' is the place where Alpine Binary bundle is created on YOUR +# local directory. +# + +# ## DECLARATIONS ##################################################################### + +# 'Make' command can use these many cores +CORES=4 +# This is the working directory INSIDE the container. You can map it +# outside the container using docker -v argument +WK_DIR=/tmp +# get cmd-line argument in an appropriate variable: the GATB-Tool to process +PLAST_TOOL_DESCRIPTION=$1 +# Sample string format (only for help message) +WKDIR_HELP="/path/to/wkdir" +CMD_HELP="docker run --rm -it -v $WKDIR_HELP:/tmp plast_compiler" +DESC_HELP="plast-library;plastbinary;plastbinary;2.3.2" +RES_HELP="docker execution results will be located in $WKDIR_HELP: an Alpine binary bundle." +# In case of error, this script will return a dedicated code !=0 +NB_ARGS_ERROR=1 +ARGS_ERROR=2 +CMAKE_ERROR=3 +MAKE_ERROR=4 +TEST_ERROR_CODE=5 +CD_SRC_DIR_ERROR=6 +CURL_SRC_ERROR=7 +LINUX_BIN_ERROR=9 +CP1_BIN_ERROR=10 +CP2_BIN_ERROR=11 +CP3_BIN_ERROR=12 +PLAST_EXEC_ERROR=13 +PLAST2_EXEC_ERROR=13 + +# Figure out whether or not this script get PLAST official archives +# (source and binary) from Github. Set to zero if using Docker container +# on INRIA-CI platform: access to the web is not allowed. +DO_CURL=1 +# set a dedicated time format +TIMEFORMAT=' Time - real:%3lR | user:%3lU | sys:%3lS' + +# ## MAIN ############################################################################# + +# Check argument +if [ "$#" -ne 1 ]; then + echo "ERROR: missing PLAST description string." + echo " sample: $CMD_HELP \"$DESC_HELP\"" + echo " $RES_HELP" + exit $NB_ARGS_ERROR +fi + +nb_strings=$(grep -o ";" <<< "$1" | wc -l) +if [ "$nb_strings" -ne 3 ]; then + echo "ERROR: bad format for description string" + echo " sample: $CMD_HELP \"$DESC_HELP\"" + echo " $RES_HELP" + exit $ARGS_ERROR +fi + +# == STEP 1: get source code if requested. This step is optional +# since using this script within Docker containers on Inria CI +# platform prevents any remote connection to the Internet. +# Be sure we are in the appropriate directory +cd ${WK_DIR} +# get plast-tool fields: names and release nb. +arr=(${PLAST_TOOL_DESCRIPTION//;/ }) +FNAME=${arr[0]}_v${arr[3]} +echo "## Making: ${FNAME}" +echo "" +# Prepare the curl command +if [ "$DO_CURL" -eq "1" ]; then + TOOLTGZ=${arr[2]}_v${arr[3]}.tar.gz + GIT_URL=https://github.com/PLAST-software/${arr[0]}/releases/download + TOOLURL=${GIT_URL}/v${arr[3]}/${TOOLTGZ} + echo "getting source from: ${TOOLURL} ..." + time curl -ksL ${TOOLURL} | tar xz + if [ ! $? -eq 0 ]; then + echo " FAILED" + exit $CURL_SRC_ERROR + fi + echo " OK" +fi + + +# == STEP 2: compile source code +# Prepare the cmake/make call +SOURCE_BASE_NAME=${arr[2]}_v${arr[3]} +cd ${SOURCE_BASE_NAME} +if [ ! $? -eq 0 ]; then + echo " cd ${SOURCE_BASE_NAME}: FAILED" + exit $CD_SRC_DIR_ERROR +fi +mkdir -p build +cd build +echo "running CMake in: $PWD ..." +time cmake .. > ${WK_DIR}/${FNAME}-CMake.log 2>&1 +if [ ! $? -eq 0 ]; then + echo " CMake: FAILED." + echo " See: ${WK_DIR}/${FNAME}-CMake.log" + exit $CMAKE_ERROR +fi +echo " OK" + +echo "running make ..." +time make -j${CORES} > ${WK_DIR}/${FNAME}-make.log 2>&1 +if [ ! $? -eq 0 ]; then + echo " make: FAILED" + echo " See: ${WK_DIR}/${FNAME}-make.log" + exit $MAKE_ERROR +fi +echo " OK" + +# == STEP 3: prepare Alpine binary bundle +# update that archive: replace bin programs with Alpine ones +cd ${WK_DIR} +echo "preparing Alpine binary bundle ..." +BIN_BASE_NAME=${arr[1]}_v${arr[3]}-Alpine +# remove any other old build directory +[ -e ${BIN_BASE_NAME} ] && rm -rf ${BIN_BASE_NAME} +mkdir -p ${BIN_BASE_NAME} +if [ ! -d ${BIN_BASE_NAME} ]; then + echo " FAILED: unable to locate: ${BIN_BASE_NAME}" + exit $LINUX_BIN_ERROR +fi +cd ${BIN_BASE_NAME} +cp ${WK_DIR}/${arr[2]}_v${arr[3]}/build/bin/plast . +if [ ! $? -eq 0 ]; then + echo " FAILED: unable to copy ${arr[0]} Alpine binaries" + exit $CP1_BIN_ERROR +fi +mkdir db +cp ${WK_DIR}/${arr[2]}_v${arr[3]}/db/query.fa ./db +if [ ! $? -eq 0 ]; then + echo " FAILED: unable to copy db sample files" + exit $CP2_BIN_ERROR +fi +cp ${WK_DIR}/${arr[2]}_v${arr[3]}/db/tursiops.fa ./db +if [ ! $? -eq 0 ]; then + echo " FAILED: unable to copy db sample files" + exit $CP3_BIN_ERROR +fi +echo " OK" + +# == STEP 4: test PLAST +echo "testing PLAST binary bundle ..." +export PLAST_RES=plast.res +./plast -p plastp -i ./db/query.fa -d ./db/tursiops.fa -o $PLAST_RES -bargraph +if [ ! $? -eq 0 ]; then + echo " FAILED: unable to run PLAST" + exit $PLAST_EXEC_ERROR +fi + +if [ ! -e "$PLAST_RES" ]; then + echo " FAILED: unable to locate PLAST result file: $PLAST_RES" + exit $PLAST2_EXEC_ERROR +fi +rm -f $PLAST_RES ./db/tursiops.fa +echo " OK" + +# == STEP 5: package Alpine binary bundle +TAR_BAL=${BIN_BASE_NAME}.tar.gz +echo "archiving Alpine bundle in: ${TAR_BAL} ..." +cd ${WK_DIR} +# remove any 'old' tarball +[ -e ${TAR_BAL} ] && rm -f ${TAR_BAL} +# package the Alpine bundle +tar -cf ${BIN_BASE_NAME}.tar ${BIN_BASE_NAME} +gzip ${BIN_BASE_NAME}.tar +# made some additional cleanup +rm -rf ${SOURCE_BASE_NAME} ${BIN_BASE_NAME} +echo " OK" + +exit 0