容器技术介绍

前言

虚拟化技术变革了数据中心技术

  • 一切都在软件定义 SDN,软件定义网络(Software Defined Network,SDN)是由美国斯坦福大学CLean State课题研究组提出的一种新型网络创新架构,是网络虚拟化的一种实现方式。
  • 在一个物理机上运行多个VM,切割利用物理机资源
  • 最大的问题是分派给VM系统的资源浪费,如1G内存的VM,app应用仅用100M。就是说在你的虚拟机还没有跑任何应用之前,它就已经消耗了相当大的系统资源了。
  • 虽然可共享未使用资源,但是效率损失较大

容器再次颠覆IT业界

  • 轻量级的虚拟环境(开销小),但不是我们通常意义认为的虚拟机服务器
  • 容器使用宿主机的CPU(VM有自己的CPU)
  • 容器共享宿主机的OS内核和只读库
  • 容器也可以实现应用隔离(与VM相同又不相同)。
    • 虚拟机是 应用安装在独立的虚拟机里面,是通过操作系统层面甚至是硬件层面,利用硬件层面的特点来实现的进程的隔离。
    • 而容器是 在一个宿主机上 隔离出一个应用程序的运行环境,在这个环境里面,所有的东西也是由一个宿主机里面的进程的形式去运行。不同的容器可以跑不同的程序,不同容器里面的程序彼此之间是互相隔离的。
    • 虚拟机和容器都可以实现应用的隔离,虚拟机是从硬件层面上隔离的,而容器是从操作系统内部的进程之间隔离的。它们隔离的层次不一样,从理论上讲,容器隔离出来的效果,性能是更优的。但实际比较复杂,要看实际的部署情况。
    • 虚拟机毕竟是一个独立的操作系统,它是和你的宿主机的硬件CPU打交道的,所有它对程序的隔离更加的底层、更加彻底。从安全的角度上来讲,它更安全。而容器是从操作系统里面的进程之间来隔离的,虽然也是从内核级别去完成的隔离,通过控制组的方式来实现进程之间的隔离。但是它的层级已经要比虚拟机更接近应用层,它隔离的应用的安全性要比虚拟机隔离的应用要差一些。
  • 可移植的软件实例,提高部署效率,改变开发方式

什么是容器

容器是一类技术很多产品的统称,这些的产品都会使用容器相关的手段。但是不同的容器产品,不同的人开发出来的容器的产品、技术各有各的特点,有的特点彼此不相同,设置是相反的。

  • 建议将容器看做是一个文件系统,而非虚拟机。
  • 在LInux内核里打造的轻便的、接近裸机速度的虚拟环境
  • 容器包含一个与宿主机一致的文件系统
    • ubuntu上的容器拥有一致的文件系统,看起来像是虚拟机或物理机
  • 会拷贝宿主机ubuntu中的文件,进入到它独立的文件结构里面,然后把这些程序固定在独立的文件结构里面,让它只在这个文件结里面去运行,让它逃不出这个目录结构。(放到一个新的目录中)
    • 独立运行二进制程序,而不是运行实际的操作系统
    • 应用运行在这个独立的文件系统中,与宿主机隔离
    • 拷贝宿主机的什么文件,为什么要拷贝这些。 都是依据上层要运行的应用程序来定的,把相应的应用要依赖的库环境拷贝进来。但是仅仅拷贝上层应用程序需要运行依赖的底层的系统文件,它不会把你整个宿主机的操作系统和你上层应用程序无关的文件拷贝下来。不会像虚拟机一样为了跑一个小程序把整个操作系统拷贝下来。
  • 容器只包含应用运行所需的最小资源集
  • 一个容器倾向于只运行一个应用(也可以运行多个)
  • 云时代容器技术会得到更多的重视

可移植性

  • 可移植性是容器的另一重大优势,是容器设计的核心技术
  • 保证在不同宿主机系统上获取完全相同的开发运行环境
  • 虚拟机也可导入导出,但容器移植更简单

容器并非新技术

  • Docker是目前最火的容器
  • LXC(Linux Container)

对比虚拟化技术

虚拟化技术是不是完蛋了?

  • 目前虚拟化更加成熟
  • 虚拟化拥有自己独特的优势
  • 生态已经非常成熟,包括产品、解决方案、管理工具
  • 某些场景更适合使用虚拟化
  • 会与容器长期共存

并非所有的应用都可运行于容器中,但是所有应用可以在虚拟机上运行

  • 容器适合web应用或者各种服务
  • 容器还处于飞速的发展进化阶段,特性很吸引人,但还没有一统江湖
