将pebuilder变成dibuilder.sh,将di tools集入boot层(3):发明minstack live os

本文关键字:initrd多个gz,将td弄成tdpe和tdpanel,将dipe弄成*dd url,不死的boot配mian zang免脏的os:slax,can be in a rom flash,自己发明一个tinycorelinux

pebuilder.sh是一个利用debianinstall cd进行remaster打包的脚本,在《把DI当online packer用:利用installnet制作一个云装机packerpe》1,2和《利用onedrive加packerpebuilder实现本地网络统一装机》中,我们多次重构过这个脚本。最近的《将pebuilder变成dibuilder.sh,将di tools集入boot层(1)(2)》中我们陆续讲到了其原理并修补了它,并做了一些新的工作,最终是为了将dibuilder.sh发展成为一个支持normal debian os打包和debian live netinstall os打包的脚本(其中对于后者的支持已经相当好)。

其中本文继续讲述这个系列的第三部分:在(1)建立的一个基础的可供日照后remaster的最小包:td-initrd.gz的基础上,利用dibuilder.sh打造原来《一种混合包管理和容器管理方案,及在tinycorelinux上安装containerd和openfaas》《在tc上安装buildkit.tcz,vscode.tcz,打通vscodeonline与openfaas模拟cloudbase打造碎片化编程开发部署环境》中用tc实现的minstackos,解决上面第一段所述目标中dibuilder对于前者normal debian os的支持部分

不废话,直接上脚本,脚本整合为四个大流程,prepare prerequisites,prepare Essentials,prepare miscs,finishing phase,除了prepare prerequisites不用提其它会依次提到(以最近一次的脚本修改结果为参考讲解):

前置改动:

把原来的tmpDDURL抽象掉,以及原来的IncPkgrepo->GENMIRRORBAK也抽象掉,提出mode,target二个新变量,这是新的全局变量,

export tmpMODE='0' #DI?TD?
export tmpTARGET='' #dimirror,dsm61715284(di),winsrvcore2019(di),deepin20(di),minstackos(td)
export tmpINSTANTWITHOUTVNC='0'

export tmpWORD=''
export ipAddr=''
export ipMask=''
export ipGate=''

export myMirror='http://10.211.55.2:8000/mirrors'

export UNKNOWHW='0'
export UNVER='6.4'

这样的目的很清楚:正是为了能使dibuilder同时容纳di,td式remaster,,mode取值0,1就是支持分别从di-initrd.gz和td-initrd.gz remaster的变量,而target可以是dimirror(原来的GENMIRRORBAK:udeb package.gz所有条目和整个仓库打包),dsm61715284,winsrvcore2019,deepin20(这三都是原来的ddurl+di remaster)以及新的minstackos(它不是基于di而是基于td)

这二变量其实保留target在整个脚本中用于判断和分支就逻辑足够,但是不够逻辑清晰,所以增加的mode一层用来区别“5个target,3个是mode di,1个是mode td”

另,注意到我的mirror设置为不带debian后缀是为了稍后其也能表达同域下的target image gz as ddurl,如tmpDDURL=$myMirror/$tmpTARGET".gz",稍后的MIRROR=$(Select1stValidMirrorFrom3 $myMirror"/debian")和preseed中的mirror host/dir也是$myMirror,/debian处理

接下来是输入参数判断,可以看到case判断嵌套,mode和target联动,默认就是原来的mode0+ddurl target,targets中那些be prefined的一部分只是ddurl局变的封装,也支持raw http式的ddurl,当然,也支持dimirror和minstackos这二无关ddurl局变的特例。

while [[ $# -ge 1 ]]; do
  case $1 in
    -m|--mode)
      shift
      tmpMODE="$1"
      shift
      ;;
    -t|--target)
      shift

      tmpTARGET="$1"
      tmpDDURL=''
      case $tmpTARGET in
	dimirror) ;;
	winsrvcore2019) tmpDDURL=$myMirror/$tmpTARGET".gz" ;;
	dsm61715284) tmpDDURL=$myMirror/$tmpTARGET".gz" ;;
	deepin20) tmpDDURL=$myMirror/$tmpTARGET".gz" ;;
	minstackos) tmpMODE='1' ;;

        在unix界,0是正确,1是异常。所以eq 0是判断的正确面。

	*) echo "$tmpTARGET" |grep -q '^http://\|^ftp://\|^https://';[[ $? -eq '0' ]] && tmpDDURL=$tmpTARGET || echo "target not supported";exit 1 ;;
      esac

      shift
      ;;

.......

新的全局变量给原来脚本只有一种di+ddurl mode+target的原分支带来一些改变,如:

