Docker 介绍

Posted 牛牛VS妞妞

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker 介绍相关的知识,希望对你有一定的参考价值。

Docker 介绍

1.1 Docker 是什么?

  • Docker (码头工人)是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司(后由于 Docker 开
    源后大受欢迎就将公司改名为 Docker Inc ,总部位于美国加州的旧金山)内部的一个开源的 PAAS 服
    务 (Platform as a ServiceService )的业余项目。它基于 Google 公司推出的 Go 语言实现。 项目后来加
    入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在 GitHub 上进行维护。

  • Docker 是基于 linux 内核实现,Docker 最早采用 LXC 技术 ,LXC 是 Linux 原生支持的容器技术 ,可
    以提供轻量级的虚拟化 ,可以说 docker 就是基于 LXC 发展起来 的,提供 LXC 的高级封装,标准的配
    置方法,在LXC的基础之上,docker提供了一系列更强大的功能。而虚拟化技术 KVM(KernelKernelbased
    Virtual Machine Machine) 基于 模块实现, 后来Docker 改为自己研发并开源的 runc 技术运行
    容器,彻底抛弃了LXC。

  • Docker 相比虚拟机的交付速度更快,资源消耗更低,Docker 采用客户端/服务端架构,使用远程API来
    管理和创建容器,其可以轻松的创建一个轻量级的、可移植的、自给自足的容器,docker 的三大理念
    是build(构建)、ship(运输)、 run(运行),Docker遵从apache 2.0协议,并通过(namespace及cgroup
    等)来提供容器的资源隔离与安全保障等,所以Docke容器在运行时不需要类似虚拟机(空运行的虚拟
    机占用物理机6-8%性能)的额外资源开销,因此可以大幅提高资源利用率,总而言之Docker是一种用了
    新颖方式实现的轻量级虚拟机.类似于VM但是在原理和应用上和VM的差别还是很大的,并且docker的
    专业叫法是应用容器(Application Container)。

Docker的主要目标

  • Build, Ship and Run Any App, Anywhere,即通过对应用组件的封装(Packaging)、分发
    (Distribution)、部署(Deployment)、运行(Runtime)等生命周期的管理,达到应用组件级别的
    “一次封装,到处运行”。这里的应用组件,既可以是一个Web应用,也可以是一套数据库服务,甚至是
    一个操作系统。将应用运行在Docker 容器上,可以实现跨平台,跨服务器,只需一次配置准备好相关
    的应用环境,即可实现到处运行,保证研发和生产环境的一致性,解决了应用和运行环境的兼容性问
    题,从而极大提升了部署效率,减少故障的可能性。

1.2 Docker、虚拟机、物理机

容器和虚拟机技术比较

  • 传统虚拟机是虚拟出一个主机硬件,并且运行一个完整的操作系统 ,然后在这个系统上安装和运行软
  • 容器内的应用直接运行在宿主机的内核之上,容器并没有自己的内核,也不需要虚拟硬件,相当轻量化
  • 每个容器间是互相隔离,每个容器内都有一个属于自己的独立文件系统,独立的进程空间,网络空间,用
    户空间等,所以在同一个宿主机上的多个容器之间彼此不会相互影响

容器和虚拟机表现比较

  • 资源利用率更高: 开销更小,不需要启动单独的虚拟机OS内核占用硬件资源,可以将服务器性能压榨
    至极致.虚拟机一般会有5-20%的损耗,容器运行基本无损耗,所以生产中一台物理机只能运行数十个
    虚拟机,但是一般可以运行数百个容器
  • 启动速度更快: 可以在数秒内完成启动
  • 占用空间更小: 容器一般占用的磁盘空间以MB为单位,而虚拟机以GB
  • 集成性更好: 和CI/CD(持续集成/持续部署)相关技术结合性更好,实现打包镜像发布测试可以一
    键运行,做到自动化并快速的部署管理,实现高效的开发生命周期

1.3 Docker 组成

  • Docker 主机(Host): 一个物理机或虚拟机,用于运行Docker服务进程和容器,也称为宿主机,
    node节点
  • Docker 服务端(Server): Docker守护进程,运行docker容器
  • Docker 客户端(Client): 客户端使用 docker 命令或其他工具调用docker API
  • Docker 镜像(Images): 镜像可以理解为创建实例使用的模板,本质上就是一些程序文件的集合
  • Docker 仓库(Registry): 保存镜像的仓库,官方仓库: https://hub.docker.com/,可以搭建私有仓
    库harbor
  • Docker 容器(Container): 容器是从镜像生成对外提供服务的一个或一组服务,其本质就是将镜像中
    的程序启动后生成的进程

1.4 Namespace

