diff --git a/Dockerfile b/Dockerfile index a43c096..08d798a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM debian:buster-slim # APT源配置:default / tencent / ustc / aliyun / huawei -ARG apt_source=tencent +ARG apt_source=aliyun ENV APP_NAME=dbuilder \ APP_USER=builder @@ -39,8 +39,8 @@ RUN select_source ${apt_source} # patch perl perl-modules-5.28 pinentry-curses pkg-config procps python3 # python3-minimal python3.7 python3.7-minimal readline-common sudo wget # xz-utils -RUN install_pkg sudo wget curl git ca-certificates iproute2 net-tools nano \ - dpkg gnupg dirmngr apt-utils apt-transport-https lsb-release iputils-ping \ +RUN install_pkg sudo wget curl git ca-certificates iproute2 net-tools nano dpkg gnupg \ + dirmngr apt-utils apt-transport-https lsb-release iputils-ping \ build-essential cmake libcmocka-dev pkg-config libssl-dev RUN prepare_env && create_user diff --git a/Makefile b/Makefile index 4040488..e7c8b04 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ current_tag:=$(shell if [ ! `git status >/dev/null 2>&1` ]; then git rev-parse - build-arg:=--build-arg apt_source=aliyun # 设置本地下载服务器路径,加速调试时的本地编译速度 -local_ip:=`ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $$2}'|tr -d "addr:"` +local_ip:=`echo "en0 eth0" |xargs -n1 ip addr show 2>/dev/null|grep inet|grep -v 127.0.0.1|grep -v inet6|tr "/" " "|awk '{print $$2}'` build-arg+=--build-arg local_url=http://$(local_ip)/dist-files .PHONY: build clean clearclean upgrade tag push @@ -32,7 +32,6 @@ build: @echo "Add tag: $(alpine_name):latest" @docker tag "$(alpine_name):$(current_tag)" $(alpine_name):latest -# 清理悬空的镜像(无TAG)及停止的容器 # 清理悬空的镜像(无TAG)及停止的容器 clearclean: clean @echo "Clean untaged images and stoped containers..." @@ -65,3 +64,4 @@ push: tag upgrade: @echo "Upgrade all images..." @docker images | grep 'colovu' | grep -v '' | grep -v "latest-" | awk '{print $$1":"$$2}' | sort -u | xargs -L 1 docker pull + diff --git a/README.md b/README.md index 8f9d1bc..3fe3ccc 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ 其中: - dbuilder:基于 Debian 系统的 Builder 环境 -- abuilder:基于 Alpine 系统的 Builder环境 +- abuilder:基于 Alpine 系统的 Builder 环境 **版本信息:** @@ -16,8 +16,9 @@ **镜像信息:** * 镜像地址: - * colovu/dbuilder:latest - * colovu/abuilder:latest + * registry.cn-shenzhen.aliyuncs.com/colovu/dbuilder:latest + * registry.cn-shenzhen.aliyuncs.com/colovu/abuilder:latest + ## 数据卷 @@ -25,7 +26,7 @@ ```shell /srv/data # 工作目录 - /srv/conf # 配置文件目录 + /srv/conf # 配置文件目录 ``` ## 用户 @@ -39,8 +40,8 @@ 使用`--from=0`方式: ```dockerfile -# 预编译阶段 -FROM colovu/abuilder +# 预编译阶段 =============================== +FROM registry.cn-shenzhen.aliyuncs.com/colovu/abuilder WORKDIR /build RUN \ @@ -49,7 +50,9 @@ RUN \ wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/${gosu_ver}/gosu-$dpkgArch"; \ chmod +x /usr/local/bin/gosu; -# 镜像生成阶段 +# ... 省略 + +# 镜像生成阶段 ============================== FROM scratch # 从编译阶段的中拷贝编译结果到当前镜像中 COPY --from=0 /usr/local/bin/gosu /usr/local/bin/ @@ -59,12 +62,19 @@ CMD [] 使用`--from=name`方式: ```dockerfile -# 预编译阶段。命名为`builder` -FROM colovu/abuilder as builder +# 预编译阶段。命名为`builder` ================== +FROM registry.cn-shenzhen.aliyuncs.com/colovu/abuilder as builder + +WORKDIR /build +RUN \ + dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ + gosu_ver=1.12; \ + wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/${gosu_ver}/gosu-$dpkgArch"; \ + chmod +x /usr/local/bin/gosu; # ... 省略 -# 镜像生成阶段 +# 镜像生成阶段 ============================== FROM scratch # 从编译阶段的中拷贝编译结果到当前镜像中 COPY --from=builder /usr/local/bin/gosu /usr/local/bin/ @@ -74,8 +84,7 @@ CMD [] 使用该方式的优势: - 因系统相关软件包已更新,工具已经预先安装,不需要在每次编译镜像时耗费大量时间在类似重复工作上 - -- 不用安装、删除临时软件,方式生成多余的垃圾文件;预编译阶段的内容使用完即丢弃,不会对镜像大小产生影响 +- 不用安装、删除临时软件,放置生成多余的垃圾文件;预编译阶段的内容使用完即丢弃,不会对镜像大小产生影响 diff --git a/alpine/Dockerfile b/alpine/Dockerfile index e4ff1fc..6efa87f 100644 --- a/alpine/Dockerfile +++ b/alpine/Dockerfile @@ -1,28 +1,29 @@ -# Ver: 1.0 by Endial Fang (endial@126.com) +# Ver: 1.2 by Endial Fang (endial@126.com) # FROM alpine:3.12 -# 说明: -# 虽然原始镜像包含 wget, 但该版本存在问题,下载部分资源(如redis)会报错,因此安装官方完整版 - # APK源配置:default / tencent / ustc / aliyun / huawei -ARG apt_source=tencent +ARG apt_source=aliyun ENV APP_NAME=abuilder \ APP_USER=builder LABEL \ "Version"="v3.12" \ - "Description"="Docker image for Builder based on Alpine." \ + "Description"="Docker image for Builder based on Alpine v3.12." \ "Dockerfile"="https://github.com/colovu/docker-builder" \ "Vendor"="Endial Fang (endial@126.com)" COPY prebuilds / COPY customer / RUN select_source ${apt_source} -RUN install_pkg sudo wget git curl ca-certificates iproute2 net-tools nano \ - dpkg dpkg-dev gnupg bash build-base cmake pkgconf \ + +# 说明: +# 虽然原始镜像包含 wget, 但该版本存在问题,下载部分资源(如redis)会报错,因此安装官方完整版 +RUN install_pkg sudo wget curl git ca-certificates iproute2 net-tools nano dpkg gnupg \ + dpkg-dev bash build-base cmake pkgconf \ linux-headers cmocka-dev openssl-dev + RUN prepare_env && create_user CMD [] \ No newline at end of file diff --git a/alpine/prebuilds/usr/local/scripts/libcommon.sh b/alpine/prebuilds/usr/local/scripts/libcommon.sh index 4b10d1f..2078677 100644 --- a/alpine/prebuilds/usr/local/scripts/libcommon.sh +++ b/alpine/prebuilds/usr/local/scripts/libcommon.sh @@ -35,8 +35,8 @@ print_command_help() { local arg for arg; do case "$arg" in - -'?'|--help|-V|--version) - exec "${APP_EXEC:-/bin/bash}" "${arg}" + -'?'|--help|-V|--version|-version) + exec "$@" exit ;; esac diff --git a/alpine/prebuilds/usr/local/scripts/liblog.sh b/alpine/prebuilds/usr/local/scripts/liblog.sh index 2b3e931..62f50da 100644 --- a/alpine/prebuilds/usr/local/scripts/liblog.sh +++ b/alpine/prebuilds/usr/local/scripts/liblog.sh @@ -1,5 +1,7 @@ #!/bin/bash # Ver: 1.1 by Endial Fang (endial@126.com) +# +# 日志输出函数库 #[[ ${ENV_DEBUG:-false} = true ]] && set -x MODULE="$(basename "$0")" diff --git a/alpine/prebuilds/usr/local/scripts/libnet.sh b/alpine/prebuilds/usr/local/scripts/libnet.sh new file mode 100644 index 0000000..9853696 --- /dev/null +++ b/alpine/prebuilds/usr/local/scripts/libnet.sh @@ -0,0 +1,120 @@ +#!/bin/bash +# Ver: 1.1 by Endial Fang (endial@126.com) +# +# 文件管理函数库 + +# 加载依赖项 +. /usr/local/scripts/liblog.sh # 日志输出函数库 + +# 函数列表 + +# 域名解析 +# 参数: +# $1 - 需要解析的主机名 +dns_lookup() { + local host="${1:?host is missing}" + getent ahosts "$host" | awk '/STREAM/ {print $1 }' +} + +# 尝试解析域名并返回对应的 IP +# 参数: +# $1 - 主机名 +# $2 - 尝试次数 +# $3 - 重试间隔时间(秒) +wait_for_dns_lookup() { + local hostname="${1:?hostname is missing}" + local retries="${2:-5}" + local seconds="${3:-1}" + check_host() { + if [[ $(dns_lookup "$hostname") == "" ]]; then + false + else + true + fi + } + # Wait for the host to be ready + retry_while "check_host ${hostname}" "$retries" "$seconds" + dns_lookup "$hostname" +} + +# 获取当前主机 IP +get_machine_ip() { + local -a ip_addresses + local hostname + hostname="$(hostname)" + read -r -a ip_addresses <<< "$(dns_lookup "$hostname" | xargs echo)" + if [[ "${#ip_addresses[@]}" -gt 1 ]]; then + LOG_W "Found more than one IP address associated to hostname ${hostname}: ${ip_addresses[*]}, will use ${ip_addresses[0]}" + elif [[ "${#ip_addresses[@]}" -lt 1 ]]; then + LOG_E "Could not find any IP address associated to hostname ${hostname}" + exit 1 + fi + echo "${ip_addresses[0]}" +} + +# Check if the provided argument is a resolved hostname +# 参数: +# $1 - 待检测的主机名 +# 返回值: +# 布尔值 +is_hostname_resolved() { + local -r host="${1:?missing value}" + if [[ -n "$(dns_lookup "$host")" ]]; then + true + else + false + fi +} + +# 解析 URL +# 参数: +# $1 - URI 字符串 +# $2 - 类型字符串. 有效值 (scheme, authority, userinfo, host, port, path, query or fragment) +# 返回值: +# 字符串 +parse_uri() { + local uri="${1:?uri is missing}" + local component="${2:?component is missing}" + + # Solution based on https://tools.ietf.org/html/rfc3986#appendix-B with + # additional sub-expressions to split authority into userinfo, host and port + # Credits to Patryk Obara (see https://stackoverflow.com/a/45977232/6694969) + local -r URI_REGEX='^(([^:/?#]+):)?(//((([^@/?#]+)@)?([^:/?#]+)(:([0-9]+))?))?(/([^?#]*))?(\?([^#]*))?(#(.*))?' + # || | ||| | | | | | | | | | + # |2 scheme | ||6 userinfo 7 host | 9 port | 11 rpath | 13 query | 15 fragment + # 1 scheme: | |5 userinfo@ 8 :... 10 path 12 ?... 14 #... + # | 4 authority + # 3 //... + local index=0 + case "$component" in + scheme) + index=2 + ;; + authority) + index=4 + ;; + userinfo) + index=6 + ;; + host) + index=7 + ;; + port) + index=9 + ;; + path) + index=10 + ;; + query) + index=13 + ;; + fragment) + index=14 + ;; + *) + stderr_print "unrecognized component $component" + return 1 + ;; + esac + [[ "$uri" =~ $URI_REGEX ]] && echo "${BASH_REMATCH[${index}]}" +} diff --git a/alpine/prebuilds/usr/sbin/download_pkg b/alpine/prebuilds/usr/sbin/download_pkg index c926119..c4ec2e9 100755 --- a/alpine/prebuilds/usr/sbin/download_pkg +++ b/alpine/prebuilds/usr/sbin/download_pkg @@ -1,5 +1,5 @@ #!/bin/bash -# Ver: 1.0 by Endial Fang (endial@126.com) +# Ver: 1.1 by Endial Fang (endial@126.com) # # shell 执行参数,分别为 -e(命令执行错误则退出脚本) -u(变量未定义则报错) -x(打印实际待执行的命令行) set -eux @@ -141,12 +141,12 @@ fi # 安装或解压软件 case "$1" in - download) - LOG_I "Download success: $CACHE_ROOT/$PACKAGE" - ;; + download) + LOG_I "Download success: $CACHE_ROOT/$PACKAGE" + ;; install) LOG_I "Installing $PACKAGE" - cp $CACHE_ROOT/$PACKAGE /usr/local/bin/ + cp $CACHE_ROOT/$PACKAGE /usr/local/bin/ ;; unpack) if ! tar -taf $CACHE_ROOT/$PACKAGE >/dev/null 2>&1; then diff --git a/prebuilds/usr/local/scripts/libcommon.sh b/prebuilds/usr/local/scripts/libcommon.sh index 4b10d1f..2078677 100644 --- a/prebuilds/usr/local/scripts/libcommon.sh +++ b/prebuilds/usr/local/scripts/libcommon.sh @@ -35,8 +35,8 @@ print_command_help() { local arg for arg; do case "$arg" in - -'?'|--help|-V|--version) - exec "${APP_EXEC:-/bin/bash}" "${arg}" + -'?'|--help|-V|--version|-version) + exec "$@" exit ;; esac diff --git a/prebuilds/usr/local/scripts/liblog.sh b/prebuilds/usr/local/scripts/liblog.sh index 2b3e931..62f50da 100644 --- a/prebuilds/usr/local/scripts/liblog.sh +++ b/prebuilds/usr/local/scripts/liblog.sh @@ -1,5 +1,7 @@ #!/bin/bash # Ver: 1.1 by Endial Fang (endial@126.com) +# +# 日志输出函数库 #[[ ${ENV_DEBUG:-false} = true ]] && set -x MODULE="$(basename "$0")" diff --git a/prebuilds/usr/local/scripts/libnet.sh b/prebuilds/usr/local/scripts/libnet.sh new file mode 100644 index 0000000..9853696 --- /dev/null +++ b/prebuilds/usr/local/scripts/libnet.sh @@ -0,0 +1,120 @@ +#!/bin/bash +# Ver: 1.1 by Endial Fang (endial@126.com) +# +# 文件管理函数库 + +# 加载依赖项 +. /usr/local/scripts/liblog.sh # 日志输出函数库 + +# 函数列表 + +# 域名解析 +# 参数: +# $1 - 需要解析的主机名 +dns_lookup() { + local host="${1:?host is missing}" + getent ahosts "$host" | awk '/STREAM/ {print $1 }' +} + +# 尝试解析域名并返回对应的 IP +# 参数: +# $1 - 主机名 +# $2 - 尝试次数 +# $3 - 重试间隔时间(秒) +wait_for_dns_lookup() { + local hostname="${1:?hostname is missing}" + local retries="${2:-5}" + local seconds="${3:-1}" + check_host() { + if [[ $(dns_lookup "$hostname") == "" ]]; then + false + else + true + fi + } + # Wait for the host to be ready + retry_while "check_host ${hostname}" "$retries" "$seconds" + dns_lookup "$hostname" +} + +# 获取当前主机 IP +get_machine_ip() { + local -a ip_addresses + local hostname + hostname="$(hostname)" + read -r -a ip_addresses <<< "$(dns_lookup "$hostname" | xargs echo)" + if [[ "${#ip_addresses[@]}" -gt 1 ]]; then + LOG_W "Found more than one IP address associated to hostname ${hostname}: ${ip_addresses[*]}, will use ${ip_addresses[0]}" + elif [[ "${#ip_addresses[@]}" -lt 1 ]]; then + LOG_E "Could not find any IP address associated to hostname ${hostname}" + exit 1 + fi + echo "${ip_addresses[0]}" +} + +# Check if the provided argument is a resolved hostname +# 参数: +# $1 - 待检测的主机名 +# 返回值: +# 布尔值 +is_hostname_resolved() { + local -r host="${1:?missing value}" + if [[ -n "$(dns_lookup "$host")" ]]; then + true + else + false + fi +} + +# 解析 URL +# 参数: +# $1 - URI 字符串 +# $2 - 类型字符串. 有效值 (scheme, authority, userinfo, host, port, path, query or fragment) +# 返回值: +# 字符串 +parse_uri() { + local uri="${1:?uri is missing}" + local component="${2:?component is missing}" + + # Solution based on https://tools.ietf.org/html/rfc3986#appendix-B with + # additional sub-expressions to split authority into userinfo, host and port + # Credits to Patryk Obara (see https://stackoverflow.com/a/45977232/6694969) + local -r URI_REGEX='^(([^:/?#]+):)?(//((([^@/?#]+)@)?([^:/?#]+)(:([0-9]+))?))?(/([^?#]*))?(\?([^#]*))?(#(.*))?' + # || | ||| | | | | | | | | | + # |2 scheme | ||6 userinfo 7 host | 9 port | 11 rpath | 13 query | 15 fragment + # 1 scheme: | |5 userinfo@ 8 :... 10 path 12 ?... 14 #... + # | 4 authority + # 3 //... + local index=0 + case "$component" in + scheme) + index=2 + ;; + authority) + index=4 + ;; + userinfo) + index=6 + ;; + host) + index=7 + ;; + port) + index=9 + ;; + path) + index=10 + ;; + query) + index=13 + ;; + fragment) + index=14 + ;; + *) + stderr_print "unrecognized component $component" + return 1 + ;; + esac + [[ "$uri" =~ $URI_REGEX ]] && echo "${BASH_REMATCH[${index}]}" +} diff --git a/prebuilds/usr/sbin/download_pkg b/prebuilds/usr/sbin/download_pkg index 6bd7a96..0958b50 100755 --- a/prebuilds/usr/sbin/download_pkg +++ b/prebuilds/usr/sbin/download_pkg @@ -141,9 +141,9 @@ fi # 安装或解压软件 case "$1" in - download) - LOG_I "Download success: $CACHE_ROOT/$PACKAGE" - ;; + download) + LOG_I "Download success: $CACHE_ROOT/$PACKAGE" + ;; install) LOG_I "Installing $PACKAGE" cp $CACHE_ROOT/$PACKAGE /usr/local/bin/