虚拟机 容器
表现为硬件虚拟化 系统 / 应用 虚拟化
重量 轻量
交付速度慢 实时交付,可扩展
性能开销大 接近裸机性能
全隔离,更安全 进程级隔离
生态成熟 发展很快

Docker与LXD / LXC

Docker介绍

Docker目前最火,很大程度上和优秀的市场营销有关

  • Docker利用分层的方法实现容器化,这个在其他的容器技术上似乎没有出过
  • 对容器做的所有修改都会产生一个新层,这些层将会成为其他容器的依赖基础

所谓分层,我们对一个容器,容器里面要跑应用程序,对这个容器无论是做了底层的操作系统还是应用层面的所有修改都会产生一个层。所以一个Docker容器,是由很多层叠加在一起的,一个层依赖下一个层,下一个层依赖下下一个层,一直依赖到底层的操作系统的内核。我们对Docker容器做的所有修改都是修改某一层的内容。

LXD介绍

  • LXD源于LXC,Docker最早基于LXC,LXC是所有容器技术的鼻祖
  • LXC是基于控制组实现进程隔离的
  • LXD最初由Canonical创建,曾经是ubuntu独有(现在使用snap包管理)
  • LXD是对LXC的增强提高,可支持快照、ZFS、迁移
  • 可认为是LXC在其基础之上增加了额外的管理层和功能

两者比较

  • LXC可视为机器容器,更接近虚拟机
  • LXC基于一个文件系统实现容器化,可以从宿主机系统访问
  • Docker努力地将自己与虚拟机区分开来
  • Docker可视为应用程序容器,提供运行应用程序所需要的基础
  • Docker每个任务都运行在单独的层中

选择Docker还是LXD / LXC?

  • 都使用,按照应用的环境要求选择
  • Docker可以在Linux、macos、windows上运行Docker容器
  • 使用容器服务运行容器,而非自建容器服务器

其他容器技术

OpenVZ

是基于Linux内核的操作系统级别的虚拟化技术

虚拟化的系统实例称为

  • containers 容器
  • virtual private servers(VPSs)
  • virtual environments(VEs)

FreeBSD jail

  • OS-Level 虚拟化技术
  • 将基于freebsd 的系统划分为 多个称为监狱 的独立微型系统

WPARs

The AIX Workload partitions

工作负载分区

Solaris Containers

通过一个个zone (Solaris Zones)现在官方已经不在更新了。

Docker的安装和使用

docker介绍

  • Docker是一个开源的容器引擎
  • Docker容器包含独立的运行软件需要的一切
    • 包含二级制、库、配置文件、脚本、jar包等
    • 容器之间是完全隔离的,各自独立的根文件目录
  • Docker容器有自己的进程空间和网络接口

  • 组件
    • Docker engine :生成监视和管理所有容器
    • Docker Hub:映像库
    • Docker Client:管理工具
  • Docker引擎只可以直接运行在Linux系统上
    • 利用Boot2Docker等适配器帮助,使用轻量级Linux vm可在Mac和微软系统上运行

Docker的安装

安装Docker引擎

1
uname -m         # 仅在64位系统有保障,32位系统也能使用Docker,但是出了问题没有保障

安装ubuntu软件仓库Docker

1
2
sudo apt install docker.io        # 安装Docker
sudo systemctl status docker.service # 查看Docker运行状态

使用docker命令,有些服务需要sudo,如果想省事,直接用当前账号运行,就将当前用户加入docker组

1
sudo usermod -aG docker ${USER}      # 重启后生效

安装最新的Docker

ubuntu官方仓库中不是docker的最新版本

安装依赖包

1
sudo apt install apt-transport-https ca-certificates curl software-properties-common

添加docker官方库GPG key

1
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

添加docker官方库更新源

1
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

安装:

1
2
sudo apt update
sudo apt install docker-ce

简单的dokcer的命令

查看信息

1
2
docker version      # 查看版本信息
docker info

Docker registry

  • 应用程序仓库,包含基本的Linux映像、高级应用程序映像

下载映像

1
docker pull busybox

查看映像

1
docker images

运行程序

1
docker run busybox echo "hello world"

Docker有关的名词解释

Docker镜像

  • 是组成应用程序运行所需的全部文件合集
  • 只读 / 可读可写 分层结构(每次对映像的修改都是通过commit形成一个新层)
  • 容器层 是基于映像可读写的顶层
  • 所有的Docker映像都源自于一个基础映像
  • 其他的功能模块附加于基础映像形成最终程序
  • Docker images是构建Docker container的基础
  • Docker层 / 容器层

