initial working build and supporting scripts

master
Kebler Network System Administrator 2022-10-20 18:48:17 -07:00
parent 52d188e8c9
commit f50c85cce9
24 changed files with 659 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/archive/
/images/
/build.log

15
Dockerfile Normal file
View File

@ -0,0 +1,15 @@
ARG BASE_IMAGE
FROM $BASE_IMAGE
ARG LINUX_DISTRO=alpine
WORKDIR /opt/$LINUX_DISTRO
COPY ./distros/$LINUX_DISTRO ./distros/common ./
RUN echo "****** Building UCI Image ffrom Base $BASE_IMAGE; Distro: $LINUX_DISTRO *****"; \
chmod -R +x /opt/$LINUX_DISTRO; ls -la; pwd; \
echo " **** Running ${LINUX_DISTRO} specific init script ***** "; cat init.sh; ./init.sh; \
echo " ***** Running common initialzation script *****"; cat common.sh; ./common.sh \
echo " ********************************************************"
# ENTRYPOINT ["entrypoint.sh"]
CMD ["/bin/bash"]

105
build Executable file
View File

@ -0,0 +1,105 @@
#!/bin/bash
declare targets=(dev arm amd deploy private multi)
declare OPTION; declare OPTARG; declare OPTIND
while getopts 'b:d:t:nyr:u:px' OPTION; do
# echo processing: option:$OPTION argument:$OPTARG index:$OPTIND remaining:${@:$OPTIND}
case "$OPTION" in
b)
# CUSTOM BASE IMAGE
BASE_IMAGE=$OPTARG
;;
d)
# LINUX_DISTRO=$OPTARG
LINUX_DISTRO=$OPTARG
;;
x)
# Exclude distro from image name
exclude_distro=true
;;
t)
TAG=$OPTARG
;;
u)
RUSER=$OPTARG
;;
y)
try=true
;;
p)
push=true
;;
n)
NO_CACHE=true
;;
r)
REPO=$OPTARG
;;
*) echo unknown run option -$OPTARG
echo "USAGE: build <setup options> target(or target)"
echo "available options -d <LINUX_DISTRO>; -t <TAG>; -e execute test script after build; -n for --no_cache "
;;
esac
done
shift $((OPTIND - 1))
[ $NO_CACHE ] && nocache="--no-cache" || nocache=""
target=${1:-dev}
LINUX_DISTRO=${LINUX_DISTRO:-alpine}
name=$2
RUSER=${3:-$RUSER}
IMAGE_NAME=$([[ $RUSER ]] && echo ${RUSER}/)${name}$([[ (! $exclude_distro) && $name ]] && echo "-")$([[ ! $exclude_distro ]] && echo ${LINUX_DISTRO})
if [[ $BASE_IMAGE ]]; then
echo determining DISTRO of base image: $BASE_IMAGE
LINUX_DISTRO=$(./image-distro $BASE_IMAGE)
[[ ! $LINUX_DISTRO ]] && echo "unable to get base image OS for: $BASE_IMAGE, aborting build" && exit 1
else
BASE_IMAGE=$LINUX_DISTRO
fi
# BASE_IMAGE=$([[ $BASE_IMAGE == *:* ]] && echo $BASE_IMAGE || echo $BASE_IMAGE:latest)
#$([[ ! $BASE_IMAGE == *:* ]] && echo :latest)
export BASE_IMAGE
export TAG
export IMAGE_NAME
export LINUX_DISTRO
echo "building with base image: $BASE_IMAGE, output image name => $IMAGE_NAME"
echo "Linux Distro: $LINUX_DISTRO"
echo "***** using build target: $target ****"
docker buildx bake --print $target
echo "******************"
read -n 1 -p "do you want to continue [y]=>" REPLY
[[ $REPLY != "y" ]] && echo -e "\n" && exit 0
[[ ! "${targets[@]}" =~ $target ]] && echo $target is not a valid target && echo valid targets are: ${targets[@]} && exit 4
builder=default
if [ $target == "deploy" ]; then
builder=deploy
if ! docker buildx ls | grep -q deploy ; then
echo multiarch deploy builder does not exist, creating with docker-container driver
docker buildx create --name deploy --driver docker-container >/dev/null
docker buildx ls | grep deploy
fi
fi
[[ $target == "private" && ! $REPO ]] && echo "must use '-r <private repo>' if building to private repo" && exit 3
docker buildx --builder ${builder} bake ${nocache} ${target} 2>&1 | tee build.log
if [[ $target == "private" ]]; then
./push -a -r $REPO $IMAGE_NAME
./push -r $REPO $IMAGE_NAME
else
if [[ $push && (! $target == "dev") ]];then
echo pushing now
./push $([[ $target == "arm" ]] && echo -a) -r $REPO $IMAGE_NAME
fi
fi
[[ $try || $target == "dev" ]] && ./try $([[ $target == "deploy" ]] && echo -p) $name $RUSER

