pull-docker-image/pull-docker-image.sh
Sunday 6610f199ee Fix characters in shell script
Fix: some symbols are Chinese symbols, fix them.
2025-02-03 20:45:10 +08:00

209 lines
5.6 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# pull-docker-image.sh
# 主要功能:
# - 根据用户参数拉取指定 Docker 镜像,生成 tar 包,并支持 gzip 或 zstd 压缩。
#
# 具体参数与用法请见pull-docker-image.sh -h
set -euo pipefail
# Default values.
IMAGE=""
DEST="."
NEWNAME=""
USE_GZIP=false
USE_ZSTD=false
FORCE=false
PROXY=""
usage() {
cat <<EOF
Usage: $(basename "$0") -t image:tag [-d destination] [-n newname:tag] [-g] [-z]
[-f] [-p proxy]
-t (Required) Docker image name and tag to pull.
-d Destination of pulled image file。
- If a directory is given, a new file named as image name and tag
(with ':' replaced by '_') under the given directory is created.
Suffixes are inferred from compression options if specified.
- If a file path is given, the given file path is used directly.
- To forcefully overwrite existing file, use '-f' option.
- Default: . (Current directory).
-n Image name and tag in output image file. Keep the same as '-t' option
if not specified.
-g Compress image file with gzip.
-z Compress image file with zstd.
-f Forcefully overwrite existing destination file。
-p Set up network proxies (through 'HTTP_PROXY' and 'HTTPS_PROXY' variables).
-h Show this help information.
Example:
1. Pulling 'nginx:mainline' image to existed directory '~/nginx-images/'.
$(basename "$0") -t nginx:mainline -d ~/nginx-images/
EOF
}
# 解析命令行选项
parse_args() {
while getopts "t:d:n:gzfp:h" opt; do
case "$opt" in
t)
IMAGE="$OPTARG"
;;
d)
DEST="$OPTARG"
;;
n)
NEWNAME="$OPTARG"
;;
g)
USE_GZIP=true
;;
z)
USE_ZSTD=true
;;
f)
FORCE=true
;;
p)
PROXY="$OPTARG"
;;
h)
usage
exit 0
;;
*)
usage
exit 1
;;
esac
done
if [[ -z "$IMAGE" ]]; then
echo "Error: '-t' option (image name and tag to pull) must be specified." >&2
usage
exit 1
fi
# 如果未指定 -n则使用 -t 的值
if [[ -z "$NEWNAME" ]]; then
NEWNAME="$IMAGE"
fi
# 压缩方法 -g 和 -z 不能同时指定
if $USE_GZIP && $USE_ZSTD; then
echo "Error: '-g' and '-z' cannot be used together." >&2
exit 1
fi
}
# 检查是否安装了 skopeo
check_skopeo() {
if ! command -v skopeo >/dev/null 2>&1; then
echo "Error: skopeo is not installed, or not in PATH." >&2
exit 1
fi
}
# 设置网络代理
setup_proxy() {
if [[ -n "$PROXY" ]]; then
export HTTP_PROXY="$PROXY"
export HTTPS_PROXY="$PROXY"
echo "Use proxy at $PROXY"
fi
}
# 根据目标参数确定最终的目标文件路径
determine_target_file() {
local target=""
if [[ -d "$DEST" ]]; then
local base_name
base_name=$(echo "$IMAGE" | tr ':' '_')
target="${DEST%/}/$base_name.tar"
else
target="$DEST"
fi
echo "$target"
}
# 检查目标文件是否存在冲突
check_conflict() {
local file="$1"
if [[ -f "$file" ]]; then
if ! $FORCE; then
echo "Error: destination file '$file' exists, use '-f' option to overwrite." >&2
exit 1
else
echo "Warning: destination file '$file' exists, override as '-f' specified."
fi
fi
}
# 使用 skopeo 拉取 Docker 镜像
pull_image() {
local target_file="$1"
echo "Start pulling $IMAGE to $target_file with name $NEWNAME in archive..."
if ! skopeo copy "docker://$IMAGE" "docker-archive:$target_file:$NEWNAME"; then
echo "Error: skopeo failed during pulling image" >&2
exit 1
fi
echo "Image is saved to $target_file successfully."
}
# 根据压缩选项对镜像文件进行压缩
compress_image() {
local target_file="$1"
local final_file=""
if $USE_GZIP || $USE_ZSTD; then
if $USE_GZIP; then
local compressed="${target_file}.gz"
check_conflict "$compressed"
echo "Compress $target_file with gzip..."
if ! gzip -f "$target_file"; then
echo "Error: failed to compress image with gzip." >&2
exit 1
fi
final_file="$compressed"
elif $USE_ZSTD; then
local compressed="${target_file}.zst"
check_conflict "$compressed"
echo "Compress $target_file with zstd..."
if ! zstd -q -o "$compressed" "$target_file"; then
echo "Error: failed to compress image with zstd." >&2
exit 1
fi
rm -f "$target_file"
final_file="$compressed"
fi
echo "Compressed image is saved to $final_file."
else
final_file="$target_file"
fi
}
# 主函数
main() {
parse_args "$@"
check_skopeo
setup_proxy
local target_file
target_file=$(determine_target_file)
check_conflict "$target_file"
# 同时检查压缩后的文件是否存在冲突(如果有压缩选项)
if $USE_GZIP; then
check_conflict "${target_file}.gz"
elif $USE_ZSTD; then
check_conflict "${target_file}.zst"
fi
pull_image "$target_file"
compress_image "$target_file"
echo "OK."
}
# 主入口
main "$@"