容器基础Docker
开源基金会lsf和alf
1. 容器简介
- 什么是容器
· 统称来说,容器是一种工具,指的是可以装下其它物品的工具。
· linux容器是与系统其它部分隔开的一系列进程,从另一个镜像运行,并由该镜像提供进程所需的全部文件 - 特点
· 将应用程序封装成一个包标准化的单元用于实现开发运输和部署
· 容器提供的镜像包含了应用的所有依赖项,因而在从开发测试再到生产的整个过程中,它都具有可移植性和一致性 - linux中容器所依赖的6中名称空间
需要依赖于6种名称空间来支持才能完成实现用户空间隔离技术
Name pace | Constant | Isolates |
IPC | CLONE_NEWIPC | System V IPC,POSIX message queues进程间通信机制 |
Network | CLONE_NEWNET | Network devices(网络设备),stacks(网络协议栈),ports(接口),etc. |
Mount | CLONE_newns | Mount points(挂载点) |
PID | CLONE_NEWPID | Process IDs(进程ID树) |
User | CLONE_NEWUSER | User and group IDs(用户和组的ID) |
UTS | CLONE_NEWUTS | Hostname and NIS domain name(主机名NIS域 ) |
- 容器多进程资源分配Cgroup
- 分配机制
Cgroup将进程分成多个组,将有限的资源按量配额到不同的组中,避免资源被某个用户空间的某个或某些进程完全占用,达到公平分配资源的效果 - 分配方法
- 静态分配
将资源按数量固定分配 - 动态分配
固定分配资源,但是可以将空闲的资源调配给其他用户空间,当需要使用时有权调用回来
- Control Groups(groups)管理的资源
名称 | 描述 |
blkio | 块设备IO |
cpu | CPU |
cpuacct | CPU资源使用报告 |
cpuset | 多处理器平台上的CPU集合 |
devices | 设备访问 |
freezer | 挂载或恢复任务 |
memory | 内存用来及报告 |
perf_event | 对cgroup中的任务进行统一性能测试 |
net_cls | cgroup中的任务创建的数据报文的类别标识符 |
- 用户空间部署技术LXC
- 作用
▪ 将应用软件系统打包成一个软件容器(Container),内含应用软件本身的代码,以及所需要的操作系统核心和库。
▪ 通过统一的名字空间和共用API来分配不同软件容器的可用硬件资源,创造出应用程序的独立沙箱运行环境,使得Linux用户可以容易的创建和管理系统或应用容器
▪ 通过安装的方式帮用户生成每一个用户空间(容器)的系统环境 - 缺点
迁移、使用、隔离做的不理想 - LXC控制进程所使用的内核功能
- Kernel namespaces(ipc,uts,mount,pid,network and user):
内核名称空间,内核输出给用户空间的基础特性的隔离 - Apparmor and SELinux profiles:
安全策略,一般不启用 - Seccomp policies:
安全策略,一般不启用 - Chroots(change root directory)
创建一个完全隔离的环境,方便用户在完全隔离的环境下的开发运行 - Kernel capabilities:
将内核级很多特权权限,分别用一个名称或者一组机制,分别用于分配和提供,很少用 - CGroups (control groups):
控制组,用于将CPU、Memroy、BLKIO等有限的资源分配给不同的用户空间
- lxc简单应用
- 需要安装包
主程序包:lxc
辅助程序:lxc-templates(类似脚本,利用在线centos的镜像去下载各种rpm包,在本地chroot的环境中安装生成一个可被切换成目标的文件系统) - 命令
lxc-checkconfig,lxc-ls,lxc-create(创建用户空间,会调用lxc-templates), lxc-start,lxc-console,lxc-stop,lxc-info ,lxc-clone(克隆),lxc-snapshot ,lxc-destroy
2. Docker简介
- 什么是Docker
docker最初的实现就是基于LXC,由dotCloud公司在LXC基础上引入了镜像技术,使容器的迁移变得容易,所以docker就像名称那样(码头装运共),将容器从一个码头移动到另一个码头完成装卸的一套组件,并不是容器技术(容器特性是linux内核提供的),是一种让容器技术更加易用的技术。 - Docker和传统虚拟化的区别
- 传统虚拟化
传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程 - 容器
- 应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟
- docker基于C/S结构,将做好的镜像文件模板放到公共的共享服务上,在本地装上docker引擎(也叫守护进程)dockerd,用来接收客户端(docker)指令从公共服务器上拉取模板到本地,创建并运行容器
- 容器的优缺点
- 优点
- 调了系统资源利用率
不需要进行硬件虚拟以及运行完整操作系统等额外开销,提高了系统资源利用率 - 更快速的启动时间
直接运行在宿主机的内核上,无需启动完整的操作系统 - 一致的运行环境
Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性 - 持续交付和部署
使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署 - 更轻松的迁移
由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易,不用担心运行环境的变化导致应用无法正常运行的情况 - 更轻松的维护和扩展
Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单 - 实现业务宕机的自愈功能
基于安全考虑,默认Docker Client和 Docker daemor运行在同一台主机上 - 快速部署
- 缺点
各应用之间的隔离不如虚拟机
- docker的组成
- Docker 客户端(Client)
客户端使用docker 命令或其他工具调用docker API。 - Docker 服务端(Server)
Docker守护进程,运行docker容器。 - Docker 镜像(Images)
镜像可以理解为创建实例使用的模板。 - Docker 容器(Container)
容器是从镜像生成对外提供服务的一个或一组服务。 - Docker 仓库(Registry)
镜像仓库服务器,为从多仓库镜像提供索引和认证用户,实现对应存储功能名称空间分配的认证服务 - Docker 主机(Host)
一个物理机或虚拟机,用于运行Docker服务进程和容器,此主机上运行着Docker daemor守护进程
- Docker objects
每个对象都可以被增删改查
- images:镜像
- containers:运行时的表现,即容器
- networks:网络
- volumes:存储卷
- plugins:插件
- other objects
3 Docker基本概念
3.1 Docker Registry(仓库)
镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务
- Registry作用
docker的镜像仓库服务器(Registry),通过某个套接字接收镜像的解锁和下载请求,镜像文件放在Registry后端,Registry可以认为是一个索引,用来解锁镜像是否存在并且定位,另外提供用户身份验证功能 - 镜像存放
Registry后端的存储空间上,可以存多个仓库,每个仓库通常只放一种镜像的不同版本,对仓库中的每一个镜像使用一个标签(tag)来标记,所以如果需要下载一个镜像需要先指定仓库在指定标签以:分隔(例如httpd:v2.4.32),如果不给出标签,将以 latest 作为默认标签 - Docker Registry 公开服务
- 官方Registry
Docker Hub(https://hub.docker.com/) - 国外Docker Hub的公开服务
- Google 的 Google Container Registry(长城防火墙外)
- CoreOS 的 Quay.io(正常访问)
- 国内类似Docker Hub的公开服务
- 阿里云镜像服务:dev.aliyun.com
- 网易云镜像服务
- 仓库分类
按官方和自建仓库分
- 顶层仓库(官方,引用时,镜像为原名如httpd)
- 自建仓库
例如注册账号叫moli,在账号下自建httpd仓库,引用时需要加前缀moli/httpd
3. 2 images(镜像)
- 作用
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变 - 分层存储
为了能启动容器(Containers),需要在本地拥有镜像文件(images),镜像文件存储在本地特殊的存储位置,此存储位置必须支持一种特殊的文件系统分层挂载或称为联合挂载技术(因为镜像是分层构建的) - 目前支持分层存放的文件系统有:
- aufs:高级联合文件系统
- overlayfs2:高级叠加文件系统
- dm:devicemapper,稳定性和性能不佳
3. 3 Containers(容器)
- 描述
容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样 - 容器存储层
启动的每个容器,它的读写操作都不会影响底层的镜像文件(镜像文件是只读的),所有的读写操作都会在容器的内部联合挂载的一个专用层实现,此层就是容器的存储层
容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失 - 特点
- 不像kvm启动每个虚拟机都需要一个镜像文件,docker启动容器时可以基于一个镜像启动多个容器
- 每个容器只能运行一个进程及其子进程(如果是2个进程,有一个为超管进程init),这样做的好处在于,只需要配置单个服务需要的环境,运行多个容器服务相同也不会冲突,简化容器管理
4. 安装Docker
- 系统要求
Docker CE 支持 64 位版本 CentOS 7,并且要求内核版本不低于 3.10。 CentOS 7 满足最低内核的要求,但由于内核版本比较低,部分功能(如 overlay2 存储层驱动)无法使用,并且部分功能可能不太稳定 - 程序分类
- 商业版:docker–>docker-ee
- 社区版:moby -->docker-ce
- 包获取途径
- 阿里rpm包仓库,版本相对滞后
https://mirrors.aliyun.com/centos/7/extras/x86_64/Packages/ - 阿里上docker官方repo仓库(docker-ce.repo),有各版本,包括最新版,
https://mirrors.aliyun.com/docker-ce/linux/centos/
- 安装
- 社区版,在官方获取rpm包下载到本地系统,执行yum安装
[root@hai7-1 ~]$yum install docker-ce
- 报错解决方案
错误信息
Error: Package: docker-ce-18.06.1.ce-3.el7.x86_64 (docker-ce-stable)
Requires: container-selinux >= 2.9
- 解决方案,先安装如下包
[root@hai7-1 ~]$yum install -y http://mirror.centos.org/centos/7/extras/x86_64/Packages/container-selinux-2.66-1.el7.noarch.rpm
- 安装成功后info产看详细信息,出现如下报错
错误提示,会影响创建容器
[root@hai7-2 ~]$docker info
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
- 解决方案,将以下文件值修改为1
1. '可以命令行零时赋值修改'
[root@hai7-2 ~]$cat /proc/sys/net/bridge/bridge-nf-call-iptables
[root@hai7-2 ~]$cat /proc/sys/net/bridge/bridge-nf-call-ip6tables
2. '永久修改,保存至配置文件'
[root@hai7-2 ~]$vim /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
3. '重新载入生效'
[root@hai7-2 ~]$sysctl -p /etc/sysctl.d/docker.conf
- 镜像加速器
- 国内加速服务
- 中国科技大学提供的docker加速器
- 阿里云的加速器dev.aliyun.com 需要注册账号,登陆后在管理中心中找到镜像加速器
- 以阿里云为例
在/etc下创建docker目录
[root@hai7-1 ~]$mkdir /etc/docker
- 编辑生成daemon.json文件,加阿里加速连接复制到文件内
[root@hai7-1 ~]$vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://h480ply5.mirror.aliyuncs.com"]
}
- 查看是否生效,info中找到Registry Mirrors
[root@hai7-1 ~]$docker info
Registry Mirrors:
https://h480ply5.mirror.aliyuncs.com/
- 启动docker服务
相关文件:/usr/lib/systemd/system/docker.service
1. '通知systemd重载配置文件'
[root@hai7-1 ~]$systemctl daemon-reload
2. '启动服务'
[root@hai7-1 ~]$systemctl start docker
服务启动后,会将iptables的filter表的FORWARD链修改为默认drop,如果有需要可以修改回accept
'修改docker服务文件,需要重新载入systemctl和启动服务'
[root@hai7-1 ~]$vim /usr/lib/systemd/system/docker.service
[Service] <==在service块下,增加如下行
ExecStartPost=/usr/sbin/iptables -P FORWARD ACCEPT
- 查看docker版本
[root@hai7-1 ~]$docker version
- 查看docker信息
[root@hai7-1 ~]$docker info
Containers: 0 <==容器个数
Running: 0 <==运行中的个数
Paused: 0 <==暂停态个数
Stopped: 0 <==停止态个数
Images: 0 <==当前有多少个镜像
Server Version: 18.06.1-ce <==服务器版本
Storage Driver: overlay2 <==存储后端驱动,重要信息
Backing Filesystem: xfs <==建立在本地系统xfs上
Supports d_type: true
Native Overlay Diff: true
Logging Driver: json-file <==日志驱动
Cgroup Driver: cgroupfs <==控制组的驱动
Plugins: <==启用的插件
Volume: local <==存储卷插件
Network: bridge(桥接式) host(宿主机) macvlan null(没有) overlay(叠加网络) <==网络插件
Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog<==日志插件
Swarm: inactive <==docker内部的容器编排工具
Runtimes: runc <==运行时环境
。。。省略
Insecure Registries: <==非安全仓库
127.0.0.0/8
Registry Mirrors: <==加速器,上面配置生效的
https://h480ply5.mirror.aliyuncs.com/
Live Restore Enabled: false
5. Docker管理命令
在新版中docker命令进行二三级子命令分组,仍然支持直接执行(例如docker rmi和docker image rm效果相同),常用命令图示,圆形表示docker运行状态,长方形表示执行的操作
异常终止状态OOM:非计划内终止,容器所在的宿主机被耗尽,当内核察觉内存有被耗尽的危险时会执行结束最耗内存进程的操作
container process exited:遇到BUG或者其他问题崩溃
6. 管理容器
- 容器管理命令
- 查看管理容器子命令
[root@hai7-1 ~]$docker container
- 格式
docker container COMMAND - 常用子命令
pause
:暂停unpause
:恢复暂停create
:创建一个新容器start
:启动一个或多个已停止的容器run
:在新容器中运行命令attach
:附加到正在运行的容器上restart
:重新启动容器stop
:停止一个或多个正在运行的容器,相当于kill信号15kill
:杀掉一个或多个容器,相当于kill信号9rm
:容器删除时,其相关数据也会删除- exec:在正在运行的容器中运行命令
- 语法格式
docker container exec [OPTIONS] CONTAINER COMMAND [ARG…] - 参数描述
CONTAINER:在哪个容器内部
COMMAND:运行什么命令 - 选项
-i :交互式运行,保持STDIN开放状态,由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回
-t:附加终端 - 示例
查看容器网络地址,支持以前版本写法,可以省略container,执行后就退出
[root@hai7-1 ~]$docker exec web1 ifconfig
- 如果想要进入容器多执行几个命令 ,需要其内部运行shell命令,需要附着在控制台上
[root@hai7-1 ~]$docker exec -it web1 /bin/bash
bash-4.4# <==进入交互界面
bash-4.4# pwd
/usr/local/apache2 <==httpd登录交互式界面默认路径
bash-4.4# cd conf
bash-4.4# ls
extra httpd.conf magic mime.types original <==配置文件所在,可以修改
- 创建容器
- 当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从公有仓库下载
- 利用镜像创建并启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个 ip 地址给容器
- 执行用户指定的应用程序
- 执行完毕后容器被终止
- 创建容器
-i :打开交互式界面(不打开交互式给予容器终端,一启动就会停止),
-n: 命名
-t :附加终端,一定要保证容器内的进程运行在前台
,只要容器内的唯一进程离开了控制台,此容器就挂掉了
1. '启动容器'
[root@hai7-1 ~]$docker container run --name a1 -it alpine:3.8
2. '启动后如果输入exit(退出容器后,进程就会关掉,使用命令查看,处于Exited状态'
[root@hai7-1 ~]$docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
622f2a8614fb alpine:3.8 "/bin/sh" About a minute ago Exited (0) 10 seconds ago a1
- run的其他选项
后台运行,会释放终端-d,输出结果可以通过docker container logs
查看
[root@hai7-1 ~]$docker container run --name web1 -d httpd:2.4.37-alpine
- 启动容器时,加–rm选项,会在退出后自动删除,而不是处于Exited状态
[root@hai7-1 ~]$docker container run --name a1 -it --rm alpine
- 容器httpd前台运行命令
1. '拖一个httpd镜像'
[root@hai7-1 ~]$docker pull httpd:2.4.37-alpine
2. '查看此镜像详细信息,找到CMD,可以通过自行修改镜像中默认运行的应用程序,方法就是在docker run时后面加上自定义的命令'
[root@hai7-1 ~]$docker image inspect httpd:2.4.37-alpine
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"httpd-foreground\"]" <==-foreground默认启动为前台
- 终止容器
- 使用命令
docker container stop
- 加容器交互界面中通过
exit
或者Ctrl+d
退出终端,容器也会终止,使容器处于Exited状态
- 启动已终止的容器
- 恢复退出状态的容器,可以跟NAMES(a1)也可以跟CONTAINER ID,因为其shell一直处于运行状态,它有终端,只不过没有打开
[root@hai7-1 ~]$docker container start a1
- 启动后,需要关联进容器
[root@hai7-1 ~]$docker container attach a1
- 从终端剥离出来,不退出
CTRL+p
同时按,然后按CTRL+q
,关联回去命令同上
- 删除容器
- 删除终止状态的容器
docker container rm
- 删除运行中的容器-f选项,a1为容器名
[root@hai7-1 ~]$docker container rm -f a1
- 清除所有处于终止状态的容器
docker container prune
- 获取容器的日志信息
[root@hai7-1 ~]$docker container logs web1
- 查看容器中进程占用情况,在容器外可使用命令直接查看
[root@hai7-1 ~]$docker top web1
- 动态查看容器资源消耗情况统计信息
以下写法效果相同
[root@hai7-1 ~]$docker stats
[root@hai7-1 ~]$docker container stats
- 列出所有容器,处于停止状态的容器需要加-a
docker ps
docker container ls
7 Docker默认网络
- 默认桥
启动docker后,系统会自动生成一个桥docker0,地址为172.17.0.1/16,后续创建容器时,如果没有指定网络,会自动创建一对虚拟网卡,连接容器和此桥
1. '启动httpd容器,使用默认网络,连接至连接docker0,会分配一个172.17的地址'
[root@hai7-1 ~]$docker container run --name web1 httpd:2.4.37-alpine
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, `using 172.17.0.3`. Set the 'ServerName' directive globally to suppress this message
2. "在宿主机上查看httpd服务,显示已经运行"
[root@hai7-1 ~]$curl 172.17.0.3
<html><body><h1>It works!</h1></body></html>
- 默认生成iptables规则
自动生成ANET规则,将172.17段地址通过net桥都会伪装成host地址
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
- 宿主机之外的网络想要访问容器中的httpd,需要做DNET配置,docker网络服务部分解释
8. Docker Images管理
Docker镜像含有启动容器所需要的文件系统及其内容,因此,其用
于创建并启动docker容器
- 获取可用镜像信息命令
docker search:在Docker Hub搜索需要的镜像
[root@hai7-1 ~]$docker search busybox
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
busybox Busybox base image. 1396 [OK]
- 管理镜像命令
- 查看管理镜像的子命令
[root@hai7-1 ~]$docker image
- 语法格式
docker image COMMAND - 常用子命令
- pull:下载一个镜像
alpine是一个非常小的微型发行版,不指明标签,默认下载最新版,alpine是一个用来做镜像的基础系统环境,结合服务来做镜像可以压缩大小(例如基于alpine制作httpd大小可能为30M,基于centos可能需要50M),实际工作中不建议使用太小,因为自带工具太少,出现问题时只能使用容器内自带工具排查原因
[root@hai7-1 ~]$docker image pull alpine
拖一个带标签的版本
[root@hai7-1 ~]$docker image pull alpine:3.8
- rm:删除镜像
1. '删除带标签的版本'
[root@hai7-1 ~]$docker rmi alpine:3.8 <==rmi和image rm执行效果相同
2. '删除最新版本'
[root@hai7-1 ~]$docker image rm alpine
- ls:列出镜像,同
docker images
ls -a
: 显示所有信息ls --no-trunc
:不要截断信息长度ls --digests
:显示完整格式信息
完整的REPOSITORY写法是带有服务器地址和端口号的,没有指明说明是在dockhub上
[root@hai7-1 ~]$docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
| 所属仓库 | 标签 |镜像唯一的标识符|创建时间| 镜像大小 |
- inspect:查看镜像的详细信息
[root@hai7-1 ~]$docker image inspect alpine
"ContainerConfig": {
"Cmd": [
"/bin/sh", <==定义容器运行时启动的默认进程
"-c",
"#(nop) ",
"CMD [\"/bin/sh\"]"
- tag:管理镜像标签
- 格式
docker image tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
- 参数说明
SOURCE_IMAGE[:TAG]:已有的镜像
TARGET_IMAGE[:TAG]:打什么样的标签 - 示例
为镜像httpd:2.4.37-alpine打标签为httpd:2.4,会在镜像列表中额外生成一个标签项,相当于原镜像的连接
[root@hai7-1 ~]$docker image tag httpd:2.4.37-alpine httpd:2.4
- 指向非dockhub仓库的完整写法
[root@hai7-1 ~]$docker image tag httpd:2.4.37-alpine reg.moli.com:8443/moli/httpd:2.4
- 删除标签使用删除命令即可
[root@hai7-1 ~]$docker image rm reg.moli.com:8443/moli/httpd:2.4
- push:往仓库推镜像
- 镜像的结构
采用分层构建机制,最底层叫做bootfs,其上为rootfs
- bootfs:用于系统引导的文件系统,包括bootloader和kernel,容器启动后会被卸载以节约内存资源
- rootfs:提供用户空间的根本,表现为docker容器的根文件系统
- 传统模式中,
系统启动之时,内核挂载rootfs时会首先将其挂载为“只读”模式,完整性自检完成后将其重新挂载为读写模式 - 在Docker中
rootfs由内核挂载为“只读”模式,而后通过“联合挂载”技术额外为每个启动的容器挂载一个“可写”层
- 位于下层的镜像为父镜像(parent image),最底层的称为基础镜像(base image),最上层为“可读写”层,其下仅为“只读”
- 用户最终看到的内容为最上层镜像的内容,下层只要没有标记为隐藏,上层就可以看到所有下层的内容
- 运行分层构建镜像的文件系统Aufs
advanced multi-layered unification filesystem:高级多层联合文件系统
- 用于为Linux文件系统实现“联合挂载”
- aufs是之前的UnionFS的重新实现,2006年由Junjiro Okajima开发
- Docker最初使用aufs作为容器文件系统层,它目前仍作为存储后端之一来支持
- aufs的竞争产品是overlayfs,后者自从3.18版本开始被合并到Linux内核
- docker的分层镜像,除了aufs,docker还支持btrfs, devicemapper和vfs等
- 在Ubuntu系统下,docker默认Ubuntu的 aufs;而在CentOS7上,用的是devicemapper
- 镜像引用
docker daemon会试图从本地获取相关的镜像;本地镜像不存在时,其将从Registry中下载该镜像并保存到本地
- 格式
docker pull [OPTIONS] NAME[:TAG|@DIGEST]
- 选项:
-a:下载存储库中的所有镜像 - 镜像名称的完整格式
<域名/IP>[:端口号]<用户名>/<软件名>
- <域名/IP>[:端口号]:默认为Docker Hub
- <用户名>/<软件名>:默认为library
- 示例
没有给出 Docker 镜像仓库地址,因此将会从 Docker Hub 获取镜像。而镜像名称是 httpd:2.4.37,因此将会获取官方镜像 library/httpd 仓库中标签为 2.4.37的镜像
[root@hai7-1 ~]$docker pull httpd:2.4.37
- Docker Registry
Docker Registry,支持分层镜像文件的存储驱动服务器,让用户试图去收发镜像,存储镜像的一个集中式服务器。
Storage Driver:aufs,overlayfs(整合进CentOS7.5后的内核),dm(性能不佳)
- Docker Registry分类
- Sponsor Registry:
第三方的registry,供客户和Docker社区使用 - Mirror Registry:
第三方的registry,只让客户使用 - Vendor Registry:
由发布Docker镜像的供应商提供的registry - Private Registry:
通过设有防火墙和额外的安全层的私有实体提供的registry
- Docker Hub介绍
- 描述
Docker Hub是一个基于云的注册服务,允许您链接到它的代码存储库,构建您的镜像并测试它们,手动存储镜像,并链接到Docker云,以便您可以将镜像部署到您的主机
它为容器镜像的发现、分发提供了集中的资源以及变更管理、用户和团队协作以及工作流自动化贯穿整个开发流程 - Docker Hub提供的特性
- Image Repositories:镜像存放仓库
从社区和官方库中查找和提取图像,并管理、推送和从您可以访问的私有映像库中提取图像 - Automated Builds:自动构建
在对源代码存储库进行更改时自动创建新映像 - Webhooks:回调函数
自动化构建的一个特性,Webhooks允许在成功推送到存储库后触发操作,相当于触发器 - Organizations:组管理
创建工作组来管理对映像存储库的访问
- 自定义镜像
前面说过每启动一个容器,就会生成专用的读写层,删除容器此层所有数据也会丢失,如果想要保存此层内容,就需要将此层保存为镜像
- 命令格式
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
- 作用
可以将此属于此容器的,专属可写层中所作出的所有修改保存为镜像层,只保存最上层,下层本来就存在,挂载镜像层后,所依赖的下层会自动挂载 - 选项
-c:定义新的运行命令
-a:作者
-p:提交为镜像时,让容器暂停 - 示例1
基于镜像busybox运行容器b1,在专属层中创建web目录
[root@hai7-1 ~]$docker container run --name b1 -it busybox
# vi /data/web/htdocs/index.html
- 保存容器b1的专属层
[root@hai7-1 ~]$docker container commit b1
- 查看保存的专属层镜像文件,此时没有标签
[root@hai7-1 ~]$docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 36cf41410893 19 seconds ago 1.15MB
- 为镜像文件打标签
[root@hai7-1 ~]$docker image tag 36cf41410893 httpd:v0.0.1
- 运行保存的镜像文件
[root@hai7-1 ~]$docker container run --name b1-1 -it httpd:v0.0.1
/ # ls /data/web/htdocs/index.html <==可以看到原专属读写层的数据
- 示例2:自定义一个httpd镜像文件
- pull一个centos基础镜像
[root@hai7-1 ~]$docker pull centos:7
- 基于基础镜像运行容器centos-base1,安装网络基本工具net-tools,只要宿主机可以访问互联网,容器默认已经做了net,所以容器就可以访问
'启动容器centos-base1'
[root@hai7-1 ~]$docker container run --name centos-base1 -it centos:7
[root@3753003e8899 /]# yum install net-tools <==在容器中安装网络基本工具
- 安装httpd服务,根据需要安装php和php-mysql
[root@3753003e8899 /]# yum install httpd php php-mysql
- 安装vim,编辑测试页
[root@3753003e8899 /]# yum install vim
[root@3753003e8899 /]# vim /var/www/html/info.php
<?php
phpinfo();
?>
- 清除生成的零时文件,尽可能让镜像文件更小
[root@3753003e8899 /]# yum clean all
[root@3753003e8899 /]# rm -rf /var/cache/yum/
- 将此容器读写层做成镜像,并取名为centos-httpd:v0.1-2.4,会自动添加标签
[root@hai7-1 ~]$docker commit centos-base1 centos-httpd:v0.1-2.4
[root@hai7-1 ~]$docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
centos-httpd v0.1-2.4 91cb79322cc9 About a minute ago 333MB
- 将定义的镜像文件修改为默认前台启动httpd,并起名为centos-httpd:v0.2-2.4
[root@hai7-1 ~]$docker commit -a "moli<moli@163.com" -c 'CMD ["/usr/sbin/httpd","-DFOREGROUND"]' -p centos-base1 centos-httpd:v0.2-2.4
'查看镜像文件详细信息'
[root@hai7-1 ~]$docker image inspect centos-httpd:v0.2-2.4
"Cmd": [
"/usr/sbin/httpd", <==默认启动信息确认修改
"-DFOREGROUND"
'在宿主机上启动镜像,查看主页'
[root@hai7-1 ~]$docker run --name web4 centos-httpd:v0.2-2.4
- 推送镜像
将自定义的镜像推到仓库中,供其他人使用,命令为push
,示例为阿里云仓库
- 登录dev.aliyun.com,定义Registry密码,与登录阿里云的密码区分开
创建镜像仓库,如下图所示,点击下一步弹出源码地址,此示例选择本地,点击下一步创建完成 - 将自定义的镜像文件,打标签为阿里云个人仓库标签格式(在镜像仓库->操作->管理中可查看格式)
[root@hai7-1 ~]$docker tag centos-httpd:v0.2-2.4 registry.cn-qingdao.aliyuncs.com/v9/httpd:v0.2-2.4
- 登录阿里云Docker Registry,登录成功显示为Login Succeeded
[root@hai7-1 ~]$docker login --username=v9 registry.cn-qingdao.aliyuncs.com
- 使用push推镜像文件,推送成功后,在阿里云容器镜像仓库中管理->镜像版本可查看
[root@hai7-1 ~]$docker push registry.cn-qingdao.aliyuncs.com/v9/httpd
- 登出登录的阿里云仓库
[root@hai7-1 ~]$docker logout registry.cn-qingdao.aliyuncs.com
- 分发镜像的方法
- 上例中的Registry,push到仓库服务器中
- 本地 使用docker image save IMAGEID… -o /PATH/TO/SOMEFILE.tar,然后通过文件共享协议(如scp、ftp等)复制到另外一个节点上,在目标节点上使用docker image load -i PATH/TO/SOMEFILE.tar完成装入
示例:
- 保存镜像到本地磁盘
[root@hai7-1 ~]$docker image save centos-httpd:v0.2-2.4 centos-httpd:v0.1-2.4 -o /data/centos-httpd.tar
- 将保存的tar文件发送给节点102上
[root@hai7-1 ~]$scp /data/centos-httpd.tar 192.168.50.102:/data
- 在节点102上载入镜像
[root@hai7-2 ~]$docker load -i /data/centos-httpd.tar
查看载入的镜像
[root@hai7-2 ~]$docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
centos-httpd v0.2-2.4 5ec41b218157 About an hour ago 333MB
centos-httpd v0.1-2.4 91cb79322cc9 About an hour ago 333MB
- 示例:基于busybox基础镜像做一个web服务器
- 运行基础镜像busybox,其上有httpd服务,建一个页面测试文件
[root@hai7-1 ~]$docker run --name b1 -it busybox
/ # mkdir /data/veb/htdocs -p <==建页面文件目录
/ # vi /data/veb/htdocs/index.htm <==编辑页面文件
<h1>httpd server incontainer.<h1>
/ # ifconfig <==查看IP地址
inet addr:172.17.0.3 Bcast:172.17.255.255 Mask:255.255.0.0
/ # httpd -h /data/veb/htdocs -f <==启动测试,-f表示占据前台
- 在宿主机上curl查看
[root@hai7-1 ~]$curl 172.17.0.3
<h1>httpd server incontainer.<h1>
- 修改默认运行程序为httpd,并保存为镜像,busybox下的命令都是连接文件,需要指定为/bin/sh子进程才能运行
[root@hai7-1 ~]$docker commit -a "v9<v9@163.con>" -c 'CMD ["/bin/sh","-c","/bin/httpd -h /data/veb/htdocs -f"]' -p b1 tiny-httpd:v0.0.3
9. docker 网络
- 容器创建并启动时可用网络
- Closed container:封闭式容器
只有lo接口(Loopback interface),例如本机备份程序,批处理层(只是做计算) - Bridged container A:桥接式容器
统称至少有2个网络接口, lo和虚拟以太网网卡 - Joined container A & B:联盟式容器
kernel namespace的mount、PID、User相隔离,共享Network、IPC(本机间进程通信)、UTS(网络通信主机名解析)名称空间,两个容器看到相同的网络接口,至少2个网络接口,可以接桥接也可以直接加入宿主机,以先接入的容器为准 - Open container
在容器中看到的所有网络,就是宿主机的物理网卡信息
- 搭建网络命令
- 命令格式
docker network COMMAND - 选项
- ls:显示本机可用网络
[root@hai7-1 ~]$docker network ls
NETWORK ID NAME DRIVER SCOPE
将容器加入bridge,桥接式网络
b11f05b96e91 bridge bridge local
将容器加入到 host,表示使用宿主机的网络名称空间
c2caf08f51be host host local
容器加入none,就是封闭式容器(隔离网络)
272843f84c4f none null local
- prune:移除所有未被容器使用的网络
- inspect: 显示详细信息, 参数有-f,指定要使用的go模板,来获取对应数据项数据
[root@hai7-1 ~]$docker network inspect host
- create:创建网络
- 选项
-d
:要创建和管理的网络使用的驱动(bridge(桥接)、host(共享宿主机网络)、macvlan(基于mac地址划分的vlan网络)、null(无网络)、overlay(叠加网络,隧道式网络,如VXLAN,jre)),使用桥接式网络的话--gateway strings
:来指定网关是谁,网关指对应的子网网络配置给桥的地址;--ip-range strings
:地址池,不指定将使用除网关外的所有地址;--ipam-driver string
:获取地址的方式,建议使用默认的地址分配器( default);--subnet strings
:定义使用的子网,可以不指定,会使用默认的ip地址计算 - 示例:创建网络mynet0,网关为10.0.0.1,网络ID位为16
[root@hai7-1 ~]$docker network create -d bridge --gateway 10.0.0.1 --subnet 10.0.0.0/16 mynet0
1. '查看网络,可以看到创建的新网络'
[root@hai7-1 ~]$ifconfig
br-febdc741449f: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 10.0.0.1 netmask 255.255.0.0 broadcast 10.0.255.255
2. '支持修改网卡名,修改网络名,会导致docker网络连接失败'
[root@hai7-1 ~]$ifconfig br-febdc741449f down <==先禁用网络
[root@hai7-1 ~]$ip link set br-febdc741449f name docker1 <==修改为docker1
3. '将容器加入此网络中'
[root@hai7-1 ~]$docker run --name c1 --network mynet0 -it --rm busybox
4. '同时指定2个网络,只有后面的bridge网络生效'
[root@hai7-1 ~]$docker run --name c1 --network mynet0 --network bridge -it --rm busybox
- connect:接入网络
可以实现,一个容器接入多个网络
1. '启动容器时指定网络'
[root@hai7-1 ~]$docker run --name c1 --network mynet0 -it --rm busybox
2. '启动后的容器,使用connect再接入一个网络,此时容器就会增加到3个网络,bridge/mynet0/l0'
[root@hai7-1 ~]$docker network connect bridge c1
- disconnect:断开连接
将容器c1重网络mynet0断开
[root@hai7-1 ~]$docker network disconnect mynet0 c1
- rm:删除网络
[root@hai7-1 ~]$docker network rm mynet0
- 四种容器网络制定示例
- none网络接入,–network指定为none
[root@hai7-1 ~]$docker run --name b1 -it --network none busybox
/ # ifconfig <==网络中只有lo
lo inet addr:127.0.0.1 Mask:255.0.0.0
- bridge网络接入,默认接入bridge桥,可以省略 --network bridge
[root@hai7-1 ~]$docker run --name b2 -it --network bridge --rm busybox
/ # ifconfig <==网络中有两个网卡,lo和bridge
eth0 inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
lo inet addr:127.0.0.1 Mask:255.0.0.0
- 联盟式容器网络接入,指定接入其他桥
启动第一个容器,接入桥中
[root@hai7-1 ~]$docker run --name b1 -it --network bridge --rm busybox
/ # mkdir /data <==建httpd页面文件目录
/ # vi /data/index.html <==编辑页面文件
/ # httpd -h /data <==启动httpd服务,指定页面文件路径
- 启动第二个容器,将网络接入第一个容器b1中,引用格式为
--network container:b1
,b1为引用的容器,前半段为固定格式
[root@hai7-1 ~]$docker run --name b2 -it --network container:b1 --rm busybox
/ # wget -O - -q localhost <==访问当前终端,-表示输入到当前终端
hai <==看到b1的web页面,看上去与b1为同一个主机
- host网络接入
[root@hai7-1 ~]$docker run --name b3 -it --network host --rm busybox
/ # ifconfig <==所见网络为宿主机网络地址
docker0 inet addr:172.17.0.1 Bcast:172.17.255.255 Mask:255.255.0.0
ens33 inet addr:172.20.124.254 Bcast:172.20.255.255 Mask:255.255.0.0
lo inet addr:127.0.0.1 Mask:255.0.0.0
- 外部访问容器
- 传统DNAT规则
- 原理
Docker0为NAT桥,因此容器一般获得的是私有网络地址,可以把容器想像为宿主机NAT服务背后的主机,如果开放容器或其上的服务为外部网络访问,需要在宿主机上为其定义DNAT规则 - 配置
- 对宿主机某IP地址的访问全部映射给某容器地址
-A PREROUTING -d 主机IP -j DNAT --to-destination 容器IP
- 对宿主机某IP地址的某端口的访问映射给某容器地址的某端口
-A PREROUTING -d 主机IP -p {tcp|udp} --dport 主机端口 -j DNAT --to-destination 容器IP:容 器端口
- 为docker run命令使用-p选项即可实现端口映射,无须手动添加规则
- 选项-p
发布服务,将服务器上运行的进程发布net外部,从而使外部的客户端可以访问此进程 - 使用格式
- 将指定的容器端口映射至主机
所有地址
的一个动态端口-p <containerPort>
1. '运行一个httpd镜像,将80端口暴露出去'
[root@hai7-1 ~]$docker run --name web6 --rm -p 80 centos-httpd:v0.2-2.4
2. '查看容器映射至主机的端口,访问主机web服务指定以下端口,访问的就是容器中的httpd'
[root@hai7-1 ~]$docker port web6
80/tcp -> 0.0.0.0:32768
3. 'docker自动生成了iptables的dnet规则'
[root@hai7-1 ~]$iptables -t nat -nvL
Chain DOCKER (2 references)
0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:32768 to:172.17.0.2:80
- 将容器端口映射至指定的主机端口,例如httpd的80端口,如果映射到宿主机的80端口,那么宿主机的httpd服务将不能访问80端口
-p <hostPort>:<containerPort>
[root@hai7-1 ~]$docker run --name web6 --rm -p 80:80 centos-httpd:v0.2-2.4
[root@hai7-1 ~]$docker port web6
80/tcp -> 0.0.0.0:80 <==容器监听端口为宿主机的80端口
- 将指定的容器端口映射至主机指定的动态端口
-p <ip>::<containerPort>
1. '指定映射到宿主机的192.168.50.101地址上,两个冒号,第一个冒号表示宿主机的随机端口'
[root@hai7-1 ~]$docker run --name web6 --rm -p 192.168.50.101::80 centos-httpd:v0.2-2.4
2. '查看映射端口'
[root@hai7-1 ~]$docker port web6
80/tcp -> 192.168.50.101:32768
- 将指定的容器端口映射至主机指定的端口
-p <ip>:<hostPort>:<containerPort>
[root@hai7-1 ~]$docker run --name web6 --rm -p 192.168.50.101:8080:80 centos-httpd:v0.2-2.4
[root@hai7-1 ~]$docker port web6
80/tcp -> 192.168.50.101:8080
10. docker存储卷(Data Volume)
- 容器中修改文件
如下图所示,D表示删除,A为本层原有数据,C为修改数据
- 原理
如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会
从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,
只是已经被读写层中该文件的副本所隐藏,此即“写时复制(COW)”机
制
同理,删除底层文件,也不是真的删除底层原文件,只是将其标记为隐藏,假装看不到 - 缺点
- 由于以上独特特性,如果对容器底层数据执行写操作,就要将下层数据复制到读写层(附带大量的读操作),对于单个大文件性能会非常差,所以不建议将业务数据,尤其对磁盘IO要求较高的业务数据之间存储在镜像本身的文件系统中,会在容器中存放多个版本的底层数据,使镜像文件变的很大,
- 另一个不建议在容器中保存数据的原因,关闭并重启容器,其读写层数据不受影响;但删除Docker容器,则其更改将会全部丢失
- 存储于联合文件系统中,不易于宿主机访问;
- 容器间数据共享不便
- 删除容器其数据会丢失
- 解决方案:卷(volume)
- 存储卷描述
“卷”是容器上的一个或多个“目录”,此类目录可绕过联合文件系统,与宿主机
上的某目录“绑定(关联)”
- 特点
- Volume于容器初始化之时即会创建,由base image提供的卷中的数据会于此期间
完成复制 - 存储卷可以在容器之间共享和重用(不同容器使用相同的卷)
- 所有对存储卷数据的修改,是直接保存在存储卷中,而不是写时复制
- 升级镜像,不会影响存储数据
- 删除容器时,不会删除存储卷
- DOCKER中存储卷类型
Docker有两种类型的卷,每种类型都在容器中存在一个挂载点,但其在宿主机上的位置有所不同;
- Bind mount volume(绑定挂载卷)
需要指定容器上使用的目录,也需要指定宿主机上使用的目录,将两者建立映射关系 - Docker-managed volume(由docker管理的卷)
动态,指定容器使用哪个目录作为卷,在宿主机上使用哪个目录作为后端存储不能手动指定,由docker 守护进程在固定路径下创建一个子目录,此目录事先是不存在的
- 如何使用存储卷
为docker run命令使用 -v 选项即可使用Volume,一个容器可以支持多个存储器
- Docker-managed volume(由docker管理的卷)
- 创建存储卷,-v指定容器上存储目录
[root@hai7-1 ~]$docker run --name v1 -it -v /data busybox
/ # cd data <==进入/data目录
/data # cp /etc/hostname ./ <==拷贝一个文件到此目录下
/data # cat hostname
2ad52290759d <==容器的ID号
- 查看当前容器使用的存储卷
写法1:'在容器详细信息中找到Mounts字段'
[root@hai7-1 ~]$docker container inspect v1
"Mounts": [
{
"Type": "volume", <==类型
"Name": "82e12def5db0adbd6ef1cd553347d2676d2f88813d17dfc2171d615e137cf87b", <==存储卷名 "Source":"/var/lib/docker/volumes/82e12def5db0adbd6ef1cd553347d2676d2f88813d17dfc2171d615e137cf87b/_data", <==源,挂载默认在宿主机上的路径
"Destination": "/data", <==容器内路径
"Driver": "local", <==表示使用本地文件系统
"Mode": "",
"RW": true,
"Propagation": ""
}
写法2:'使用-f选项,显示一个指定的杰森格式数据项内部的模板机制'
[root@hai7-1 ~]$docker container inspect -f {{.Mounts}} v1
[{volume 82e12def5db0adbd6ef1cd553347d2676d2f88813d17dfc2171d615e137cf87b /var/lib/docker/volumes/82e12def5db0adbd6ef1cd553347d2676d2f88813d17dfc2171d615e137cf87b/_data /data local true }]
- Bind-mount Volume绑定卷
- 创建绑定卷,-v 源地址(宿主机):目标地址(容器),指定的目录会自动创建
[root@hai7-1 ~]$docker run --name v2 -it -v /data/volumes2/v2:/data busybox
- 查看指定容器使用的卷
[root@hai7-1 v2]$docker inspect -f {{.Mounts}} v2
[{bind /data/volumes2/v2 /data true rprivate}]
- Sharing volumes(共享卷)
- 多个容器的卷使用同一个主机目录,例如v1和v2容器,都使用/data/volumes/v2存储地址
[root@hai7-1 ~]$docker run --name v2 -it -v /data/volumes/v2:/data busybox
[root@hai7-1 ~]$docker run --name v1 -it -v /data/volumes/v2:/data busybox
- 复制使用其它容器的卷,为docker run命令使用
--volumes-from
选项
1. '首先为容器v1创建存储卷/data/volumes/v1'
[root@hai7-1 ~]$docker run --name v1 -it -v /data/volumes/v1:/data busybox
2. '在容器v2中应用v1的存储卷'
[root@hai7-1 ~]$docker run --name v1 -it --volumes-from v1 busybox
- 管理存储卷命令
- 格式
docker volume COMMAND
- 参数
ls:列出所有容器存储卷
[root@hai7-1 ~]$docker volume ls
DRIVER VOLUME NAME
local 80637fd1b7ab86e711c71820b528bb91e2fc13a85477cb911da62a652ed3dc84
- inspect:列出指定容器
VOLUME NAME
的详细信息
[root@hai7-1 ~]$docker volume inspect 80637fd1b7ab86e711c71820b528bb91e2fc13a85477cb911da62a652ed3dc84
动态存储卷在宿主机上存放的目录
"Mountpoint": "/var/lib/docker/volumes/80637fd1b7ab86e711c71820b528bb91e2fc13a85477cb911da62a652ed3dc84/_data",
- rm:删除存储卷
[root@hai7-1 ~]$docker volume rm VOLUME NAME