Fork me on GitHub

一起学 Docker(二)-- 核心概念和安装

环境介绍:

操作系统:64bit CentOS7

docker 版本:18.06.1-ce(最新版本)

版本新功能:

hhttps://github.com/docker/docker-ce/releases/tag/v18.06.1-ce

安装步骤

系统:64 位 centos7

迅雷直接下载:

http://mirrors.aliyun.com/centos/7.4.1708/isos/x86_64/CentOS-7-x86_64-DVD-1708.iso

虚拟机:virtualBox 或 VMware Workstation

最好是安装完整版本的 centos7,vm 安装 centos7 的过程我这里都不截图了,比较简单百度都可以看到。

要求: 内核版本最低为 3.10

查看当前内核版本: uname –r

要求: 更改网卡配置

更改网卡配置:vim /etc/sysconfig/network-scripts/ifcfg-ens33

更改完后重启服务:service network restart

注意:如果 ifconfig 命令不识别的话需要安装:

yum installnet-tools

通过 yum 方式安装最新版 Docker

第一步:更新 yum 源: sudo yum update

第二步:卸载旧版本(如果安装过旧版本的话)
yum remove docker  docker-common docker-selinux docker-engine

第三步:安装需要的软件包, yum-util 提供 yum-config-manager 功能,另外两个是 devicemapper 驱动依赖的

yum install -y yum-utils device-mapper-persistent-data lvm2

第四步:设置 yum 源

yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

第五步:可以查看所有仓库中所有 docker 版本,并选择特定版本安装

yum list docker-ce --showduplicates | sort -r

第六步:安装 docker

yum install docker-ce   
#由于 repo 中默认只开启 stable 仓库,故这里安装的是最新稳定版 18.06.1
或者指定 docker 版本安装:
yum install <FQPN> 
# 例如:sudo yum install docker-ce-18.06.1.ce

第七步:启动并加入开机启动

systemctl start docker
systemctl enable docker

#centos7 已不用 chkconfig 了使用 systemctl list-unit-files 可以查看启动项

第八步:验证安装是否成功(有 client 和 service 两部分表示 docker 安装启动都成功了)

docker version

第九步:添加国内镜像

添加国内 docker 镜像地址:vim /etc/docker/daemon.json
{"registry-mirrors": ["https://registry.docker-cn.com","http://hub-mirror.c.163.com","https://docker.mirrors.ustc.edu.cn"]
}

重启 docker
systemctl daemon-reload
systemctl restart docker

第十步:启动 docker

systemctl start docker


测试:sudo docker run hello-world

docker 配置(按照正常的开发应用是 docker 控制有个专门的用户,为了学习方便我直接使用了 root 用户):

创建 docker 用户组

sudo groupadd docker

增加当前用户到 docker 分组

sudo usermod -aG docker liming

验证在不使用 sudo 的情况下 docker 是否正常工作

docker run hello-world

docker 卸载

查看安装包

yum list installed | grep docker

移除安装包:

sudo yum -y remove docker-ce.x86_64

清除所有 docker 依赖文件

rm -rf /var/lib/docker

删除用户创建的配置文件

Docker 的核心概念

Docker 核心概念之镜像

Docker 镜像镜像是创建 docker 容器的基础,docker 镜像类似于虚拟机镜像,可以将它理解为一个面向 docker 引擎的只读模块,包含文件系统。

例如:一个镜像可以包含一个完整的 centos 操作系统环境,里面仅安装了 Apache 或用户需要的其它应用程序。

镜像可以用来创建 Docker 容器。

创建 Docker 镜像有几种方式,多数是在一个现有镜像基础上创建新镜像,因为几乎你需要的任何东西都有了公共镜像,包括所有主流 Linux 发行版,你应该不会找不到你需要的镜像。不过,就算你想从头构建一个镜像,也有好几种方法。

创建镜像有三种方法:

(1)基于已有镜像的容器创建。主要是利用 docker commit 命令。

(2)基于本地模板导入。推荐利用 OpenVZ 提供的模板来创建。

(3)基于 dockerfile 创建。首先按照 dockerfile 的格式,编写好 dockerfile 文件,之后通过 docker build 命令来创建镜像。docker build 会读取制定的 dockerfile,由 docker 服务器来创建镜像。

Docker 核心概念之容器

Docker 容器类似一个轻量级的沙箱,Docker 利用容器来运行和隔离应用。

容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。