拿虚拟机来对比,虚拟机先安装一个操作系统,在操作系统部署web服务、数据库,再在上面部署web应用,都是这样一个套路和思路,和Docker内部文件的分层结构是比较像的,虽然其实它们实现上差距很远。

虚拟机这边要部署应用,首先要安装一个虚拟机的操作系统,和虚拟机相对应,Docker这边有一个层。它不是说单独安装一个虚拟机,它是有一个软件的层。这个层是一个操作系统的层。如图:

上图所示,最底下就是运行Docker引擎的宿主机操作系统的内核kernel,在运行Docker引擎运行的宿主机基础之上,你要运行Docker镜像的话,你首先要一个具有操作系统功能的软件层,在这个层里面当然不是一个完整的操作系统,它只是用于支撑你应用程序正常跑起来的必须具有的操作系统的文件。所谓Docker中的操作系统层可以选择不同的Linux发行版本,操作系统层就类似于虚拟机上安装一个操作系统。这种操作系统层在Docker内部是一个只读的层,是固定的。以后在这个不变的底层操作系统之上安装nginx等服务时,每做一次变更,变更的这些东西都会沉淀下来形成一个新的层。所以Docker内部就是有很多层,底层是基础映像,就是操作系统这一层。然后我要部署Apache,安装MySQL数据库,这些都基于底层沉淀下来,形成新层,它是只读的,拿着生成好的映像可以去使用了。底层是只读的,最顶层也就是各种应用是可读可写的,被称为容器层,底层的被称为映像层。容器层加上映像层,把这些可读可写的、只读的各种层打包完成完整在一起的综合的环境,最终成为一个容器。

我们所说的Docker容器,必须要以映像也就是images为基础才能构建起来。最上面的也就是容器层,是可读可写的,在容器层下面的是只读的映像,最下面的就是基础映像,也就是提供操作系统层相应功能的。上层的每一个层都是要基于下层的基础层和它的父层才能够正常的工作起来的。

所以容器层指的是最上面的可读可写的那一层,映像层是下面每一个只读的、不可写的、固化下来的文件内容。一般我们说容器的时候,容器是指所有层,把它们综合起来形成的一个整体软件运行所需要环境的集合。

每一个映像都有唯一的ID(SHA256的前6个字节)

就是一些SHA256的哈希值,对Docker容器计算一个哈希值,我们知道哈希值都是单向加密,会生成一个唯一的一串字符串来代表文件。现在我们知道md5、SHA1这样的哈希加密算法都已经被发现存在安全漏洞了,所以现在Docker使用SHA256的哈希算法,目前来说是认为安全的。但是SHA256会生成256位二进制位的一长串数据,256位也就对应32个字节,32个字节太长了,为了方便使用,我们把32个字节的前6个字节作为每一个Docker映像的ID值。可以通过命令查看:

1
docker images

  • REPOSITORY,:表示的是 库名,如果是个人的库,用户名 / 库名。
  • TAG:标签,最新版本显示latest
  • IMAGE ID:就是SHA256的哈希值,为了方便显示,我们只显示前6个字节,是12个16进制数。
  • CREATED:创建日期
  • SIZE:映像大小

查看完整的SHA256哈希值:

1
docker images --no-trunc

下载映像默认是现在latest版本的,如果要下载全部的版本可以:

1
docker pull busybox -a

删除映像:

1
docker rmi busybox:标签名

每一个容器也有唯一的ID

容器指的是运行程序的容器,映像是容器要基于这个映像运行的。

1
2
3
4
5
6
7
docker ps -a       # 查看运行的、已经停止运行的容器

docker run busybox:1_uclibc echo "hello world" # 指定具体的标签运行,默认是latest

docker rm 容器ID # 删除容器

# 注意:删除必须先删除容器,再删除映像

Docker注册中心

Docker Registry

  • 提供开放的映像注册、查找、访问、使用的中央位置
  • 官方注册中心提供多重检查检验的高质量映像(可以个人自建)
  • 注册用户可以发布自己定制的映像

Repository

  • 映像在注册中心里的具体存储位置,命名空间
  • 注册用户拥有自己的库

Docker Hub Registry

  • Docker 社区创建的官方映像库 / 第三方映像分享平台
  • docker search ubuntu ,默认访问地址 https://index.docker.io/
  • docker pull ubuntu 下载映像,使用数字签名,异常告警
  • docker pull registry.example.com/myapp (自建映像库)

我们可以把自己的映像提交到Docker Hub Registry,其他人就可以下载使用。

