#!/usr/bin/env bash
# 用法: build.sh iso文件路径
# 例如:build.sh /data/build/os_images/Kylin-Server-V10-SP3-General-Release-2303-ARM64.iso
set -e
set -o pipefail
current_dir=$(
cd "$(dirname "$0")"
pwd
)
source $current_dir/tools/color.sh
BUILD_TOOLS="vim vi yum net-tools curl dnf-utils createrepo iproute"
function check_command(){
local r=0
`command -v $1 >/dev/null 2>&1` || r=1
return ${r}
}
install_docker(){
rpm -qa|grep podman > /dev/null 2>&1 && yum remove -y podman
if [ "$ARCH" == 'amd64' ]; then centos_repo='Centos-7.repo'; else centos_repo='Centos-altarch-7.repo'; fi
curl -o /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sed -i -e 's/$releasever/7/g' -e 's/https/http/g' /etc/yum.repos.d/docker-ce.repo
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/${centos_repo}
sed -i -e 's/$releasever/7/g' -e 's/https/http/g' /etc/yum.repos.d/CentOS-Base.repo
yum makecache
yum install docker-ce docker-ce-cli containerd.io -y
if [ $? -eq 0 ]; then
mkdir -p /etc/systemd/system/docker.service.d
cat > /etc/systemd/system/docker.service.d/docker-options.conf << 'EOF'
[Service]
Environment="DOCKER_OPTS= --iptables=true \
--insecure-registry=0.0.0.0/0 \
--registry-mirror=https://dockerhub.xxx.com \
--registry-mirror=https://registry.docker-cn.com \
--registry-mirror=https://mirror.aliyuncs.com \
--registry-mirror=https://docker.mirrors.ustc.edu.cn \
--data-root=/data/docker \
--log-opt max-size=50m --log-opt max-file=5"
EOF
cat > /etc/systemd/system/docker.service << 'EOF'
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.com
[Service]
Type=notify
Environment="DOCKER_STORAGE_OPTIONS=-s overlay2"
Environment=GOTRACEBACK=crash
ExecReload=/bin/kill -s HUP $MAINPID
ExecStartPost=/usr/sbin/iptables -P FORWARD ACCEPT
Delegate=yes
KillMode=process
ExecStart=/usr/bin/dockerd \
$DOCKER_OPTS \
$DOCKER_STORAGE_OPTIONS \
$DOCKER_DNS_OPTIONS
TasksMax=infinity
LimitNOFILE=1048576
LimitNPROC=1048576
LimitCORE=infinity
TimeoutStartSec=1min
# restart the docker process if it exits prematurely
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable docker
systemctl start docker
fi
}
create_multi_platform(){
if ! sudo docker ps | grep buildkitd >/dev/null 2>&1 || ! sudo docker buildx ls|grep 'multi-platform'>/dev/null 2>&1; then
sudo docker run -it --rm --privileged tonistiigi/binfmt --install all
if [ ! -f ~/.config/buildkit/buildkitd.toml ]; then
sudo mkdir -p ~/.config/buildkit/
echo 'debug = true' > ~/.config/buildkit/buildkitd.toml
echo 'insecure-entitlements = [ "network.host", "security.insecure" ]' >> ~/.config/buildkit/buildkitd.toml
echo '[registry."dockerhub.xxx.com"]' >> ~/.config/buildkit/buildkitd.toml
echo ' http = false' >> ~/.config/buildkit/buildkitd.toml
echo ' insecure = true' >> ~/.config/buildkit/buildkitd.toml
fi
sudo docker buildx create \
--name multi-platform \
--use \
--platform linux/amd64,linux/arm64 \
--driver docker-container \
--driver-opt network=host \
--buildkitd-flags '--allow-insecure-entitlement network.host' \
--config ~/.config/buildkit/buildkitd.toml
fi
}
main(){
cd ${current_dir}
image_repo=$(find repos/online -name "*$image_name*$image_version*.repo")
for arch in $image_arch; do
if [ ! -z "$iso_path" ]; then
iso_file=$(basename $iso_path)
iso_dir=$(echo $iso_file|sed 's/.iso//g')
iso_mount_dir=/mnt/$iso_dir
[ ! -d "$iso_mount_dir" ] && mkdir -p $iso_mount_dir || (umount -f $iso_mount_dir || true)
mount "$iso_path" $iso_mount_dir
cat > repos/local.repo << EOF
[local]
name=local repo
baseurl= file://$iso_mount_dir
enable=1
gpgcheck=0
priority=1
EOF
fi
target=${image_name}_${image_version}_${arch}
target_image=${image_name}:${image_version}-${arch}
# docker pull --platform linux/$arch centos
# docker pull --platform linux/$arch dockerhub.xxx.com/os/centos:8
docker pull dockerhub.xxx.com/os/centos:8-${arch}
docker rm -f centos_${target} > /dev/null 2>&1 || true
if [ ! -z "$iso_path" ]; then
extra_arg="-v $iso_mount_dir:$iso_mount_dir"
fi
docker run -d --name centos_${target} --network host \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ${current_dir}:/opt/os \
${extra_arg} \
dockerhub.xxx.com/os/centos:8-${arch} \
sleep 100000
docker exec centos_${target} bash -c "\
rm -rf /etc/yum.repos.d/*; \
if [ ! -z "$iso_path" ]; then \
cp /opt/os/repos/local.repo /etc/yum.repos.d/local.repo; \
fi; \
cp /opt/os/$image_repo /etc/yum.repos.d/$(basename $image_repo); \
if [ "$image_name" == "kylin" ]; then \
cp /opt/os/repos/online/kylin/RPM-GPG-KEY-kylin /etc/pki/rpm-gpg/RPM-GPG-KEY-kylin; \
elif [ "$image_name" == "uos" ]; then \
mkdir -p /opt/os/${target}/etc/dnf/vars;\
cp /opt/os/repos/online/uos/uos-auth-u /etc/dnf/vars/uos-auth-u; \
cp /opt/os/repos/online/uos/uos-auth-p /etc/dnf/vars/uos-auth-p; \
cp /opt/os/repos/online/uos/uos-auth-u /opt/os/${target}/etc/dnf/vars/uos-auth-u; \
cp /opt/os/repos/online/uos/uos-auth-p /opt/os/${target}/etc/dnf/vars/uos-auth-p; \
if [ "$image_version" == "20-1060e" ]; then \
echo 'ufu' > /etc/dnf/vars/StateMode; \
echo 'ufu' > /opt/os/${target}/etc/dnf/vars/StateMode; \
fi; \
fi; \
yum clean all; yum makecache; \
yum -y --installroot=/opt/os/${target} install $BUILD_TOOLS \
"
cp /etc/skel/.bash* $current_dir/${target}/root/
echo "" > $current_dir/${target}/root/.bash_history
rm -rf $current_dir/${target}/core.*
tar -cvpf ${target}.tar --directory=$current_dir/${target} --exclude=proc --exclude=sys --exclude=dev --exclude=run --exclude=boot .
# check_command docker || install_docker
# create_multi_platform
cat ${target}.tar | docker import - $target_image
#5. 运行镜像,测试镜像是否能正常使用
docker run --rm --tty $target_image /bin/bash -c 'echo $(grep 'PRETTY_NAME' /etc/os-release) $(uname -m) builded success!!!'
# clean
docker rm -f centos_${target}
umount -f $iso_mount_dir
rm -rf ${target} ${target}.tar
if [ $? -ne 0 ]; then
errorlog "$target_image build Failed!!!!"
exit
else
successlog "$target_image build successfull !"
fi
done
if [ "$push" == "true" ]; then
for arch in $image_arch; do
registry_image="$registry/${image_name}:${image_version}"
docker tag ${image_name}:${image_version}-${arch} ${registry_image}-${arch}
docker push ${registry_image}-${arch}
done
if [[ "$image_arch" == "amd64 arm64" ]] || \
(docker images|awk '{print $1":"$2}'|grep ${registry_image}-amd64 >/dev/null 2>&1 && \
docker images|awk '{print $1":"$2}'|grep ${registry_image}-arm64 >/dev/null 2>&1); then
docker manifest rm ${registry_image} || true
docker manifest create --insecure ${registry_image} ${registry_image}-amd64 ${registry_image}-arm64
docker manifest annotate ${registry_image} ${registry_image}-amd64 --os linux --arch amd64
docker manifest annotate ${registry_image} ${registry_image}-arm64 --os linux --arch arm64 --variant v8
docker manifest push --insecure ${registry_image}
if [ $? -ne 0 ]; then
errorlog "${registry_image} build Failed!!!!"
exit
else
successlog "${registry_image} build successfull !"
fi
fi
fi
}
# 报错:x509: certificate has expired or is not yet valid,解决:docker.service.d/docker-options.conf里添加:--registry-mirror=https://dockerhub.xxx.com
function Usage() {
INFO="\
功能:构建操作系统docker镜像
用法:$0 [选项] ... [参数] ...
支持参数:
--image string [必选参数]镜像名称,如kylin:v10-sp3-arm64,openeuler:20.03-sp3-amd64,如果后面不带架构,如kylin:v10-sp3,则默认同时构建双架构
--image_arch string [可选参数]要构建的镜像的架构,默认是'amd64 arm64'
--iso_path string [可选参数]不提供此参数,默认从在线官方软件源制作;如提供此参数,则默认以挂载iso文件作为软件源安装软件,如:/data/Kylin-Server-V10-SP3-General-Release-2303-ARM64.iso
--registry string [可选参数]镜像仓库地址,比如要推送到dockerhub.xxx.com/os/kylin:v10-sp3,则值为dockerhub.xxx.com/os
--push [可选参数]是否推送至镜像仓库,默认false
--help 帮助文档
"
infolog "$INFO"
}
ARGS=`getopt -o vh --long image:,image_arch:,iso_path:,push,help -- "$@"`
([[ $? -ne 0 ]] || [[ -z "$@" ]]) && Usage && exit
eval set -- "$ARGS"
while true; do
case "$1" in
--image)
case "$2" in
"") exit 1 ;;
*) image=$2; shift 2 ;;
esac ;;
--image_arch)
case "$2" in
"") exit 1 ;;
*) image_arch=$2; shift 2 ;;
esac ;;
--push)
push='true';shift ;;
--iso_path)
case "$2" in
"") exit 1 ;;
*) iso_path=$2; shift 2 ;;
esac ;;
--registry)
case "$2" in
"") exit 1 ;;
*) registry=$2; shift 2 ;;
esac ;;
-h|--help|-help)
Usage; exit 0 ;;
--)
shift; break ;;
*)
warnlog "Invalid option, use -h or --help to get help message."; exit 1 ;;
esac
done
: ${image_arch:="amd64 arm64"}
: ${push:=false}
: ${registry:="dockerhub.xxx.com/os"}
image_name=$(echo $image|awk -F':' '{print $1}')
image_tag=$(echo $image|awk -F':' '{print $2}')
image_version=$(echo $image_tag|awk '{gsub(/-x86_64|amd64|-arm64|-aarch64/, "");print}')
if [[ $? == 0 ]] ; then
main
else
Usage
exit 1
fi