6
distros/alpine/init.sh Normal file
View File

@ -0,0 +1,6 @@
#!/bin/sh
echo alpine distro uci script
apk update; apk upgrade;
echo ">>>> installing packages => $(cat packages) $(cat common-packages)"
apk add --no-cache bash bash-completion $(cat packages) $(cat common-packages)
# apk add bindfs --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing

0
distros/alpine/packages Normal file
View File

View File

@ -0,0 +1 @@
wget curl git rsync

12
distros/common/common.sh Normal file
View File

@ -0,0 +1,12 @@
#!/bin/bash
echo -e "\n##################################"
mkdir -p /opt/scripts /opt/bin /shell /data
git clone https://git.kebler.net/bash/shell-base.git /shell/base
cp ucishell.sh /shell/base/setup
/shell/base/setup/ucishell.sh
if [[ -f post_common.sh ]]; then
echo "running distro specific commands after common install in post_common.sh"
./post_common.sh
fi
# install and display distro info
./info.sh

4
distros/common/info.sh Normal file
View File

@ -0,0 +1,4 @@
#!/bin/bash
wget -O /opt/scripts/info https://git.io/vaHfR;
chmod +x /opt/scripts/info
ln -s /opt/scripts/info /opt/bin

23
distros/common/ucishell.sh Executable file
View File

@ -0,0 +1,23 @@
#!/bin/bash
DIR=$(cd "$(dirname "$BASH_SOURCE")" >/dev/null 2>&1 ; pwd -P )
if [ $EUID != 0 ]; then
sudo $DIR/deploy.sh $(whoami)
fi
BASH_SHELL_BASE="$(dirname $DIR)"
echo Base Shell Directory as detected is $BASH_SHELL_BASE
echo -----------------;echo deploying /etc shell files
files=$(find $BASH_SHELL_BASE/setup/etc/ -maxdepth 1 -type f)
for file in $files; do install -m 644 -o root -g root $file /etc; done
echo setting BASH_SHELL_BASE to $BASH_SHELL_BASE in etc/bash.bashrc and /etc/profile
sed -i 's:_BASH_SHELL_BASE_:'${BASH_SHELL_BASE}':' /etc/bash.bashrc
sed -i 's:BASH_SHELL_BASE=.*:BASH_SHELL_BASE='${BASH_SHELL_BASE}':' /etc/profile
files=$(find $BASH_SHELL_BASE/setup/etc/profile.d -maxdepth 1 -type f)
for file in $files; do install -m 644 -o root -g root $file /etc/profile.d; done
echo -----------------;echo deploying /root shell files
group=root
files=$(find $BASH_SHELL_BASE/setup/root/ -type f)
for file in $files; do install -m 640 -o root -g $group $file /root; done
echo -----------------

4
distros/debian/init.sh Normal file
View File

@ -0,0 +1,4 @@
#!/bin/sh
echo ubuntu distro uci script
apt-get update
apt-get install wget -y

117
distros/ubuntu/add-ppa.sh Executable file
View File

