本文目录导读:

我来详细说明如何从源码构建基础镜像的Shell脚本。
基础构建脚本
#!/bin/bash
# build_base_image.sh - 从源码构建基础镜像
set -euo pipefail
# 配置变量
SOURCE_DIR="/tmp/source"
IMAGE_NAME="my-base-image:latest"
BUILD_DIR="/tmp/build"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# 清理函数
cleanup() {
log_info "清理构建环境..."
rm -rf "$BUILD_DIR"
}
# 错误处理
trap 'cleanup' EXIT
# 创建构建目录
prepare_build_dir() {
log_info "准备构建目录..."
mkdir -p "$BUILD_DIR"
}
# 构建Dockerfile
create_dockerfile() {
local dockerfile="$BUILD_DIR/Dockerfile"
cat > "$dockerfile" << 'EOF'
# 使用最小的基础镜像
FROM alpine:latest AS builder
# 安装构建依赖
RUN apk add --no-cache \
build-base \
gcc \
make \
cmake \
git \
curl \
openssl-dev \
zlib-dev \
readline-dev
# 设置工作目录
WORKDIR /app
# 复制源码
COPY . .
# 编译配置
RUN mkdir -p build && \
cd build && \
cmake .. && \
make -j$(nproc)
# 第二阶段:创建最小镜像
FROM alpine:latest
# 安装运行时依赖
RUN apk add --no-cache \
libstdc++ \
libgcc \
ca-certificates \
tzdata
# 创建运行用户
RUN addgroup -g 1000 appuser && \
adduser -u 1000 -G appuser -s /bin/sh -D appuser
# 复制编译产出的二进制文件
COPY --from=builder /app/build/bin/ /usr/local/bin/
# 设置时区
ENV TZ=Asia/Shanghai
# 切换用户
USER appuser
# 暴露端口
EXPOSE 8080
# 设置入口点
ENTRYPOINT ["app"]
CMD ["--help"]
EOF
}
# 克隆源码
clone_source() {
local repo_url="$1"
local branch="${2:-main}"
log_info "克隆源码: $repo_url (branch: $branch)"
if [ -d "$BUILD_DIR/source" ]; then
log_warn "源码目录已存在,更新中..."
cd "$BUILD_DIR/source"
git checkout "$branch"
git pull origin "$branch"
else
git clone --depth 1 --branch "$branch" "$repo_url" "$BUILD_DIR/source"
fi
}
# 自定义构建参数
configure_build() {
local config_file="$BUILD_DIR/build.config"
cat > "$config_file" << 'CONFIG'
# 构建配置
BUILD_TYPE="Release"
INSTALL_PREFIX="/usr/local"
EXTRA_CFLAGS="-O2 -march=x86-64-v2"
ENABLE_DEBUG=0
ENABLE_TESTS=0
CONFIG
}
# 构建镜像
build_image() {
log_info "开始构建Docker镜像..."
cd "$BUILD_DIR/source"
# 复制Dockerfile到源码目录
cp "$BUILD_DIR/Dockerfile" .
# 构建命令
docker build \
--build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
--build-arg VERSION=$(git describe --tags --always 2>/dev/null || echo "unknown") \
--build-arg COMMIT_HASH=$(git rev-parse HEAD 2>/dev/null || echo "unknown") \
-t "$IMAGE_NAME" \
-f Dockerfile \
.
log_info "镜像构建完成: $IMAGE_NAME"
}
# 多阶段构建(大型项目)
multi_stage_build() {
local dockerfile="$BUILD_DIR/Dockerfile.multistage"
cat > "$dockerfile" << 'EOF'
# 第一阶段:编译依赖
FROM alpine:latest AS deps
RUN apk add --no-cache \
autoconf \
automake \
libtool \
pkgconfig
# 第二阶段:构建应用
FROM alpine:latest AS build
COPY --from=deps /usr/bin/ /usr/bin/
COPY --from=deps /usr/lib/ /usr/lib/
# 第三阶段:运行环境
FROM alpine:latest AS runtime
RUN apk add --no-cache runtime-deps
COPY --from=build /app/bin/ /app/
EOF
}
# 验证镜像
verify_image() {
log_info "验证构建的镜像..."
# 检查镜像是否存在
if ! docker image inspect "$IMAGE_NAME" >/dev/null 2>&1; then
log_error "镜像 $IMAGE_NAME 不存在"
return 1
fi
# 检查镜像大小
local size=$(docker images --format "{{.Size}}" "$IMAGE_NAME")
log_info "镜像大小: $size"
# 扫描安全漏洞
if command -v trivy &>/dev/null; then
log_info "执行安全扫描..."
trivy image --severity HIGH,CRITICAL "$IMAGE_NAME"
fi
}
# 推送镜像到仓库
push_image() {
local registry="${1:-docker.io}"
local username="${2:-}"
local password="${3:-}"
if [ -n "$username" ] && [ -n "$password" ]; then
log_info "登录到镜像仓库..."
echo "$password" | docker login "$registry" -u "$username" --password-stdin
fi
# 打标签并推送
local full_image_name="${registry}/${IMAGE_NAME}"
docker tag "$IMAGE_NAME" "$full_image_name"
docker push "$full_image_name"
log_info "镜像已推送: $full_image_name"
}
# 清理旧版本
cleanup_old_images() {
local keep_versions="${1:-3}"
log_info "清理旧版本(保留最近 $keep_versions 个版本)..."
# 获取所有版本(按时间排序)
docker images --format "{{.Repository}}:{{.Tag}}" | \
grep "^${IMAGE_NAME%:*}" | \
tail -n +$((keep_versions + 1)) | \
xargs -r docker rmi
}
# 主函数
main() {
local repo_url="${1:-}"
local branch="${2:-main}"
if [ -z "$repo_url" ]; then
echo "用法: $0 <git仓库URL> [分支名]"
echo "示例: $0 https://github.com/user/app.git main"
exit 1
fi
log_info "开始从源码构建基础镜像..."
# 准备环境
prepare_build_dir
configure_build
# 获取源码
clone_source "$repo_url" "$branch"
# 创建并构建
create_dockerfile
build_image
# 验证
verify_image
log_info "构建完成!"
log_info "镜像名称: $IMAGE_NAME"
# 可选:推送镜像
if [ "${PUSH_IMAGE:-false}" = "true" ]; then
push_image "${REGISTRY:-}" "${REGISTRY_USER:-}" "${REGISTRY_PASS:-}"
fi
# 可选:清理旧版本
if [ "${CLEANUP_OLD:-false}" = "true" ]; then
cleanup_old_images "${KEEP_VERSIONS:-3}"
fi
}
# 执行主函数
main "$@"
高级构建脚本
#!/bin/bash
# advanced_build.sh - 高级构建脚本
# 缓存优化
setup_build_cache() {
log_info "设置构建缓存..."
# Docker BuildKit 缓存
export DOCKER_BUILDKIT=1
export BUILDKIT_PROGRESS=plain
# 创建缓存目录
mkdir -p /tmp/docker-cache
}
# 并行构建
parallel_build() {
local components=("$@")
for component in "${components[@]}"; do
{
log_info "构建组件: $component"
docker build -t "component-${component}:latest" -f "Dockerfile.${component}" .
} &
done
wait
log_info "所有组件构建完成"
}
# 条件构建
conditional_build() {
local arch=$(uname -m)
case "$arch" in
x86_64)
BUILD_FLAGS="-march=x86-64-v3"
;;
aarch64)
BUILD_FLAGS="-march=armv8-a"
;;
*)
BUILD_FLAGS=""
;;
esac
docker build \
--build-arg ARCH="$arch" \
--build-arg BUILD_FLAGS="$BUILD_FLAGS" \
-t "$IMAGE_NAME" \
.
}
# 增量构建
incremental_build() {
local cache_from="${1:-}"
if [ -n "$cache_from" ]; then
docker build \
--cache-from "$cache_from" \
--build-arg BUILDKIT_INLINE_CACHE=1 \
-t "$IMAGE_NAME" \
.
else
docker build \
--no-cache \
-t "$IMAGE_NAME" \
.
fi
}
# 交叉编译
cross_compile_build() {
local target_arch="${1:-arm64}"
# 设置QEMU模拟器
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
# 交叉编译构建
docker buildx build \
--platform "linux/${target_arch}" \
--tag "${IMAGE_NAME}-${target_arch}" \
--load \
.
}
# 构建优化
optimize_build() {
# 使用BuildKit
export DOCKER_BUILDKIT=1
# 启用缓存挂载
docker build \
--mount type=cache,target=/root/.cache/pip \
--mount type=cache,target=/root/.cache/go-build \
-t "$IMAGE_NAME" \
.
}
# 环境检测
check_environment() {
log_info "检查构建环境..."
# 检查Docker
if ! command -v docker &>/dev/null; then
log_error "Docker未安装"
exit 1
fi
# 检查磁盘空间
local free_space=$(df /var/lib/docker | awk 'NR==2 {print $4}')
if [ "$free_space" -lt 10485760 ]; then # 小于10GB
log_warn "磁盘空间不足: $((free_space/1024/1024))GB"
fi
# 检查内存
local total_mem=$(free -m | awk 'NR==2 {print $2}')
if [ "$total_mem" -lt 2048 ]; then
log_warn "内存不足: ${total_mem}MB"
fi
}
# 使用示例
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
# 检查环境
check_environment
# 设置缓存
setup_build_cache
# 执行构建
main "$@"
fi
使用示例
# 基本用法 ./build_base_image.sh https://github.com/example/myapp.git main # 高级用法 PUSH_IMAGE=true \ REGISTRY="registry.example.com" \ REGISTRY_USER="admin" \ REGISTRY_PASS="password" \ CLEANUP_OLD=true \ KEEP_VERSIONS=5 \ ./build_base_image.sh https://github.com/example/myapp.git develop # 交叉编译 ./cross_compile_build.sh arm64
最佳实践
-
安全考虑
- 使用非root用户运行应用
- 定期扫描安全漏洞
- 使用最小基础镜像
-
性能优化
- 利用多阶段构建
- 使用构建缓存
- 合理分层Dockerfile
-
可靠性
- 版本控制构建脚本
- 添加错误处理
- 保存构建日志
这个脚本提供了完整的从源码构建基础镜像的解决方案,可根据实际需求调整。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播