Docker 基础知识之——容器常用操作以及与虚拟机的区别2021-12-01

Docker是一个轻量级虚拟化技术,它具备传统虚拟机无可比拟的优势。它更简易的安装和使用方式、更快的速度、服务集成与开发流程自动化,都使Docker被广大技术爱好者青睐。
用户在使用Docker时,需要使用Docker命令行工具docker与Docker daemon建立通信。Docker daemon是Docker守护进程,负责接收并分发执行Docker命令。为了了解Docker命令行工具的概况,我们可以使用docker命令或docker help命令来获取docker的命令清单。

容器的增删改查和进入容器操作

接下来我们就从创建一个最简单的docker busybox容器开始,了解docker容器的创建、启动、交互、停止、删除等过程。
使用root用户在安装docker的Ubuntu 18.0.4系统中启动最简单的docker busybox沙箱,并在容器内运行/bin/sh交互。

root@k8s-worker01:~# docker run -it busybox /bin/sh  

首次运行需要从docker官方pull busybox这个镜像,成功后容器启动,可以在容器内部执行ps,如下:

/ # ps
 PID   USER     TIME  COMMAND
     1 root      0:00 /bin/sh
    10 root      0:00 ps

当前容器内1号进程为root,其他系统进程都看不到了,其实这个root进程不是真正的宿主机操作系统系统的root进程,它不过是经过障眼法设计在容器显示自己是1号进程而已,这个进程在宿主机上有真实的进程编号,也可以在容器内尝试reboot,不会成功。

/ # reboot
/ # shutdown -h now
/bin/sh: shutdown: not found

总结:容器,其实就是操作系统在启动进程时通过设置一些参数实现了隔离不相关资源后的一个特殊进程。

执行exit退出容器,容器不见了?
此时要用到docker ps命令,最常用的功能就是查看容器的CONTAINER ID,以便对特定容器进行操作。命令常用的选项有a和l。a参数可以查看所有容器,包括停止的容器;l选项则只查看最新创建的容器,包括不在运行中的容器。使用方法如下:

root@k8s-worker01:~# docker ps -a
CONTAINER ID   IMAGE    COMMAND     CREATED  STATUS      PORTS     NAMES
50a0061fcd8a   busybox    "/bin/sh" 2 minutes ago   Exited (0) About a minute ago vibrant_elion

此时可以看到容器ID为:50a0061fcd8a
我们想进入容器,需要docker exec

root@k8s-worker01:~# docker exec -it 50a0061fcd8a /bin/sh
Error response from daemon: Container 0a0061fcd8ab6bddeef417bf357790902db944e8f663f48f02def961b2e083b is not running

发现容器not running,说明需要启动容器,docker start命令排上用场,用-i实现容器交互

root@k8s-worker01:~# docker start --help
Usage:  docker start [OPTIONS] CONTAINER [CONTAINER...]
Start one or more stopped containers
Options:
  -a, --attach               Attach STDOUT/STDERR and forward signals
      --detach-keys string   Override the key sequence for detaching a container
  -i, --interactive          Attach container's STDIN

运行docker start -i 容器ID进入交互模式,熟悉的容器又回来了。

root@k8s-worker01:~# docker start -i 50a0061fcd8a
/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/sh
    7 root      0:00 ps

如果docker start没有指定参数,仅仅运行了docker start 容器ID,此时需要运行docker exec才能交互进入容器。

root@k8s-worker01:~# docker start 50a0061fcd8a
50a0061fcd8a
root@k8s-worker01:~# docker exec -it 50a0061fcd8a /bin/sh
/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/sh
    7 root      0:00 /bin/sh
   14 root      0:00 ps

最后,总结一下docker常见命令如下图所示,从docker registry 下载image,然后docker images可以查看本地的images,从docker image静态文件生成容器运行时,此时用到docker run,容器生命周期管理包括start/stop/restart等,还有包括常用的查看已经运行和停止运行容器的命令docker ps -a,最后如果有需要与容器交互的命令docker exec。


接下来我们关闭容器,运行docker ps -a检查确实已经关闭。

root@k8s-worker01:~# docker stop 50a0061fcd8a
50a0061fcd8a

删除容器,此后运行docker ps -a看不到busybox容器了。

root@k8s-worker01:~# docker rm 50a0061fcd8a
50a0061fcd8a

删除容器镜像,首先看到images中有busybox这个镜像,并且能看到Image ID,使用docker rmi(remove image)然后删除容器镜像。