@ -0,0 +1,117 @@
#!/bin/bash
add-ppa () {
if [ $EUID != 0 ]; then
sudo bash -c "$(declare -f add-ppa); add-ppa $*"
else
VERSION=jammy
KEYSDIR=/etc/apt/trusted.gpg.d
KEYSERVER=keyserver.ubuntu.com
declare OPTION; declare OPTARG; declare OPTIND
while getopts 'v:p:s:k:c:d:oi' OPTION; do
echo processing: option:$OPTION argument:$OPTARG index:$OPTIND remaining:${@:$OPTIND}
case "$OPTION" in
i)
INSTALL=true
;;
v)
VERSION=$OPTARG
;;
p)
PACKAGE=$OPTARG
;;
c)
CMD=$OPTARG
;;
d)
KEYSDIR=$OPTARG
;;
s)
KEYSERVER=$OPTARG
;;
o)
# overwrite any exising public key
KEYOVERWRITE=true
;;
*) echo unknown run option -$OPTARG
echo "USAGE: add-ppa <options> package/branch (e.g. git-core/ppa)"
echo "available options -v <ubnutu version name - default Jammy>; -p <apt install package name if not the same>"
;;
esac
done
shift $((OPTIND - 1))
#check input
if [ -z ${1+x} ]; then
echo "No ppa provided!"
return 1
fi
LAUNCHPAD="https://ppa.launchpadcontent.net"
DEV=$(echo $1 | cut -d ':' -f 2 | cut -d '/' -f1 )
PACKAGE=${PACKAGE:-$DEV}
CMD=${CMD:-$PACKAGE}
BRANCH=${2:-$(echo $1| cut -d '/' -f 2)}
URL="$LAUNCHPAD/$DEV/$BRANCH/ubuntu $VERSION main"
echo "*********** Adding PPA Repository ************"
echo DEVELOPER: $DEV
echo BRANCH: $BRANCH
echo PACKAGE: $PACKAGE
echo COMMAND: $CMD
echo URL: $URL
if [[ -t 0 ]]; then
read -n 1 -p "do you want to continue [y]=>" REPLY
[[ $REPLY != "y" ]] && return 0
fi
echo -e "\n*********************************************"
#create source list file
echo "deb $URL" > /etc/apt/sources.list.d/$DEV.list
echo "***** added /etc/apt/sources.list.d/$DEV.list with****"
cat /etc/apt/sources.list.d/$DEV.list
echo "*********************************************"
KEYFILE=$KEYSDIR/$DEV.gpg
[[ $KEYOVERWRITE ]] && rm $KEYFILE
if [ ! -f $KEYFILE ]; then
# using an update error to grab key id
KEY_ERROR=/tmp/${DEV}_key_error
touch $KEY_ERROR
apt-get update > /dev/null 2> $KEY_ERROR
cat $KEY_ERROR
KEY=$(sed -n 's/^.*NO_PUBKEY //p' "$KEY_ERROR" | head -1)
# echo Reposity Public Key Settings
# echo KEYS DIRECTORY: $KEYSDIR
# echo KEY SERVER: $KEYSERVER
# echo KEY: $KEY
if [ ! $KEY ]; then
echo can not determine $DEV/$BRANCH key sign
echo "removing file: /etc/apt/sources.list.d/$DEV.list and aborting"
rm /etc/apt/sources.list.d/$DEV.list
return 1
fi
echo downloading and saving public key $KEY for $DEV/$BRANCH to $KEYFILE
gpg --keyserver $KEYSERVER --recv $KEY
gpg --export $KEY > $KEYFILE
else
echo " >>>>>> $KEYFILE already exists, using that key $KEY <<<<<"
fi
echo ppa repo $DEV/$BRANCH for package $PACKAGE now registered, updating...
apt-get update 1> /dev/null
if [[ $INSTALL ]]; then
echo installing $PACKAGE
[[ -t 0 ]] && apt policy $PACKAGE
apt-get install $PACKAGE -y
$CMD --version
fi
fi
}
# # if script was executed then call the function
(return 0 2>/dev/null) || add-ppa $@

