How OneBuild Cuts Docker Image Build Time by 66% with Multi‑Stage Reuse
This article introduces the OneBuild approach for cloud‑native image delivery, detailing how standardized Dockerfiles and shell scripts enable a single build to be reused across multiple deployments, cutting build time from 21 minutes to 7 minutes and improving efficiency by 66 %.
In the cloud‑native ecosystem—whether using Kubernetes, Docker Swarm, OpenShift, or other orchestration platforms—applications are delivered as container images. Our team has practiced a "Source‑to‑Image" and chained‑build workflow, summarizing it as the "OneBuild" model, whose core idea is "build once, use many times".
1. Problem
Typically we use a CI system such as Jenkins to build images for continuous integration, development, and delivery. When a fix or feature needs to be applied to an existing branch, or a vulnerability in a released image must be patched across many instances, we must rebuild the image, identify base images, and manage dependencies. Improving efficiency here yields measurable cost savings for the platform.
2. Solution
Standard Docker builds using a Dockerfile are common but insufficient for large‑scale, fast delivery. We therefore defined a standardized, production‑ready process called "OneBuild" that integrates with the internal "Xingyun" platform.
Dockerfile naming convention
<code>Dockerfile # standard version
Dockerfile.kylinv10 # kylinv10 base version
Dockerfile.oel22 # openeuler base version</code>Base Dockerfile (multi‑stage)
<code>ARG ARCH
ARG BUILD_IMAGE
ARG BASE_IMAGE
FROM ${BUILD_IMAGE} as builder
ARG ARCH
ENV GOPATH=/go
COPY go.mod go.mod
COPY go.sum go.sum
COPY main.go main.go
COPY api/ api/
COPY controllers/ controllers/
COPY pkg/ pkg/
COPY vendor/ vendor/
# Build
RUN CGO_ENABLED=0 GO111MODULE=on GOOS=linux GOARCH=${ARCH} \
go build --mod=vendor -a -o manager main.go
ARG ARCH
ARG BASE_IMAGE
FROM ${BASE_IMAGE}
ENV PIP3_SOURCE=https://pypi.tuna.tsinghua.edu.cn/simple
ENV DEFAULT_FORKS=50
ENV DEFAULT_TIMEOUT=600
ENV DEFAULT_GATHER_TIMEOUT=600
ENV TZ=Asia/Shanghai
ENV PYTHONWARNINGS=ignore::UserWarning
WORKDIR /
COPY --from=builder /manager .
COPY inventory/ inventory/
COPY roles/ roles/
COPY etcd-restore.yml etcd-restore.yml
COPY facts.yml facts.yml
COPY requirements.txt requirements.txt
COPY inventory.tmpl.ini inventory.tmpl.ini
COPY ansible.cfg ansible.cfg
RUN yum -y install kde-l10n-Chinese && \
yum -y reinstall glibc-common && \
localedef -c -f UTF-8 -i zh_CN zh_CN.UFT-8 && \
echo 'LANG="zh_CN.UTF-8"' > /etc/locale.conf && \
source /etc/locale.conf && \
yum clean all
ENV LANG=zh_CN.UTF-8
ENV LC_ALL=zh_CN.UTF-8
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
echo $TZ > /etc/timezone && \
yum install python3 python3-devel sshpass openssh-clients -y && \
yum clean all && \
/usr/bin/python3 -m pip --no-cache-dir install pip==21.3.1 -U -i $PIP3_SOURCE && \
/usr/bin/python3 -m pip --no-cache-dir install -r requirements.txt -i $PIP3_SOURCE
USER root
ENTRYPOINT ["/manager"]</code>The above Dockerfile uses a two‑stage build; the first stage (builder) compiles the binary, while the second stage parameterizes both the build and base images, allowing changes via build arguments only.
Dockerfile.kylinv10 (inherits the built binary from the first stage):
<code>ARG BASE_IMAGE
FROM ${BASE_IMAGE}
ENV PIP3_SOURCE=https://pypi.tuna.tsinghua.edu.cn/simple
ENV DEFAULT_FORKS=50
ENV LANG=en_US.UTF-8
ENV DEFAULT_TIMEOUT=600
ENV DEFAULT_GATHER_TIMEOUT=600
ENV TZ=Asia/Shanghai
ENV PYTHONWARNINGS=ignore::UserWarning
WORKDIR /
COPY --from=jdos-etcd-restore-helper:latest /manager /
COPY inventory/ inventory/
COPY roles/ roles/
COPY etcd-restore.yml etcd-restore.yml
COPY facts.yml facts.yml
COPY requirements.txt requirements.txt
COPY inventory.tmpl.ini inventory.tmpl.ini
COPY ansible.cfg ansible.cfg
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
echo $TZ > /etc/timezone && \
yum install python3 python3-devel python3-pip sshpass openssh-clients -y && \
/usr/bin/python3 -m pip --no-cache-dir install pip==21.3.1 -U -i $PIP3_SOURCE && \
/usr/bin/python3 -m pip --no-cache-dir install -r requirements.txt -i $PIP3_SOURCE
USER root
ENTRYPOINT ["/manager"]</code>Dockerfile.oel22 follows the same pattern as the kylinv10 file and could be merged for simplicity.
Shell script standardization
<code># Support multi‑line shell input
cd /
sudo docker login -u $IMAGE_REPO_USER -p $IMAGE_REPO_PASSWD $(echo $IMAGE_REPO | awk -F '/' '{print $1}')
git_commit=${output.Download_Code.GIT_LAST_COMMIT_SHA1}
build_date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
image_tag="${env.GenerateNewVersion}-${git_commit:0:6}"
echo "start build image - standard"
new_image_repo="${IMAGE_REPO}"
sudo docker build -t ${new_image_repo}:${image_tag} -f Dockerfile --build-arg ARCH="amd64" .
sudo docker login -u $IMAGE_REPO_USER -p $IMAGE_REPO_PASSWD $(echo $IMAGE_REPO | awk -F '/' '{print $1}')
sudo docker push ${new_image_repo}:${image_tag}
echo "end to build image - standard"
echo "amd64ImageName=${new_image_repo}:${image_tag}" > ./amd64_output
# Tag the built image for later multi‑stage reuse
sudo docker tag ${new_image_repo}:${image_tag} jdos-etcd-restore-helper:latest
# Conditional build for kylinv10 base image
if [[ -f Dockerfile.kylinv10 ]]; then
echo "start build image - security - kylin base"
new_image_repo="${IMAGE_REPO}-kylinv10-amd64"
sudo docker build -t ${new_image_repo}:${image_tag} -f Dockerfile.kylinv10 --build-arg ARCH="amd64" .
sudo docker login -u $IMAGE_REPO_USER -p $IMAGE_REPO_PASSWD $(echo $IMAGE_REPO | awk -F '/' '{print $1}')
sudo docker push ${new_image_repo}:${image_tag}
echo "end to build image - security - kylin base"
echo "amd64KylinImageName=${new_image_repo}:${image_tag}" >> ./amd64_output
fi
# Conditional build for openeuler22 base image
if [[ -f Dockerfile.oel22 ]]; then
echo "start build image - security - openeuler22 base"
new_image_repo="${IMAGE_REPO}-openeuler22-amd64"
sudo docker build -t ${new_image_repo}:${image_tag} -f Dockerfile.oel22 --build-arg ARCH="amd64" .
sudo docker login -u $IMAGE_REPO_USER -p $IMAGE_REPO_PASSWD $(echo $IMAGE_REPO | awk -F '/' '{print $1}')
sudo docker push ${new_image_repo}:${image_tag}
echo "end to build image - security - openeuler22 base"
echo "amd64Oel22ImageName=${new_image_repo}:${image_tag}" >> ./amd64_output
fi
# Clean up temporary builder image
sudo docker rmi jdos-etcd-restore-helper:latest --force</code>3. Discussion
The complete description above shows the workflow and design standards for building multiple images. The "OneBuild" method enables rapid construction, reducing build time from 21 minutes to 7 minutes—a 66 % efficiency gain—making it valuable for medium‑to‑large organizations or teams with fast delivery requirements.
-end-
JD Cloud Developers
JD Cloud Developers (Developer of JD Technology) is a JD Technology Group platform offering technical sharing and communication for AI, cloud computing, IoT and related developers. It publishes JD product technical information, industry content, and tech event news. Embrace technology and partner with developers to envision the future.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.