陈沙克

Dec 232021
 

以前搞OpenStack的时候,对虚拟机镜像都没怎么折腾过。这次折腾镜像,倒是学了不少东西,这里总结一下。

工具

虚拟机镜像定制工具很多,原理有很大的差异,理论上用一个工具,就可以搞定。不过我这次制作镜像,使用到2个工具

  • Disk image builder (DIB)它是OpenStack的开发过程中产生的一个工具,可以把OpenStack项目的agent集成到镜像里,对镜像镜像深度的定制。
  • virt-customize,这个其实不是一个工具,是一套工具,红帽出品。基本上你对虚拟机镜像操作,都可以通过它来完成。

如果全部功能都使用DIB完成,那么这些定制,都需要自己写自己的element,这个对我以前的团队,是小case,维护一套自己需要定制的内容,写好相关的element,一条命令,就完成镜像的制作。

如果希望使用virt完成全部的镜像定制,有些比较繁琐的步骤,利用镜像格式转换,压缩,其实都比较折腾。

所以我的方案就是使用virt,对虚拟机进行相应的定制,最后一步,通过DIB,完成镜像的压缩和初始化。

我们都是采用操作系统官方提供的虚拟机镜像,进行定制开发

  • CentOS 7.6
  • CentOS 7.9
  • CentOS 8.4
  • Ubuntu 20.04

定制内容

官方提供的镜像有哪些内容需要定制呢,我这里整理一下,具体这些定制如何修改,我已经把相应的文档放到github上。

CentOS

针对CentOS的定制,主要是下面的内容

  • 虚拟机的repo,指向国内,华为,清华的repo。我是使用公司内部nexus的proxy repo
  • 内核升级到5.4,CentOS 7,官方有repo,可以直接升级,CentOS 8,需要使用外部的repo。5.4的内核,可以让CentOS 7工作更久,升级到5.4内核,virt的工具效率都提升很多,也减少很多麻烦。
  • qemu-guest-agent,现在虚拟机的修改密码都需要靠它。
  • 常用软件和k8s相关依赖,这样大幅提升效率
  • 设置时区
  • ssh定制,尤其dns,在内网不能联网的情况,ssh很慢,CentOS 8默认已经关闭dns。
  • 登陆CentOS ,运行命令,会出现很多中文,看起来很别扭,虚拟机的语言是英文,所以需要修改语言的环境变量
  • CentOS 8 ssh登陆,会有cockpit提示,很烦人,去掉。
  • 利用cloud init,来解决虚拟机第一次启动,运行脚本。以前是通过virt first boot来实现,不过在CentOS 8 下出现问题,改成cloud init的per-once,完美解决了这个问题。主要解决zstack环境的agent安装和端口修改,和普罗米修斯端口冲突。
  • 设置alias,提升效率,vi alias vim,c alias clear。大幅提升幸福感。
  • cloud init一些定制,运行root密码登陆,运行远程ssh访问。这个是通过DIB来实现
  • 关闭selinux,对镜像镜像压缩,调整镜像大小。这个也是通过DIB实现。
  • 针对OpenStack的cloud-init,ConfigDrive,提升虚拟机的启动速度,这块以前同事专门有文章介绍过。

Ubuntu

针对Ubuntu 定制的内容就少很多,通过下载镜像,定制完成,再DIB,这种方式行不通,ubuntu官方做了限制,不过由于ubuntu需要修改的内容不多,virt就能满足需求。

  • Repo定制,ubuntu的官方镜像,cloud init有设置,不让你修改repo,需要修改一下cloud init的配置文件,你替换repo文件才能生效。
  • qemu-guest-agent
  • 直接使用root ssh登陆,不需要sudo
  • 去掉登陆的banner
  • 利用cloud init,安装一次性运行脚本,如果需要,zstack的agent,通过这种方式,比较简单。
  • resize 镜像,对于zstack的平台,调整到80G,OpenStack是不需要修改。

效果

制作一个镜像,大概是10分钟,其实后续,真的可以锻炼一下自己的shell的能力,改成shell脚本。这样效率更高。

  • CentOS 定制 https://github.com/shake/shell/blob/main/custom-centos-image
  • ubuntu 定制 https://github.com/shake/shell/blob/main/ubuntu-image-custom

如果你希望镜像给root设置一个默认密码,我坚持不加默认密码

记得设置环境变量或者export一次。

virt-customize -a $image_name --root-password password:chenshake 
##替换repo