6
distros/ubuntu/init.sh Normal file
View File

@ -0,0 +1,6 @@
#!/bin/bash
echo ubuntu distro uci script
apt-get update
echo ">>>> installing packages => $(cat packages) $(cat common-packages)"
apt-get install $(cat packages) $(cat common-packages) -y
./add-ppa.sh -i -p git git-core/ppa

1
distros/ubuntu/packages Normal file
View File

@ -0,0 +1 @@
gpg

82
docker-bake.hcl Normal file
View File

@ -0,0 +1,82 @@
# variables
variable "TAG" {
default = "latest"
}
variable "LINUX_DISTRO" {
default = "alpine"
}
variable "IMAGE_NAME" {
default = "alpine"
}
variable "BASE_IMAGE" {
default = "alpine"
}
function "tag" {
params = [suffix]
result = [format("${IMAGE_NAME}%s:${TAG}", notequal("", suffix) ? "-${suffix}" : "")]
}
# groups
group "dev" {
targets = ["amd"]
}
group "default" {
targets = ["amd"]
}
group "deploy" {
targets = ["multi"]
}
group "private" {
targets = [
"amd",
"arm"
]
}
# intended for use with default local docker builder
# uses 'dev' group in docker-bake.hcl
# assume dev machine is amd64 machine
target "amd" {
context = "."
dockerfile = "Dockerfile"
args = {
LINUX_DISTRO = "${LINUX_DISTRO}"
BASE_IMAGE = "${BASE_IMAGE}"
TAG = "${TAG}"
}
tags = tag("")
platforms = ["linux/amd64"]
}
# intended for use with default docker driver on an arm64 machine
# use with 'arm' group
target "arm" {
inherits = ["amd"]
tags = tag("arm64")
platforms = ["linux/arm64"]
}
# must use with docker-container driver for multiarch image deployment to registry
# uses 'deploy' group in docker-bake.hcl
target "multi" {
inherits = ["amd"]
tags = tag("")
platforms = ["linux/amd64", "linux/arm64"]
output = ["type=registry"]
}
// variable "RUSER" {
// default = ""
// }
// function "user" {
// params = []
// result = [notequal("", RUSER) ? "${RUSER}/" : ""]
// }
// function "tagamd" {
// params = []
// result = [
// format("%s${LINUX_DISTRO}:${TAG}", notequal("", RUSER) ? "${RUSER}/" : ""),
// format("%s${LINUX_DISTRO}-amd64:${TAG}", notequal("", RUSER) ? "${RUSER}/" : "")
// ]
// }

3
image-arch Executable file
View File

@ -0,0 +1,3 @@
tag=$(./make-tag $@)
info=$(docker image inspect $tag)
echo $info | jq '.[] | .Architecture'

4
image-distro Executable file
View File

@ -0,0 +1,4 @@
docker run -it $1 /bin/sh -c "cat /etc/os-release" > /tmp/container-os.tmp 2> /dev/null
. /tmp/container-os.tmp
echo $ID
rm /tmp/container-os.tmp

12
image-info Executable file
View File

@ -0,0 +1,12 @@
#!/bin/bash
[[ $1 == "-k" ]] && key=$2 && shift 2
tag=$(./make-tag $@)
info=$(docker image inspect $tag 2> /dev/null) || info=$(docker image inspect $1) ||
exit
if [[ $key ]]; then
# echo image: $tag, key:$key
echo $info | jq --arg k "$key" '.[] | .[$k]'
else
# quote to preserve newlines
echo "$info"
fi

46
make-tag Executable file
View File