官方提供的是Docker Hub Registry,我们个人可以在自己的电脑上安装自己的Docker Registry,这样可以把你的这台服务器安装成Registry,内部可以创建自建的映像,可以传到公司内部的Registry服务器上保存。这样可以使用公司自己搭建的Docker Registry去下载映像。这样的好处是,可以使用适合自己公司应用系统所需要的映像,可以简化和提高应用环境的部署效率。

Registry相当于一个目录,相当于软件包管理的索引,它不是存放具体的映像位置,只是注册中心。具体存放映像文件的是Repository。

Docker命令

搜索映像

1
docker search mysql

交互登录

1
2
3
4
5
6
docker run -it ubuntu /bin/bash        # 基于ubuntu映像运行终端,运行这个容器的时候,基于这个映像去创建一个容器,在容器里面去运行bash这个程序,通过-it参数,t就是terminal,i就是一种交互式的形式,这样就会得到一个docker终端的命令提示符,在这个提示符下输入命令都是运行在在容器里面的。

PORTS:端口映射(对外提供服务)
NAMES:自动随机生成的容器名

exit 或者 ctrl+D #

我们发现登录进来就是以root账号运行的,主机名就是容器sha256哈希值的前6个字节,但是这个名字不好记忆。我们可以在创建容器的时候指定名字

1
docker run --name D01 -it ubuntu /bin/bash

exit 或者 ctrl+D退出的时候,容器已经是停止的状态,这样不方便使用。我们可以退出容器,但是又能保证退出容器之后保持运行的状态:

1
(ctrl+P) + (ctrl+Q)     # 使用组合键,可以退出并保持容器运行

如图所示,容器的状态是up,没有关闭,NAMES就是我们自己改的名字,我们可以使用这个名字也可以使用ID值。

1
2
3
4
5
6
7
8
docker start 3f7ee034a5c1      # 启动已经关闭的容器

# 当容器处于up 的状态,进入容器
docker attach D01

docker ps -a --no-trunc # 显示完整的容器的哈希值

docker rename 3f7ee034a5c1 D02 # 改名字

容器与映像的变化

1
2
3
4
5
docker diff D01

C: 修改
A:增加
D:删除

日常管理的命令

1
2
3
4
5
6
docker start D01    # 开启
docker stop D01 # 关闭
docker restart D01 # 重启
docker rename D01 D03 # 重命名
docker pause D01 # 状态冻结住,冻结住不能做其他操作
docker unpause D01 # 解除冻结状态

创建映像

1
2
3
4
5
6
docker run  -it ubuntu /bin/bash
touch {a,b,c,d}.txt
(ctrl+P) + (ctrl+Q)

# 对Docker容器修改好了,如果想把这个版本的Docker容器保留下来,形成一个新的Docker
docker commit 3f7ee034a5c1 cwz/web:0.1 # 以自己用户名在中心注册器上面注册账号,image的名称,标签标识的版本号,形成一个新的映像,当前是保存在自己的计算机上的,但是可以按照路径、命名上传到Docker Hub Registry官方服务器上。

基于新映像创建容器

1
docker run -it cwz/web:0.1 /bin/bash

后台运行容器

1
docker run -d cwz/web:0.1 /bin/bash -c "while true; do date; sleep 5; done"   # 一直循环,每隔5秒钟显示date

查看日志

1
docker logs b3a167814fdd

容器运行服务

运行Apache服务

1
2
3
4
5
6
7
8
9
10
11
# 外部网络默认是不能访问Docker内部网络
docker run --name web -dit -p 8080:80 ubuntu /bin/bash # 宿主机的8080端口会映射到80端口中,-d是以后台形式运行

docker attach 97e4dd8bd0a6 # 进入bash终端
apt update && apt install apache2 # 在容器内部安装Apache

/etc/init.d/apache2 start # 在容器内部启动apache服务

(ctrl+P+Q) # 退出

# 宿主机浏览器访问:http://localhost:8080

服务自动启动

上述是手动启动了apache服务,如果下次还要启动容器,还需要手动启动Apache服务,就会比较麻烦。

1
2
3
4
5
apt install nano    # 安装文本编辑器,Docker映像系统为了更精简,只安装了操作系统必须的文件,其他什么都没有

nano /etc/bash.bashrc
# 编辑文件,在文件的最下方加上
/etc/init.d/apache2 start

创建新映像

1
2
3
docker commit web cwz/apache:1.0

# 可以上传到服务器上去,供其他人使用

使用Dockerfiles自动创建映像

