You can build it once, then extract whatever labels you need by running commands against the built image and then rebuild by adding --label flags. Since the build is cached, everything you built will remain the same.
This what I've come up with in some CI job of mine
date_tag=$(date +%Y-%m-%d)
image=$CI_REGISTRY/$CI_PROJECT_PATH/devops-runner
# Log in and build the image both as latest and with the current date
docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY
docker build \
-t $image:latest \
-t $image:$date_tag \
docker/
# Extract the versions of the tools installed in the image
debian_version=$(docker run --rm $image -c "cat /etc/debian_version")
aws_cli_version=$(docker run --rm $image -c "aws --version" | awk '{print $1}' | cut -d/ -f2)
terraform_version=$(docker run --rm $image -c "terraform --version" | head -n 1 | awk '{print $2}')
kubectl_version=$(docker run --rm $image -c "kubectl version --client --short" | awk 'NR==1{print $3}')
helm_version=$(docker run --rm $image -c "helm version --short" | awk '{print $1}')
# Rebuilding with the cache from the last step but adding labels to image
docker build \
-t $image:latest \
-t $image:$date_tag \
--label "debian_version=${debian_version}" \
--label "aws_cli_version=${aws_cli_version}" \
--label "terraform_version=${terraform_version}" \
--label "kubectl_version=${kubectl_version}" \
--label "helm_version=${helm_version}" \
docker/
# Push the image to the registry
docker push $image:latest
docker push $image:$date_tag
# Log the image metadata
docker inspect --format='{{json .Config.Labels}}' $image:latest | jq .
$ docker run --label-file ./labels ubuntu bash
docker run with labels – Acantho