Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e17bc168a1 | |||
| 782e10787c |
+1
-1
@@ -1,7 +1,7 @@
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
./Makefile
|
||||
./build.sh
|
||||
|
||||
*.yml
|
||||
*.yaml
|
||||
|
||||
+1
-3
@@ -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 [] # 空命令,启动容器时如不设置相应命令,容器会在启动后直接退出(一般用于基础镜像)
|
||||
|
||||
@@ -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"
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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}"
|
||||
|
||||
# 个性化变量
|
||||
|
||||
@@ -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
|
||||
@@ -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[@]}"
|
||||
@@ -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 "$@"
|
||||
Executable
+26
@@ -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
|
||||
Executable
+30
@@ -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[@]}"
|
||||
Executable
+40
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user