echo -en "checking deps ......:"
if [[ "$tmpTARGET" == 'dimirror' ]] && [[ "$tmpMODE" == '0' ]]; then
  CheckDependence wget,ar,awk,grep,sed,cut,cat,cpio,curl,gzip,find,dirname,basename,md5sum,sha1sum,sha256sum;
else
  CheckDependence wget,ar,awk,grep,sed,cut,cat,cpio,curl,gzip,find,dirname,basename;
fi

还有主体doremaster处(这也是prepare Essentials开始的地方):原来的buildrepo也改为了function doremaster(),意思更明确,同时,原来函数外的  echo -e "Downloading basic kernel and rootfs files from: [\033[32m ${MIRROR}/xxx.gz \033[0m]\n"也被放进了函数内部。逻辑布局更聚集合理(3 Downloading all in oneplace),同样也有关于mode+target的分支判断:

function doremaster(){

  echo -e "Downloading basic kernel and rootfs files from: [\033[32m ${MIRROR}/xxx.gz \033[0m]\n"

  IncFirmware='0'

  wget --no-check-certificate -qO '/boot/vmlinuz' "${MIRROR}/linux"
  [[ $? -ne '0' ]] && echo -ne "\033[31mError! \033[0mDownload 'vmlinuz' for \033[33mdebian\033[0m failed! \n" && exit 1

  if [[ "$tmpMODE" == '0' ]]; then
    wget --no-check-certificate -qO '/boot/initrd.img' "${MIRROR}/di-initrd.gz"
    [[ $? -ne '0' ]] && echo -ne "\033[31mError! \033[0mDownload 'initrd.img' for \033[33mdebian\033[0m failed! \n" && exit 1
  else
    wget --no-check-certificate -qO '/boot/initrd.img' "${MIRROR}/td-initrd.gz"
    [[ $? -ne '0' ]] && echo -ne "\033[31mError! \033[0mDownload 'initrd.img' for \033[33mdebian\033[0m failed! \n" && exit 1
  fi

  bakdir='/tmp/boot/var/log/debian'
  if [[ "$tmpTARGET" == 'dimirror' ]] && [[ "$tmpMODE" == '0' ]]; then
    mkdir -p "$bakdir"
    cp "/boot/initrd.img" "${bakdir}/di-initrd.gz"
    cp "/boot/vmlinuz" "${bakdir}/linux"
  elif [[ "$tmpTARGET" == 'minstackos' ]] && [[ "$tmpMODE" == '1' ]]; then
    mkdir -p "$bakdir"
    cp "/boot/initrd.img" "${bakdir}/td-initrd.gz"
    cp "/boot/vmlinuz" "${bakdir}/linux"
  fi

......

被加进OPTPKGS的minstackos条目:

  declare -A OPTPKGS
  OPTPKGS=(
......
    ["faasd1"]="pool/minstack/containerd.deb"
    ["faasd2"]="pool/minstack/buildkit.deb"
    ["faasd3"]="pool/minstack/faasd.deb"
    ["fmtfaasd"]="xz"
    ["binfaasd"]=""

    ["vscodeonline1"]="pool/minstack/vscodeonline.deb"
    ["fmtvscodeonline"]="xz"
    ["binvscodeonline"]=""

这些deb都是原来tcz加了一个极简DEBIAN/control文件直接dpkg -b打包来的。不能apt-get install安装,也没有内部依赖设定。不过刚好适合dibuilder.sh这种没有debootstrap式递归依赖处理的。仅用来支持minstack target够用就好。

  if [[ "$tmpTARGET" == 'dimirror' ]] && [[ "$tmpMODE" == '0' ]]; then

    echo -e "Downloading full udebs pkg files from ..... [\033[32m ${MIRROR}/dists/jessie/main/debian-installer/binary-amd64/Packages.gz \033[0m]\n"
......
  else
    echo -e "Downloading full udebs pkg files from ..... [\033[32m skipping!! \033[0m]\n"
  fi
  echo -e "Downloading optional/necessary deb pkg files from ...... [\033[32m ${MIRROR}/dists/jessie/main/binary-amd64/Packages.gz \033[0m]\n";
.......
}

if [[ "$tmpMODE" == '0' ]]; then
  doremaster libc,common,wgetssl;
elif [[ "$tmpTARGET" == 'minstackos' ]] && [[ "$tmpMODE" == '1' ]]; then
  doremaster faasd,vscodeonline;
fi
sleep 2s

这里的工作其实就是提高了一些抽象到mode+target组合,并开辟了一些新的流程判断。并没有给dibuilder带来改观的变化,不过足够支持minstackos remaster的完成而已。(到这里也是prepare Essentials结束,prepare misc开始的地方)

后置改变

prepare misc包括prepare net,prepare bootload,prepare preseed,我们将产生preseed的地方提前到net后,bootloader前,是因为grub的准备涉及到前二者,比如,未来可能我们为了让ddurl可以被定制,让preseed file作为url放在linux cmdline中作为auto url。这样往grubcmd加add options,boot options,形如net给grub加的:auto=true priority=critical interface=auto netcfg/no_default_route=true preseed/url=http://192.168.100.1/preseed.cfg ,grub应该放在最后。

\r是为了在......后输出CalcDDExt $tmpDDURL的结果

echo -en "\rthe preseed ......."

UNZIP=''
IMGSIZE=''

function CalcDDExt(){

  if [[ -n "$1" ]]; then
    echo "$1" |grep -q '^http://\|^ftp://\|^https://';
    [[ $? -ne '0' ]] && echo 'No valid URL in the DD argument,Only support http://, ftp:// and https:// !' && exit 1;

    IMGHEADERCHECK="$(curl -IsL "$1")";
    IMGTYPECHECK="$(echo "$IMGHEADERCHECK"|grep -E -o '200|302'|head -n 1)" || IMGTYPECHECK='0';

.......


}
if [[ "$tmpMODE" == '0' ]]; then
  CalcDDExt $tmpDDURL;

  # wget -qO- '$DDURL' |gzip -dc |dd of=$(list-devices disk |head -n1)|(pv -s \$IMGSIZE -n) 2&>1|dialog --gauge "progress" 10 70 0
  [[ "$UNZIP" == '0' ]] && PIPECMDSTR='wget -qO- '$tmpDDURL' |dd of=$(list-devices disk |head -n1)';
  [[ "$UNZIP" == '1' ]] && PIPECMDSTR='wget -qO- '$tmpDDURL' |tar zOx |dd of=$(list-devices disk |head -n1)';
  [[ "$UNZIP" == '2' ]] && PIPECMDSTR='wget -qO- '$tmpDDURL' |gzip -dc |dd of=$(list-devices disk |head -n1)';

  cat >/tmp/boot/preseed.cfg<<EOF
d-i preseed/early_command string anna-install

......
sbin/reboot
EOF

else
  echo -e "[\033[32m skipping!! \033[0m]"
fi

echo -e "the grub loader"

......

然后是prepare misc的结束,finishing phase的开始(里面有unpacking):

.......

  sed -i '$a\\n' /tmp/grub.new;
fi


echo -e "\n\n\033[36m# Finishing \033[0m\n"


[[ "$tmpINSTANTWITHOUTVNC" == '0' ]] && {
  GRUBPATCH='0';

  if [[ "$LoaderMode" == "0" ]]; then
  [ -f '/etc/network/interfaces' -o -d '/etc/sysconfig/network-scripts' ] || {
    echo "Error, Not found interfaces config.";
    exit 1;
  }

  sed -i ''${INSERTGRUB}'i\\n' $GRUBDIR/$GRUBFILE;
  sed -i ''${INSERTGRUB}'r /tmp/grub.new' $GRUBDIR/$GRUBFILE;

  sed -i 's/timeout_style=hidden/timeout_style=menu/g' $GRUBDIR/$GRUBFILE;
  sed -i 's/timeout=[0-9]*/timeout=30/g' $GRUBDIR/$GRUBFILE;

  [[ -f  $GRUBDIR/grubenv ]] && sed -i 's/saved_entry/#saved_entry/g' $GRUBDIR/grubenv;
  fi


  echo -e "unpacking ......"

  cd /tmp/boot;
  COMPTYPE="gzip";
  CompDected='0'
  for ListCOMP in `echo -en 'gzip\nlzma\nxz'`
    do
.......
  $UNCOMP < /tmp/$NewIMG | cpio --extract --verbose --make-directories --no-absolute-filenames >>/dev/null 2>&1

  [[ -f '/boot/firmware.cpio.gz' ]] && {
    gzip -d < /boot/firmware.cpio.gz | cpio --extract --verbose --make-directories --no-absolute-filenames >>/dev/null 2>&1
  }

  if [[ "$tmpMODE" == '0' ]]; then

    sleep 2s &&   echo -en "fix minios in the preseed file\n"

    这里是原来preseed开始的地方,这里上提作为finishing->sub过程的unpacking之后fix minios in preseed file,仅保留fix部分:

    [[ "$LoaderMode" != "0" ]] && AutoNet='1'

    [[ "$setNet" == '0' ]] && [[ "$AutoNet" == '1' ]] && {
      sed -i '/netcfg\/disable_autoconfig/d' /tmp/boot/preseed.cfg
      sed -i '/netcfg\/dhcp_options/d' /tmp/boot/preseed.cfg
      sed -i '/netcfg\/get_.*/d' /tmp/boot/preseed.cfg
      sed -i '/netcfg\/confirm_static/d' /tmp/boot/preseed.cfg
    }

    #[[ "$GRUBPATCH" == '1' ]] && {
    #  sed -i 's/^d-i\ grub-installer\/bootdev\ string\ default//g' /tmp/boot/preseed.cfg
    #}
    #[[ "$GRUBPATCH" == '0' ]] && {
    #  sed -i 's/debconf-set\ grub-installer\/bootdev.*\"\;//g' /tmp/boot/preseed.cfg
    #}

    sed -i '/user-setup\/allow-password-weak/d' /tmp/boot/preseed.cfg
    sed -i '/user-setup\/encrypt-home/d' /tmp/boot/preseed.cfg
    #sed -i '/pkgsel\/update-policy/d' /tmp/boot/preseed.cfg
    #sed -i 's/umount\ \/media.*true\;\ //g' /tmp/boot/preseed.cfg

    sleep 2s &&   echo -en "make a safe wget wrapper to inc --no-check-certificate\n"

......

  sleep 2s && echo -en "packaging all up .....\n"
  find . | cpio -H newc --create --quiet | gzip -9 > /boot/initrd.img;

  [[ "$tmpMODE" == '1' ]] &&  echo -en "packaging finished,and all done! auto reboot after 9999s...(if needed, you can press ctrl c to interrupt to bak the repodir under tmp/boot/, then manually reboot to continue)" && sleep 9999s

  rm -rf /tmp/boot;

}

[[ "$tmpINSTANTWITHOUTVNC" == '1' ]] && {
......


如果让preseed不内置,而作为一个独立的url放在grub commandline,那么可以做更多*的事情,比如:

1,在pressed中自动产生一个boot区,自动完成《将pebuilder变成dibuilder.sh,将di tools集入boot层(2)》做的事情。
2,做那种带cdrom file:// as deb source的live install cd
当然这些在cat <<内置preseed中也可以做,只是调试出来比较麻烦。没有分出去调试方便。

发明minstack live os

我们利用上述脚本td mode+minstack target跑出来的是一个巨大的initramfs,还要加入一个释放到硬盘的过程,形如《利用增强tinycorelinux remaster tool打造你的硬盘镜像及一种让tinycorelinux变成Debian install体的设想》中的preparehd那样,当然也可以像tc一样,将占据此发行版主体的包部分作为live加载部分,利用容器联合文件系统的思路独立出去+动态加载进来:

在前面我们不断讲过用容器思路解决OS应用沙盒的问题,免脏的原理是利用应用沙盒,这里是利用系统沙盒,将系统和数据(要写入到系统中的数据,用户数据)分离。免去我们一次次因为装太多软件导致系统变慢弄脏重新装机的需要。。

slax正是这样一种live系统和live工具,Slax Linux 9.2.1 不再基于 Slackware,现已切换至基于 Debian 的最新稳定版 Stretch。因此,Slax Linux 也将采用 APT 软件包管理工具和 Systemd 这款 init 程序。尽管新版本已经基于 Debian GNU/Linux 9.2.1 “Stretch”,但依然保留 Slackware 的前缀名字。这款系统的容量依然保持了轻量设计,Slax 9.2.1 的 64 位 live ISO 镜像只有 208MB。 ------ 但实际上,这些都是squashfs包,解包有1G多都说不定。也不小。它支持把整个系统当成一个子目录,所以我们从《子目录分离的linux》开始的就不用了,除非用于纯粹的硬盘安装需要子目录化。

它的原理是跟tc一样,Having the temporary root filesystem in initramfs is not ideal, since it doesn't support pivot_root system call - an important operation which will be used later in the boot up process. We need to switch from initramfs to something else. To do that, the temporary init firstly mounts a tmpfs filesystem over /m, moves all files and directories in there including the init script itself, and uses switch_root to make this tmpfs /m the new root and to restart the init itself from there too. Blue star denotes the directory which is moved.

他好像还搞了个linux-live.org,它的sb包是on-the-fly savechange制作的。因此它自己不用维护一个类似tce的仓库。tc与slax区别是一个是软件库打包,一个是巨打包(core.gz,xorg,desktop,etc..)

但实际上deb,systemd,容器这些,远没有tinycorelinux的"plain raw" 的tce,Slackwarepkg对人的亲和。否则我们也不必《在tc上安装buildkit.tcz,vscode.tcz,打通vscodeonline与openfaas模拟cloudbase打造碎片化编程开发部署环境》搞一套instant commit,容器的持续提交与构建很不原生。

然而,如果数据和系统可以做到原生分开,符合用户习惯,像群晖一样,系统存储中不混入任何应用和用户数据,也是不错的。

上一篇:Spring框架


下一篇:Android 依赖注入 DI - Dagger2