一个宿主机运行了N个容器,多个容器共用一个 OS,必然带来的以下问题:

  • 怎么样保证每个容器都有不同的文件系统并且能互不影响?
  • 一个docker主进程内的各个容器都是其子进程,那么如果实现同一个主进程下不同类型的子进
    程?各个容器子进程间能相互通信(内存数据)吗?
  • 每个容器怎么解决IP及端口分配的问题?
  • 多个容器的主机名能一样吗?
  • 每个容器都要不要有root用户?怎么解决账户重名问题?

namespace是Linux系统的底层概念,在内核层实现,即有一些不同类型的命名空间被部署在核内,各
个docker容器运行在同一个docker主进程并且共用同一个宿主机系统内核,各docker容器运行在宿主
机的用户空间,每个容器都要有类似于虚拟机一样的相互隔离的运行空间,但是容器技术是在一个进程
内实现运行指定服务的运行环境,并且还可以保护宿主机内核不受其他进程的干扰和影响,如文件系统
空间、网络空间、进程空间等,目前主要通过以下技术实现容器运行空间的相互隔离:

隔离类型 功能 调用参数 内核版本
MNT Namespace(mount) 提供磁盘挂载点和文件系统的<br/>隔离能力 CLONE_NEWNS 2.4.19
IPC Namespace(Inter-<br/>Process Communication) 提供进程间通信的隔离能力,<br/>包括信号量,消息队列和共享<br/>内存 CLONE_NEWIPC 2.6.19
UTS Namespace(UNIX<br/>Timesharing System) 提供内核,主机名和域名隔离<br/>能力 CLONE_NEWUTS 2.6.19
PID Namespace(Process<br/>Identification) 提供进程隔离能力 CLONE_NEWPID 2.6.24
Net Namespace(network) 提供网络隔离能力,包括网络<br/>设备,网络栈,端口等 CLONE_NEWNET 2.6.29
User Namespace(user) 提供用户隔离能力,包括用户<br/>和组 CLONE_NEWUSER 3.8

1.4.1 MNT Namespace

每个容器都要有独立的根文件系统有独立的用户空间,以实现在容器里面启动服务并且使用容器的运行
环境,即一个宿主机是ubuntu的服务器,可以在里面启动一个centos运行环境的容器并且在容器里面
启动一个nginx服务,此Nginx运行时使用的运行环境就是centos系统目录的运行环境,但是在容器里
面是不能访问宿主机的资源,宿主机是使用了chroot技术把容器锁定到一个指定的运行目录里面。

例如:

/var/lib/containerd/io.containerd.runtime.v1.linux/moby/容器ID

根目录:

/var/lib/docker/overlay2/ID

实例:

[root@localhost ~]# docker version
Client: Docker Engine - Community
 Version:           20.10.8
 API version:       1.41
 Go version:        go1.16.6
 Git commit:        3967b7d
 Built:             Fri Jul 30 19:55:49 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.8
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.6
  Git commit:       75249d8
  Built:            Fri Jul 30 19:54:13 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.4.9
  GitCommit:        e25210fe30a0a703442421b0f60afac609f950a3
 runc:
  Version:          1.0.1
  GitCommit:        v1.0.1-0-g4144b63
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

范例: 查看存储

