349 lines
9.9 KiB
Bash
Executable file
349 lines
9.9 KiB
Bash
Executable file
#! /bin/bash
|
|
|
|
# Purpose: install Debian packages in a Docker image
|
|
#
|
|
# Usage: deb2docker [options] packages
|
|
# -B do NOT build the image (default is to build)
|
|
# -c CMD command to run in the container (default to '/bin/bash')
|
|
# -f FROM indicate which distribution is to be used (default to debian:stable)
|
|
# -h show this help
|
|
# -n NAME name of the image (default to package list)
|
|
# -o DIR use given directory for the build (default in /tmp)
|
|
# -p PRE execute the given script during the container build (before packages install)
|
|
# -s POST execute the given script during the container build (after packages install)
|
|
# -v show package version
|
|
# The package list can be any Debian package, as well as local .deb
|
|
#
|
|
# Example: 'deb2docker -o /tmp/xeyes x11-apps' then '/tmp/xeyes/start xeyes'
|
|
|
|
# build: docker build --rm Dockerfile
|
|
# run: docker run --rm -it NAME
|
|
# clean: docker rmi NAME
|
|
# clean ALL: docker system prune -a
|
|
|
|
# (c) E. Farhi - Synchrotron SOLEIL - GPL3
|
|
|
|
# requires:
|
|
# bash
|
|
# docker.io
|
|
# requires: docker privileges:
|
|
# sudo usermod -aG docker $USER
|
|
|
|
set -e
|
|
|
|
# default settings -------------------------------------------------------------
|
|
FROM=debian:stable
|
|
BUILD=1
|
|
NAME=
|
|
SETNAME=0
|
|
CMD="/bin/bash"
|
|
WORK_DIR=
|
|
SCRIPT=
|
|
PRE=
|
|
VERSION=1.0.8
|
|
ARGS="$@"
|
|
|
|
# handle input arguments -------------------------------------------------------
|
|
while getopts vhBf:n:c:o:d:p:s: flag
|
|
do
|
|
case "${flag}" in
|
|
h) # display help
|
|
echo "Usage: $0 [-hB][-c CMD][-f FROM][-n NAME][-o DIR][-s SCRIPT] packages..."
|
|
echo " Build a Docker image with given Debian packages."
|
|
echo " Options:"
|
|
echo " -B do NOT build the image (default is to build)"
|
|
echo " -c EXEC command to run in the container (default to $CMD)"
|
|
echo " -f FROM indicate which distribution is to be used (default to $FROM)"
|
|
echo " -h show this help"
|
|
echo " -n NAME name of the image (default to package list)"
|
|
echo " -o DIR use given directory for the build (default is in /tmp)"
|
|
echo " -p PRE execute script PRE before packages install"
|
|
echo " -s POST execute script POST after packages install"
|
|
echo " -v show package version"
|
|
echo " The package list can be any Debian package, as well as local .deb"
|
|
echo " "
|
|
echo "Example: '$0 -o /tmp/xeyes x11-apps' then '/tmp/xeyes/start xeyes'"
|
|
exit 0;
|
|
;;
|
|
B) # do not build the image
|
|
BUILD=0
|
|
;;
|
|
f) # set FROM image
|
|
FROM=${OPTARG}
|
|
;;
|
|
n) # set image name
|
|
NAME=${OPTARG}
|
|
;;
|
|
c) # command to execute
|
|
CMD=${OPTARG}
|
|
;;
|
|
o|d) # output directory
|
|
WORK_DIR=${OPTARG}
|
|
;;
|
|
p) # PRE SCRIPT
|
|
PRE=${OPTARG}
|
|
;;
|
|
s) # SCRIPT (POST)
|
|
SCRIPT=${OPTARG}
|
|
;;
|
|
v) # VERSION
|
|
echo "$0 version $VERSION"
|
|
exit 0;
|
|
;;
|
|
*)
|
|
echo "ERROR: Invalid option. Use -h for help."
|
|
exit 1;
|
|
;;
|
|
esac
|
|
done
|
|
shift $((OPTIND-1))
|
|
|
|
# check that docker is installed
|
|
if ! command -v docker > /dev/null
|
|
then
|
|
echo "ERROR: docker could not be found. Install it with: apt install docker.io"
|
|
exit 1
|
|
fi
|
|
|
|
# set name when not set
|
|
if [ "x$NAME" = "x" ]; then
|
|
SETNAME=1
|
|
fi
|
|
|
|
# create a temporary directory to work in --------------------------------------
|
|
if [ "x$WORK_DIR" = "x" ]; then
|
|
N=`basename $0`
|
|
WORK_DIR=`mktemp -p /tmp -d $N-XXXXXXXX`
|
|
else
|
|
mkdir -p $WORK_DIR || echo "ERROR: Invalid directory $WORK_DIR"
|
|
fi
|
|
PW=$PWD
|
|
|
|
|
|
# search for executable commands -----------------
|
|
DEB=
|
|
# get a local copy of packages and find bin and desktop files
|
|
mkdir -p $WORK_DIR/apt || exit # hold deb pkg copies for analysis
|
|
|
|
echo "$0: creating image $NAME in $WORK_DIR"
|
|
echo "Getting Debian packages..."
|
|
for i in $@; do
|
|
echo " $i"
|
|
if [ -f "$i" ]; then
|
|
cp $i $WORK_DIR/apt/
|
|
n=`basename $i`
|
|
DEB="$DEB /opt/install/$n"
|
|
else
|
|
DEB="$DEB $i"
|
|
cd $WORK_DIR/apt
|
|
apt download $i
|
|
cd $PW
|
|
fi
|
|
done
|
|
|
|
|
|
echo " " >> $WORK_DIR/README
|
|
echo "Created with $0" >> $WORK_DIR/README
|
|
echo "$ARGS" >> $WORK_DIR/README
|
|
echo " " >> $WORK_DIR/file_list.txt
|
|
for i in $WORK_DIR/apt/*.deb; do
|
|
echo "Analyzing $i"
|
|
|
|
N=$(dpkg-deb -f $i Package) || continue
|
|
# set the container name if needed
|
|
if [ "x$SETNAME" = "x2" ]; then
|
|
NAME="$NAME-$N"
|
|
fi
|
|
if [ "x$SETNAME" = "x1" ]; then
|
|
SETNAME=2
|
|
NAME=$N
|
|
fi
|
|
echo "Package $N ------------------------------------------" >> $WORK_DIR/README
|
|
dpkg-deb -I $i >> $WORK_DIR/README
|
|
|
|
F=`dpkg -c $i`
|
|
echo "$F" >> $WORK_DIR/file_list.txt
|
|
echo " " >> $WORK_DIR/README
|
|
|
|
done
|
|
|
|
# the base command to start the containers from image
|
|
cmd="docker run -it --net=host --env=DISPLAY --env='QT_X11_NO_MITSHM=1' --volume=\$HOME/.Xauthority:/home/user/.Xauthority:rw $NAME"
|
|
|
|
# prepare the Dockerfile -------------------------------------------------------
|
|
FILE="$WORK_DIR/Dockerfile"
|
|
DATE=`date`
|
|
|
|
if [ -f "$PRE" ]; then
|
|
cp $PRE $WORK_DIR/
|
|
N=`basename $PRE`
|
|
PRE="RUN chmod a+x /opt/install/$N && sh -c \"/opt/install/$N\""
|
|
PRE_FILE="ADD $N /opt/install/"
|
|
else
|
|
PRE_FILE=
|
|
fi
|
|
|
|
if [ -f "$SCRIPT" ]; then
|
|
cp $SCRIPT $WORK_DIR/
|
|
N=`basename $SCRIPT`
|
|
SCRIPT="RUN chmod a+x /opt/install/$N && sh -c \"/opt/install/$N\""
|
|
SCRIPT_FILE="ADD $N /opt/install/"
|
|
else
|
|
SCRIPT_FILE=
|
|
fi
|
|
|
|
echo "Creating Dockerfile $NAME into $FILE"
|
|
dd status=none of=${FILE} << EOF
|
|
# created by $0 on $DATE
|
|
# $ARGS
|
|
#
|
|
# Docker image $NAME
|
|
#
|
|
# build: docker build --rm Dockerfile
|
|
# run: docker run --rm -it $NAME
|
|
# clean: docker rmi $NAME
|
|
# clean ALL: docker system prune -a
|
|
|
|
FROM $FROM
|
|
|
|
# copy required packages
|
|
ADD apt/ /opt/install/
|
|
ADD README /opt/install/
|
|
ADD file_list.txt /opt/install/
|
|
ADD Dockerfile /opt/install/
|
|
$PRE_FILE
|
|
$SCRIPT_FILE
|
|
|
|
# execute/install
|
|
$PRE
|
|
RUN apt-get update -y
|
|
RUN apt-get install -y --no-install-recommends bash xauth $DEB
|
|
$SCRIPT
|
|
RUN rm /opt/install/*.deb || echo " "
|
|
|
|
# start the container (interactive/terminal)
|
|
RUN useradd -ms /bin/bash user
|
|
ENV DISPLAY :0
|
|
USER user
|
|
CMD ["$CMD"]
|
|
EOF
|
|
|
|
# build docker -----------------------------------------------------------------
|
|
FILE=$WORK_DIR/build
|
|
dd status=none of=${FILE} << EOF
|
|
#!/bin/bash
|
|
# created by $0 on $DATE
|
|
# $ARGS
|
|
#
|
|
# build image $NAME
|
|
#
|
|
# Usage: build
|
|
|
|
docker build --rm -t $NAME .
|
|
|
|
# handle of Desktop launchers
|
|
mkdir -p launchers/
|
|
mkdir -p icons/
|
|
|
|
# get .desktop files ----------------------------------------------------------
|
|
D=\$(grep '\.desktop' file_list.txt) || echo "WARNING: No desktop files found."
|
|
# get the desktop files
|
|
D=\$(echo "\$D" | awk '{ print \$6 }')
|
|
|
|
# we need to copy them back, as well as their icons, and change the Exec lines
|
|
# create a container from image to access the files
|
|
id=\$(docker create $NAME)
|
|
for i in \$D; do
|
|
docker cp \$id:\$i launchers/ || echo "WARNING: Failed to get desktop launcher \$i"
|
|
done
|
|
|
|
# get icon files --------------------------------------------------------------
|
|
D=\$(grep 'icon' file_list.txt) || echo "WARNING: No icon files found."
|
|
# get the icon files
|
|
D=\$(echo "\$D" | awk '{ print \$6 }')
|
|
|
|
# we need to copy them back, as well as their icons, and change the Exec lines
|
|
# create a container from image to access the files
|
|
id=\$(docker create $NAME)
|
|
for i in \$D; do
|
|
docker cp \$id:\$i icons/ &> /dev/null|| echo "WARNING: Failed to get icon \$i"
|
|
done
|
|
|
|
# cleanup
|
|
docker rm -v \$id
|
|
|
|
# adapt the Desktop launchers to insert 'run', set Icons=
|
|
for i in launchers/*; do
|
|
if [ ! -f "\$i" ]; then continue; fi
|
|
I=\$(grep 'Icon=' \$i | cut -d = -f 2) || I=
|
|
if [ ! -z "\$I" ]; then
|
|
n=\`basename \$I\`
|
|
if [ ! -f "icons/\$n" ]; then
|
|
# get closest file that match Icon name when initial name is not present as a file
|
|
n1=( icons/\$n* ) || n1=
|
|
if [ ! -z "\$n1" ]; then
|
|
n=\`basename \${n1[0]}\`
|
|
fi
|
|
fi
|
|
sed -i "s|Icon=.*|Icon=icons/\$n|g" \$i || echo " "
|
|
fi
|
|
I=\$(grep 'Exec=' \$i | cut -d = -f 2-) || I=
|
|
sed -i "s|Exec=.*|Exec=sh -c \"echo '$NAME'; $cmd \$I\"|g" \$i || echo " "
|
|
# make sure terminal is set (else 'docker -it' fails)
|
|
I=\$(grep 'Terminal=' \$i | cut -d = -f 2) || I=
|
|
if [ ! -z "\$I" ]; then
|
|
sed -i 's|Terminal=.*|Terminal=true|g' \$i || echo " "
|
|
else
|
|
echo "Terminal=true" >> \$i
|
|
fi
|
|
chmod a+x \$i || echo " "
|
|
done
|
|
|
|
# create a Terminal launcher
|
|
echo "[Desktop Entry]" > launchers/$NAME-terminal.desktop
|
|
echo "Type=Application" >> launchers/$NAME-terminal.desktop
|
|
echo "Name=$NAME Terminal" >> launchers/$NAME-terminal.desktop
|
|
echo "Terminal=true" >> launchers/$NAME-terminal.desktop
|
|
echo "Exec=sh -c \"echo '$NAME'; $cmd\"" >> launchers/$NAME-terminal.desktop
|
|
chmod a+x launchers/$NAME-terminal.desktop
|
|
|
|
EOF
|
|
chmod a+x $WORK_DIR/build
|
|
|
|
if [ "x$BUILD" = "x1" ]; then
|
|
# build the image
|
|
(cd $WORK_DIR && ./build)
|
|
|
|
else
|
|
echo "INFO: To build this image, use: cd $WORK_DIR; ./build"
|
|
echo " "
|
|
cat $WORK_DIR/build
|
|
fi
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# get executables and Desktop launchers (from the Docker)
|
|
echo "------------------------------------------------------" >> $WORK_DIR/README
|
|
B=$(grep '\.desktop' $WORK_DIR/file_list.txt) || echo " "
|
|
echo "$B" >> $WORK_DIR/README
|
|
|
|
FILE=$WORK_DIR/start
|
|
dd status=none of=${FILE} << EOF
|
|
#!/bin/bash
|
|
# created by $0 on $DATE
|
|
#
|
|
# start a container from image $NAME
|
|
#
|
|
# Usage: start [CMD]
|
|
# default CMD is $CMD
|
|
|
|
$cmd \$@
|
|
EOF
|
|
chmod a+x $WORK_DIR/start
|
|
|
|
# display final message
|
|
echo "--------------------------------------------"
|
|
echo "The image $NAME has been prepared in $WORK_DIR"
|
|
echo " Desktop launchers are available in $WORK_DIR/launchers"
|
|
echo "To start $NAME, use:"
|
|
echo " cd $WORK_DIR; ./start [cmd]"
|
|
echo " "
|