容器是一种沙盒技术,主要目的是为了将应用运行在其中,与外界隔离;及方便这个沙盒可以被转移到其它宿主机器。本质上,它是一个特殊的进程。通过名称空间(Namespace)、控制组(Control groups)、切根(chroot)技术把资源、文件、设备、状态和配置划分到一个独立的空间。
通俗点的理解就是一个装应用软件的箱子,箱子里面有软件运行所需的依赖库和配置。开发人员可以把这个箱子搬到任何机器上,且不影响里面软件的运行。
容器原理
为了实现容器进程对外界的隔离,容器底层主要运用了名称空间(Namespaces)、控制组(Control groups)和切根(chroot)。
名称空间(Namespace)
每个运行的容器都有自己的名称空间。这是Linux操作系统默认提供的API,包括:
·PID Namespace:不同容器就是通过pid名字空间隔离开的,不同名字空间中可以有相同的pid。
·Mount Namespace:mount允许不同名称空间的进程看到的文件结构不同,因此不同名称空间中的进程所看到的文件目录就被隔离了。另外,每个名称空间中的容器在/proc/mounts的信息只包含当前名称的挂载点。
·IPC Namespace:容器中进程交互还是采用Linux常见的进程交互方法(interprocess communication -IPC),包括信号量、消息队列和共享内存等。
·Network Namespace:网络隔离是通过Net实现,每个Net有独立的网络设备,IP地址,路由表,/proc/net目录。这样每个容器的网络就能隔离开来。
·UTS Namespace:UTS(UNIX Time-sharing System)允许每个容器拥有独立的hostname和domain name,使其在网络上可以被视作一个独立的节点而非主机上的一个进程。
·User Namespace:每个容器可以有不同的用户和组id,也就是说可以在容器内用容器内部的用户执行程序而非主机上的用户。
控制组(Control groups):
Cgroups是Linux内核提供的一种可以限制、记录、隔离进程组的物理资源机制。因为Namespace技术只能改变进程的视觉范围,不能真实地对资源做出限制。所以就必须采用Cgroup技术对容器进行资源限制,防止某个容器把宿主机资源全部用完导致其它容器也宕掉。在Linux的/sys/fs/cgroup目录中,有cpu、memory、devices、net_cls等子目录,可以根据需要修改相应的配置文件来设置某个进程ID对物理资源的最大使用率。
切根(change to root):
切根的意思就是改变一个程序运行时参考的根目录位置,让不同容器在不同的虚拟根目录下工作,从而相互不直接影响。
容器与虚拟机
虚拟机通常包括整个操作系统和应用程序,里面运行的是一个真实的操作系统。本质上虚拟机是Hypervisor虚拟化出来的硬件上安装不同的操作系统,而容器是宿主机上运行的不同进程。从用户体验上来看,虚拟机是重量级的,占用物理资源多,启动时间长。容器则占用物理资源少,启动迅速。相对地,虚拟机隔离的更彻底,容器则要差一些。
二、容器发展史
虽然现在提到容器,大家就想到docker,但事实上容器是从1979年的Chroot Jail开始的。而docker是在2013年才开始推出第一个版本。大致发展史可以参考下图。
三、docker与nvidia-docker
为什么是docker
聊到容器,大家都默认指docker,为啥其它不行?原因很简单,就是因为docker使用起来简单方便,解决了绝大多数用户需求。其它容器或多或少存在打包不方便、兼容性差等问题。而docker的方案中,不仅打包了本地应用程序,同时将本地环境(操作系统一部分)一起打包,实现本地与服务器的环境完全一致,做到了真正的一次开发随处运行。
docker和nvidia-docker
docker是容器,nvidia-docker是支持docker使用的插件。对于一般web应用而言,无需用到nvidia-docker。
安装(ubuntu)
docker安装
自动安装:
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
或:
curl -sSL https://get.daocloud.io/docker | sh
手动安装:
卸载旧版本:
sudo apt-get remove docker docker-engine docker.io containerd runc
更新包索引:
sudo apt-get update
安装apt依赖包:
sudoapt-get install
apt-transport-https
ca-certificates
curl
gnupg-agent
software-properties-common
添加官方GPG密钥:
curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
验证是否有密钥:
sudoapt-key fingerprint 0EBFCD88
更新apt包索引:
sudo apt-get update
安装最新版本:
sudo apt-get install docker-ce docker-ce-cli containerd.io
或者安装指定版本:
sudo apt-get install docker-ce=<VERSION_STRING> docker-ce-cli=<VERSION_STRING> containerd.io
测试:
sudo docker run hello-world
nvidia-docker安装
卸载老版本:
docker volume ls -q -f driver=nvidia-docker | xargs -r -I{} -n1 docker ps -q -a -f volume={} | xargs -r docker rm -f
sudo apt-get purge -y nvidia-docker
获取密钥:
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey |
sudo apt-key add -
根据系统获取安装软件列表:
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list |
sudo tee /etc/apt/sources.list.d/nvidia-docker.list
更新apt包索引:
sudo apt-get update
安装nvidia-docker:
sudo apt-get install -y nvidia-docker2
sudo pkill -SIGHUP dockerd
测试:
docker run --runtime=nvidia --rm nvidia/cuda:9.0-base nvidia-smi
踩过的一些坑
·nvidia-docker1最高只能支持cuda9,而且容器内cuda镜像与宿主机器要一致。
·有时出现容器内部不能识别显卡的问题需要重启一下docker服务。
·docker 19.03版本之后,只需要安装nvidia-container-runtime就可以了,而安装nvidia-docker2会默认把nvidia-container-runtime安装上,因此安装nvidia-docker2并不影响使用。
·安装nvidia-docker的时候,可能会遇到https://nvidia.github.io 无法访问的情况,此时需要找到该网站对应的ip,将其写入本机host,即可解决。
·挂载本地目录到docker容器中,挂载的目录文件有可能会影响程序的运行。
docker中常用到的概念和使用方法
镜像与容器
docker的生命周期中,镜像和容器是最重要的两部分。其中镜像是文件,是一个只读的模板,一个独立的文件系统,里面包含运行容器所需的数据,可以用来创建新的容器;而容器是基于镜像创建的进程,容器中的进程依赖于镜像中的文件,容器具有写的功能,可以根据需要改写里面的软件、配置等,并可以保存为新的镜像。如果是用import方法生成,则是一个完全新的镜像。如果用的是commit方法生成的新的镜像,则新镜像与原来的镜像之间存在着继承关系。
常用使用命令
使用容器时一般从官网直接拉取与自己环境最相近的镜像。网址:
https://hub.docker.com/ 再在此基础上搭建开发或部署环境。
启动docker服务:systemctl start docker
重启docker服务:systemctl restart docker
停止docker服务:systemctl stop docker
拉取镜像:docker pull 镜像名
查看镜像:docker images
创建运行容器:docker run [options] image [command] [arg…]
-i 交互式操作
-t 伪终端
-v 挂载
-p 指定端口映射
-e 设置环境变量
-d 后台运行容器,返回容器ID
查看容器:docker ps [options]
进入容器:docker exec [options] container command [arg…]
-d 分离模式,在后台运行
-i 即使没有附加也保持STDIN打开
-t 伪终端
容器保存为镜像:docker commit 容器ID 镜像名称:TAG信息
镜像文件保存:docker save -o 文件名.tar 镜像名称:TAG信息
镜像文件导入:docker load -o 文件名.tar
删除容器:docker rm 容器ID
删除镜像:docker rmi 镜像ID
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/292184.html