root@k8s-worker01:~# docker images
REPOSITORY  TAG       IMAGE ID       CREATED        SIZE
busybox      latest    d23834f29b38   29 hours ago   1.24MB
root@k8s-worker01:~# docker rmi d23834f29b38
Untagged: busybox:latest
Untagged: busybox@sha256:52817dece4cfe26f581c834d27a8e1bcc82194f914afe6d50afad5a101234ef1
Deleted: sha256:d23834f29b3875b6759be00a48013ba523c6a89fcbaeaa63607512118a9c4c19
Deleted: sha256:9f2549622fec760f90ed0383b7ca50e23c12254accf9cb2bc0db705454de852a

容器与虚拟机

过去数年间虚拟机都是大多数企业基础设施的承载最小单位,随着容器技术的出现,有很多关于虚拟机和容器的对比。如下图所示,图中左侧是虚拟机的结构图, Hypervisor 的软件是虚拟机最主要的部分。它通过硬件虚拟化功能,模拟出了运行一个操作系统需要的各种硬件,比如 CPU、内存、I/O 设备等等。然后,它在这些虚拟的硬件上安装了一个新的操作系统,即 Guest OS。这样,用户的应用进程就可以运行在这个虚拟的机器中,它能看到的自然也只有 Guest OS 的文件和目录,以及这个机器里的虚拟设备。这意味着虚拟机作为一个隔离最小单元,但同时也明确看到虚拟机也能起到将不同的应用进程相互隔离的作用。而图中右侧,则用一个名为 Docker Engine 的软件替换了 Hypervisor。这也是为什么,很多人会把 Docker 项目称为“轻量级”虚拟化技术的原因,实际上就是把虚拟机的概念套在了容器上。

可是这样的说法,却并不严谨。
在理解了 Namespace 的工作方式之后,你就会明白,跟真实存在的虚拟机不同,在使用 Docker 的时候,并没有一个真正的“Docker 容器引擎”运行在宿主机里面,而是通过宿主机的操作系统通过namespace对应用进程进行隔离,通过cgroups对被隔离的应用进程限制相关资源属性。Docker 项目帮助用户启动的,还是原来的应用进程,只不过在创建这些进程时,Docker 为它们加上了各种各样的 Namespace 参数,如PID、Mount,UTS、Network、IPC等,实现进程空间、文件系统、网络、主机名域名和信号量等资源隔离。

uts:主机名和域名隔离
ipc:信号量,消息队列和共享内存隔离
mnt:文件系统挂载点隔离
net:网络隔离,每个namespace都有自己独立的ip,路由和端口
pid:隔离进程ID

虚拟机的强隔离性和资源分配能力比较强,适合单体应用,而容器相比虚拟机更加灵活轻量,适合快速打包,快速发布,并且没有虚拟化层的性能损失。 但缺点是没有虚拟化层的隔离性,同时这对容器的管理、调度和安全提出了较高的挑战,从这个层面,可以理解市场为什么最后会拥抱kubernetes作为容器云管理和调度的标准。相比于在虚拟机里面可以随便折腾的自由度,在容器里部署应用的时候,“什么能做,什么不能做”,就是用户必须考虑的一个问题。此外,由于上述问题,尤其是共享宿主机内核的事实,容器给应用暴露出来的攻击面是相当大的,应用“越狱”的难度自然也比虚拟机低得多。
所以说,“敏捷”和“高性能”是容器相较于虚拟机最大的优势,也是它能够在 PaaS 这种更细粒度的资源管理平台上大行其道的重要原因。不过,有利就有弊,基于 Linux Namespace 的隔离机制相比于虚拟化技术也有很多不足之处,其中最主要的问题就是:隔离得不彻底。首先,既然容器只是运行在宿主机上的一种特殊的进程,那么多个容器之间使用的就还是同一个宿主机的操作系统内核。另外,在 Linux 内核中,有很多资源和对象是不能被 Namespace 化的,最典型的例子就是:时间。
此外,由于上述问题,尤其是共享宿主机内核的事实,容器给应用暴露出来的攻击面是相当大的,应用“越狱”的难度自然也比虚拟机低得多。更为棘手的是,尽管在实践中我们确实可以使用 Seccomp 等技术,对容器内部发起的所有系统调用进行过滤和甄别来进行安全加固,但这种方法因为多了一层对系统调用的过滤,必然会拖累容器的性能。何况,默认情况下,谁也不知道到底该开启哪些系统调用,禁止哪些系统调用。所以,在生产环境中,没有人敢把运行在物理机上的 Linux 容器直接暴露到公网上。当然,有些基于虚拟化或者独立内核技术的容器实现,则可以比较好地在隔离与性能之间做出平衡。

暂无评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注


虚拟化 | 云计算 | 机器学习 | 股市复盘
© 2024 涛哥,版权所有, 京ICP备20014492-2号