virt-customize -a $image_name --run-command ‘rm /etc/yum.repos.d/CentOS-7-all.repo'
virt-customize -a $image_name --run-command ‘wget -O /etc/yum.repos.d/all-huawei.repo https://raw.fastgit.org/shake/shell/main/CentOS7/all-huawei.repo'
Dec 012021
 

记录一下日常的使用

##创建:
screen -S abc

##查看有多少会话:

screen -ls

##重新连接

screen -r abc

#离开

control+a+d


##删除 
screen -S -X abc quit
screen -wipe

参考文章

  • https://www.cnblogs.com/mchina/archive/2013/01/30/2880680.html
Nov 262021
 

这里记录一下简单的过程,后续再完善,已经知道如何操作。

export LIBGUESTFS_BACKEND=direct
export image_name='focal-server-cloudimg-amd64.img' 

virt-customize -a $image_name --run-command 'sudo cp -a /etc/apt/sources.list /etc/apt/sources.list.bak'

virt-customize -a $image_name --run-command 'sudo sed -i "s@http://.*archive.ubuntu.com@http://repo.huaweicloud.com@g" /etc/apt/sources.list'

virt-customize -a $image_name --run-command 'sudo sed -i "s@http://.*security.ubuntu.com@http://repo.huaweicloud.com@g" /etc/apt/sources.list'

virt-customize -a $image_name --install qemu-guest-agent
virt-customize -a $image_name --run-command 'systemctl enable qemu-guest-agent'
virt-customize -a $image_name --timezone "Asia/Shanghai" 

virt-customize -a $image_name --edit '/etc/ssh/sshd_config:s/PasswordAuthentication no/PasswordAuthentication yes/'
virt-customize -a $image_name --edit '/etc/ssh/sshd_config:s/#PermitRootLogin prohibit-password/PermitRootLogin yes/'

#zstack
virt-customize -a $image_name --firstboot-command 'sudo /bin/bash -c "$(curl -s -S http://169.254.169.254/vm-tools.sh)"'
virt-customize -a $image_name --firstboot-command "sudo sed -i 's/9100/9104/g' /usr/local/zstack/zwatch-vm-agent/conf.yaml"
virt-customize -a $image_name --firstboot-command "sudo /bin/systemctl restart zwatch-vm-agent.service"
virt-customize -a $image_name --run-command 'mv /usr/lib/virt-sysprep/scripts/0001-sudo--bin-systemctl-restart-zwatch-vm-agent-service /usr/lib/virt-sysprep/scripts/0002-sudo--bin-systemctl-restart-zwatch-vm-agent-service'

#DIB 部分需要调整
export image_name='ubuntu-20.04.qcow2'
export DIB_RELEASE=focal
disk-image-create -a amd64 -o  $image_name -x --image-size 80 vm ubuntu dhcp-all-interfaces

#extend disk
qemu-img info focal-server-cloudimg-amd64.img
virt-filesystems --long --parts --blkdevs -h -a focal-server-cloudimg-amd64.img 
qemu-img resize focal-server-cloudimg-amd64.img +78g
qemu-img info focal-server-cloudimg-amd64.img
Nov 242021
 

一个pod,容器,要两块网卡,我以前也觉得很变态,吃饱没事撑着。当你真的实际场景,真的有这样的需求

对着官方文档,先来一遍,体验一下

我需要实现的就是下图的数据网络

我是使用kubekey来进行安装,用2个vm来做试验。使用calico的网络

# kubectl get nodes
NAME       STATUS   ROLES                         AGE     VERSION
master01   Ready    control-plane,master,worker   3h54m   v1.22.1
work01     Ready    worker                        3h54m   v1.22.1

下载multus代码

git clone https://github.com/k8snetworkplumbingwg/multus-cni.git && cd multus-cni
cat ./deployments/multus-daemonset.yml | kubectl apply -f -

没搞明白,为啥官方文档使用multus-daemonset-thick-plugin.yml,外面的文档都是:multus-daemonset.yml

如果顺利

# kubectl get pods -n kube-system | grep -i multus
kube-multus-ds-tdcf4                           1/1     Running   0          133m
kube-multus-ds-xlf4m                           1/1     Running   0          133m

macvlan-conf.yaml

master :eth0, 这个地方设置,应该是重点,如果机器有另外一块网卡,我应该可以考虑指向它。

apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: macvlan-conf
spec:
  config: '{
      "cniVersion": "0.3.0",
      "type": "macvlan",
      "master": "eth0",
      "mode": "bridge",
      "ipam": {
        "type": "host-local",
        "subnet": "192.168.4.0/24",
        "rangeStart": "192.168.4.200",
        "rangeEnd": "192.168.4.216",
        "routes": [
          { "dst": "0.0.0.0/0" }
        ],
        "gateway": "192.168.4.1"
      }
    }'