可以把容器看做是一个简易版的 Linux 环境(包括 root 用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。

注:镜像是本身是只读的,容器从镜像启动的时候,Docker 会在镜像的最上层创建一个可写层,镜像本身保持不变。

可以利用 docker create 命令创建一个容器,创建后的的容器处于停止状态,可以使用 docker start 命令来启动它。也可以直接利用 docker run 命令来直接从镜像启动运行一个容器。docker run = docker creat + docker start。

当利用 docker run 创建并启动一个容器时,docker 在后台的标准操作包括:

(1)检查本地是否存在指定的镜像,不存在就从公有仓库下载。

(2)利用镜像创建并启动一个容器。

(3)分配一个文件系统,并在只读的镜像层外面挂载一层可读写层。

(4)从宿主机配置的网桥接口中桥接一个虚拟的接口到容器中。

(5)从地址池中配置一个 IP 地址给容器。

(6)执行用户指定的应用程序。

(7)执行完毕后容器终止。

Docker 核心概念之仓库

仓库是集中存放 Docker 镜像文件的地方。

有时候会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。Centos 的 6.0 和 7.0 就是 tag。

仓库分为公有仓库和私有仓库,DockerHub 是目前最大的公有仓库。可以通过 docker push/pull 命令从仓库中上传和下载镜像,docker search 命令来搜索镜像。

Docker 的其他核心技术预览

Docker 核心是一个 操作系统级虚拟化 方法, 理解起来可能并不像 VM 那样直观。我们从虚拟化方法的四个方面:隔离性、可配额 / 可度量、便携性、安全性 来详细介绍 Docker 的技术细节。

LXC 介绍

1、Linux Container 容器是一种 内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源。

2、LXC 为 Linux Container的简写。可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性。LXC 在资源管理方面依赖于 Linux 内核的 cgroups 子系统,LXC 在隔离控制方面依赖于 Linux 内核的 namespace 特性。容器有效地将由单个操作系统管理的资源划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资源使用需求。与传统虚拟化技术相比,它的优势在于:

(1)与宿主机使用同一个内核,性能损耗小;

(2)不需要指令级模拟;

(3)不需要即时 (Just-in-time) 编译;

(4)容器可以在 CPU 核心的本地运行指令,不需要任何专门的解释机制;

(5)避免了准虚拟化和系统调用替换中的复杂性;

(6)轻量级隔离,在隔离的同时还提供共享机制,以实现容器与宿主机的资源共享。

总结:Linux Container 是一种轻量级的虚拟化的手段。

3、Linux Container 提供了在单一可控主机节点上支持多个相互隔离的 server container 同时执行的机制。Linux Container 有点像 chroot,提供了一个拥有自己进程和网络空间的虚拟环境,但又有别于虚拟机,因为 lxc 是一种操作系统层次上的资源的虚拟化。

4、LXC 与 docker 的关系

(1)Docker 并不是 LXC 的替代品,Docker 的底层就是使用了 LXC 来实现的。LXC 将 Linux 进程沙盒化,使得进程之间相互隔离,并且能够控制各进程的资源分配。
(2)在 LXC 的基础之上,Docker 提供了一系列更强的功能。

隔离性: Linux Namespace(ns)

每个用户实例之间相互隔离, 互不影响。 一般的硬件虚拟化方法给出的方法是 VM,而 LXC 给出的方法是 container,更细一点讲就是 kernel namespace。其中 pid、net、ipc、mnt、uts、user 等 namespace 将 container 的进程、网络、消息、文件系统、UTS(“UNIX Time-sharing System”)和用户空间隔离开。

1) pid namespace

不同用户的进程就是通过 pid namespace 隔离开的,且不同 namespace 中可以有相同 pid。所有的 LXC 进程在 docker 中的父进程为 docker 进程,每个 lxc 进程具有不同的 namespace。同时由于允许嵌套,因此可以很方便的实现 Docker in Docker。

2) net namespace

有了 pid namespace, 每个 namespace 中的 pid 能够相互隔离,但是网络端口还是共享 host 的端口。网络隔离是通过 net namespace 实现的, 每个 net namespace 有独立的 network devices, IP addresses, IP routing tables, /proc/net 目录。这样每个 container 的网络就能隔离开来。docker 默认采用 veth 的方式将 container 中的虚拟网卡同 host 上的一个 docker bridge: docker0 连接在一起。

3) ipc namespace

container 中进程交互还是采用 linux 常见的进程间交互方法(interprocess communication - IPC), 包括常见的信号量、消息队列和共享内存。然而同 VM 不同的是,container 的进程间交互实际上还是 host 上具有相同 pid namespace 中的进程间交互,因此需要在 IPC 资源申请时加入 namespace 信息 - 每个 IPC 资源有一个唯一的 32 位 ID。

4) mnt namespace

类似 chroot,将一个进程放到一个特定的目录执行。mnt namespace 允许不同 namespace 的进程看到的文件结构不同,这样每个 namespace 中的进程所看到的文件目录就被隔离开了。同 chroot 不同,每个 namespace 中的 container 在 /proc/mounts 的信息只包含所在 namespace 的 mount point。

5) uts namespace

UTS(“UNIX Time-sharing System”) namespace 允许每个 container 拥有独立的 hostname 和 domain name, 使其在网络上可以被视作一个独立的节点而非 Host 上的一个进程。

6) user namespace

每个 container 可以有不同的 user 和 group id, 也就是说可以在 container 内部用 container 内部的用户执行程序而非 Host 上的用户。

