工作站的容器化和虚拟化实践 - Go语言中文社区

工作站的容器化和虚拟化实践


1. 环境说明

  对于一个配置略高的工作站如果一个人使用有点浪费了,可以考虑把资源分享给小组成员,大家时分复用或者资源复用可以有效的提高生产力,现在容器化和虚拟技术为我们提供了这样的方式,并且可以很方便的管理和分配。Windows 10 已经可以很好的实现工作站级别的容器和虚拟化,比如 Hyper-V 与 Docker for Windows 的组合,但是从容器的效率来讲,还是采用 Linux 平台比较精彩。下面来记录一下我将自己的工作站容器化(Docker)和虚拟化(KVM)的实践过程。
   相对于服务器级别的容器化和虚拟化,在工作站上面要轻松许多,因为毕竟工作站的主要用途是开发的调试和测试,对服务的稳定性和安全性都和服务器不再一个等级上,可以大胆的使用社区版的软件,可以大胆的手动解决开源软件中的Bug .
  首先需要一个用着顺手的 Linux 发行版,从安装的便捷性和大众性考虑我这里使用 Ubuntu 16.04 作为本次实践的宿主操作系统(host). 使用下面命令检测以下工作站硬件是否支持虚拟化:

egrep '(vmx|svm)' /proc/cpuinfo

然后是网络连接方式,一个人使用的工作站生成的虚拟机或者容器可以采用NAT的方式,这样比较安全,也是很多虚拟化软件的默认网络配置,但如果想把宿主主机生成的容器和虚拟机分享给组织内的其他成员,就需要使用网桥(bridge)的方式来连接host生成的容器和虚拟机,下面是需要实现的工作站网络连接示意图:
工作站网络连接示意图

安全提示:修改网络操作可能会导致工作站不可远程访问,配置时请尽可能使用本地显示器+本地键盘的方式进行

Ubuntu 16.04默认情况下有线网卡的命名是 enp3sxx 的格式,把它还原成 eth0 的命名方式。在 /etc/default/grub 中,GRUB_CMDLINE_LINUX里添加参数net.ifnames=0 biosdevname=0,sudo方式执行下面命令:

echo "GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0"" >> /etc/default/grub && update-grub

安装 bridge-utils 网桥管理工具

apt-get install bridge-utils

停止使用 NetworkManager 自动化网络配置工具,因为我们要使用纯手动的方式(networking)来管理网络配置:

systemctl stop NetworkManager && systemctl disable NetworkManager

手动修改网络配置文件 /etc/network/interfaces

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet loopback

auto br0
iface br0 inet static
address /*YOUR_HOST_IP_ADDRESS*/
netmask /*YOUR_HOST_NET_MASK*/
gateway /*YOUR_HOST_GATEWAY*/
dns-nameservers /*YOUR_HOST_DNS*/
bridge_stp off
bridge_fd 0
bridge_ports eth0

保存文件并重启(reboot)后通过 ifconfig 或者 ls /proc/sys/net/ipv4/conf 看到生成的网桥配置
如果出现问题,可以通过 systemctl status networking 或者 journalctl -xe 查看日志排除问题。


2. 容器化

  Docker CE 的安装这里就不去赘述了,可以参考这个链接: https://docs.docker.com/install/linux/docker-ce/ubuntu/
如果是Nvidia显卡的主机,建议安装 nvidia-docker 插件 https://github.com/NVIDIA/nvidia-docker ,使用 nvidia-container-runtime 可以将硬件GPU映射到容器内,对于视频处理和深度学习的容器非常有用。
Docker CE 默认情况下容器是不能直接暴露到真实网络中的,这时你需要docker工程师自己写的一个脚本 pipework

wget -P /usr/local/bin/ 
https://raw.githubusercontent.com/jpetazzo/pipework/master/pipework 

Docker CE 只提供了命令行的访问和控制方式,掌握CLI(command line interface)的方式是必须的,但对于多人协作时,还是WBI(web interface)的方式比较靠谱,综合对比了几种 Docker web UI 的软件( DockerUI, Shipyard, Portainer ),最后还是觉得 Portainer 比较适合工作站上面部署,首先把 portainer 的镜像 pull 到本地:

docker pull portainer/portainer

通过下面命令查看 portainer/portainer 镜像需要映射的 port 和需要挂载的 volume :

image="portainer/portainer"
docker inspect ${image} | jq -r '.[0].ContainerConfig.Volumes'
docker inspect ${image} | jq -r '.[0].ContainerConfig.ExposedPorts'

下面描述三种部署 Portainer 的方式:
1. 以 Docker container 的方式运行:

docker run -d 
--name portainer 
--privileged=true 
--restart=always 
-p 9000:9000 
-v /data/volume/portainer-data:/data 
-v /var/run/docker.sock:/var/run/docker.sock 
portainer/portainer

2. 以 Docker service 的方式运行:

docker swarm init
docker service create 
--name portainer 
--publish 9000:9000 
--constraint 'node.role == manager' 
--mount type=bind,src=//var/run/docker.sock,dst=/var/run/docker.sock 
--mount type=bind,src=//data/volume/portainer-data,dst=/data 
portainer/portainer 
-H unix:///var/run/docker.sock

3. 以系统服务的方式运行:

新建并编辑文件 /etc/systemd/system/docker-portainer.service :

 [Unit]
Description=Docker portainer Server
After=docker.service
Requires=docker.service

[Service]
ExecStartPre=/usr/bin/docker kill portainer
ExecStartPre=/usr/bin/docker rm portainer
ExecStart=/usr/bin/docker run --name portainer --privileged=true -v /data/volume/portainer-data:/data -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer
ExecStartPost=/usr/local/bin/pipework br0 portainer YOUR_IP_ADDRESS/YOUR_NET_MASK@YOUR_GATEWAY
ExecStop=/usr/bin/docker stop portainer

[Install]
WantedBy=multi-user.target

然后启动服务:

systemctl start docker-portainer.service
systemctl enable docker-portainer.service

第3种方法的优点是:我们可以通过将容器封装成系统服务的同时,在容器启动后自动执行 pipework 将容器的网络映射到真实网络中。
下面是 portainer 容器运行后的截图,管理工作站的 docker 服务非常方便并且一目了然。
这里写图片描述

  在这里填一个小坑,默认情况下使用 ‘docker exec -it xxx bash’ 进入一个容器时,默认打开的terminal大小是 80X24 的分辨率,使用起来非常不方便,与自己的显示器极不协调,尤其是想在容器内使用 tmux 的情况,在 stackoverflow 上找到了一种解决方法,把下面代码加入到 ~/.bashrc 文件中,然后 srouce ~/.bashrc 使其生效:

# docker 容器 tty 默认分辨率修改 
docker-inside(){
    docker exec -it $1 bash -c "stty cols $COLUMNS rows $LINES && bash";
}
export -f docker-inside

使用 stty 将进入的容器的 terminfo 参数修改成当前 shell 相同的行数和列数,使用起来非常方便。


3. 虚拟化

  虚拟组件的系统堆栈是这样子的:
kvm stack

  下面来描述虚拟化的实践过程,Ubuntu 发行版的内核中已经默认挂载了 KVM 模块:

lsmod | grep kvm

所以我们只需要安装 libvirtd 服务,通过 libvirtd 服务与 libvirt API 通信来管理和控制虚拟机的运行。

  • Libvirtd 是一个 daemon 进程,可以被本地的virsh调用,也可以被远程的virsh调用
  • Libvirtd 调用 qemu-kvm 操作KVM 虚拟机

安装必要的虚拟化组件:

apt-get install kvm libvirt-bin bridge-utils sasl2-bin

修改 libvirtd 的配置文件,使其可以远程访问:

sed -i 's/#libvirtd_opts=""/libvirtd_opts="-l"/g' /etc/default/libvirt-bin