@ -0,0 +1,46 @@
#!/bin/bash
DIR=$(cd "$(dirname "$BASH_SOURCE")" >/dev/null 2>&1 ; pwd -P )
#tags an image and pushes it to a <custom private> repository
# if not reposity is given will use docker.io and push to hub.docker.com
# $1 name, $2 user(or repo), $3 repo
[[ $# -lt 1 ]] && echo "image base name required" && exit
declare OPTION; declare OPTARG; declare OPTIND
while getopts 'daht:r:u:' OPTION; do
# echo processing: option:$OPTION argument:$OPTARG index:$OPTIND remaining:${@:$OPTIND}
case "$OPTION" in
d)
delete=true
;;
r)
REPO=$OPTARG
;;
u)
RUSER=$OPTARG
;;
t)
TAG=$OPTARG
;;
a) # add -arm64 to image
arm=arm64
;;
*) echo unknown run option -$OPTARG
echo "USAGE: tag <options>"
echo "available options: -a add -arm64 to tag, -d delete tag "
;;
esac
done
shift $((OPTIND - 1))
# image tag
name=$1
user=${2:-$RUSER}
repo=${3:-$REPO}
tag=$([[ $repo ]] && echo ${repo}/)$([[ $user ]] && echo ${user}/)$name$([[ $arm ]] && echo -arm64):${TAG:-latest}
echo $tag

85
push Executable file
View File

