Compare commits

2 Commits

Author SHA1 Message Date
endial e17bc168a1 feat: 修改Dockerfile 2025-04-21 18:18:13 +08:00
endial 782e10787c feat: 修改脚本 2025-04-21 17:09:10 +08:00
15 changed files with 211 additions and 305 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
.git
.gitignore
./Makefile
./build.sh
*.yml
*.yaml
+1 -3
View File
@@ -147,7 +147,5 @@ STOPSIGNAL SIGINT
#HEALTHCHECK --interval=10s --timeout=10s --retries=3 CMD netstat -ltun | grep 8080
# 使用 dumb-init 启动入口 Shell,确保容器可以接收控制信号;并使用前台方式启动应用程序
ENTRYPOINT ["dumb-init", "entry.sh"]
ENTRYPOINT ["dumb-init", "--", "entry.sh"]
CMD ["run.sh"]
#CMD ["tail", "-f", "/dev/null"] # 没有应用时,保证当前容器运行
#CMD [] # 空命令,启动容器时如不设置相应命令,容器会在启动后直接退出(一般用于基础镜像)
-67
View File
@@ -1,67 +0,0 @@
# Ver: 1.11 by Endial Fang (endial@126.com)
#
# 当前 Docker 镜像的编译脚本
# 定义镜像名称
image_name :=template
# 定义默认镜像仓库地址
REGISTRY_URL :=swr.cn-north-4.myhuaweicloud.com/colovu/
# 定义系统默认使用的源服务器,包含: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/' | sed -e 's/main/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.colovu.com/dist
.PHONY: build clean clearclean upgrade push
build:
@echo "Build $(image_name):$(image_tag)"
@docker buildx build --progress plain --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
# 推送镜像至华为云 SWR 的 colovu 空间及 registry.colovu.com 的默认空间
push:
@echo "Push $(image_name):$(image_tag) to Huawei Cloud SWR colovu space"
@docker tag $(image_name):$(image_tag) swr.cn-north-4.myhuaweicloud.com/colovu/$(image_name):$(image_tag)
@docker push swr.cn-north-4.myhuaweicloud.com/colovu/$(image_name):$(image_tag)
@echo "Push $(image_name):$(image_tag) to registry.colovu.com"
@docker tag $(image_name):$(image_tag) registry.colovu.com/library/$(image_name):$(image_tag)
@docker push registry.colovu.com/library/$(image_name):$(image_tag)
@echo "Push $(image_name):latest to Huawei Cloud SWR colovu space"
@docker tag $(image_name):latest swr.cn-north-4.myhuaweicloud.com/colovu/$(image_name):latest
@docker push swr.cn-north-4.myhuaweicloud.com/colovu/$(image_name):latest
@echo "Push $(image_name):latest to registry.colovu.com"
@docker tag $(image_name):latest registry.colovu.com/library/$(image_name):latest
@docker push registry.colovu.com/library/$(image_name):latest
@echo "Push complete"
+11 -48
View File
@@ -13,24 +13,23 @@
**镜像信息:**
* 镜像地址:
- 华为云: swr.cn-north-4.myhuaweicloud.com/colovu/imgname:latest
- Colovu: registry.colovu.com/library/imgname:latest
- 依赖镜像:registry.colovu.com/library/debian:12
swr.cn-north-4.myhuaweicloud.com/colovu/debian:12
- 华为云: swr.cn-north-4.myhuaweicloud.com/colovu/imgname
- 阿里云: registry.cn-shenzhen.aliyuncs.com/colovu/imgname
- 依赖镜像:swr.cn-north-4.myhuaweicloud.com/colovu/debian
> 后续相关命令行默认使用华为云 SWR 镜像服务器做说明。
## TL;DR
## 快捷命令
Docker 快速启动命令:
```shell
# 从 Registry 服务器下载镜像并启动
docker run -d -e ALLOW_ANONYMOUS=yes --name imgname registry.cn-shenzhen.aliyuncs.com/colovu/imgname:latest
docker run -e ALLOW_ANONYMOUS=yes --name imgname swr.cn-north-4.myhuaweicloud.com/colovu/imgname:latest
```
- `registry.cn-shenzhen.aliyuncs.com/colovu/imgname:<TAG>`:镜像名称及版本标签 TAG;标签不指定时默认使用最新版本
- latest:为镜像的 TAG,可针对性选择不同的 TAG 进行下载
- 不指定 TAG 时,默认下载`latest`镜像
Docker-Compose 快速启动命令:
@@ -38,9 +37,6 @@ Docker-Compose 快速启动命令:
# 从 Gitee 下载 Compose 文件
curl -sSL -o https://gitee.com/colovu/docker-imgname/raw/master/docker-compose.yml
# 从 Github 下载 Compose 文件
curl -sSL -o https://raw.githubusercontent.com/colovu/docker-imgname/master/docker-compose.yml
# 创建并启动容器
docker-compose up -d
```
@@ -57,25 +53,14 @@ docker-compose up -d
镜像默认提供以下数据卷定义:
```shell
/srv/imgname/conf # 配置文件
/srv/imgname/data # 数据文件,主要存放应用数据
/srv/imgname/cert # 证书文件存放目录
/srv/imgname/binlog # 数据操作日志文件
/srv/imgname/log # 日志输出
- `/data`:工作目录,主要存放应用数据
- `/var/run`:系统运行时文件,如 PID 文件
/var/run/imgname # 系统运行时文件,如 PID 文件
```
如果需要持久化存储相应数据,需要**在宿主机建立本地目录**,并在使用镜像初始化容器时进行映射。宿主机相关的目录中如果不存在对应应用`imgname`的子目录或相应数据文件,则容器会在初始化时创建相应目录及文件。
如果需要持久化存储相应数据,需要**在宿主机建立本地目录**,并在使用镜像初始化容器时进行映射。
## 容器配置
在初始化 `AppName` 容器时,如果没有预置配置文件,可以在命令行中设置相应环境变量对默认参数进行修改。类似命令如下(配置环境变量`APP_ENV_KEY_NAME`的值为`key_value`):
```shell
docker run -d -e "APP_ENV_KEY_NAME=key_value" registry.cn-shenzhen.aliyuncs.com/colovu/imgname:latest
```
在初始化 `AppName` 容器时,主要通过如下的环境变量进行配置。
### 自动变量替换
@@ -149,24 +134,6 @@ APP_CFG_yarn__log___aggregation___enable=true
ALLOW_ANONYMOUS=yes
```
通过配置类似环境变量`APPNAME_USER``APPNAME_PASSWORD`,可以启用基于密码的用户认证功能。命令行使用参考:
```shell
$ docker run -d -e APPNAME_USER=colovu -e APPNAME_PASSWORD=colovu123 registry.cn-shenzhen.aliyuncs.com/colovu/imgname:latest
```
使用 Docker-Compose 时,`docker-compose.yml`应包含类似如下配置:
```yaml
services:
imgname:
...
environment:
- APPNAME_USER=colovu
- APPNAME_PASSWORD=colovu123
...
```
### 容器安全
本容器默认使用`non-root`运行应用,以加强容器的安全性。在使用`non-root`用户运行容器时,相关的资源访问会受限;应用仅能操作镜像创建时指定的路径及数据。使用`non-root`方式的容器,更适合在生产环境中使用。
@@ -182,10 +149,6 @@ services:
- 容器中应用的启动参数不能配置为后台运行,如果应用使用后台方式运行,则容器的启动命令会在运行后自动退出,从而导致容器退出
## 更新记录
- 2021/1/1 (1.0): 初始版本
----
本文原始来源 [Endial Fang](https://gitee.com/colovu) @ [Gitee.com](https://gitee.com)
+17 -4
View File
@@ -63,7 +63,7 @@ build() {
echo "Build complete"
}
# 推送镜像到colovu仓库
# 推送镜像到 Colovu 私有仓库
push_colovu() {
local TAG=${1:-$(get_image_tag)}
echo "Pushing ${IMAGE_NAME}:${TAG} to registry.colovu.com"
@@ -75,7 +75,19 @@ push_colovu() {
podman push "registry.colovu.com/library/${IMAGE_NAME}:latest"
}
# 推送镜像到华为云仓库
# 推送镜像到阿里云 ACR 仓库
push_ali() {
local TAG=${1:-$(get_image_tag)}
echo "Pushing ${IMAGE_NAME}:${TAG} to registry.cn-shenzhen.aliyuncs.com"
podman tag "${IMAGE_NAME}:${TAG}" "registry.cn-shenzhen.aliyuncs.com/colovu/${IMAGE_NAME}:${TAG}"
podman push "registry.cn-shenzhen.aliyuncs.com/colovu/${IMAGE_NAME}:${TAG}"
podman tag "${IMAGE_NAME}:latest" "registry.cn-shenzhen.aliyuncs.com/colovu/${IMAGE_NAME}:latest"
podman push "registry.cn-shenzhen.aliyuncs.com/colovu/${IMAGE_NAME}:latest"
}
# 推送镜像到华为云 SWR 仓库
push_huawei() {
local TAG=${1:-$(get_release_tag)}
echo "Pushing ${IMAGE_NAME}:${TAG} to swr.cn-north-4.myhuaweicloud.com"
@@ -101,9 +113,10 @@ main() {
build) build "$2" ;; # 传递第二个参数作为标签
clean) clean ;;
push-cv) push_colovu "$2" ;;
push-ali) push_ali "$2" ;;
push-hw) push_huawei "$2" ;;
push) push_colovu "$2"; push_huawei "$2" ;;
*) echo "Usage: $0 {build [tag]|clean|push-cv [tag]|push-hw [tag]|push [tag]}"; exit 1 ;;
push) push_ali "$2"; push_huawei "$2" ;;
*) echo "Usage: $0 {build [tag]|clean|push-ali [tag]|push-hw [tag]|push [tag]}"; exit 1 ;;
esac
}
-43
View File
@@ -1,43 +0,0 @@
#!/bin/bash
# Ver: 1.3 by Endial Fang (endial@126.com)
#
# 应用环境变量定义及初始化
export ENV_DEBUG=${ENV_DEBUG:-false}
export ALLOW_ANONYMOUS="${ALLOW_ANONYMOUS:-no}"
# 通过读取变量名对应的`*_FILE`文件,获取变量值
# 变量优先级: *_FILE > 传入变量 > 默认值
app_env_file_lists=(
APP_PASSWORD
)
for env_var in "${app_env_file_lists[@]}"; do
file_env_var="${env_var}_FILE"
if [[ -n "${!file_env_var:-}" ]]; then
export "${env_var}=$(< "${!file_env_var}")"
unset "${file_env_var}"
fi
done
unset app_env_file_lists
# 应用路径参数(Dockerfile 已定义:APP_NAME、APP_VER,可能定义 APP_USER、APP_EXEC
export APP_EXEC="${APP_EXEC:-${APP_NAME}}"
export APP_USER="${APP_USER:-${APP_NAME}}"
export APP_GROUP="${APP_GROUP:-${APP_USER}}"
export APP_HOME="${APP_HOME:-/srv/${APP_NAME}}"
export APP_BASE="${APP_BASE:-/usr/local/${APP_NAME}}"
export APP_DEF_DIR="${APP_BASE}/etc/${APP_NAME}"
export APP_CONF_DIR="/srv/${APP_NAME}/conf"
export APP_DATA_DIR="/srv/${APP_NAME}/data"
export APP_CERT_DIR="/srv/${APP_NAME}/cert"
export APP_LOG_DIR="/srv/${APP_NAME}/log"
export APP_CACHE_DIR="/var/cache/${APP_NAME}"
export APP_RUN_DIR="/var/run/${APP_NAME}"
# 应用配置参数
export APP_CONF_FILE="${APP_CONF_FILE:-${APP_CONF_DIR}/default.conf}"
export APP_PID_FILE="${APP_PID_FILE:-${APP_RUN_DIR}/${APP_NAME}.pid}"
# 个性化变量
-26
View File
@@ -1,26 +0,0 @@
#!/bin/bash
# Ver: 1.4 by Endial Fang (endial@126.com)
#
# 应用初始化脚本;当前脚本使用‘gosu ${APP_USER}’方式切换至用户空间执行
# 设置 shell 执行参数,可使用'-'(打开)'+'(关闭)控制。常用:
# -e: 命令执行错误则报错; -u: 变量未定义则报错; -x: 打印实际待执行的命令行; -o pipefail: 设置管道中命令遇到失败则报错
set -euo pipefail
. /usr/local/bin/environment.sh # 设置环境变量
. /usr/local/bin/common.sh # 应用专用函数库
LOG_I "** Processing init.sh **"
trap "app_stop_server" EXIT
# 检测最小环境变量配置
app_verify_minimum_env
# 执行应用预初始化操作
app_custom_preinit
# 执行应用初始化操作
app_default_init
# 执行用户自定义初始化脚本
app_custom_init
-24
View File
@@ -1,24 +0,0 @@
#!/bin/bash
# Ver: 1.7 by Endial Fang (endial@126.com)
#
# 应用启动脚本;组合默认的配置参数及容器启动时传入的 CMD 参数,启动应用
# 设置 shell 执行参数,可使用'-'(打开)'+'(关闭)控制。常用:
# -e: 命令执行错误则报错(errexit); -u: 变量未定义则报错(nounset); -x: 打印实际待执行的命令行; -o pipefail: 设置管道中命令遇到失败则报错
set -euo pipefail
. /colovu/lib/liblog.sh # 日志输出函数库
. /usr/local/bin/environment.sh # 设置环境变量
LOG_I "** Processing run.sh **"
readonly START_COMMAND="$(command -v ${APP_EXEC:-${APP_NAME}})"
# 配置默认启动参数(应用配置文件、前台方式启动)
flags=()
[[ -n "${APP_CONF_FILE:-}" ]] && flags+=("-c" "${APP_CONF_FILE}")
[[ -n "${APP_EXTRA_FLAGS:-}" ]] && flags+=("${APP_EXTRA_FLAGS[@]}")
flags+=("$@")
LOG_I "Start ${APP_NAME} with command: ${START_COMMAND} ${flags[@]}"
exec "${START_COMMAND}" "${flags[@]}"
-35
View File
@@ -1,35 +0,0 @@
#!/bin/bash
# Ver: 1.4 by Endial Fang (endial@126.com)
#
# 应用环境及依赖文件设置脚本;当前脚本以‘root’用户执行
# 设置 shell 执行参数,可使用'-'(打开)'+'(关闭)控制。常用:
# -e: 命令执行错误则报错(errexit); -u: 变量未定义则报错(nounset); -x: 打印实际待执行的命令行; -o pipefail: 设置管道中命令遇到失败则报错
set -euo pipefail
. /colovu/lib/libcommon.sh # 加载通用函数库
. /colovu/lib/libfs.sh # 加载文件操作函数库
. /colovu/lib/libos.sh # 加载系统管理函数库
. /usr/local/bin/environment.sh # 设置环境变量
. /usr/local/bin/common.sh # 应用专用函数库
LOG_I "** Processing setup.sh **"
APP_DIRS=(/var/log/${APP_NAME} /var/run/${APP_NAME} /var/cache/${APP_NAME} ${APP_HOME})
APP_DIRS+=(${APP_HOME}/conf ${APP_HOME}/data ${APP_HOME}/cert ${APP_HOME}/log)
LOG_I "Ensure directory exists: ${APP_DIRS[@]}"
for dir in ${APP_DIRS[@]}; do
ensure_dir_exists ${dir} ${APP_USER}
done
# 检测指定文件是否在配置文件存储目录存在,如果不存在则拷贝(新挂载数据卷、手动删除都会导致不存在)
LOG_I "Check config files in: ${APP_CONF_DIR}"
if [[ -z "$(ls -A "${APP_CONF_DIR}")" ]]; then
app_ensure_config_file_exist "${APP_CONF_DIR}" "${APP_DEF_DIR}" $(ls -A "${APP_DEF_DIR}")
fi
# 解决使用non-root后,[emerg] open() "/dev/stdout" failed (13: Permission denied)
LOG_D "Change permissions of stdout/stderr to 0662"
chmod 0662 /dev/stdout /dev/stderr
@@ -1,17 +1,18 @@
#!/usr/bin/dumb-init /bin/bash
# Ver: 1.6 by Endial Fang (endial@126.com)
# Ver: 1.7 by Endial Fang (endial@126.com)
#
# 容器入口脚本;当前脚本执行完毕时,使用默认用户执行镜像 CMD 定义的命令(默认为'/usr/local/bin/run.sh'
# 设置 shell 执行参数,可使用'-'(打开)'+'(关闭)控制。常用:
# -e: 命令执行错误则报错(errexit); -u: 变量未定义则报错(nounset); -x: 打印实际待执行的命令行; -o pipefail: 设置管道中命令遇到失败则报错
set -euo pipefail
set -o errexit
set -o nounset
set -o pipefail
. /colovu/lib/libcommon.sh # 加载通用函数库
. /usr/local/lib/libapplication.sh
. /usr/local/bin/environment.sh # 设置环境变量
info "** Processing entry.sh **"
LOG_I "** Processing entry.sh **"
# 加载应用环境变量
eval "$(app_env)"
# 优先处理'-'开始的版本信息、帮助信息显示命令,如果是该类命令,处理后退出容器
[[ "${1:0:1}" == '-' ]] && set -- "${APP_EXEC:-/bin/bash}" "$@" && print_command_help "$@"
@@ -33,5 +34,5 @@ if [[ "$(id -u)" == '0' ]] && [[ "$1" == "init.sh" ]]; then
fi
# 处理非以上情形的自定义命令
LOG_I "Start container with command: $@"
info "Start container with command: $@"
exec "$@"
+26
View File
@@ -0,0 +1,26 @@
#!/bin/bash
# Ver: 1.5 by Endial Fang (endial@126.com)
#
# 应用初始化脚本;当前脚本使用‘gosu ${APP_USER}’方式切换至用户空间执行
set -o errexit
set -o nounset
set -o pipefail
. /usr/local/lib/libapplication.sh
info "** Processing init.sh **"
# 加载应用环境变量
eval "$(app_env)"
# 检测环境变量是否有效
app_env_validate
# 注册脚本退出时执行的应用停止操作
trap "app_stop_server" EXIT
# 确认用户为`root`时,守护进城执行操作的用户存在
is_root && ensure_user_exists "$APP_USER" --group "$APP_GROUP"
# 执行应用初始化操作
app_default_init
# 执行用户自定义初始化脚本
app_custom_init
+30
View File
@@ -0,0 +1,30 @@
#!/bin/bash
# Ver: 1.8 by Endial Fang (endial@126.com)
#
# 应用启动脚本;组合默认的配置参数及容器启动时传入的 CMD 参数,启动应用
set -o errexit
set -o nounset
set -o pipefail
. /usr/local/lib/liblog.sh
. /usr/local/lib/libapplication.sh
info "** Processing run.sh **"
# 加载应用环境变量
eval "$(app_env)"
readonly START_COMMAND="$(command -v ${APP_EXEC:-${APP_NAME}})"
# 配置默认启动参数(应用配置文件、前台方式启动)
flags=()
[[ -n "${APP_CONF_FILE:-}" ]] && flags+=("-c" "${APP_CONF_FILE}")
[[ -n "${APP_EXTRA_FLAGS:-}" ]] && flags+=("${APP_EXTRA_FLAGS[@]}")
# 增加容器启动时传入的 CMD 参数
flags+=("$@")
info "Starting ${APP_NAME}..."
debug "Startup cmd: ${START_COMMAND} ${flags[*]}"
exec "${START_COMMAND}" "${flags[@]}"
+40
View File
@@ -0,0 +1,40 @@
#!/bin/bash
# Ver: 1.5 by Endial Fang (endial@126.com)
#
# 应用环境及依赖文件设置脚本;当前脚本以‘root’用户执行
set -o errexit
set -o nounset
set -o pipefail
. /usr/local/lib/libcommon.sh
. /usr/local/lib/libfs.sh
. /usr/local/lib/libos.sh
. /usr/local/lib/libapplication.sh
info "** Processing setup.sh **"
# 加载应用环境变量
eval "$(app_env)"
APP_DIRS=(/var/log/${APP_NAME} /var/run/${APP_NAME} /var/cache/${APP_NAME} ${APP_HOME})
APP_DIRS+=(${APP_HOME}/conf ${APP_HOME}/data ${APP_HOME}/cert ${APP_HOME}/log)
info "Ensure directory exists: ${APP_DIRS[@]}"
for dir in ${APP_DIRS[@]}; do
ensure_dir_exists ${dir} ${APP_USER}
chmod -R g+rwX "${dir}"
done
# 检测指定文件是否在配置文件存储目录存在,如果不存在则拷贝(新挂载数据卷、手动删除都会导致不存在)
info "Check config files in: ${APP_CONF_DIR}"
if [[ -z "$(ls -A "${APP_CONF_DIR}")" ]]; then
app_ensure_config_file_exist "${APP_CONF_DIR}" "${APP_DEF_DIR}" $(ls -A "${APP_DEF_DIR}")
fi
# 解决使用non-root后,[emerg] open() "/dev/stdout" failed (13: Permission denied)
debug "Change permissions of stdout/stderr to 0662"
chmod 0662 /dev/stdout /dev/stderr
# setcap CAP_NET_BIND_SERVICE=+eip $(command -v ${APP_EXEC:-${APP_NAME}})
@@ -3,13 +3,43 @@
#
# 应用通用业务处理函数
. /colovu/lib/libcommon.sh # 通用函数库
. /colovu/lib/libfile.sh
. /colovu/lib/libfs.sh
. /colovu/lib/liblog.sh
. /colovu/lib/libos.sh
. /colovu/lib/libservice.sh
. /colovu/lib/libvalidations.sh
. /usr/local/lib/libcommon.sh # 通用函数库
. /usr/local/lib/libfile.sh
. /usr/local/lib/libfs.sh
. /usr/local/lib/liblog.sh
. /usr/local/lib/libos.sh
. /usr/local/lib/libservice.sh
. /usr/local/lib/libvalidations.sh
# 应用环境变量初始化
# 环境变量格式:
# APP_<key>=<value>
app_env() {
cat << "EOF"
export ALLOW_ANONYMOUS="${ALLOW_ANONYMOUS:-no}"
# 应用路径参数(Dockerfile 已定义:APP_NAME、APP_VER,可能定义 APP_USER、APP_EXEC
export APP_EXEC="${APP_EXEC:-${APP_NAME}}"
export APP_USER="${APP_USER:-${APP_NAME}}"
export APP_GROUP="${APP_GROUP:-${APP_USER}}"
export APP_HOME="${APP_HOME:-/srv/${APP_NAME}}"
export APP_BASE="${APP_BASE:-/usr/local/${APP_NAME}}"
export APP_DEF_DIR="${APP_BASE}/etc/${APP_NAME}"
export APP_CONF_DIR="/srv/${APP_NAME}/conf"
export APP_DATA_DIR="/srv/${APP_NAME}/data"
export APP_CERT_DIR="/srv/${APP_NAME}/cert"
export APP_debugIR="/srv/${APP_NAME}/log"
export APP_CACHE_DIR="/var/cache/${APP_NAME}"
export APP_RUN_DIR="/var/run/${APP_NAME}"
# 应用配置参数
export APP_CONF_FILE="${APP_CONF_FILE:-${APP_CONF_DIR}/default.conf}"
export APP_PID_FILE="${APP_PID_FILE:-${APP_RUN_DIR}/${APP_NAME}.pid}"
# 个性化变量
EOF
}
# 检测应用相应的配置文件是否存在,如果不存在,则从默认配置文件目录拷贝一份
# 默认配置文件路径:/etc/${APP_NAME}
@@ -26,15 +56,15 @@ app_ensure_config_file_exist() {
local f=""
shift 2
LOG_D "List to check in ${base_path}: $@"
debug "List to check in ${base_path}: $@"
while [ "$#" -gt 0 ]; do
f="${1}"
LOG_D " Process \"${f}\""
debug " Process \"${f}\""
if [ -d "${base_path}/${f}" ]; then
[[ ! -d "${dist_path}/${f}" ]] && LOG_D " Create directory: ${dist_path}/${f}" && mkdir -p "${dist_path}/${f}"
[[ ! -d "${dist_path}/${f}" ]] && debug " Create directory: ${dist_path}/${f}" && mkdir -p "${dist_path}/${f}"
[[ ! -z $(ls -A "${base_path}/${f}") ]] && app_ensure_config_file_exist "${dist_path}/${f}" "${base_path}/${f}" $(ls -A "${base_path}/${f}")
else
[[ ! -e "${dist_path}/${f}" ]] && LOG_D " Copy: ${base_path}/${f} to ${dist_path}" && cp "${base_path}/${f}" "${dist_path}"
[[ ! -e "${dist_path}/${f}" ]] && debug " Copy: ${base_path}/${f} to ${dist_path}" && cp "${base_path}/${f}" "${dist_path}"
fi
shift
done
@@ -54,14 +84,14 @@ app_configure_from_environment() {
local confFile="${1:?missing file}"
local envPrefix="${2:-APP_CFG}"
LOG_D "Configuration File: ${confFile}"
debug "Configuration File: ${confFile}"
if [[ ${file#*.} != "xml" ]]; then
# 更新普通key-value配置文件,转换为小写后写入文件
for var in $(eval echo \${!${envPrefix}_@}); do
key="$(echo "$var" | sed -e 's/^'${envPrefix}'_//g' -e 's/___/-/g' -e 's/__/./g' | tr '[:upper:]' '[:lower:]')"
value="${!var}"
LOG_D " ${key}: ${value}"
debug " ${key}: ${value}"
app_common_conf_set "$confFile" "$key" "$value"
done
else
@@ -69,7 +99,7 @@ app_configure_from_environment() {
for var in $(eval echo \${!${envPrefix}_@}); do
key=$(echo "$var" | sed -e 's/^'${envPrefix}'_//g' -e 's/___/-/g' -e 's/__/./g')
value="${!var}"
LOG_D " ${key}: ${value}"
debug " ${key}: ${value}"
app_common_xml_set "${confFile}" "${key}" "${value}"
done
fi
@@ -88,7 +118,7 @@ app_common_conf_set() {
local values=("$@")
if [[ "${#values[@]}" -eq 0 ]]; then
LOG_E "missing value"
error "missing value"
return 1
elif [[ "${#values[@]}" -ne 1 ]]; then
for i in "${!values[@]}"; do
@@ -109,7 +139,7 @@ app_common_conf_set() {
# 使用环境变量中配置,更新配置文件
app_update_conf() {
LOG_I "Update configure files from APP_CFG_*..."
info "Update configure files from APP_CFG_*..."
app_configure_from_environment "${APP_CONF_FILE}" "APP_CFG"
}
@@ -122,25 +152,25 @@ app_generate_conf() {
# 根据容器参数,设置配置文件
app_common_conf_set "${APP_CONF_DIR}/log4j.properties" "zookeeper.console.threshold" "${ZOO_LOG_LEVEL}"
app_common_conf_set "${APP_CONF_DIR}/log4j.properties" "zookeeper.log.dir" "${APP_LOG_DIR}"
app_common_conf_set "${APP_CONF_DIR}/log4j.properties" "zookeeper.log.dir" "${APP_debugIR}"
app_update_conf
}
# 检测用户参数信息是否满足条件; 针对部分权限过于开放情况,打印提示信息
app_verify_minimum_env() {
app_env_validate() {
local error_code=0
LOG_D "Validating settings in ENV vars..."
debug "Validating settings in ENV vars..."
print_validation_error() {
LOG_E "$1"
error "$1"
error_code=1
}
# 检测认证设置。如果不允许匿名登录,检测登录用户名及密码是否设置
if is_boolean_yes "${ALLOW_ANONYMOUS}"; then
LOG_W "You have set the environment variable ALLOW_ANONYMOUS=${ALLOW_ANONYMOUS}. For safety reasons, do not use this flag in a production environment."
warn "You have set the environment variable ALLOW_ANONYMOUS=${ALLOW_ANONYMOUS}. For safety reasons, do not use this flag in a production environment."
else
# 检测相应密码是否设置
# print_validation_error "The ZOO_ENABLE_AUTH environment variable does not configure authentication. Set the environment variable ALLOW_ANONYMOUS=yes to allow unauthenticated users to connect to ZooKeeper."
@@ -153,13 +183,13 @@ app_verify_minimum_env() {
# 更改默认监听地址为 "*" 或 "0.0.0.0",以对容器外提供服务
app_enable_remote_connections() {
LOG_I "Modify default config to ENABLE external IP access"
info "Modify default config to ENABLE external IP access"
}
# 更改默认监听地址为 "localhost" 或 "127.0.0.1",以禁止对容器外提供服务
app_disable_remote_connections() {
LOG_I "Modify default config to DISABLE external IP access"
info "Modify default config to DISABLE external IP access"
}
@@ -178,7 +208,7 @@ app_wait_service() {
install_pkg ncat
fi
LOG_I "[0/${max_try}] check for ${service}:${port}..."
info "[0/${max_try}] check for ${service}:${port}..."
set +e
nc -z ${service} ${port}
@@ -186,10 +216,10 @@ app_wait_service() {
until [ $result -eq 0 ]; do
if (( $i == ${max_try} )); then
LOG_E "${service}:${port} is still not available; giving up after ${max_try} tries."
error "${service}:${port} is still not available; giving up after ${max_try} tries."
exit 1
fi
LOG_D " [$i/${max_try}] not available yet, try in ${retry_seconds}'s latter ..."
debug " [$i/${max_try}] not available yet, try in ${retry_seconds}'s latter ..."
let "i++"
sleep ${retry_seconds}
@@ -199,14 +229,14 @@ app_wait_service() {
done
set -e
LOG_I "[$i/${max_try}] ${service}:${port} is available."
info "[$i/${max_try}] ${service}:${port} is available."
}
# 以后台方式启动应用服务,并等待启动就绪
app_start_server_bg() {
app_is_server_running && return
LOG_I "Starting ${APP_NAME} in background..."
info "Starting ${APP_NAME} in background..."
# 使用 debug_execute 并以守护进程方式启动服务
# debug_execute "zkServer.sh" start
@@ -229,10 +259,10 @@ app_start_server_bg() {
sleep 1
counter=$(( counter - 1 ))
if (( counter <= 0 )); then
LOG_E "${APP_NAME} is not ready after 30 seconds"
error "${APP_NAME} is not ready after 30 seconds"
exit 1
fi
LOG_D "Waiting for ${APP_NAME} to ready ... $counter"
debug "Waiting for ${APP_NAME} to ready ... $counter"
done
}
@@ -240,7 +270,7 @@ app_start_server_bg() {
app_stop_server() {
app_is_server_not_running && return
LOG_I "Stopping ${APP_NAME} background service..."
info "Stopping ${APP_NAME} background service..."
# 使用 debug_execute 关闭服务
# debug_execute "zkServer.sh" stop
@@ -262,10 +292,10 @@ app_stop_server() {
sleep 1
counter=$(( counter - 1 ))
if (( counter <= 0 )); then
LOG_E "${APP_NAME} is not stoped after 30 seconds"
error "${APP_NAME} is not stoped after 30 seconds"
exit 1
fi
LOG_D "Waiting for ${APP_NAME} to stop ... $counter"
debug "Waiting for ${APP_NAME} to stop ... $counter"
done
}
@@ -273,7 +303,7 @@ app_stop_server() {
app_is_server_running() {
local pid
pid="$(get_pid_from_file ${APP_PID_FILE})"
LOG_D "Checking ${APP_NAME} running status with PID: ${pid}"
debug "Checking ${APP_NAME} running status with PID: ${pid}"
if [[ -n "${pid}" ]]; then
is_service_running "${pid}"
@@ -292,7 +322,7 @@ app_is_server_not_running() {
# 清理初始化应用时生成的临时文件
app_clean_tmp_file() {
LOG_D "Clean ${APP_NAME} tmp files ..."
debug "Clean ${APP_NAME} tmp files ..."
local -r -a files=(
"${APP_PID_FILE}"
@@ -300,7 +330,7 @@ app_clean_tmp_file() {
for file in ${files[@]}; do
if [[ -f "$file" ]]; then
LOG_D " Remove $file"
debug " Remove $file"
rm -rf "$file"
fi
done
@@ -309,7 +339,7 @@ app_clean_tmp_file() {
# 用户自定义的前置初始化操作,依次执行目录 preinit.d 中的初始化脚本
# 执行完毕后,生成以当前时间命名的'.tar'的文件,包含执行记录、已执行的脚本,同时删除已执行的脚本
app_custom_preinit() {
LOG_I "Process pre-init for ${APP_NAME}..."
info "Process pre-init for ${APP_NAME}..."
# 检测用户配置文件目录是否存在 preinit.d 文件夹,如果存在,尝试执行目录中的初始化脚本
if [[ -d "${APP_CONF_DIR}/preinit.d" ]] && [[ -n $(find "${APP_CONF_DIR}/preinit.d/" -type f -regex ".*\.\(sh\)") ]]; then
@@ -318,7 +348,7 @@ app_custom_preinit() {
tar --remove-files -cf "${tarFile}" "${APP_CONF_DIR}/preinit.d/preinit_info"
for f in $(find "${APP_CONF_DIR}/preinit.d/" -type f -regex ".*\.\(sh\)" | sort); do
LOG_D " Process: ${f}"
debug " Process: ${f}"
process_init_files "${f}"
tar --remove-files -f "${tarFile}" -r "${f}"
done
@@ -327,7 +357,7 @@ app_custom_preinit() {
# 应用默认初始化操作
app_default_init() {
LOG_I "Process default init for ${APP_NAME}..."
info "Process default init for ${APP_NAME}..."
# 特殊情况下,生成默认配置文件(如默认不存在或仅存在 sample 配置文件)
app_generate_conf
@@ -342,7 +372,7 @@ app_default_init() {
# 用户自定义的应用初始化操作,依次执行目录 initdb.d 中的初始化脚本
# 执行完毕后,生成以当前时间命名的'.tar'的文件,包含执行记录、已执行的脚本,同时删除已执行的脚本
app_custom_init() {
LOG_I "Process DB-init for ${APP_NAME}..."
info "Process DB-init for ${APP_NAME}..."
# 检测用户配置文件目录是否存在 preinit.d 文件夹,如果存在,尝试执行目录中的初始化脚本
if [[ -d "${APP_CONF_DIR}/initdb.d" ]] && [[ -n $(find "${APP_CONF_DIR}/initdb.d/" -type f -regex ".*\.\(sh\|sql\|sql.gz\)") ]]; then
@@ -357,19 +387,19 @@ app_custom_init() {
for f in $(find "${APP_CONF_DIR}/initdb.d/" -type f -regex ".*\.\(sh\|sql\|sql.gz\)" | sort); do
case "$f" in
*.sh)
LOG_D " Process Shell: ${f}"
debug " Process Shell: ${f}"
process_init_files "$f"
;;
*.sql)
LOG_D " Process SQL: ${f}";
debug " Process SQL: ${f}";
postgresql_execute "${PG_DATABASE}" "${PG_INITSCRIPTS_USERNAME}" "${PG_INITSCRIPTS_PASSWORD}" < "$f"
;;
*.sql.gz)
LOG_D " Process SQLs in ${f}";
debug " Process SQLs in ${f}";
gunzip -c "$f" | postgresql_execute "${PG_DATABASE}" "${PG_INITSCRIPTS_USERNAME}" "${PG_INITSCRIPTS_PASSWORD}" <
;;
*)
LOG_D " Ignoring $f"
debug " Ignoring $f"
;;
esac
@@ -400,9 +430,9 @@ app_configure_heap_size() {
local -r heap_size="${1:?heap_size is required}"
if [[ "${JVMFLAGS}" =~ -Xm[xs].*-Xm[xs] ]]; then
LOG_D "Using specified values (JVMFLAGS=${JVMFLAGS})"
debug "Using specified values (JVMFLAGS=${JVMFLAGS})"
else
LOG_D "Setting '-Xmx${heap_size}m -Xms${heap_size}m' heap options..."
debug "Setting '-Xmx${heap_size}m -Xms${heap_size}m' heap options..."
app_export_jvmflags "-Xmx${heap_size}m -Xms${heap_size}m"
fi
}