77 Commits
11 ... 13

Author SHA1 Message Date
endial 30cc6e3627 feat: 更新 Submodule 版本,支持单段纯数字分支生成标签
ci/woodpecker/push/woodpecker Pipeline was successful
2026-01-20 11:32:04 +08:00
endial 8aeab53490 docs: 更新说明文档
ci/woodpecker/push/woodpecker Pipeline was successful
2026-01-20 10:29:44 +08:00
endial 77781826f6 feat: 删除Dockerfile中的架构参数 2026-01-20 10:29:38 +08:00
endial 9c787cc178 feat: 更新本地编译脚本 2026-01-20 10:29:29 +08:00
endial 06c26ced8c feat: 更新用户自定义配置路径 2026-01-20 10:23:35 +08:00
endial cc2f114a10 feat: 更新默认源仓库为 aliyun
ci/woodpecker/push/woodpecker Pipeline was successful
2026-01-13 17:03:36 +08:00
endial 9eec253689 feat: 更新 Submodule 版本
ci/woodpecker/push/woodpecker Pipeline failed
2026-01-13 17:01:36 +08:00
endial b8b81cdd49 fix: 修复流水线配置中触发条件错误[SKIP CI] 2026-01-13 10:53:22 +08:00
endial 6ba6be6105 feat: 增加流水线配置文件
ci/woodpecker/push/woodpecker Pipeline was successful
2026-01-12 18:20:17 +08:00
endial 1f65e16196 feat: 更新为基于 Woodpecker 流水线的编译版本 2026-01-12 18:19:51 +08:00
endial 23333f771e feat: 脚本删除异常检测 2025-04-21 18:24:48 +08:00
endial ed50c9f00c docs: 更新说明 2025-04-21 14:27:14 +08:00
endial 7890ae736b feat: Dockerfile增加脚本异常检测 2025-04-21 12:28:42 +08:00
endial 6392a92452 feat: 删除脚本中的命令回显 2025-04-21 11:15:50 +08:00
endial 19dd3b17b0 feat: 变更脚本库文件至/usr/local 2025-04-21 11:15:03 +08:00
endial 5f6f1dd229 feat: 增加粗体定义 2025-04-21 09:21:02 +08:00
endial e0938e3468 docs: 更新描述文档 2025-04-09 17:33:09 +08:00
endial e7e0ebba82 feat: 优化脚本,删除无用信息 2025-04-09 17:32:03 +08:00
endial 5117f79d44 docs: 更新描述文档 2025-04-09 16:34:03 +08:00
endial e6413d9018 feat: 更新镜像打包脚本 2025-04-09 09:04:28 +08:00
endial 4bfc4341bb feat: 合并12版本分支的修改,删除无效文件 2025-04-08 11:07:03 +08:00
endial b6192f1eea feat: 脚本增加执行权限 2025-04-08 10:57:26 +08:00
endial 205cfb1b24 feat: 合并12版本分支的修改 2025-04-08 10:56:25 +08:00
endial 9208145f7d feat: 更新默认shell脚本 2025-04-08 10:49:21 +08:00
endial 02fe9112bd feat: 更新工具脚本 2025-04-07 12:04:15 +08:00
endial b0d7ef1443 feat: 更新编译脚本 2025-04-07 12:02:16 +08:00
endial 541bedc8d7 docs: 更新描述文档 2025-04-07 11:59:49 +08:00
endial 7981754a15 feat: 变更使用新版Dockerfile模板 2023-09-06 14:57:44 +08:00
endial 9b0c36f9b4 feat: 变更使用新版Dockerfile模板 2023-09-06 14:57:32 +08:00
endial 09c9b94fe6 feat: 本地编译脚本增加main/master分支的识别 2023-09-06 14:51:59 +08:00
endial 9308353269 feat: 本地编译脚本增加main/master分支的识别 2023-09-06 14:51:34 +08:00
endial 7458ddbb04 docs: 更新文档中有关镜像仓库地址 2023-09-06 14:49:32 +08:00
endial e7ace2f265 docs: 更新文档中有关镜像仓库地址 2023-09-06 14:49:16 +08:00
endial ea5a08d2a1 feat: 更新临时镜像清理命令 2023-09-06 14:36:06 +08:00
endial 687ad446b1 feat: 更新临时镜像清理命令 2023-09-06 14:35:49 +08:00
endial 811a173bcb feat: 更新Docker打包时的忽略信息 2023-09-06 14:34:48 +08:00
endial 33bca9c36a feat: 更新Docker打包时的忽略信息 2023-09-06 14:33:15 +08:00
endial b95c1f1e6b feat: 更新脚本库路径 2023-08-14 10:01:12 +08:00
endial a1854ff46b feat: 更新本地编译命令 2023-08-14 10:00:50 +08:00
endial 6a5e8bd8b1 feat: 更新脚本库路径 2023-08-14 09:59:45 +08:00
endial 26cefdf70a feat: 更新常用脚本库路径;删除 Docker Hub Hooks 2023-08-14 09:59:05 +08:00
endial f96ab0856f fix: 因为runner为动态分配,清理工作应该在每个阶段直接执行 2023-08-11 09:44:25 +08:00
endial e558641efa fix: 因为runner为动态分配,清理工作应该在每个阶段直接执行 2023-08-11 09:43:54 +08:00
endial fc7a702490 feat: 更新本地缓存资源路径 2023-08-11 09:34:41 +08:00
endial c4d6c6139c feat: 更新本地缓存资源路径 2023-08-11 09:34:21 +08:00
endial baa4ae442e feat: 增加 CI/CD 清理临时资源处理 2023-08-11 09:26:54 +08:00
endial 71dbb24855 feat: 增加 CI/CD 清理临时资源处理 2023-08-11 09:25:55 +08:00
endial fbab292cf6 fix: 帮助命令增加检测参数 2023-08-04 17:11:25 +08:00
endial 105cd5ea48 fix: 帮助命令增加检测参数 2023-08-04 17:09:10 +08:00
endial 640e5d76db feat: 优化 Dockerfile 2023-08-04 14:14:18 +08:00
endial 7ba5c9d5b2 feat: 增加默认 LICENSE 文件,优化镜像层数 2023-08-04 14:12:22 +08:00
endial cc7856e226 feat: 更新系统管理工具脚本 2023-08-04 14:12:22 +08:00
endial 0eab6d2e54 feat: 更新 CI/CD 编译阶段定义 2023-08-04 14:12:22 +08:00
endial a4bd3c4fe0 fix: 解决 APP_NAME 未定义时脚本退出问题 2023-08-04 14:12:22 +08:00
endial 77063b241a feat: 更新系统源定义 2023-08-04 14:12:22 +08:00
endial e89f4671f1 feat: 优化 Dockerfile 2023-08-04 14:00:33 +08:00
endial 7c4c814866 feat: 增加默认 LICENSE 文件,优化镜像层数 2023-08-04 12:13:48 +08:00
endial fb22f8a250 feat: 更新系统管理工具脚本 2023-08-04 12:02:41 +08:00
endial 1023af1160 feat: 更新 CI/CD 编译阶段定义 2023-08-04 11:16:26 +08:00
endial 4cac36aa57 fix: 解决 APP_NAME 未定义时脚本退出问题 2023-08-04 11:13:16 +08:00
endial 9b3ba3c09c feat: 更新系统源定义 2023-08-04 11:12:36 +08:00
endial 8ba9e0795d feat: 更新 Colovu 脚本存储路径 2023-08-04 10:25:54 +08:00
endial 2bf365e2ab feat: 更新环境变量定义及脚本调用(APP_NAME/APP_VER) 2023-08-03 12:31:31 +08:00
endial 952dd74fce feat: 更新环境变量定义及脚本调用(APP_NAME/APP_VER) 2023-08-03 12:30:32 +08:00
endial 455242e2cb feat: CI/CD 增加 tag 选择编译环境 2023-08-02 09:24:08 +08:00
endial b63661dd2c feat: CI/CD 增加 tag 选择编译环境 2023-08-02 09:17:42 +08:00
endial 3a471d8ccd fix: 解决默认软件源配置错误 2023-07-31 16:09:50 +08:00
endial c0d5cebd8e fix: 解决默认软件源配置错误 2023-07-31 16:07:38 +08:00
endial df94964234 fix: 解决默认软件源配置错误 2023-07-31 15:45:37 +08:00
endial 702905b7eb fix: 解决默认软件源配置错误 2023-07-31 15:28:51 +08:00
endial 6b87f72424 feat: 更新 Dockerfile 中变量定义及使用方式 2023-07-28 09:25:31 +08:00
endial 4a2f272762 feat: 更新 Dockerfile 中变量定义及使用方式 2023-07-28 09:22:28 +08:00
endial db31eece54 docs: 更新文档中有关acr描述信息 2023-07-28 08:59:00 +08:00
endial 3152a73294 docs: 更新文档中有关acr描述信息 2023-07-28 08:57:48 +08:00
endial d96d9f00a7 docs: 更新版本描述信息 2023-07-27 17:41:24 +08:00
endial 7ba68b9919 feat: 更新为 Debian 12 2023-07-27 17:37:56 +08:00
endial 5b61fb11d9 feat: 更新 Debian 12 的 apt 源信息及对应的脚本文件 2023-07-27 17:37:19 +08:00
29 changed files with 195 additions and 1810 deletions
Submodule
+1
Submodule .ci/common added at b0ca0dc3a3
+1 -1
View File
@@ -1,7 +1,7 @@
.git
.gitignore
.gitmodules
./alpine
./Makefile
*.yml
-61
View File
@@ -1,61 +0,0 @@
# CI/CD 的阶段定义,按顺序执行各阶段;默认包含`.pre`(最先执行)/`.post`(最后执行)两个阶段,不用显示定义
stages:
- build
- test
- deploy
# 全局变量定义
variables:
IMG_URL: "$HARBOR_HOST/$HARBOR_PROJECT/$CI_PROJECT_NAME"
IMG_TAG: ":latest"
# 默认值信息配置
default:
# 各 stage 使用的默认镜像,如果不定义,则为 gitlab-runner 创建时指定的镜像;各 stage 可以覆盖该值以使用不同的镜像
image: docker.colovu.com/library/docker:20.10.16
# Gitlab-runner 配置的执行器为 Docker 时,需要 配置对应的 dind 服务
services:
- name: docker.colovu.com/library/docker:20.10.16-dind
alias: docker
# 流水线中,各阶段都会执行的脚本命令,包括`before_script`(在各阶段 script 前执行)/`after_script`(在各阶段 script 后执行)
before_script:
- |
if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
IMG_TAG=":latest"
else
IMG_TAG=":$CI_COMMIT_REF_SLUG"
fi
- docker login -u "$HARBOR_USERNAME" -p "$HARBOR_PASSWORD" $HARBOR_URL
# 编译阶段任务
build-arm64:
stage: build
script:
- export
- env
- docker buildx build --platform=linux/arm64 --pull -t "$IMG_URL$IMG_TAG-linux-arm64" . --push
build-amd64:
stage: build
script:
- docker buildx build --platform=linux/amd64 --pull -t "$IMG_URL$IMG_TAG-linux-amd64" . --push
build-artifact:
stage: build
needs: [build-amd64, build-arm64]
script:
- docker manifest create "$IMG_URL$IMG_TAG" "$IMG_URL$IMG_TAG-linux-arm64" "$IMG_URL$IMG_TAG-linux-amd64"
- docker manifest push "$IMG_URL$IMG_TAG"
# 测试阶段任务
test:
stage: test
script:
- docker run --rm --platform=linux/arm64 "$IMG_URL$IMG_TAG" /bin/uname -a
- docker run --rm --platform=linux/amd64 "$IMG_URL$IMG_TAG" /bin/uname -a
# 部署阶段任务
deploy:
stage: deploy
script:
- echo "deploy stage"
+3
View File
@@ -0,0 +1,3 @@
[submodule ".ci/common"]
path = .ci/common
url = https://git.colovu.com/docker/common.git
+55
View File
@@ -0,0 +1,55 @@
# 注意:
# 1. git commit 信息中包含"[CI SKIP]"或"[SKIP CI]"则不触发工作流(注意大小写)
# 2. 工作步骤中包含 volumes 挂载时,需在 Woodpecker 配置中添加 volumes 挂载信任(Trust
# 3. lables 配置项,可配置多个;如果存在,则必须完全符合 Runner 创建时设置的 Lables 配置项
# 4. command 中,引用自定义变量不能使用`${VAR}`方式,需要使用`$VAR`方式;带花括号的变量,会在 Woodpecker 模板引擎解析阶段被替换(此时变量为空)
# 5. 多架构编译后推送至 SWR 报错,或单架构编译后必须在推送时明确指定架构信息才能推送;可通过在编译命令中增加参数`--provenance=false --sbom=false`解决
# 6. 使用 Git Submodule 管理通用脚本时,需手动更新 Submodule
when:
# 匹配 main
- event: push
branch: main
# 匹配 master
- event: push
branch: master
# 匹配数字开头的分支,如 1.0, 2, 3.2.1
- event: push
branch: "[0-9]*"
# 匹配 v 开头的版本分支,如 v1, v2.0
- event: push
branch: "v[0-9]*"
# 匹配 tag 事件
- event: tag
ref: "refs/tags/(v?[0-9].*)"
labels:
runtime: docker
arch: amd64
multiarch: "true"
steps:
- name: 初始化子模块
image: alpine/git
commands:
- git submodule update --init --recursive
- name: 编译并推送镜像
image: docker:cli
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
SWR_REGISTRY: "swr.cn-north-4.myhuaweicloud.com"
DOCKER_CLI_EXPERIMENTAL: enabled
SWR_USERNAME:
from_secret: swr_colovu_user
SWR_PASSWORD:
from_secret: swr_colovu_passwd
commands:
- |
# 直接执行 Submodule .ci/common 下的构建推送脚本
if [ ! -f ".ci/common/build_push.sh" ]; then
echo "错误: 未找到 .ci/common/build_push.sh 脚本"
exit 1
fi
- sh ./.ci/common/build_push.sh
+42 -93
View File
@@ -1,123 +1,72 @@
# Ver: 1.9 by Endial Fang (endial@126.com)
# Ver: 1.11 by Endial Fang (endial@126.com)
#
# 默认变量 ========================================================================
# 系统默认变量 ====================================================================
# 该部分变量为系统根据编译命令默认设置
# `TARGETPLATFORM`:构建后的目标平台信息。如 `linux/amd64``linux/arm/v7``windows/amd64`
# `TARGETPLATFORM`:构建后的目标平台信息。如 `linux/amd64``linux/arm/v7``windows/amd64`
# `TARGETOS`:目标平台信息(TARGETPLATFORM)中的操作系统部分,如:`linux`、`windows`
# `TARGETARCH`:目标平台信息(TARGETPLATFORM)中的平台架构部分,如:`amd64`、`arm`
# `TARGETVARIANT`:目标平台信息(TARGETPLATFORM)中的版本变体部分,如:`v7`
# `BUILDPLATFORM`:用于构建的节点平台信息
# `BUILDOS`:用于构建的节点平台信息(BUILDPLATFORM)中的操作系统部分
# `BUILDARCH`用于构建的节点平台信息(BUILDPLATFORM)中的平台架构部分
# `BUILDVARIANT`用于构建的节点平台信息(BUILDPLATFORM)中的版本变体部分
# `BUILDARCH`用于构建的节点平台信息(BUILDPLATFORM)中的平台架构部分
# `BUILDVARIANT`用于构建的节点平台信息(BUILDPLATFORM)中的版本变体部分
# 可变参数 ========================================================================
# 该部分变量,在编译命令中通过 `--build-arg` 传入;如果未设置,则使用下面对应的默认值
# 设置当前应用名称及版本
ARG APP_NAME=debian
ARG APP_VER=11
# 设置默认仓库地址,默认为本地仓库
ARG REGISTRY_URL="docker.colovu.com"
# 设置 apt-get 源:default / ustc / aliyun
ARG APP_VER=13
ARG REGISTRY_URL="docker.io/"
ARG APT_SOURCE=aliyun
# 编译镜像时指定用于加速的本地软件包存储服务器地址
ARG LOCAL_URL=""
# 0. 预处理 ======================================================================
FROM --platform=${TARGETPLATFORM:-linux/amd64} ${REGISTRY_URL}/library/debian:${APP_VER}-slim as builder
# 声明需要使用的全局可变参数
ARG APP_NAME
ARG APP_VER
ARG REGISTRY_URL
ARG APT_SOURCE
ARG LOCAL_URL
# 拷贝默认的通用脚本文件
COPY prebuilds /
# 选择软件包源(Optional),以加速后续软件包安装
RUN select_source ${APT_SOURCE};
# 设置工作目录
WORKDIR /usr/local
#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 libssl1.1 libssl-dev \
# libtool libltdl7 libltdl-dev
RUN install_pkg wget ca-certificates dpkg
# 下载并解压软件包
RUN set -eux; \
appVersion=1.16; \
appName=gosu-"$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
appKeys="0xB42F6819007F00F88E364FD4036A9C25BF357DD4"; \
[ ! -z ${LOCAL_URL} ] && localURL=${LOCAL_URL}/gosu; \
appUrls="${LOCAL_URL:-}/${appVersion} \
https://github.com/tianon/gosu/releases/download/${appVersion} \
"; \
download_pkg install ${appName} "${appUrls}" ; \
chmod +x /usr/local/bin/${appName};
# 1. 生成镜像 =====================================================================
FROM --platform=${TARGETPLATFORM:-linux/amd64} ${REGISTRY_URL}/library/debian:${APP_VER}-slim
FROM ${REGISTRY_URL}debian:${APP_VER}-slim
# 声明需要使用的全局可变参数
# 声明需要使用的全局可变参数ARG声明的变量仅编译打包阶段有效)
ARG APP_NAME
ARG APP_VER
ARG REGISTRY_URL
ARG APT_SOURCE
ARG LOCAL_URL
ARG TARGETARCH
LABEL \
"Version"="v${APP_VER}" \
"Description"="Docker image for Debian." \
"Github"="https://github.com/colovu/docker-debian" \
"Vendor"="Endial Fang (endial@126.com)"
# 镜像元数据标签 - 符合OCI镜像规范
LABEL org.opencontainers.image.title="${APP_NAME}" \
org.opencontainers.image.version="${APP_VER}" \
org.opencontainers.image.description="Docker image for Debian LTS Slim." \
org.opencontainers.image.authors="Endial Fang <endial@126.com>" \
org.opencontainers.image.url="https://gitee.com/colovu/docker-${APP_NAME}" \
org.opencontainers.image.vendor="Endial Fang (colovu)" \
org.opencontainers.image.licenses="Apache-2.0" \
org.opencontainers.image.source="https://gitee.com/colovu/docker-${APP_NAME}" \
org.opencontainers.image.documentation="https://gitee.com/colovu/docker-${APP_NAME}/blob/main/README.md" \
maintainer="Endial Fang <endial@126.com>"
# 拷贝源仓库配置文件
COPY customer /
# 拷贝默认的通用脚本文件
COPY prebuilds /
COPY .ci/common/debian /
# 从预处理过程中拷贝软件包
COPY --from=builder /usr/local/bin/gosu-${TARGETARCH} /usr/local/bin/gosu
# 选择软件包源(Optional),以加速后续软件包安装
RUN select_source ${APT_SOURCE}
# 增加 NSS_WRAPPER 支持
RUN install_pkg locales apt-utils tini libnss-wrapper curl
# 增加locales支持,并设置默认为 UTF-8;配置时区默认为 Shanghai
# 选择软件包源,安装常用软件包,配置locale和时区,并清理缓存
RUN set -eux; \
sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen; \
sed -i -e 's/# zh_CN.UTF-8 UTF-8/zh_CN.UTF-8 UTF-8/' /etc/locale.gen; \
locale-gen; \
update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LC_MESSAGES=POSIX; \
dpkg-reconfigure -f noninteractive locales; \
\
ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime; \
dpkg-reconfigure -f noninteractive tzdata;
\
select_source ${APT_SOURCE}; \
\
install_pkg gosu dumb-init curl locales; \
\
sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen; \
locale-gen; \
update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LC_MESSAGES=POSIX; \
dpkg-reconfigure -f noninteractive locales; \
\
ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime; \
dpkg-reconfigure -f noninteractive tzdata; \
\
apt-get clean && rm -rf /var/lib/apt/lists/*
# 在安装像相应软件包后,设置对应的环境变量
ENV LANG=en_US.UTF-8 \
LANGUAGE=en_US.UTF-8 \
LC_ALL=en_US.UTF-8
# 执行预处理脚本,并验证安装的软件包
RUN set -eux; \
gosu nobody true; \
gosu --version; \
tini --version;
WORKDIR /
LANGUAGE=en_US.UTF-8 \
LC_ALL=en_US.UTF-8
# 应用程序的服务命令,必须使用非守护进程方式运行。如果使用变量,则该变量必须在运行环境中存在(ENV可以获取)
CMD []
-52
View File
@@ -1,52 +0,0 @@
# Ver: 1.9 by Endial Fang (endial@126.com)
#
# 当前 Docker 镜像的编译脚本
# 定义镜像名称
image_name :=colovu/debian
# 定义默认镜像仓库地址
REGISTRY_URL :=docker.colovu.com
# 定义系统默认使用的源服务器,包含:default / ustc / aliyun
APT_SOURCE :=aliyun
# 定义镜像TAG,类似:
# <镜像名>:<分支名>-<7位Git ID> # Git 仓库且无文件修改直接编译
# <镜像名>:<分支名>-<年月日>-<时分秒> # Git 仓库有文件修改后的编译
# <镜像名>:latest-<年月日>-<时分秒> # 非 Git 仓库编译
current_subversion:=$(shell if [ ! `git status >/dev/null 2>&1` ]; then git rev-parse --short HEAD; else date +%y%m%d-%H%M%S; fi)
image_tag:=$(shell if [ ! `git status >/dev/null 2>&1` ]; then git rev-parse --abbrev-ref HEAD | sed -e 's/master/latest/'; else echo "latest"; fi)-$(current_subversion)
build-arg:=--build-arg REGISTRY_URL=$(REGISTRY_URL)
build-arg+=--build-arg APT_SOURCE=$(APT_SOURCE)
# 设置本地下载服务器路径,加速调试时的本地编译速度
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
build:
@echo "Build $(image_name):$(image_tag)"
@docker build --force-rm $(build-arg) -t $(image_name):$(image_tag) .
@echo "Add tag: $(image_name):latest"
@docker tag $(image_name):$(image_tag) $(image_name):latest
@echo "Build complete"
# 清理悬空的镜像(无TAG)及停止的容器
clearclean: clean
@echo "Clean untaged images and stoped containers..."
@docker ps -a | grep "Exited" | awk '{print $$1}' | sort -u | xargs -L 1 docker rm
@docker images | grep '<none>' | awk '{print $$3}' | sort -u | xargs -L 1 docker rmi -f
# 为了防止删除前缀名相同的镜像,在过滤条件中加入一个空格进行过滤
clean:
@echo "Clean all images for current application..."
@docker images | grep "$(image_name) " | awk '{print $$3}' | sort -u | xargs -L 1 docker rmi -f
# 更新所有 colovu 仓库的镜像
upgrade:
@echo "Upgrade all images..."
@docker images | grep 'colovu' | grep -v '<none>' | grep -v "latest-" | awk '{print $$1":"$$2}' | sort -u | xargs -L 1 docker pull
+32 -32
View File
@@ -1,21 +1,19 @@
# Debian
[Debian 系统](https://www.debian.org/)的基础 Docker 镜像。基于官方 [Debian LTS 版本 slim](https://hub.docker.com/_/debian) 镜像。
[Debian 系统](https://www.debian.org/)的基础 Docker 镜像。基于官方 [Debian LTS Slim 版本](https://hub.docker.com/_/debian) 镜像。
**版本信息:**
- latest
- 11bullseye
- 13trixie
**镜像信息:**
* 镜像地址:
* 阿里云(仅`amd64`: registry.cn-shenzhen.aliyuncs.com/colovu/debian:11
* Docker Hub: colovu/debian:11
* Colovu Registry: docker.colovu.com/colovu/debian:11
* 依赖镜像:docker.io/library/debian:11-slim
* 华为云: swr.cn-north-4.myhuaweicloud.com/colovu/debian
* 依赖镜像:docker.io/library/debian:12-slim
registry.colovu.com/docker-proxy/debian:12-slim
> 后续相关命令行默认使用`[Colovu Registry](https://docker.colovu.com)`镜像服务器做说明
> 后续相关命令行默认使用华为云 SWR 镜像服务器做说明
**与官方镜像差异:**
@@ -23,10 +21,10 @@
- 增加常用 Shell 脚本文件
- 更新已安装的软件包
- 增加`locales`,并设置默认编码格式为`en_US.utf8`
- 增加`gosu`
- 设置默认时区信息为 `Asia/Shanghai`
- 默认增加 nss_wrapper 支持
- 默认增加 curl 软件,用作镜像健康检查
- 增加`gosu`软件,用作镜像的 non-root 应用执行
- 增加`dumb-init`软件,用作镜像的入口命令,以确保中断被正确响应和转发
- 增加`curl`软件,用作镜像健康检查
## TL;DR
@@ -34,9 +32,12 @@ Docker 快速启动命令:
```shell
# 从 Registry 服务器下载镜像并启动
$ docker run -it docker.colovu.com/colovu/debian:11 /bin/bash
docker run -it swr.cn-north-4.myhuaweicloud.com/colovu/debian:latest /bin/bash
```
- latest:为镜像的 TAG,可针对性选择不同的 TAG 进行下载
- 不指定 TAG 时,默认下载`latest`镜像
---
## 使用说明
@@ -44,27 +45,27 @@ $ docker run -it docker.colovu.com/colovu/debian:11 /bin/bash
**下载镜像:**
```shell
$ docker pull docker.colovu.com/colovu/debian:11
docker pull swr.cn-north-4.myhuaweicloud.com/colovu/debian:12
```
- 11:为镜像的 TAG,可针对性选择不同的 TAG 进行下载;可使用`latest`选择最新的镜像
- latest:为镜像的 TAG,可针对性选择不同的 TAG 进行下载
- 不指定 TAG 时,默认下载`latest`镜像
**查看镜像:**
```shell
$ docker images
docker images
```
**命令行方式运行容器:**
```shell
$ docker run -it --rm docker.colovu.com/colovu/debian:11 /bin/bash
docker run -it --rm swr.cn-north-4.myhuaweicloud.com/colovu/debian:12 /bin/bash
```
- `-it`:使用交互式终端启动容器
- `--rm`:退出时删除容器
- `docker.colovu.com/colovu/debian:11`:镜像名称及版本标签
- `swr.cn-north-4.myhuaweicloud.com/colovu/debian:12`:镜像名称及版本标签
- `/bin/bash`:在容器中执行`/bin/bash`命令;如果不执行命令,容器会在启动后立即结束并退出。
以该方式启动后,直接进入容器的命令行操作界面。如果需要退出,直接使用命令`exit`退出。
@@ -72,22 +73,22 @@ $ docker run -it --rm docker.colovu.com/colovu/debian:11 /bin/bash
**后台方式运行容器:**
```shell
$ docker run -d --name test docker.colovu.com/colovu/debian:11 tail /dev/stderr
docker run -d --name debian swr.cn-north-4.myhuaweicloud.com/colovu/debian:12 tail /dev/stderr
```
- `--name test`:命名容器为`test`
- `--name debian`:命名容器为`debian`,可按照实际情况自定义容器名称
- `-d`:以后台进程方式启动容器
- `docker.colovu.com/colovu/debian:11`:镜像名称及版本标签
- `swr.cn-north-4.myhuaweicloud.com/colovu/debian:12`:镜像名称及版本标签
- `tail /dev/stderr`:在容器中执行`tail /dev/stderr`命令,以防止容器直接退出
以该方式启动后,如果想进入容器,可以使用以下命令:
```shell
$ docker exec -it test /bin/bash
docker exec -it debian /bin/bash
```
- `-it`:使用交互式执行
- `test`:之前启动的容器名
- `debian`:之前启动的容器名
- `/bin/bash`:执行的命令
## 配置修改
@@ -98,10 +99,10 @@ $ docker exec -it test /bin/bash
```shell
# 修改时区为 UTC
$ ln -fs /usr/share/zoneinfo/UTC /etc/localtime
ln -fs /usr/share/zoneinfo/UTC /etc/localtime
# 重新配置系统
$ dpkg-reconfigure -f noninteractive tzdata
dpkg-reconfigure -f noninteractive tzdata
```
更新成功后会显示当前时区信息,如:
@@ -118,22 +119,21 @@ Universal Time is now: Tue Jul 21 09:16:14 UTC 2020.
``` shell
# 更改默认字符编码为 zh_CN.UTF-8
$ sed -i -e 's/# zh_CN.UTF-8 UTF-8/zh_CN.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
$ update-locale LC_ALL=zh_CN.UTF-8 LANG=zh_CN.UTF-8 LANGUAGE=zh_CN.UTF-8 LC_MESSAGES=POSIX
$ dpkg-reconfigure -f noninteractive locales
sed -i -e 's/# zh_CN.UTF-8 UTF-8/zh_CN.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
update-locale LC_ALL=zh_CN.UTF-8 LANG=zh_CN.UTF-8 LANGUAGE=zh_CN.UTF-8 LC_MESSAGES=POSIX
dpkg-reconfigure -f noninteractive locales
# 设置环境变量
$ export LC_ALL=zh_CN.UTF-8 LANG=zh_CN.UTF-8 LANGUAGE=zh_CN.UTF-8
export LC_ALL=zh_CN.UTF-8 LANG=zh_CN.UTF-8 LANGUAGE=zh_CN.UTF-8
```
更新成功后,可使用`locale`命令查看字符编码信息。
## 更新记录
- latest
- 11、bullseye
- 20260115: 增加 v13 版本
- 12、bookworm
----
本文原始来源 [Endial Fang](https://github.com/colovu) @ [Github.com](https://github.com)
本文原始来源 [Endial Fang](https://gitee.com/colovu) @ [Gitee.com](https://gitee.com)
Executable
+22
View File
@@ -0,0 +1,22 @@
#!/bin/bash
# Ver: 3.0 by Endial Fang (endial@126.com)
#
# Docker 镜像构建脚本 - 主入口
# 编译后镜像名称
export IMAGE_NAME="debian"
# 依赖镜像的仓库地址(本镜像需要依赖原生 debian 镜像)
export REGISTRY_URL="swr.cn-north-4.myhuaweicloud.com/img-sync/docker.io/"
# 源仓库地址(本地编译时,使用阿里云源仓库)
export APT_SOURCE="aliyun"
# 针对无法直接下载到软件包,本地变异时,使用缓存的软件包
export LOCAL_URL="http://pkgs.colovu.com/dist"
# 引入本地构建脚本
if [ -f ".ci/common/build_local.sh" ]; then
# 执行本地构建脚本并传递参数
exec ".ci/common/build_local.sh" "$@"
else
echo "Error: .ci/common/build_local.sh script not found!"
exit 1
fi
+13
View File
@@ -0,0 +1,13 @@
Types: deb
# http://snapshot.debian.org/archive/debian/20230703T000000Z
URIs: http://mirrors.aliyun.com/debian
Suites: trixie trixie-updates
Components: main
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
Types: deb
# http://snapshot.debian.org/archive/debian-security/20230703T000000Z
URIs: http://mirrors.aliyun.com/debian-security
Suites: trixie-security
Components: main
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
+13
View File
@@ -0,0 +1,13 @@
Types: deb
# http://snapshot.debian.org/archive/debian/20230703T000000Z
URIs: http://deb.debian.org/debian
Suites: trixie trixie-updates
Components: main
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
Types: deb
# http://snapshot.debian.org/archive/debian-security/20230703T000000Z
URIs: http://deb.debian.org/debian-security
Suites: trixie-security
Components: main
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
+13
View File
@@ -0,0 +1,13 @@
Types: deb
# http://snapshot.debian.org/archive/debian/20230703T000000Z
URIs: http://mirrors.ustc.edu.cn/debian
Suites: trixie trixie-updates
Components: main
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
Types: deb
# http://snapshot.debian.org/archive/debian-security/20230703T000000Z
URIs: http://mirrors.ustc.edu.cn/debian-security
Suites: trixie-security
Components: main
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
-8
View File
@@ -1,8 +0,0 @@
# 说明
## 用途
本目录下相关 Hooks 脚本主要用于 Docker Hub 服务器编译镜像时,获取用户设置的环境变量,并根据环境变量进行条件编译。相关脚本说明参照[官方文档](https://docs.docker.com/docker-hub/builds/advanced/)。
目录`hooks`必须与镜像编译文件 Dockerfile 同目录。
-7
View File
@@ -1,7 +0,0 @@
#!/bin/bash
# v1.0 by Endial Fang (endial@126.com)
#
# 用户 docker.hub 的自动编译钩子文件,相应的变量在镜像库自动编译界面进行配置(如:registry_url、apt_source
# 参见: https://docs.docker.com/docker-hub/builds/advanced/
docker build --build-arg registry_url=${registry_url:-docker.io} --build-arg apt_source=${apt_source:-default} -f $DOCKERFILE_PATH -t $IMAGE_NAME .
@@ -1,3 +0,0 @@
deb http://mirrors.aliyun.com/debian/ bullseye main non-free contrib
deb http://mirrors.aliyun.com/debian/ bullseye-updates main non-free contrib
deb http://mirrors.aliyun.com/debian-security/ bullseye-security main
@@ -1,3 +0,0 @@
deb http://deb.debian.org/debian bullseye main
deb http://security.debian.org/debian-security bullseye/updates main
deb http://deb.debian.org/debian bullseye-updates main
@@ -1,3 +0,0 @@
deb http://mirrors.ustc.edu.cn/debian/ bullseye main contrib non-free
deb http://mirrors.ustc.edu.cn/debian/ bullseye-updates main contrib non-free
deb http://mirrors.ustc.edu.cn/debian-security/ bullseye/updates main contrib non-free
-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020 Endial Fang (endial@126.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-108
View File
@@ -1,108 +0,0 @@
#!/bin/bash
# Ver: 1.3 by Endial Fang (endial@126.com)
#
# 通用函数库
# 加载依赖项
. /usr/local/scripts/liblog.sh # 日志输出函数库
# 函数列表
# 打印包含包含Logo的欢迎信息
print_welcome_info() {
[[ -n "${APP_NAME}" ]] && github_url="/docker-${APP_NAME}"
LOG_I ' ____ _ '
LOG_I ' / ___|___ | | _____ ___ _ '
LOG_I '| | / _ \| |/ _ \ \ / / | | | '"Docker : ${BOLD}${APP_NAME:-undefined}${RESET}"
LOG_I '| |__| (_) | | (_) \ V /| |_| | '"Version: ${BOLD}${APP_VERSION:-0.0}${RESET}"
LOG_I ' \____\___/|_|\___/ \_/ \__,_| '"PowerBy: ${BOLD}Endial@126.com${RESET}"
LOG_D " Project Repo: https://github.com/colovu/${github_url:-}"
LOG_I ""
}
# 根据需要打印欢迎信息
print_image_welcome() {
if [[ ! "$(id -u)" = "0" ]]; then
print_welcome_info
fi
}
# 检测可能导致容器执行后直接退出的命令,如"--help";如果存在,直接返回 0
# 参数:
# $1 - 待检测的参数表
print_command_help() {
local arg
for arg; do
case "$arg" in
-'?'|--help|-V|--version|-version)
exec "$@"
exit
;;
esac
done
}
# 检测应用相应的配置文件是否存在,如果不存在,则从默认配置文件目录拷贝一份
# 默认配置文件路径:/etc/${APP_NAME}
# 目标配置文件路径:/srv/conf/${APP_NAME}
# 参数:
# $1 - 基础路径
# $* - 基础路径下的文件及目录列表,以" "分割
# 例子:
# ensure_config_file_exist /etc/${APP_NAME} conf.d server.conf
ensure_config_file_exist() {
local -r base_path="${1:?paths is missing}"
local f=""
local dist=""
shift 1
LOG_D "List to check: $@"
while [ "$#" -gt 0 ]; do
f="${1}"
LOG_D " Process \"${f}\""
if [ -d "${base_path}/${f}" ]; then
dist="$(echo ${base_path}/${f} | sed -e 's/\/etc/\/srv\/conf/g')"
[[ ! -d "${dist}" ]] && LOG_D " Create directory: ${dist}" && mkdir -p "${dist}"
[[ ! -z $(ls -A "${base_path}/${f}") ]] && ensure_config_file_exist "${base_path}/${f}" $(ls -A "${base_path}/${f}")
else
dist="$(echo ${base_path}/${f} | sed -e 's/\/etc/\/srv\/conf/g')"
[[ ! -e "${dist}" ]] && LOG_D " Copy: ${base_path}/${f} ===> ${dist}" && cp "${base_path}/${f}" "${dist}" && rm -rf "/srv/conf/${APP_NAME}/.app_init_flag"
fi
shift
done
}
# 根据脚本扩展名及权限,执行相应的初始化脚本
# 参数:
# $1 - 文件列表,支持路径通配符
# 使用:
# process_init_files [file [file [...]]]
# 例子:
# process_init_files /src/conf/${APP_NAME}/initdb.d/*
process_init_files() {
echo
local f
for f; do
case "$f" in
*.sh)
if [ -x "$f" ]; then
LOG_I "$0: running $f"
"$f"
else
LOG_I "$0: sourcing $f"
. "$f"
fi
;;
*) LOG_W "$0: ignoring $f" ;;
esac
echo
done
}
# 检测当前脚本是被直接执行的,还是从其他脚本中使用 "source" 调用的
is_sourced() {
[ "${#FUNCNAME[@]}" -ge 2 ] \
&& [ "${FUNCNAME[0]}" = 'is_sourced' ] \
&& [ "${FUNCNAME[1]}" = 'source' ]
}
-93
View File
@@ -1,93 +0,0 @@
#!/bin/bash
# Ver: 1.0 by Endial Fang (endial@126.com)
#
# 文件操作函数库
# 加载依赖项
. /usr/local/scripts/liblog.sh # 日志输出函数库
# 函数列表
# 检测"*_FILE"文件,并从文件中读取信息作为参数值;环境变量不允许 VAR 与 VAR_FILE 方式并存
# 变量:
# $1 - 需要设置的环境变量名称
# $2 - 该变量对应的默认值(Option)
#
# 使用: file_env ENV_VAR [DEFAULT]
file_env() {
local var="$1"
local fileVar="${var}_FILE"
local def="${2:-}"
if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
LOG_E "Both $var and $fileVar are set (but are exclusive)"
exit 1
fi
local val="$def"
if [ "${!var:-}" ]; then
val="${!var}"
elif [ "${!fileVar:-}" ]; then
val="$(< "${!fileVar}")"
fi
export "$var"="$val"
unset "$fileVar"
}
# 使用规则表达式在文件中替换数据
# 参数:
# $1 - 文件名
# $2 - 正则表达式
# $3 - 替代数据表达式
# $4 - 是否使用POSIX表达式. Default: true
replace_in_file() {
local filename="${1:?filename is required}"
local match_regex="${2:?match regex is required}"
local substitute_regex="${3:?substitute regex is required}"
local posix_regex=${4:-true}
local result
del=$'\001' # Use a non-printable character as a 'sed' delimiter to avoid issues
if [[ $posix_regex = true ]]; then
result="$(sed -E "s${del}${match_regex}${del}${substitute_regex}${del}g" "$filename")"
else
result="$(sed "s${del}${match_regex}${del}${substitute_regex}${del}g" "$filename")"
fi
echo "$result" > "$filename"
}
# 使用规则表达式在文件中删除数据
# 参数:
# $1 - 文件名
# $2 - 正则表达式
# $3 - 是否使用POSIX表达式. Default: true
remove_in_file() {
local filename="${1:?filename is required}"
local match_regex="${2:?match regex is required}"
local posix_regex=${3:-true}
local result
# 因部分系统兼容性问题,需要防止使用 'sed in-place' 方式操作
if [[ $posix_regex = true ]]; then
result="$(sed -E "/$match_regex/d" "$filename")"
else
result="$(sed "/$match_regex/d" "$filename")"
fi
echo "$result" > "$filename"
}
# 在符合条件的行后增加文本
# 参数:
# $1 - 文件名
# $2 - 正则表达式
# $3 - 待增加的文本
append_in_file() {
local file="${1:?missing file}"
local match_regex="${2:?missing pattern}"
local value="${3:?missing value}"
# We read the file in reverse, replace the first match (0,/pattern/s) and then reverse the results again
result="$(tac "$file" | sed -E "0,/($match_regex)/s||${value}\n\1|" | tac)"
echo "$result" > "$file"
}
-135
View File
@@ -1,135 +0,0 @@
#!/bin/bash
# Ver: 1.1 by Endial Fang (endial@126.com)
#
# 文件管理函数库
# 加载依赖项
. /usr/local/scripts/liblog.sh # 日志输出函数库
# 函数列表
# 确保指定的 文件/路径 所属权为指定的 用户/组
# 参数:
# $1 - 文件路径
# $2 - 用户
ensure_owned_by() {
local path="${1:?path is missing}"
local owner="${2:?owner is missing}"
chown "$owner":"$owner" "$path"
}
# 检测目录是否存在,如果不存在则创建,同时修改为指定的用户
# 参数:
# $1 - 目录路径
# $2 - 用户
ensure_dir_exists() {
local dir="${1:?directory is missing}"
local owner="${2:-}"
mkdir -p "${dir}"
if [[ -n $owner ]]; then
ensure_owned_by "$dir" "$owner"
fi
}
# 检测目录是否存在或为空
# 参数:
# $1 - 目录路径
is_dir_empty() {
local dir="${1:?missing directory}"
if [[ ! -e "$dir" ]] || [[ -z "$(ls -A "$dir")" ]]; then
true
else
false
fi
}
# 检测指定的路径当前用户是否可写入
# 参数:
# $1 - 文件或路径
# 返回值:
# true / false
is_writable() {
local file="${1:?missing file}"
local dir
dir="$(dirname "$file")"
if [[ ( -f "$file" && -w "$file" ) || ( ! -f "$file" && -d "$dir" && -w "$dir" ) ]]; then
true
else
false
fi
}
# 循环设置目录中子目录及文件权限
# 参数:
# $1 - paths (as a string).
# Flags:
# -f|--file-mode - 文件权限模式
# -d|--dir-mode - 目录权限模式
# -u|--user - 用户
# -g|--group - 用户组
configure_permissions_ownership() {
local -r paths="${1:?paths is missing}"
local dir_mode=""
local file_mode=""
local user=""
local group=""
# Validate arguments
shift 1
while [ "$#" -gt 0 ]; do
case "$1" in
-f|--file-mode)
shift
file_mode="${1:?missing mode for files}"
;;
-d|--dir-mode)
shift
dir_mode="${1:?missing mode for directories}"
;;
-u|--user)
shift
user="${1:?missing user}"
;;
-g|--group)
shift
group="${1:?missing group}"
;;
*)
LOG_E "Invalid command line flag $1" >&2
return 1
;;
esac
shift
done
read -r -a filepaths <<< "$paths"
for p in "${filepaths[@]}"; do
if [[ -e "$p" ]]; then
LOG_D "Check $p"
if [[ -n ${dir_mode} ]]; then
LOG_D "Change permissions to ${dir_mode} of directories in $p"
find -L "$p" -type d -exec chmod "$dir_mode" {} \;
fi
if [[ -n ${file_mode} ]]; then
LOG_D "Change permissions to ${file_mode} of files in $p"
find -L "$p" -type f -exec chmod "$file_mode" {} \;
fi
if [[ -n $user ]] && [[ -n ${group} ]]; then
LOG_D "Change ownership to ${user}:${group} of files and directories in $p"
chown -LR "$user":"$group" "$p"
elif [[ -n $user ]] && [[ -z $group ]]; then
LOG_D "Change user to ${user} of files and directories in $p"
chown -LR "$user" "$p"
elif [[ -z $user ]] && [[ -n $group ]]; then
LOG_D "Change group to ${group} of files and directories in $p"
chgrp -LR "$group" "$p"
fi
else
LOG_E "$p does not exist"
fi
done
}
-83
View File
@@ -1,83 +0,0 @@
#!/bin/bash
# Ver: 1.1 by Endial Fang (endial@126.com)
#
# 日志输出函数库
#[[ ${ENV_DEBUG:-false} = true ]] && set -x
MODULE="$(basename "$0")"
RESET='\033[0m'
BOLD='\033[1m'
# 前景色
BLACK='\033[38;5;0m'
RED='\033[38;5;1m'
GREEN='\033[38;5;2m'
YELLOW='\033[38;5;3m'
BLUE='\033[38;5;4m'
MAGENTA='\033[38;5;5m'
CYAN='\033[38;5;6m'
WHITE='\033[38;5;7m'
# 背景色
ON_BLACK='\033[48;5;0m'
ON_RED='\033[48;5;1m'
ON_GREEN='\033[48;5;2m'
ON_YELLOW='\033[48;5;3m'
ON_BLUE='\033[48;5;4m'
ON_MAGENTA='\033[48;5;5m'
ON_CYAN='\033[48;5;6m'
ON_WHITE='\033[48;5;7m'
# 函数列表
# 打印输出到 STDERR 设备
stderr_print() {
printf "%b\\n" "${*}" >&2
}
# 输出实际日志信息
# 参数:
# $1 - 日志信息
LOG() {
local -r bool="${ENV_DEBUG:-false}"
shopt -s nocasematch
if [[ "$bool" = 1 || "$bool" =~ ^(yes|true)$ ]]; then
debugInfo="${CYAN}${APP_NAME:-}:${MODULE:-}"
else
debugInfo="${CYAN}${APP_NAME:-}"
fi
stderr_print "${debugInfo} ${MAGENTA}$(date "+%F %T.%3N")${RESET} ${*}"
}
# 输出调试类日志信息,尽量少使用
# 参数:
# $1 - 日志信息
LOG_D() {
local -r bool="${ENV_DEBUG:-false}"
shopt -s nocasematch
if [[ "$bool" = 1 || "$bool" =~ ^(yes|true)$ ]]; then
LOG "${BLUE}DBG${RESET}: ${*}"
fi
}
# 输出提示信息类日志信息
# 参数:
# $1 - 日志信息
LOG_I() {
LOG "${GREEN}INF${RESET}: ${*}"
}
# 输出警告类日志信息至sterr
# 参数:
# $1 - 日志信息
LOG_W() {
LOG "${YELLOW}WRN${RESET}: ${*}"
}
# 输出错误类日志信息至sterr,并退出脚本
# 参数:
# $1 - 日志信息
LOG_E() {
LOG "${RED}ERR${RESET}: ${*}"
}
-129
View File
@@ -1,129 +0,0 @@
#!/bin/bash
# Ver: 1.1 by Endial Fang (endial@126.com)
#
# 文件管理函数库
# 加载依赖项
. /usr/local/scripts/liblog.sh # 日志输出函数库
# 函数列表
# 域名解析
# 参数:
# $1 - 需要解析的主机名
# $2 - IP 地址版本 v4/v6, 为空时解析所有版本
# 返回值:
# IP地址
dns_lookup() {
local host="${1:?host is missing}"
local ip_version="${2:-}"
getent "ahosts${ip_version}" "$host" | awk '/STREAM/ {print $1 }' | head -n 1
}
# 尝试解析域名并返回对应的 IP
# 参数:
# $1 - 主机名
# $2 - 尝试次数
# $3 - 重试间隔时间(秒)
# 返回值:
# IP地址
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
# 返回值:
# 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]}"
}
# 检测指定的主机名是否可解析
# 参数:
# $1 - 待检测的主机名
# 返回值:
# true / false
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}]}"
}
-303
View File
@@ -1,303 +0,0 @@
#!/bin/bash
# Ver: 1.2 by Endial Fang (endial@126.com)
#
# 操作系统控制函数库
# 加载依赖项
. /usr/local/scripts/liblog.sh # 日志输出函数库
. /usr/local/scripts/libfs.sh # 文件系统函数库
# 函数列表
# 检测指定用户账户是否存在
# 参数:
# $1 - 用户账户
# 返回值:
# 0 / 1
is_user_exists() {
local user="${1:?user is missing}"
id "$user" >/dev/null 2>&1
}
# 检测指定用户分组是否存在
# 参数:
# $1 - 用户组
# 返回值:
# 0 / 1
is_group_exists() {
local group="${1:?group is missing}"
getent group "$group" >/dev/null 2>&1
}
# 检测当前是否为 root 用户
# 返回值:
# true / false
is_root() {
if [[ "$(id -u)" = "0" ]]; then
LOG_D "Run as root."
true
else
LOG_D "Run as non-root: $(id -u)"
false
fi
}
# 确保指定用户组在系统中存在
# 参数:
# $1 - 用户组
# 标志位:
# -s|--system - 创建系统用户 (uid <= 999)
ensure_group_exists() {
local group="${1:?group is missing}"
local is_system_user=false
# 检测标志位
shift 1
while [ "$#" -gt 0 ]; do
case "$1" in
-s|--system)
is_system_user=true
;;
*)
echo "Invalid command line flag $1" >&2
return 1
;;
esac
shift
done
if ! is_group_exists "$group"; then
local -a args=("$group")
$is_system_user && args+=("--system")
groupadd "${args[@]}" >/dev/null 2>&1
fi
}
# 确保指定用户在系统中存在
# 参数:
# $1 - 用户
# 标志位:
# -g|--group - 用户组
# -h|--home - 用户家目录
# -s|--system - 创建系统用户 (uid <= 999)
ensure_user_exists() {
local user="${1:?user is missing}"
local group=""
local home=""
local is_system_user=false
# Validate arguments
shift 1
while [ "$#" -gt 0 ]; do
case "$1" in
-g|--group)
shift
group="${1:?missing group}"
;;
-h|--home)
shift
home="${1:?missing home directory}"
;;
-s|--system)
is_system_user=true
;;
*)
echo "Invalid command line flag $1" >&2
return 1
;;
esac
shift
done
if ! is_user_exists "$user"; then
local -a user_args=("-N" "$user")
$is_system_user && user_args+=("--system")
useradd "${user_args[@]}" >/dev/null 2>&1
fi
if [[ -n "$group" ]]; then
local -a group_args=("$group")
$is_system_user && group_args+=("--system")
ensure_group_exists "${group_args[@]}"
usermod -g "$group" "$user" >/dev/null 2>&1
fi
if [[ -n "$home" ]]; then
mkdir -p "$home"
usermod -d "$home" "$user" >/dev/null 2>&1
configure_permissions_ownership "$home" -d "775" -f "664" -u "$user" -g "$group"
fi
}
# 获取系统可用内存大小(MB)信息
# 返回值:
# 内存大小(兆字节)
get_total_memory() {
echo $(($(grep MemTotal /proc/meminfo | awk '{print $2}') / 1024))
}
# 获取以内存定量方式描述的机器类型
# 标志位:
# --memory - 内存大小 (MB,可选)
# 返回值:
# 类型名称
get_machine_size() {
local memory=""
# 检测标志位
while [[ "$#" -gt 0 ]]; do
case "$1" in
--memory)
shift
memory="${1:?missing memory}"
;;
*)
echo "Invalid command line flag $1" >&2
return 1
;;
esac
shift
done
if [[ -z "$memory" ]]; then
debug "Memory was not specified, detecting available memory automatically"
memory="$(get_total_memory)"
fi
sanitized_memory=$(convert_to_mb "$memory")
if [[ "$sanitized_memory" -gt 26000 ]]; then
echo 2xlarge
elif [[ "$sanitized_memory" -gt 13000 ]]; then
echo xlarge
elif [[ "$sanitized_memory" -gt 6000 ]]; then
echo large
elif [[ "$sanitized_memory" -gt 3000 ]]; then
echo medium
elif [[ "$sanitized_memory" -gt 1500 ]]; then
echo small
else
echo micro
fi
}
# 获取已定义的所有内存大小描述
# 返回值:
# 描述值列表
get_supported_machine_sizes() {
echo micro small medium large xlarge 2xlarge
}
# 将以字符串表示的内存大小转换为以MB为单位的内存大小值 (i.e. 2G -> 2048)
# 参数:
# $1 - 内存大小
# 返回值:
# 转换后的数值
convert_to_mb() {
local amount="${1:-}"
if [[ $amount =~ ^([0-9]+)(M|G) ]]; then
size="${BASH_REMATCH[1]}"
unit="${BASH_REMATCH[2]}"
if [[ "$unit" = "G" ]]; then
amount="$((size * 1024))"
else
amount="$size"
fi
fi
echo "$amount"
}
# 如果禁用调试模式,将输出信息重定向至 /dev/null
# 参数:
# $@ - 待执行的命令
debug_execute() {
local bool="${ENV_DEBUG:-false}"
shopt -s nocasematch
if [[ "$bool" = 1 || "$bool" =~ ^(yes|true)$ ]]; then
"$@"
else
"$@" >/dev/null 2>&1
fi
}
# 重试执行命令
# 参数:
# $1 - 命令 (字符串)
# $2 - 最大尝试次数. 默认值: 12
# $3 - 重试前等待时间(秒). 默认值: 5
# 返回值:
# 0 / 1
retry_while() {
local -r cmd="${1:?cmd is missing}"
local -r retries="${2:-12}"
local -r sleep_time="${3:-5}"
local return_value=1
read -r -a command <<< "$cmd"
for ((i = 1 ; i <= retries ; i+=1 )); do
"${command[@]}" && return_value=0 && break
sleep "$sleep_time"
done
return $return_value
}
# 生成随机字符串
# 标志位:
# -t|--type - 字符串类型 (ascii, alphanumeric, numeric). 默认值: ascii
# -c|--count - 字符串长度. 默认值: 32
# 返回值:
# 字符串
generate_random_string() {
local type="ascii"
local count="32"
local filter
local result
# 检测标志位
while [[ "$#" -gt 0 ]]; do
case "$1" in
-t|--type)
shift
type="$1"
;;
-c|--count)
shift
count="$1"
;;
*)
echo "Invalid command line flag $1" >&2
return 1
;;
esac
shift
done
# 检测类型
case "$type" in
ascii)
filter="[:print:]"
;;
alphanumeric)
filter="a-zA-Z0-9"
;;
numeric)
filter="0-9"
;;
*)
echo "Invalid type ${type}" >&2
return 1
esac
# Obtain count + 10 lines from /dev/urandom to ensure that the resulting string has the expected size
# Note there is a very small chance of strings starting with EOL character
# Therefore, the higher amount of lines read, this will happen less frequently
result="$(head -n "$((count + 10))" /dev/urandom | tr -dc "$filter" | head -c "$count")"
echo "$result"
}
# 为指定字符串生成 MD5 值
# 参数:
# $1 - 字符串
# 返回值:
# 字符串对应的 MD5
generate_md5_hash() {
local -r str="${1:?missing input string}"
echo -n "$str" | md5sum | awk '{print $1}'
}
-213
View File
@@ -1,213 +0,0 @@
#!/bin/bash
# Ver: 1.0 by Endial Fang (endial@126.com)
#
# 服务管理函数库
# shellcheck disable=SC1091
# 加载依赖项
. /usr/local/scripts/liblog.sh # 日志输出函数库
. /usr/local/scripts/libvalidations.sh # 数据有效性检测函数库
# 函数列表
# 获取并返回服务 PID
# 参数:
# $1 - PID 文件
# 返回值:
# PID
get_pid_from_file() {
local pid_file="${1:?pid file is missing}"
if [[ -f "$pid_file" ]]; then
if [[ -n "$(< "$pid_file")" ]] && [[ "$(< "$pid_file")" -gt 0 ]]; then
echo "$(< "$pid_file")"
fi
fi
}
# 检测 PID 对应的服务是否在运行中
# 参数:
# $1 - PID
# 返回值:
# 0 / 1
is_service_running() {
local pid="${1:?pid is missing}"
kill -0 "$pid" 2>/dev/null
}
# 通过发送信号停止一个指定 PID 的服务
# 参数:
# $1 - PID 文件
# $2 - 信号 (可选)
stop_service_using_pid() {
local pid_file="${1:?pid file is missing}"
local signal="${2:-}"
local pid
pid="$(get_pid_from_file "$pid_file")"
[[ -z "$pid" ]] || ! is_service_running "$pid" && return
if [[ -n "$signal" ]]; then
kill "-${signal}" "$pid"
else
kill "$pid"
fi
local counter=10
while [[ "$counter" -ne 0 ]] && is_service_running "$pid"; do
sleep 1
counter=$((counter - 1))
done
}
# 启动一个 cron 守护进程
# 返回值:
# true / false
cron_start() {
if [[ -x "/usr/sbin/cron" ]]; then
/usr/sbin/cron
elif [[ -x "/usr/sbin/crond" ]]; then
/usr/sbin/crond
else
false
fi
}
# 为指定的服务生成 cron 配置文件
# 参数:
# $1 - 服务名称
# $2 - 命令
# 标志位:
# --run-as - 运行的用户. 默认值: root
# --schedule - Cron 周期配置. 默认值: * * * * *
generate_cron_conf() {
local service_name="${1:?service name is missing}"
local cmd="${2:?command is missing}"
local run_as="root"
local schedule="* * * * *"
local clean="true"
local clean="true"
# 检测标志位
shift 2
while [[ "$#" -gt 0 ]]; do
case "$1" in
--run-as)
shift
run_as="$1"
;;
--schedule)
shift
schedule="$1"
;;
--no-clean)
clean="false"
;;
*)
echo "Invalid command line flag ${1}" >&2
return 1
;;
esac
shift
done
mkdir -p /etc/cron.d
if "$clean"; then
echo "${schedule} ${run_as} ${cmd}" > /etc/cron.d/"$service_name"
else
echo "${schedule} ${run_as} ${cmd}" >> /etc/cron.d/"$service_name"
fi
}
# 为指定的服务生成 monit 配置文件
# 参数:
# $1 - 服务名
# $2 - PID 文件
# $3 - 启动命令
# $4 - 停止命令
# 标志位:
# --disabled - 是否禁用. 默认值: no
generate_monit_conf() {
local service_name="${1:?service name is missing}"
local pid_file="${2:?pid file is missing}"
local start_command="${3:?start command is missing}"
local stop_command="${4:?stop command is missing}"
local monit_conf_dir="/etc/monit/conf.d"
local disabled="no"
# 检测标志位
shift 4
while [[ "$#" -gt 0 ]]; do
case "$1" in
--disabled)
shift
disabled="$1"
;;
*)
echo "Invalid command line flag ${1}" >&2
return 1
;;
esac
shift
done
is_boolean_yes "$disabled" && conf_suffix=".disabled"
mkdir -p "$monit_conf_dir"
cat >"${monit_conf_dir}/${service_name}.conf${conf_suffix:-}" <<EOF
check process ${service_name}
with pidfile "${pid_file}"
start program = "${start_command}" with timeout 90 seconds
stop program = "${stop_command}" with timeout 90 seconds
EOF
}
# 为指定的服务生成 Logrotate 配置文件
# 参数:
# $1 - 应用名称
# $2 - 日志路径
# 标志位:
# --period - 周期
# --rotations - Rotations 存储的数量
# --extra - 扩展参数 (可选)
generate_logrotate_conf() {
local service_name="${1:?service name is missing}"
local log_path="${2:?log path is missing}"
local period="weekly"
local rotations="150"
local extra=""
local logrotate_conf_dir="/etc/logrotate.d"
local var_name
# 检测标志位
shift 2
while [[ "$#" -gt 0 ]]; do
case "$1" in
--period|--rotations|--extra)
var_name="$(echo "$1" | sed -e "s/^--//" -e "s/-/_/g")"
shift
declare "$var_name"="${1:?"$var_name" is missing}"
;;
*)
echo "Invalid command line flag ${1}" >&2
return 1
;;
esac
shift
done
mkdir -p "$logrotate_conf_dir"
cat <<EOF | sed '/^\s*$/d' >"${logrotate_conf_dir}/${service_name}"
${log_path} {
${period}
rotate ${rotations}
dateext
compress
copytruncate
missingok
$(indent "$extra" 2)
}
EOF
}
@@ -1,234 +0,0 @@
#!/bin/bash
# Ver: 1.0 by Endial Fang (endial@126.com)
#
# 数据有效性校验函数库
# 加载依赖项
. /usr/local/scripts/liblog.sh # 日志输出函数库
# 函数列表
# 检测数据是否为整数
# 参数:
# $1 - 待检测的数据
# 返回值:
# true / false
is_int() {
local -r int="${1:?missing value}"
if [[ "$int" =~ ^-?[0-9]+ ]]; then
true
else
false
fi
}
# 检测数据是否为正整数
# 参数:
# $1 - 待检测的数据
# 返回值:
# true / false
is_positive_int() {
local -r int="${1:?missing value}"
if is_int "$int" && (( "${int}" >= 0 )); then
true
else
false
fi
}
# 检测数据是否为布尔值 '1' 或字符串 'yes/true'
# 参数:
# $1 - 待检测的数据
# 返回值:
# true / false
is_boolean_yes() {
local -r bool="${1:-}"
# comparison is performed without regard to the case of alphabetic characters
shopt -s nocasematch
if [[ "$bool" = 1 || "$bool" =~ ^(yes|true)$ ]]; then
true
else
false
fi
}
# 检测数据是否为字符串 'yes/no'
# 参数:
# $1 - 待检测的数据
# 返回值:
# true / false
is_yes_no_value() {
local -r bool="${1:-}"
if [[ "$bool" =~ ^(yes|no)$ ]]; then
true
else
false
fi
}
# 检测数据是否为字符串 'true/false'
# 参数:
# $1 - 待检测的数据
# 返回值:
# true / false
is_true_false_value() {
local -r bool="${1:-}"
if [[ "$bool" =~ ^(true|false)$ ]]; then
true
else
false
fi
}
# 检测提供的参数是否为空字符串或未定义
# 参数:
# $1 - 待检测的数据
# 返回值:
# true / false
is_empty_value() {
local -r val="${1:-}"
if [[ -z "$val" ]]; then
true
else
false
fi
}
# 检测数据是否为有效的端口号
# 标志位:
# -unprivileged - 没有特权的端口
# 参数:
# $1 - 待检测的数据
# 返回值:
# true / false 或 错误消息
validate_port() {
local value
local unprivileged=0
# Parse flags
while [[ "$#" -gt 0 ]]; do
case "$1" in
-unprivileged)
unprivileged=1
;;
--)
shift
break
;;
-*)
LOG_E "unrecognized flag $1"
return 1
;;
*)
break
;;
esac
shift
done
if [[ "$#" -gt 1 ]]; then
LOG_E "too many arguments provided"
return 2
elif [[ "$#" -eq 0 ]]; then
LOG_E "missing port argument"
return 1
else
value=$1
fi
if [[ -z "$value" ]]; then
LOG_E "the value is empty"
return 1
else
if ! is_int "$value"; then
LOG_W "value is not an integer"
return 2
elif [[ "$value" -lt 0 ]]; then
LOG_W "negative value provided"
return 2
elif [[ "$value" -gt 65535 ]]; then
LOG_W "requested port is greater than 65535"
return 2
elif [[ "$unprivileged" = 1 && "$value" -lt 1024 ]]; then
LOG_W "privileged port requested"
return 3
fi
fi
}
# 检测数据是否为有效的IPv4地址
# 参数:
# $1 - 待检测的数据
# 返回值:
# 0 / 1
validate_ipv4() {
local ip="${1:?ip is missing}"
local stat=1
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
read -r -a ip_array <<< "$(tr '.' ' ' <<< "$ip")"
[[ ${ip_array[0]} -le 255 && ${ip_array[1]} -le 255 \
&& ${ip_array[2]} -le 255 && ${ip_array[3]} -le 255 ]]
stat=$?
fi
return $stat
}
# 校验字符串格式
# 标志位:
# -min-length - 最小长度
# -max-length - 最大长度
# 参数:
# $1 - 待检测的数据
# 返回值:
# 0 / 1
validate_string() {
local string
local min_length=-1
local max_length=-1
# Parse flags
while [ "$#" -gt 0 ]; do
case "$1" in
-min-length)
shift
min_length=${1:-}
;;
-max-length)
shift
max_length=${1:-}
;;
--)
shift
break
;;
-*)
LOG_E "unrecognized flag $1"
return 1
;;
*)
break
;;
esac
shift
done
if [ "$#" -gt 1 ]; then
LOG_E "too many arguments provided"
return 2
elif [ "$#" -eq 0 ]; then
LOG_W "missing string"
return 1
else
string=$1
fi
if [[ "$min_length" -ge 0 ]] && [[ "${#string}" -lt "$min_length" ]]; then
LOG_I "string length is less than $min_length"
return 1
fi
if [[ "$max_length" -ge 0 ]] && [[ "${#string}" -gt "$max_length" ]]; then
LOG_I "string length is great than $max_length"
return 1
fi
}
-164
View File
@@ -1,164 +0,0 @@
#!/bin/bash
# Ver: 1.0 by Endial Fang (endial@126.com)
#
# shell 执行参数,分别为 -e(命令执行错误则退出脚本) -u(变量未定义则报错) -x(打印实际待执行的命令行)
set -eux
. /usr/local/scripts/liblog.sh
print_usage() {
LOG "Usage: download_pkg <COMMAND> <PACKAGE-NAME> \"<URLS>\" [OPTIONS]"
LOG ""
LOG "Download and install Third-Part packages"
LOG ""
LOG "Commands:"
LOG " download Download a package."
LOG " install Download and install a package."
LOG " unpack Download and unpack a package."
LOG ""
LOG "Options:"
LOG " -g, --checkpgp Package release bucket."
LOG " -s, --checksum SHA256 verification checksum."
LOG " -h, --help Show this help message and exit."
LOG ""
LOG "PACKAGE-NAME: Name with extern name"
LOG "URLS: String with URL list"
LOG ""
LOG "Examples:"
LOG " - Unpack package"
LOG " \$ download_pkg unpack redis-5.0.8.tar.gz \"http://download.redis.io/releases\""
LOG ""
LOG " - Verify and Install package"
LOG " \$ download_pkg install redis-5.0.8.tar.gz \"http://download.redis.io/releases\" -s 42cf86a114d2a451b898fcda96acd4d01062a7dbaaad2801d9164a36f898f596"
LOG ""
}
check_pgp() {
local name_asc=${1:?missing asc file name}
local name=${2:?missing file name}
local keys="${3:?missing key id}"
GNUPGHOME="$(mktemp -d)"
if which gpg >/dev/null 2>&1; then
for key in $keys; do
gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "${key}" ||
gpg --batch --keyserver pgp.mit.edu --recv-keys "${key}" ||
gpg --batch --keyserver keys.gnupg.net --recv-keys "${key}" ||
gpg --batch --keyserver keyserver.pgp.com --recv-keys "${key}";
done
gpg --batch --verify "$name_asc" "$name"
command -v gpgconf > /dev/null && gpgconf --kill all
fi
}
# 获取并解析参数
ARGS=$(getopt -o g:s:h -l "checkpgp:,checksum:,help" -n "download-pkg" -- "$@")
if [ $? -ne 0 ];
then
exit 1
fi
eval set -- "$ARGS";
while true; do
case "$1" in
-g|--checkpgp)
shift
if [ -n "$1" ]; then
PACKAGE_KEYS=$1
shift
fi
;;
-s|--checksum)
shift
if [ -n "$1" ]; then
PACKAGE_SHA256=$1
shift
fi
;;
-h|--help)
print_usage
exit 0
;;
--)
shift
break
;;
esac
done
# 检测输入的命令是否合法
case "$1" in
download|install|unpack) ;;
*)
error "Unrecognized command: $1"
print_usage
exit 1
;;
esac
# 检测输入参数是否足够,需要至少提供软件包名称 及 下载路径
if [ $# -lt 3 ]; then
print_usage
exit 1
fi
INSTALL_ROOT=/usr/local
CACHE_ROOT=/tmp
PACKAGE="$2"
PACKAGE_URLS=$3
cd $INSTALL_ROOT
LOG_I "Downloading $PACKAGE package"
for url in $PACKAGE_URLS; do
LOG_D "Try $url/$PACKAGE"
if wget -O "$CACHE_ROOT/$PACKAGE" "$url/$PACKAGE" && [ -s "$CACHE_ROOT/$PACKAGE" ]; then
if [ -n "${PACKAGE_KEYS:-}" ]; then
wget -O "$CACHE_ROOT/$PACKAGE.asc" "$url/$PACKAGE.asc" || wget -O "$CACHE_ROOT/$PACKAGE.asc" "$url/$PACKAGE.sign" || :
if [ ! -e "$CACHE_ROOT/$PACKAGE.asc" ]; then
exit 1
fi
fi
break
fi
done
if [ -n "${PACKAGE_SHA256:-}" ]; then
LOG_I "Verifying package integrity"
echo "$PACKAGE_SHA256 *$CACHE_ROOT/$PACKAGE" | sha256sum -c -
fi
if [ -e "$CACHE_ROOT/$PACKAGE.asc" ]; then
LOG_I "Verifying package with PGP"
check_pgp "$CACHE_ROOT/$PACKAGE.asc" "$CACHE_ROOT/$PACKAGE" "$PACKAGE_KEYS"
fi
# If the tarball has too many files, it can trigger a bug
# in overlayfs when using tar. Install bsdtar in the container image
# to workaround it. As the overhead is too big (~40 MB), it is not added by
# default. Source: https://github.com/coreos/bugs/issues/1095
# 安装或解压软件
case "$1" in
download)
LOG_I "Download success: $CACHE_ROOT/$PACKAGE"
;;
install)
LOG_I "Installing $PACKAGE"
cp $CACHE_ROOT/$PACKAGE /usr/local/bin/
;;
unpack)
if ! tar -taf $CACHE_ROOT/$PACKAGE >/dev/null 2>&1; then
LOG_E "Invalid or corrupt '$PACKAGE' package."
exit 1
fi
LOG_I "Unpacking $PACKAGE to $CACHE_ROOT"
cd $CACHE_ROOT
if which bsdtar >/dev/null 2>&1; then
bsdtar -xf $CACHE_ROOT/$PACKAGE
else
tar --no-same-owner -xaf $CACHE_ROOT/$PACKAGE
fi
;;
esac
-58
View File
@@ -1,58 +0,0 @@
#!/bin/bash
# Ver: 1.0 by Endial Fang (endial@126.com)
#
# shell 执行参数,分别为 -e(命令执行错误则退出脚本) -u(变量未定义则报错) -x(打印实际待执行的命令行)
set -eux
print_usage() {
echo "Usage: install_pkg <PACKAGE-NAME>"
echo ""
echo "Download and install packages"
echo ""
echo "Options:"
echo " -h, --help Show this help message and exit."
echo ""
echo "Examples:"
echo " - Install bash & curl"
echo " \$ install_pkg bash curl"
echo ""
}
if [ $# -lt 1 ]; then
print_usage
exit 1
fi
case "$1" in
-h|--help)
print_usage
exit 0
;;
esac
retry=0
max=2
until [ $retry -gt $max ]; do
set +e
(
export DEBIAN_FRONTEND=noninteractive &&
apt-get update &&
apt-get upgrade -y &&
apt-get install -y --no-install-recommends "$@"
)
CODE=$?
set -e
if [ $CODE -eq 0 ]; then
break
fi
if [ $retry -eq $max ]; then
exit $CODE
fi
echo "apt failed, retrying"
retry=$(($retry + 1))
done
apt-get purge -y --auto-remove
apt-get autoclean -y
rm -r /var/lib/apt/lists /var/cache/apt/archives || :
-6
View File
@@ -1,6 +0,0 @@
#!/bin/bash
# Ver: 1.0 by Endial Fang (endial@126.com)
#
# shell 执行参数,分别为 -e(命令执行错误则退出脚本) -u(变量未定义则报错) -x(打印实际待执行的命令行)
set -eux
cp /etc/apt/sources/sources.list.${1:-default} /etc/apt/sources.list