[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                               NAMES
9dad2e67c7a6   nginx     "/docker-entrypoint.…"   59 seconds ago   Up 58 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   nginx

[root@localhost merged]# ls /var/lib/docker/overlay2/1db69606746ed9a41b990f71bb8ad6edb1f21a22cc01e7ae565102c7a712ad9c/merged
bin  boot  dev  docker-entrypoint.d  docker-entrypoint.sh  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

范例: 验证容器的根文件系统

[root@localhost merged]# docker exec nginx cat /etc/issue
Debian GNU/Linux 10 \\n \\l

[root@localhost merged]# docker exec nginx ls /
bin
boot
dev
docker-entrypoint.d
docker-entrypoint.sh
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

1.4.2 IPC Namespace

一个容器内的进程间通信,允许一个容器内的不同进程的(内存、缓存等)数据访问,但是不能跨容器直
接访问其他容器的数据

1.4.3 UTS Namespace

UTS namespace(UNIX Timesharing System包含了运行内核的名称、版本、底层体系结构类型等信
息)用于系统标识,其中包含了主机名hostname 和域名domainname ,它使得一个容器拥有属于自
己主机名标识,这个主机名标识独立于宿主机系统和其上的其他容器。

实例:

[root@localhost merged]# docker exec -it 9dad2e67c7a6 sh
# hostname
9dad2e67c7a6
# cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2      9dad2e67c7a6

1.4.4 PID Namespace

Linux系统中,有一个PID为1的进程(init/systemd)是其他所有进程的父进程,那么在每个容器内也要有
一个父进程来管理其下属的子进程,那么多个容器的进程通PID namespace进程隔离(比如PID编号重
复、器内的主进程生成与回收子进程等)。

范例:

[root@localhost merged]# pstree -p
systemd(1)─┬─NetworkManager(6294)─┬─{NetworkManager}(6301)
           │                      └─{NetworkManager}(6308)
           ├─VGAuthService(6204)
           ├─auditd(37682)───{auditd}(37683)
           ├─containerd(37721)─┬─{containerd}(37723)
           │                   ├─{containerd}(37724)
           │                   ├─{containerd}(37725)
           │                   ├─{containerd}(37726)
           │                   ├─{containerd}(37727)
           │                   ├─{containerd}(37728)
           │                   ├─{containerd}(37729)
           │                   ├─{containerd}(37730)
           │                   ├─{containerd}(37731)
           │                   └─{containerd}(38120)
           ├─containerd-shim(38127)─┬─nginx(38150)─┬─nginx(38204)
           │                        │              ├─nginx(38205)
           │                        │              ├─nginx(38206)
           │                        │              └─nginx(38207)
           │                        ├─{containerd-shim}(38129)
           │                        ├─{containerd-shim}(38130)
           │                        ├─{containerd-shim}(38131)
           │                        ├─{containerd-shim}(38132)
           │                        ├─{containerd-shim}(38133)
           │                        ├─{containerd-shim}(38134)
           │                        ├─{containerd-shim}(38135)
           │                        ├─{containerd-shim}(38136)
           │                        ├─{containerd-shim}(38137)
           │                        └─{containerd-shim}(38208)
           ├─crond(24467)
           ├─dbus-daemon(6208)───{dbus-daemon}(6216)
           ├─dockerd(37733)─┬─docker-proxy(38103)─┬─{docker-proxy}(38104)
           │                │                     ├─{docker-proxy}(38105)
           │                │                     ├─{docker-proxy}(38106)
           │                │                     ├─{docker-proxy}(38107)
           │                │                     ├─{docker-proxy}(38108)
           │                │                     ├─{docker-proxy}(38109)
           │                │                     ├─{docker-proxy}(38110)
           │                │                     └─{docker-proxy}(38111)
           │                ├─docker-proxy(38112)─┬─{docker-proxy}(38113)
           │                │                     ├─{docker-proxy}(38114)
           │                │                     ├─{docker-proxy}(38115)
           │                │                     ├─{docker-proxy}(38116)
           │                │                     ├─{docker-proxy}(38117)
           │                │                     └─{docker-proxy}(38118)

宿主机的PID究竟与容器内的PID是什么关系

[root@localhost merged]# ps -ef |grep docker
root      37733      1  0 22:53 ?        00:00:06 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
root      38103  37733  0 22:54 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 80 -container-ip 172.17.0.2 -container-port 80
root      38112  37733  0 22:54 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 80 -container-ip 172.17.0.2 -container-port 80
root      38397  37063  0 23:11 pts/0    00:00:00 grep --color=auto docker
[root@localhost merged]# ps -ef |grep 37733
root      37733      1  0 22:53 ?        00:00:06 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
root      38103  37733  0 22:54 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 80 -container-ip 172.17.0.2 -container-port 80
root      38112  37733  0 22:54 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 80 -container-ip 172.17.0.2 -container-port 80
root      38400  37063  0 23:11 pts/0    00:00:00 grep --color=auto 37733
[root@localhost merged]# ps -ef |grep 38103
root      38103  37733  0 22:54 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 80 -container-ip 172.17.0.2 -container-port 80
root      38402  37063  0 23:12 pts/0    00:00:00 grep --color=auto 38103

1.4.5 NET Namespace

每一个容器都类似于虚拟机一样有自己的网卡、监听端口、TCP/IP协议栈等

Docker使用network namespace启动一个vethX接口,这样你的容器将拥有它自己的桥接ip地址,通常
是docker0,而docker0实质就是Linux的虚拟网桥,网桥是在OSI七层模型的数据链路层的网络设备,通
过mac地址对网络进行划分,并且在不同网络直接传递数据。

1.4.6 User Namespace

各个容器内可能会出现重名的用户和用户组名称,或重复的用户UID或者GID,那么怎么隔离各个容器
内的用户空间呢?
User Namespace允许在各个宿主机的各个容器空间内创建相同的用户名以及相同的用户UID和GID,
只是会把用户的作用范围限制在每个容器内,即A容器和B容器可以有相同的用户名称和ID的账户,但是
此用户的有效范围仅是当前容器内,不能访问另外一个容器内的文件系统,即相互隔离、互不影响、永
不相见

更新中。。。

以上是关于Docker 介绍的主要内容,如果未能解决你的问题,请参考以下文章

Docker初级——介绍安装和使用

markdown [Docker] Docker片段列表和命令#linux #docker #snippets

linux_docker入门

markdown docker-compose片段

sh Docker片段

Android课程---Android Studio使用小技巧:提取方法代码片段