build-docker-optimized.sh 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. #!/bin/bash
  2. # ============================================
  3. # 快速 Docker 构建脚本 - 使用优化版 Dockerfile
  4. # 使用文档:
  5. # 首次使用: bash init-dependencies.sh
  6. # 构建单个: bash build-docker-optimized.sh gateway:1.0.0
  7. # 构建多个: bash build-docker-optimized.sh gateway:3.0.2 order-service:3.0.5 payment-service:3.0.5
  8. # 自定义仓库: bash build-docker-optimized.sh gateway:1.0.0 -r myregistry.com
  9. # ============================================
  10. set -o pipefail # 管道中任何命令失败都会导致脚本退出
  11. # 颜色定义
  12. RED='\033[0;31m'
  13. GREEN='\033[0;32m'
  14. YELLOW='\033[1;33m'
  15. BLUE='\033[0;34m'
  16. CYAN='\033[0;36m'
  17. NC='\033[0m' # No Color
  18. # 函数:打印颜色信息
  19. log_info() {
  20. echo -e "${BLUE}[INFO]${NC} $1"
  21. }
  22. log_success() {
  23. echo -e "${GREEN}[✓]${NC} $1"
  24. }
  25. log_error() {
  26. echo -e "${RED}[✗]${NC} $1" >&2
  27. }
  28. log_warn() {
  29. echo -e "${YELLOW}[!]${NC} $1"
  30. }
  31. log_title() {
  32. echo -e "${CYAN}$1${NC}"
  33. }
  34. # 函数:显示使用帮助
  35. show_help() {
  36. cat << EOF
  37. 用法: $0 [OPTIONS] SERVICE:TAG [SERVICE:TAG] ...
  38. 服务简称:
  39. gateway - shop-recycle-gateway 网关服务
  40. order - shop-recycle-order-service 订单服务
  41. order-service - shop-recycle-order-service (别名)
  42. payment - shop-recycle-payment-service 支付服务
  43. payment-service - shop-recycle-payment-service (别名)
  44. 全局选项:
  45. -h, --help 显示此帮助信息
  46. -r, --registry ADDR 镜像仓库地址 (默认: harbor.stardance)
  47. --no-cache 构建时不使用缓存
  48. --push 构建完成后自动推送到镜像仓库
  49. 示例:
  50. # 构建单个服务
  51. bash $0 gateway:1.0.0
  52. # 构建多个服务(依次进行)
  53. bash $0 gateway:3.0.2 order-service:3.0.5 payment-service:3.0.5
  54. # 自定义镜像仓库
  55. bash $0 gateway:1.0.0 -r myregistry.com
  56. # 禁用缓存并推送
  57. bash $0 gateway:1.0.0 --no-cache --push
  58. EOF
  59. }
  60. # 参数处理
  61. REGISTRY="harbor.stardance"
  62. NO_CACHE=""
  63. PUSH_IMAGE=false
  64. BUILD_TARGETS=()
  65. # 解析参数
  66. while [[ $# -gt 0 ]]; do
  67. case $1 in
  68. -h|--help)
  69. show_help
  70. exit 0
  71. ;;
  72. -r|--registry)
  73. REGISTRY="$2"
  74. shift 2
  75. ;;
  76. --no-cache)
  77. NO_CACHE="--no-cache"
  78. shift
  79. ;;
  80. --push)
  81. PUSH_IMAGE=true
  82. shift
  83. ;;
  84. *)
  85. # 服务:标签 格式的参数
  86. BUILD_TARGETS+=("$1")
  87. shift
  88. ;;
  89. esac
  90. done
  91. # 验证必要参数
  92. if [ ${#BUILD_TARGETS[@]} -eq 0 ]; then
  93. log_error "缺少构建目标"
  94. echo ""
  95. show_help
  96. exit 1
  97. fi
  98. # 函数:解析 service:tag 格式
  99. parse_service_tag() {
  100. local input="$1"
  101. if [[ ! "$input" =~ : ]]; then
  102. log_error "格式错误: $input (应为 service:tag 格式)"
  103. return 1
  104. fi
  105. local service="${input%%:*}"
  106. local tag="${input##*:}"
  107. # 映射服务名称
  108. local dockerfile=""
  109. local image_name=""
  110. case "$service" in
  111. gateway)
  112. dockerfile="shop-recycle-gateway/Dockerfile.optimized"
  113. image_name="$REGISTRY/shop-recycle-gateway:$tag"
  114. ;;
  115. order|order-service)
  116. dockerfile="shop-recycle-order-service/Dockerfile.optimized"
  117. image_name="$REGISTRY/shop-recycle-order-service:$tag"
  118. ;;
  119. payment|payment-service)
  120. dockerfile="shop-recycle-payment-service/Dockerfile.optimized"
  121. image_name="$REGISTRY/shop-recycle-payment-service:$tag"
  122. ;;
  123. *)
  124. log_error "未知服务: $service"
  125. return 1
  126. ;;
  127. esac
  128. # 输出为 json 格式便于后续处理
  129. echo "{\"service\":\"$service\",\"tag\":\"$tag\",\"dockerfile\":\"$dockerfile\",\"image\":\"$image_name\"}"
  130. }
  131. # 函数:构建单个镜像
  132. build_image() {
  133. local service="$1"
  134. local tag="$2"
  135. local dockerfile="$3"
  136. local image_name="$4"
  137. # 检查 Dockerfile 是否存在
  138. if [ ! -f "$dockerfile" ]; then
  139. log_error "Dockerfile 不存在: $dockerfile"
  140. return 1
  141. fi
  142. local build_number=$(date +%Y%m%d%H%M%S)
  143. local git_commit=$(git rev-parse --short HEAD 2>/dev/null ; echo "unknown")
  144. local start_time=$(date +%s)
  145. # 打印构建信息
  146. echo ""
  147. log_title "════════════════════════════════════════════════════════════"
  148. log_title "Docker 镜像构建"
  149. log_title "════════════════════════════════════════════════════════════"
  150. log_info "服务: $service"
  151. log_info "镜像标签: $tag"
  152. log_info "仓库地址: $REGISTRY"
  153. log_info "镜像名称: $image_name"
  154. log_info "Git 提交: $git_commit"
  155. log_info "构建号: $build_number"
  156. [ -n "$NO_CACHE" ] && log_warn "禁用构建缓存"
  157. echo ""
  158. log_info "开始构建镜像..."
  159. echo ""
  160. # 执行 Docker 构建
  161. if docker build $NO_CACHE \
  162. --build-arg BUILD_NUMBER="$build_number" \
  163. --build-arg GIT_COMMIT="$git_commit" \
  164. -t "$image_name" \
  165. -f "$dockerfile" \
  166. .; then
  167. local end_time=$(date +%s)
  168. local duration=$((end_time - start_time))
  169. local minutes=$((duration / 60))
  170. local seconds=$((duration % 60))
  171. echo ""
  172. log_success "════════════════════════════════════════════════════════════"
  173. log_success "构建完成!"
  174. log_success "════════════════════════════════════════════════════════════"
  175. log_success "用时: ${minutes}分${seconds}秒"
  176. echo ""
  177. # 显示镜像信息
  178. log_info "镜像详细信息:"
  179. docker images "$image_name" --no-trunc
  180. echo ""
  181. # 获取镜像大小
  182. local image_size=$(docker images --format "{{.Size}}" "$image_name")
  183. log_info "镜像大小: $image_size"
  184. # 推送镜像
  185. if [ "$PUSH_IMAGE" = true ]; then
  186. echo ""
  187. log_info "准备推送镜像到仓库: $REGISTRY"
  188. if docker push "$image_name"; then
  189. log_success "镜像推送成功!"
  190. else
  191. log_error "镜像推送失败"
  192. return 1
  193. fi
  194. fi
  195. return 0
  196. else
  197. local end_time=$(date +%s)
  198. local duration=$((end_time - start_time))
  199. local minutes=$((duration / 60))
  200. local seconds=$((duration % 60))
  201. echo ""
  202. log_error "════════════════════════════════════════════════════════════"
  203. log_error "构建失败!用时: ${minutes}分${seconds}秒"
  204. log_error "════════════════════════════════════════════════════════════"
  205. echo ""
  206. log_error "调试建议:"
  207. echo " # 查看 Docker 构建日志(详细信息)"
  208. echo " docker build $NO_CACHE --build-arg BUILD_NUMBER=\"$build_number\" -t \"$image_name\" -f \"$dockerfile\" . --progress=plain"
  209. echo ""
  210. return 1
  211. fi
  212. }
  213. # 主程序流程
  214. echo ""
  215. log_title "╔════════════════════════════════════════════════════════════╗"
  216. log_title "║ Shop Recycle Docker 批量构建工具 ║"
  217. log_title "╚════════════════════════════════════════════════════════════╝"
  218. echo ""
  219. # 解析所有构建目标
  220. declare -a services
  221. declare -a tags
  222. declare -a dockerfiles
  223. declare -a images
  224. log_info "解析构建目标..."
  225. for target in "${BUILD_TARGETS[@]}"; do
  226. parsed=$(parse_service_tag "$target")
  227. if [ $? -ne 0 ]; then
  228. log_error "无法解析构建目标: $target"
  229. exit 1
  230. fi
  231. # 从 json 中提取字段
  232. service=$(echo "$parsed" | grep -o '"service":"[^"]*"' | cut -d'"' -f4)
  233. tag=$(echo "$parsed" | grep -o '"tag":"[^"]*"' | cut -d'"' -f4)
  234. dockerfile=$(echo "$parsed" | grep -o '"dockerfile":"[^"]*"' | cut -d'"' -f4)
  235. image=$(echo "$parsed" | grep -o '"image":"[^"]*"' | cut -d'"' -f4)
  236. services+=("$service")
  237. tags+=("$tag")
  238. dockerfiles+=("$dockerfile")
  239. images+=("$image")
  240. log_success "$target"
  241. done
  242. echo ""
  243. log_info "将按顺序构建 ${#BUILD_TARGETS[@]} 个镜像"
  244. # 检查 git 仓库状态
  245. if [ -z "$(git status --porcelain 2>/dev/null)" ]; then
  246. log_success "Git 工作目录干净"
  247. else
  248. log_warn "Git 工作目录有未提交的更改"
  249. fi
  250. echo ""
  251. # 依次构建每个镜像
  252. failed_builds=()
  253. successful_builds=()
  254. for i in "${!services[@]}"; do
  255. echo ""
  256. log_title "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  257. log_title "进度: $((i+1))/${#BUILD_TARGETS[@]} - ${BUILD_TARGETS[$i]}"
  258. log_title "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  259. if build_image "${services[$i]}" "${tags[$i]}" "${dockerfiles[$i]}" "${images[$i]}"; then
  260. successful_builds+=("${BUILD_TARGETS[$i]}")
  261. else
  262. failed_builds+=("${BUILD_TARGETS[$i]}")
  263. log_error "构建失败: ${BUILD_TARGETS[$i]}"
  264. exit 1
  265. fi
  266. done
  267. # 汇总报告
  268. echo ""
  269. echo ""
  270. log_title "╔════════════════════════════════════════════════════════════╗"
  271. log_title "║ 构建汇总 ║"
  272. log_title "╚════════════════════════════════════════════════════════════╝"
  273. echo ""
  274. log_success "成功构建 ${#successful_builds[@]} 个镜像:"
  275. for build in "${successful_builds[@]}"; do
  276. echo " ✓ $build"
  277. done
  278. if [ ${#failed_builds[@]} -gt 0 ]; then
  279. echo ""
  280. log_error "失败 ${#failed_builds[@]} 个:"
  281. for build in "${failed_builds[@]}"; do
  282. echo " ✗ $build"
  283. done
  284. fi
  285. echo ""
  286. log_info "════════════════════════════════════════════════════════════"
  287. log_info "下一步操作:"
  288. log_info "════════════════════════════════════════════════════════════"
  289. echo " # 查看镜像列表"
  290. echo " docker images | grep harbor.stardance"
  291. echo ""
  292. echo " # 运行容器"
  293. echo " docker run -d -p 8080:8080 --name gateway-container \\"
  294. echo " harbor.stardance/shop-recycle-gateway:3.0.2"
  295. echo ""
  296. if [ "$PUSH_IMAGE" = false ]; then
  297. echo " # 推送所有镜像到仓库"
  298. for image in "${images[@]}"; do
  299. echo " docker push $image"
  300. done
  301. echo ""
  302. fi
  303. echo ""