feat(database-dump-via-docker-sock): 支持指定容器内执行命令的用户

This commit is contained in:
严浩
2025-09-23 15:04:51 +08:00
parent adfa640822
commit 055b8ad63e
2 changed files with 49 additions and 9 deletions

View File

@@ -12,7 +12,7 @@ print_usage() {
cat <<EOF_USAGE >&2 cat <<EOF_USAGE >&2
Usage: $0 [--socket=PATH] [--api-version=VERSION] --container=NAME \\ Usage: $0 [--socket=PATH] [--api-version=VERSION] --container=NAME \\
[--type=postgres|mysql|kingbase] --backup-prefix=PREFIX [--backup-dir=DIR] \\ [--type=postgres|mysql|kingbase] --backup-prefix=PREFIX [--backup-dir=DIR] \\
[--mysql-user=USER] [--mysql-password=PASSWORD] [--mysql-user=USER] [--mysql-password=PASSWORD] [--exec-user=NAME]
Options: Options:
--socket=PATH Docker Engine unix socket path (default: /var/run/docker.sock) --socket=PATH Docker Engine unix socket path (default: /var/run/docker.sock)
@@ -23,6 +23,7 @@ Options:
--backup-prefix=PREFIX Backup filename prefix --backup-prefix=PREFIX Backup filename prefix
--mysql-user=USER MySQL user (default: root) --mysql-user=USER MySQL user (default: root)
--mysql-password=PASSWORD MySQL password (optional) --mysql-password=PASSWORD MySQL password (optional)
--exec-user=NAME Force a specific user when running commands inside the container
--help Show this help message --help Show this help message
EOF_USAGE EOF_USAGE
} }
@@ -36,6 +37,7 @@ BACKUP_PREFIX=""
MYSQL_USER="root" MYSQL_USER="root"
MYSQL_PASSWORD="" MYSQL_PASSWORD=""
MYSQL_PASSWORD_SET=0 MYSQL_PASSWORD_SET=0
EXEC_USER_OVERRIDE=""
detect_db_type_from_name() { detect_db_type_from_name() {
name_lower=$(printf '%s' "$1" | tr 'A-Z' 'a-z') name_lower=$(printf '%s' "$1" | tr 'A-Z' 'a-z')
@@ -82,12 +84,19 @@ escape_for_double_quotes() {
docker_exec() { docker_exec() {
exec_container_name=$1 exec_container_name=$1
exec_cmd=$2 exec_cmd=$2
exec_user=${3:-}
curl -fsSL "https://Git.1-H.CC/Scripts/Linux/raw/branch/main/docker-exec-via-sock.sh" | sh -s -- \ set -- \
--socket="$DOCKER_SOCKET" \ --socket="$DOCKER_SOCKET" \
--api-version="$DOCKER_API_VERSION" \ --api-version="$DOCKER_API_VERSION" \
--container="$exec_container_name" \ --container="$exec_container_name" \
--cmd="$exec_cmd" --cmd="$exec_cmd"
if [ -n "$exec_user" ]; then
set -- "$@" --user="$exec_user"
fi
curl -fsSL "https://Git.1-H.CC/Scripts/Linux/raw/branch/main/docker-exec-via-sock.sh" | sh -s -- "$@"
} }
while [ "$#" -gt 0 ]; do while [ "$#" -gt 0 ]; do
@@ -158,6 +167,14 @@ while [ "$#" -gt 0 ]; do
MYSQL_PASSWORD="$1" MYSQL_PASSWORD="$1"
MYSQL_PASSWORD_SET=1 MYSQL_PASSWORD_SET=1
;; ;;
--exec-user=*)
EXEC_USER_OVERRIDE="${1#*=}"
;;
--exec-user)
if [ "$#" -lt 2 ]; then missing_value '--exec-user'; fi
shift
EXEC_USER_OVERRIDE="$1"
;;
--help) --help)
print_usage print_usage
exit 0 exit 0
@@ -207,6 +224,8 @@ if [ -z "$DB_TYPE" ]; then
fi fi
fi fi
EXEC_USER_DEFAULT=""
case $DB_TYPE in case $DB_TYPE in
postgres) postgres)
BACKUP_EXTENSION=".sql.zst" BACKUP_EXTENSION=".sql.zst"
@@ -227,6 +246,7 @@ case $DB_TYPE in
BACKUP_EXTENSION=".sql.zst" BACKUP_EXTENSION=".sql.zst"
DUMP_CMD="sys_dumpall --clean --username=\"\${DB_USER:-kingbase}\"" DUMP_CMD="sys_dumpall --clean --username=\"\${DB_USER:-kingbase}\""
COMPRESS_CMD="zstd" COMPRESS_CMD="zstd"
EXEC_USER_DEFAULT="root"
;; ;;
*) *)
printf 'Unsupported database type: %s\n' "$DB_TYPE" >&2 printf 'Unsupported database type: %s\n' "$DB_TYPE" >&2
@@ -234,6 +254,12 @@ case $DB_TYPE in
;; ;;
esac esac
if [ -n "$EXEC_USER_OVERRIDE" ]; then
EXEC_USER="$EXEC_USER_OVERRIDE"
else
EXEC_USER="$EXEC_USER_DEFAULT"
fi
timestamp=$(date +%Y-%m-%d_%H-%M-%S) timestamp=$(date +%Y-%m-%d_%H-%M-%S)
backup_path="$BACKUP_DIR/${BACKUP_PREFIX}${timestamp}${BACKUP_EXTENSION}" backup_path="$BACKUP_DIR/${BACKUP_PREFIX}${timestamp}${BACKUP_EXTENSION}"
@@ -244,7 +270,7 @@ cmd="mkdir -p \"${BACKUP_DIR}\" && set -o pipefail && ${DUMP_CMD} | ${COMPRESS_C
log_border="----------------------------------------------------------------------" log_border="----------------------------------------------------------------------"
printf '%s\n' "$log_border" >&2 printf '%s\n' "$log_border" >&2
if ! docker_exec "$CONTAINER_NAME" "$cmd"; then if ! docker_exec "$CONTAINER_NAME" "$cmd" "${EXEC_USER:-}"; then
printf '%s\n' "$log_border" >&2 printf '%s\n' "$log_border" >&2
log "backup command failed" log "backup command failed"
exit 1 exit 1
@@ -257,7 +283,7 @@ log "backup command finished, verifying file size inside container"
verify_cmd="du -h \"${backup_path}\" 2>/dev/null | awk 'NR==1{print \$1}'" verify_cmd="du -h \"${backup_path}\" 2>/dev/null | awk 'NR==1{print \$1}'"
printf '%s\n' "$log_border" >&2 printf '%s\n' "$log_border" >&2
size=$(docker_exec "$CONTAINER_NAME" "$verify_cmd" | tr -d '\r') size=$(docker_exec "$CONTAINER_NAME" "$verify_cmd" "${EXEC_USER:-}" | tr -d '\r')
printf '%s\n' "$log_border" >&2 printf '%s\n' "$log_border" >&2
printf '\n' >&2 printf '\n' >&2