可配额 / 可度量 - Control Groups (cgroups)

cgroups 实现了对资源的配额和度量。 cgroups 的使用非常简单,提供类似文件的接口,在 /cgroup 目录下新建一个文件夹即可新建一个 group,在此文件夹中新建 task 文件,并将 pid 写入该文件,即可实现对该进程的资源控制。groups 可以限制 blkio、cpu、cpuacct、cpuset、devices、freezer、memory、net_cls、ns 九大子系统的资源,以下是每个子系统的详细说明:

blkio 这个子系统设置限制每个块设备的输入输出控制。例如: 磁盘,光盘以及 usb 等等。

cpu 这个子系统使用调度程序为 cgroup 任务提供 cpu 的访问。

cpuacct 产生 cgroup 任务的 cpu 资源报告。

cpuset 如果是多核心的 cpu,这个子系统会为 cgroup 任务分配单独的 cpu 和内存。

devices 允许或拒绝 cgroup 任务对设备的访问。

freezer 暂停和恢复 cgroup 任务。

memory 设置每个 cgroup 的内存限制以及产生内存资源报告。

net_cls 标记每个网络包以供 cgroup 方便使用。

ns 名称空间子系统。

以上九个子系统之间也存在着一定的关系. 详情请参阅 官方文档

便携性: AUFS

AUFS (AnotherUnionFS) 是一种 Union FS, 简单来说就是支持将不同目录挂载到同一个虚拟文件系统下 (unite several directories into a single virtual filesystem) 的文件系统, 更进一步的理解, AUFS 支持为每一个成员目录 (类似 Git Branch) 设定 readonly、readwrite 和 whiteout-able 权限, 同时 AUFS 里有一个类似分层的概念, 对 readonly 权限的 branch 可以逻辑上进行修改(增量地, 不影响 readonly 部分的)。通常 Union FS 有两个用途, 一方面可以实现不借助 LVM、RAID 将多个 disk 挂到同一个目录下, 另一个更常用的就是将一个 readonly 的 branch 和一个 writeable 的 branch 联合在一起,Live CD 正是基于此方法可以允许在 OS image 不变的基础上允许用户在其上进行一些写操作。Docker 在 AUFS 上构建的 container image 也正是如此,接下来我们从启动 container 中的 linux 为例来介绍 docker 对 AUFS 特性的运用。

典型的启动 Linux 运行需要两个 FS: bootfs + rootfs:

bootfs (boot file system) 主要包含 bootloader 和 kernel, bootloader 主要是引导加载 kernel, 当 boot 成功后 kernel 被加载到内存中后 bootfs 就被 umount 了. rootfs (root file system) 包含的就是典型 Linux 系统中的 /dev, /proc,/bin, /etc 等标准目录和文件。

对于不同的 linux 发行版, bootfs 基本是一致的, 但 rootfs 会有差别, 因此不同的发行版可以公用 bootfs 如下图:

典型的 Linux 在启动后,首先将 rootfs 设置为 readonly, 进行一系列检查, 然后将其切换为 “readwrite” 供用户使用。在 Docker 中,初始化时也是将 rootfs 以 readonly 方式加载并检查,然而接下来利用 union mount 的方式将一个 readwrite 文件系统挂载在 readonly 的 rootfs 之上,并且允许再次将下层的 FS(file system) 设定为 readonly 并且向上叠加, 这样一组 readonly 和一个 writeable 的结构构成一个 container 的运行时态, 每一个 FS 被称作一个 FS 层。如下图:

得益于 AUFS 的特性, 每一个对 readonly 层文件 / 目录的修改都只会存在于上层的 writeable 层中。这样由于不存在竞争, 多个 container 可以共享 readonly 的 FS 层。 所以 Docker 将 readonly 的 FS 层称作 “image” - 对于 container 而言整个 rootfs 都是 read-write 的,但事实上所有的修改都写入最上层的 writeable 层中, image 不保存用户状态,只用于模板、新建和复制使用。

上层的 image 依赖下层的 image,因此 Docker 中把下层的 image 称作父 image,没有父 image 的 image 称作 base image。因此想要从一个 image 启动一个 container,Docker 会先加载这个 image 和依赖的父 images 以及 base image,用户的进程运行在 writeable 的 layer 中。所有 parent image 中的数据信息以及 ID、网络和 lxc 管理的资源限制等具体 container 的配置,构成一个 Docker 概念上的 container。如下图:

安全性: AppArmor, SELinux, GRSEC

安全永远是相对的,这里有三个方面可以考虑 Docker 的安全特性:

由 kernel namespaces 和 cgroups 实现的 Linux 系统固有的安全标准;
Docker Deamon 的安全接口;
Linux 本身的安全加固解决方案, 类如 AppArmor, SELinux;
由于安全属于非常具体的技术,这里不在赘述,请直接参阅Docker 官方文档

赞赏是最好的支持与鼓励!
-------------本文结束感谢您的阅读-------------