sed -i 's/#listen_tls/listen_tls/g' /etc/libvirt/libvirtd.conf
sed -i 's/#listen_tcp/listen_tcp/g' /etc/libvirt/libvirtd.conf
sed -i 's/#auth_tcp/auth_tcp/g'     /etc/libvirt/libvirtd.conf

sed -i 's/#vnc_listen/vnc_listen/g' /etc/libvirt/qemu.conf

重新启动 libvirtd 服务:

systemctl daemon-reload
systemctl restart libvirtd

  • 创建一个可以远程访问 libvirtd 的用户:
saslpasswd2 -a libvirt aggresss
  • 查看用户列表:
sasldblistusers2 -f /etc/libvirt/passwd.db
  • 删除一个可以远程访问 libvirtd 的用户:
saslpasswd2 -a libvirt -d aggresss

测试 libvirtd 服务是否可以远程访问:

virsh -c qemu+tcp://localhost/system nodeinfo

创建虚拟机的磁盘空间(参考命令,请根据自己的磁盘结构自行划分):

lvcreate -L 200G -n lv-virt vgpool
mkfs.ext4 /dev/vgpool/lv-virt
blkid
vim /etc/fstab
mount -a

  理论上现在就可以使用 virsh 来管理虚拟机了,就像CLI模式下的 docker命令,但是 virsh 命令要比 docker 命令复杂很多,而且用它来创建虚拟机的参数文件需要使用 xml 格式,如果没有可视化的管理工具,实施起来将非常耗时,如果不需要远程管理虚拟机,virt-manager 是一个不错的轻量化管理工具,同时还有很多支持 KVM 的管理工具,可以在这个链接里选择: https://www.linux-kvm.org/page/Management_Tools
   管理工具的配置可能比较繁琐,而且管理工具可能会更换,所以我的原则是管理工具尽量不运行在宿主主机的环境下,一个更好的方式是将管理工具容器化,达到一个用过即抛的效果,同时也便于迁移和数据管理,经过筛选最后使用 webvirtmgr 来通过WBI的方式管理虚拟服务,并且将 webvirtmgr 容器化到一个镜像里面,可以通过下面的 GitHub repository 构建镜像: https://github.com/aggresss/docker-webvirtmgr ,也可以使用命令直接下载镜像:

docker pull aggresss/docker-webvirtmgr

运行镜像:

docker run -d 
--name webvirtmgr 
--privileged=true 
--restart=always 
-p 8080:8080 
-p 6080:6080 
aggresss/webvirtmgr

webvirtmgr 从2016年就没有更新了,GitHub 上的 Issues 和 Pull requests 也没有人处理,所以作为工作站的虚拟机管理还勉强能用,遇到 Bug 需要自行解决了。
webvirtmgr 在创建网络时不能创建本地的网桥网络,会提示 “The pool bridge name must not contain any special characters” 的 Bug,需要手动将本地网桥添加到 libvirtd 服务的配置文件中:

创建一个xml文件,比如 host-bridge.xml ,内容如下:

<network>
  <name>host-bridge</name>
  <forward mode="bridge"/>
  <bridge name="br0"/>
</network>

然后执行:

virsh net-define ./host-bridge.xml
virsh net-autostart host-bridge
virsh net-start host-bridge

webvirtmgr 默认通过 noVNC 的方式远程控制Guest主机,下面是运行截图:

这里写图片描述


4. 总结

  将工作站容器化和虚拟化的过程记录了下来,方便大家填坑,感谢参考文档中各位大神的文章的帮助,在这里表示真诚的感谢。欢迎各位提出指导意见。


参考文档

  1. Docker网络详解及pipework源码解读与实践
  2. Advanced Docker Networking with Pipework
  3. KVM 介绍(5):libvirt 介绍 [ Libvrit for KVM/QEMU ]
  4. CentOS7.2部署KVM虚拟机
  5. libvirt.org -> Network XML format
  6. 通过noVNC和websockify连接到QEMU/KVM
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/aggresss/article/details/79478116
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2019-08-27 22:24:29
  • 阅读 ( 2177 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