@ -0,0 +1,85 @@
#!/bin/bash
DIR=$(cd "$(dirname "$BASH_SOURCE")" >/dev/null 2>&1 ; pwd -P )
#tags an image and pushes it to a <custom private> repository
# if not reposity is given will use docker.io and push to hub.docker.com
# $1 name, $2 user(or repo), $3 repo
[[ $# -lt 1 ]] && echo "image base name required" && exit
declare OPTION; declare OPTARG; declare OPTIND
while getopts 'aht:r:u:' OPTION; do
# echo processing: option:$OPTION argument:$OPTARG index:$OPTIND remaining:${@:$OPTIND}
case "$OPTION" in
r)
REPO=$OPTARG
;;
u)
RUSER=$OPTARG
;;
t)
TAG=$OPTARG
;;
h) # pull image from dockerhub if not available
hub=true
;;
a) # arm image
arm=arm64
;;
*) echo unknown run option -$OPTARG
echo "USAGE: start <options>"
echo "available options: -h pull from hub.docker.com if not available, -a push arm64 image, -t <latest> custom tag "
;;
esac
done
shift $((OPTIND - 1))
# image tag
name=$1
user=${2:-$RUSER}
repo=${3:-$REPO}
source=$([[ $user ]] && echo ${user}/)$name:${TAG:-latest}
source2=$([[ $arm ]] && echo ${source//:/-arm64:} || echo $source)
target=$([[ $repo ]] && echo ${repo}/)$source2
if ! docker image inspect $source2 > /dev/null 2>&1; then
echo "no image $source2 available to push"
[[ ! $hub ]] &&echo use -h to attempt to pull image from hub.docker.com
if [[ $hub ]]; then
echo attempting to pull $source2
if ! docker pull $source2 > /dev/null 2>&1; then
echo unable to pull $source2 from hub.docker.com
platform=$([[ $arm ]] && echo "--platform linux/$arm")
echo trying to pull $platform $source from hub.docker.com
if ! docker pull $platform $source > /dev/null 2>&1; then
echo unable to pull $platform $source, aborting
exit 2
else
hub=downloaded
source2=$source
fi
else
hub=downloaded
fi
else
exit 1
fi
fi
echo pushing $source2 to $target
docker tag $source2 $target
if ! docker image push $target > /dev/null 2>&1; then
echo ERROR: unable to push $source2 to repository at $1 as $target
fi
if [[ $hub == downloaded ]]; then
echo removing $source2 downloaded from hub.docker.com docker
docker image rm $source2 > /dev/null 2>&1
fi
echo removing tag $target
docker image rm $target > /dev/null 2>&1

20
readme.md Normal file
View File

@ -0,0 +1,20 @@
# UCI Docker Image Builder
A set of scripts to facilitate building docker linux (amd64/arm64) images using any of three distros (alpine,debian,ubuntu)
The Dockerfile is minimal calling a set of distro specific scripts and common scripts in order to build the image
The build environment makes user of docker's "buildx bake" commands and a docker-bake.hcl file
The master branch is configured to build base images from the docker hub distro base images
The main script is "build" At the very minimum run as just `./build` it will build an alpine image from the docker hub official alpine latest image with a minimal set of packages installed (e.g. git) and a custom uci shell environment.
By using the -b flag you can set an alternative FROM image. In this way you can make your own script that builds multiple tiers of images
The repo also supports (with scripts) pushing to alternate private repositories (like self hosted gitea)
starting a new branch is a good way to work on a new image by editing the script files in the distros folder

12
rebuild Executable file
View File

@ -0,0 +1,12 @@
#!/bin/bash
# three ways to invoke with --no-cache
# inline
# NO_CACHE=true ./build "$@"
# with -n option (prefered)
./build -n "$@"
# as export
#export NO_CACHE=true
#./build "$@"

28
tag Executable file
View File

@ -0,0 +1,28 @@
#!/bin/bash
DIR=$(cd "$(dirname "$BASH_SOURCE")" >/dev/null 2>&1 ; pwd -P )
#tags an image and pushes it to a <custom private> repository
# if not reposity is given will use docker.io and push to hub.docker.com
# $1 name, $2 user(or repo), $3 repo
[[ $# -lt 1 ]] && echo "image base name required" && exit
[[ $1 == "-d" ]] && delete=true && shift 1
[[ $1 == "-f" ]] && force=true && shift 1
[[ $force ]] && docker rmi -f $(docker images -q $(./make-tag $@)) && exit 0
if [[ $delete ]];then
id=$(docker images -q $(./make-tag $@))
docker rmi $(./make-tag $@)
else
docker tag $(./make-tag $1) $(./make-tag $2)
id=$(docker images -q $(./make-tag $2))
fi
echo tags after operation for image $id
./image-info -k RepoTags $id

62
try Executable file
View File

@ -0,0 +1,62 @@
#!/bin/bash
file=try.yml
DIR=$(cd "$(dirname "$BASH_SOURCE")" >/dev/null 2>&1 ; pwd -P )
#tags an images and pushes it to a <custom private> repository
# if not reposity is given will use docker.io and push to hub.docker.com
# $1 name, $2 user
declare -A arch=( ["x86_64"]="" ["aarch64"]="-arm64")
[[ $# -lt 1 ]] && echo "image name required to try" && exit
declare OPTION; declare OPTARG; declare OPTIND
while getopts 'pt:u:' OPTION; do
# echo processing: option:$OPTION argument:$OPTARG index:$OPTIND remaining:${@:$OPTIND}
case "$OPTION" in
u)
RUSER=$OPTARG
;;
t)
TAG=$OPTARG
;;
p)
PROD=$OPTARG
;;
*) echo unknown run option -$OPTARG
echo "USAGE: try <options>"
echo "available options: -t <latest> custom tag "
;;
esac
done
shift $((OPTIND - 1))
# build up package tag
name=$1
user=${2:-$RUSER}
image=$([[ $user ]] && echo ${user}/)$name:${TAG:-latest}
if [[ $PROD ]]; then
echo removing any local copy of image $image
docker image rm $source
HOST=prod
else
HOST=local
image=${image/:/${arch[$(uname -p)]}:}
fi
echo starting container with image $image
export IMAGE=$image
export HOST
shopt -s extglob
export NAME=${image//+([^A-Za-z0-9])/-}
docker-compose -f $file down;
docker-compose -f $file up -d;
docker exec -it try-$NAME /bin/bash -l
docker-compose -f $file down;
# return to starting directory
# popd

8
try.yml Normal file
View File

@ -0,0 +1,8 @@
version: "3"
services:
uci:
image: $IMAGE
container_name: try-$NAME
hostname: try-$HOST-$NAME
command: ["sleep", "infinity"]