View File

@@ -21,13 +21,14 @@ log_stream() {
print_usage() { print_usage() {
cat <<EOF >&2 cat <<EOF >&2
Usage: $0 [--socket=PATH] [--api-version=VERSION] --container=NAME --cmd=COMMAND Usage: $0 [--socket=PATH] [--api-version=VERSION] --container=NAME --cmd=COMMAND [--user=NAME]
Options: Options:
--socket=PATH Docker Engine unix socket path (default: /var/run/docker.sock) --socket=PATH Docker Engine unix socket path (default: /var/run/docker.sock)
--api-version=VERSION Docker API version (default: v1.51) --api-version=VERSION Docker API version (default: v1.51)
--container=NAME Container name to execute command in --container=NAME Container name to execute command in
--cmd=COMMAND Command to execute in the container --cmd=COMMAND Command to execute in the container
--user=NAME Run command as the specified user (default: container default user)
--shell=SHELL Shell to use (default: sh) 暂未实现 --shell=SHELL Shell to use (default: sh) 暂未实现
--help Show this help message --help Show this help message
EOF EOF
@@ -37,6 +38,7 @@ DOCKER_SOCKET="/var/run/docker.sock"
DOCKER_API_VERSION="v1.51" DOCKER_API_VERSION="v1.51"
CONTAINER_NAME="" CONTAINER_NAME=""
CMD_TO_EXEC="" CMD_TO_EXEC=""
EXEC_USER=""
DOCKER_LAST_RESPONSE="" DOCKER_LAST_RESPONSE=""
require_command() { require_command() {
@@ -55,13 +57,13 @@ missing_value() {
docker_exec_create() { docker_exec_create() {
docker_exec_create_desc=$1 docker_exec_create_desc=$1
docker_exec_create_cmd=$2 docker_exec_create_cmd=$2
docker_exec_create_payload=$(jq -n --arg cmd "$docker_exec_create_cmd" '{ docker_exec_create_payload=$(jq -n --arg cmd "$docker_exec_create_cmd" --arg user "$EXEC_USER" '{
AttachStdin: false, AttachStdin: false,
AttachStdout: true, AttachStdout: true,
AttachStderr: true, AttachStderr: true,
Tty: true, Tty: true,
Cmd: ["sh", "-c", $cmd] Cmd: ["sh", "-c", $cmd]
}') } | if ($user | length) > 0 then .User = $user else . end)
DOCKER_LAST_RESPONSE=$(curl --silent --show-error --unix-socket "$DOCKER_SOCKET" \ DOCKER_LAST_RESPONSE=$(curl --silent --show-error --unix-socket "$DOCKER_SOCKET" \
-X POST \ -X POST \
@@ -141,6 +143,14 @@ while [ "$#" -gt 0 ]; do
shift shift
CMD_TO_EXEC="$1" CMD_TO_EXEC="$1"
;; ;;
--user=*)
EXEC_USER="${1#*=}"
;;
--user)
if [ "$#" -lt 2 ]; then missing_value '--user'; fi
shift
EXEC_USER="$1"
;;
--help) --help)
print_usage print_usage
exit 0 exit 0
@@ -180,7 +190,11 @@ fi
docker_api_base="http://localhost/${DOCKER_API_VERSION}" docker_api_base="http://localhost/${DOCKER_API_VERSION}"
exec_create_endpoint="${docker_api_base}/containers/${CONTAINER_NAME}/exec" exec_create_endpoint="${docker_api_base}/containers/${CONTAINER_NAME}/exec"
log "executing command in container '$CONTAINER_NAME': $CMD_TO_EXEC" if [ -n "$EXEC_USER" ]; then
log "executing command in container '$CONTAINER_NAME' as '$EXEC_USER': $CMD_TO_EXEC"
else
log "executing command in container '$CONTAINER_NAME': $CMD_TO_EXEC"
fi
exec_id=$(docker_exec_create "command" "$CMD_TO_EXEC") exec_id=$(docker_exec_create "command" "$CMD_TO_EXEC")
if [ -z "$exec_id" ]; then if [ -z "$exec_id" ]; then
@@ -203,4 +217,4 @@ else
# 将错误输出打印到 stderr # 将错误输出打印到 stderr
echo "$output" >&2 echo "$output" >&2
exit "$exit_code" exit "$exit_code"
fi fi