在上面的操作中,你打包好了一个容器上传到服务器上,你的同事下载下来使用,在这一过程中,虽然只是下载了几百兆,但还是感觉不是很方便。在实际的环境中,可以更加的高效的使用。

使用Dockerfiles自动创建映像,不把最终创建的结果作为传递给使用者的最终文件,而把我是怎么准备、怎么最终创建的映像 这一过程所有的指令保存到一个文本文件里面,让使用者拿着所有指令的文件到他们的电脑里面再运行一遍。这样就只需要拷贝几十k文件就行了。

1
2
3
4
5
6
7
vi Dockerfile
# 配置:
FROM ubuntu # 会去官方服务器的库里面找到ubuntu,下载下来
MAINTAINER cwz <cwzdzg@163.com> # 维护者的名字、邮箱地址
RUN apt update; apt dis-upgrade -y
RUN apt install -y apache2 nano
RUN echo "etc/init.d/apache2 start" >> /etc/bash.bashrc

使用者拿到Dockerfile文件,前提是使用者安装好了docker软件。容器什么也没有创建,也不知道怎么创建。他只要运行一下命令:

1
docker build -t yyy/apache:1.0 .      # 只要指定容器的名称和标签信息,不要忘了后面的.,.是使用当前的Dockerfile文件

使用:

1
docker run -dit -p 8080:80 yyy/apache:1.0 /bin/bash

LXD安装与使用

LXD的安装

1
2
3
sudo snap install lxd 
sudo usermod -aG lxd ${USER} # 将当前用户名加入到lxd组
# 重启主机

初始化

1
2
lxd init
# 会有一些提示,默认即可

LXD和Docker最大的不同就是LXD更倾向于是一个操作系统的容器,更接近一个虚拟机。

运行容器:

1
2
lxc launch ubuntu:18.04 C01   # 默认情况下基于ubuntu远程的存储服务器库,下载ubuntu18.04的版本的映像,把它作为底层的基础映像
# 自动下载映像并创建、运行容器

lxd命令针对lxd管理层,容器管理命令仍然使用lxc

LXD常用管理命令

1
2
3
4
5
6
lxc list        # 列出容器
lxc start <container> # 启动容器
lxc stop <container> # 停止容器
lxc delete <container> # 删除容器
lxc image list # 查看映像
lxc image delete <img_name> # 删除映像

交互登录容器

1
2
3
4
5
lxc exec C01 bash       # 以root账号登录,获得一个shell
lxc exec C01 --sudo --login --user ubuntu
# ubuntu映像包含一个默认用户账户 ubuntu,以ubuntu账号登录

lxc exec C01 -- apt update # 不登录容器使用

LXD特点

  • lxd部署容器过程比Docker更容易
  • lxd容器没有分层的概念,Docker进行分层的好处就是创建容器的时候会更加的灵活,能更加容易去组合不同层的功能。lxd不能分层,在灵活性上比Docker存在劣势,但管理起来更加直接、清晰。
  • Docker中的层可以使得部署更快,但是管理起来会比较乱。
  • 退出方面也有不同,输入ctrl+d或者exit,docker会停止容器,而lxd不会。
1
2
# 随着宿主机启动而启动容器
lxc config set C01 boot.autostart 1

lxd创建容器

远程映像存储服务器

1
2
3
4
5
lxc remote list       # 默认远程连接了3个存储

images下放的不是ubuntu的映像,是其他Linux发行版的映像
ubuntu 是稳定版的ubuntu映像
ubuntu-daily 是每日最新的ubuntu映像

从远程复制映像

1
2
3
4
lxc launch images:debian/stretch test01

lxc image copy ubuntu:18.10 local: --alias u1810
# 从ubuntu存储复制映像到本地存储,其别名为u1810

创建容器

1
lxc launch u1810 C02  

上传下载文件

1
2
lxc file pull C01 /etc/hosts .      # 在宿主机里面下载容器里面的文件
lxc file push hosts C01 /tmp/ # 上传文件到C01容器里面

映像自动更新间隔

1
lxc config set images.auto_update_interval 24   # 每隔24小时更新映像

自动清除未使用的映像

1
lxc config set images.remote_cache_expiry 5     # 5天清除一次

查看配置

1
lxc config show

安装apache2服务

1
2
3
4
5
lxc exec C01 bash
apt update && apt install apache2

ip addr show
curl 1.1.1.1

外网访问

需要在宿主机上创建桥接网卡br0,通过桥接网卡将外部的访问引到lxd容器里面,两种方式:

  • 防火墙规则路由流量
  • 创建配置文件 DHCP 获取物理网络地址(类似于虚拟机)