根据自己需求,修改一下macvlan的网段

kubectl create -f macvlan-conf.yaml
kubectl get network-attachment-definitions
kubectl describe network-attachment-definitions macvlan-conf

验证

samplepod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: samplepod
  annotations:
    k8s.v1.cni.cncf.io/networks: macvlan-conf
spec:
  containers:
  - name: samplepod
    command: ["/bin/ash", "-c", "trap : TERM INT; sleep infinity & wait"]
    image: alpine

kubectl create -f samplepod.yaml
kubectl exec -it samplepod -- ip a

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
4: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1440 qdisc noqueue state UP 
    link/ether c6:c1:90:ac:c4:e4 brd ff:ff:ff:ff:ff:ff
    inet 10.233.106.10/32 brd 10.233.106.10 scope global eth0
       valid_lft forever preferred_lft forever
5: net1@tunl0: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
    link/ether 82:84:7e:da:6f:b8 brd ff:ff:ff:ff:ff:ff
    inet 192.168.4.200/24 brd 192.168.4.255 scope global net1
       valid_lft forever preferred_lft forever

查看一下pod

# kubectl describe pod samplepod
Name:         samplepod
Namespace:    default
Priority:     0
Node:         master01/192.168.20.21
Start Time:   Wed, 24 Nov 2021 16:48:04 +0800
Labels:       <none>
Annotations:  cni.projectcalico.org/containerID: 75777c27377709cfba50d9f8ef59209869c26d0707f0ad38343351eae904d16a
              cni.projectcalico.org/podIP: 10.233.106.10/32
              cni.projectcalico.org/podIPs: 10.233.106.10/32
              k8s.v1.cni.cncf.io/network-status:
                [{
                    "name": "k8s-pod-network",
                    "ips": [
                        "10.233.106.10"
                    ],
                    "default": true,
                    "dns": {}
                },{
                    "name": "default/macvlan-conf",
                    "interface": "net1",
                    "ips": [
                        "192.168.4.200"
                    ],
                    "mac": "82:84:7e:da:6f:b8",
                    "dns": {}
                }]
              k8s.v1.cni.cncf.io/networks: macvlan-conf
              k8s.v1.cni.cncf.io/networks-status:
                [{
                    "name": "k8s-pod-network",
                    "ips": [
                        "10.233.106.10"
                    ],
                    "default": true,
                    "dns": {}
                },{
                    "name": "default/macvlan-conf",
                    "interface": "net1",
                    "ips": [
                        "192.168.4.200"
                    ],
                    "mac": "82:84:7e:da:6f:b8",
                    "dns": {}
                }]
Status:       Running
IP:           10.233.106.10
IPs:
  IP:  10.233.106.10
Nov 242021
 

最近搬运了2次docker 镜像,有点体会。你肯定需要一台国外的机器才行。

如果有docker

docker pull ghcr.io/k8snetworkplumbingwg/multus-cni:stable
docker save ghcr.io/k8snetworkplumbingwg/multus-cni > ./multus-cni.tar
##把tar包下载到有docker服务的节点
docker load < ./multus-cni.tar
docker images

如果海外的机器上没有docker,那么有一个另外一种玩法

# 可以直接yum install,版本低,我是编译,1.3的版本
./skopeo --insecure-policy copy docker://ghcr.io/k8snetworkplumbingwg/multus-cni:stable docker-archive:multus-cni.tar

遗憾的是skopeo,还不能通过proxy去下载。

  • https://github.com/containers/skopeo/issues/1433

Nov 072021
 

其实现在大家都应该用的是64bit的系统,那么对于64bit的系统,你要同时把这两个文件的32bit和64bit,都装上才行。记录一下。

  • https://docs.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170

把Visual Studio 2015, 2017, 2019, or 2022 x86和64的两个安装包都装一遍就可以解决这个问题。

VCRUNTIME140.DLL

https://www.dll-files.com/vcruntime140.dll.html

一定要把x86和x64,都装上,才能解决问题。

msvcp140.dll

这个也是一样的道理

https://www.sts-tutorial.com/download/msvcp140

-- 64-Bit Windows:
          - 32-Bit Version - C:\Windows\SysWOW64
          - 64-Bit Version - C:\Windows\System32

要下载两个文件,分别放到不同的地方,就可以。