Docker系列文章
第一章 Docker 的认识与使用
文章目录
- 前言
- 一、Docker架构
- 1.1.Docker是什么?
- 1.2.Docker的优势
- 1.2.1.与传统虚拟机对比
- 1.3.Docker基本概念
- 1.3.1.架构
- 1.3.2.镜像(Image)
- 1.3.3.容器(Container)
- 1.3.4.仓库(Registry)
- 1.3.5.数据卷(Volume)
- 二、Docker安装
- 2.1.CentOS安装Docker
- 2.1.1.安装Docker-ce
- 2.2.Docker镜像加速
- 2.2.1.方式一:镜像中心仓库拉取(无需配置)
- 2.2.2.方式二:配置加速器地址(推荐)
- 三、Docker配置文件认识
- 3.1.key.json
- 3.2.daemon.json
- 3.3.1.配置参数详解
- 四、Docker基本操作
- 4.1.docker info|version|帮助命令
- 4.2.容器声明周期管理命令
- 4.3.容器操作
- 4.4.容器rootfs命令
- 4.5.镜像仓库命令
- 4.6.本地镜像管理命令
- 五、Docker构建镜像的三种方式
- 5.1.基于容器构建镜像
- 5.1.1.构建镜像步骤
- 5.1.2.构建部署war包案例
- 5.2.基于本地模板导入
- 5.3.Dockerfile构建
- 5.3.1.什么是Dockerfile
- 5.3.2.Dockerfile指令分类
- 5.3.2.Dockerfile指令说明
- 5.3.3.Dockerfile构建案例
- 5.3.3.1.Dockerfile构建nginx
- 5.3.3.2.Dockerfile构建springboot手动打包
- 5.3.3.3.Dockerfile构建springboot maven源码打包
- 5.3.3.3.Dockerfile构建springboot maven插件打包
- 六、Docker仓库使用
- 6.1.Docker官方仓库
- 6.1.1注册仓库
- 6.1.2.登录仓库
- 6.1.3.推送镜像
- 6.1.4.拉取镜像
- 6.2.私有仓库
- 6.2.1.搭建仓库
- 6.2.2.配置仓库
- 6.2.3.推送镜像
- 6.2.4.拉取镜像
- 七、Docker使用数据卷挂载
- 7.1.数据卷普通挂载:-v
- 7.1.1.不指定主机目录
- 7.1.2.指定主机目录
- 7.2.数据卷容器:volumes-from
- 7.2.1.基本使用
- 7.2.2.挂载多个
- 7.2.2.1.mysql5.7部署准备工作
- 7.2.2.2.nginx部署准备工作
- 7.2.2.3. 创建数据卷容器
- 7.2.2.4. 启动容器指定数据卷容器
- 7.2.3.数据卷容器备份、迁移、恢复数据
- 7.2.3.1.创建数据卷容器
- 7.2.3.2.使用数据卷容器
- 7.2.3.3.备份数据卷数据
- 7.2.3.4.备份数据迁移
- 7.2.3.5.恢复数据卷数据
前言
断断续续花了两个月时间,吐血整理分享,全网最详细,如有引用转载还请标明出处,谢谢
一、Docker架构
1.1.Docker是什么?
Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机)、 bare metal、OpenStack 集群和其他的基础应用平台。Docker是使用Go语言实现,基于Linux内核的Cgroups,Namespace以及Union FS等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术。简单地说Docker作为一个软件集装箱化平台,可以让开发者构建应用程序时,将它与其依赖环境一起打包到一个容器中,很容易地发布和应用到任意平台中。
1.2.Docker的优势
- 更高效地利用系统资源
节省硬件虚拟化及完整OS的开销,应用执行速度、内存损耗、文件存储更高效,一个相同配置的主机,往往可以运行更多的应用 - 更高效的虚拟化
Docker 容器的运行不需要额外的 hypervisor 支持, 它是内核级的虚拟化, 因此可以实
现更高的性能和效率 - 更快速的启动时间
直接运行于宿主机内核,无需启动完整的OS,启动时间为秒级、甚至毫秒级 - 一致的运行环境
Docker镜像提供了除内核外完整的运行时环境,确保了应用运行环境的一致性。 - 持续集成持续部署快速交付
利用Dockerfile进行镜像构建,并结合CI/CD系统进行测试和部署。一次的创建于配置即可在任何地方运行。开发者使用标准镜像构建容器后,运维可直接使用该容器部署,并且可以快速创建容器,迭代应用程序 - 更轻松的迁移扩展
Docker可以在很多平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、 服务器等 - 更简单的管理
使用 Docker, 只需要小小的修改, 就可以替代以往大量的更新工作。 所有的修改都以
增量的方式被分发和更新, 从而实现自动化并且高效的管理
1.2.1.与传统虚拟机对比
对比项 | Docker容器 | 虚拟机 |
启动 | 秒级 | 分钟级 |
性能 | 接近原生 | 弱于 |
内存代价 | 很小 | 较弱 |
迁移性 | 优秀 | 一般 |
硬盘使用 | 一般为 MB | 一般为 GB |
系统支持量 | 单机支持上千个容器 | 一般几十个 |
连同环境一起构建打包(备份),一次打包处处运行。直接把项目发布到Docker容器中,测试、迭代,上线时直接运行镜像(代码连同配置都无变化)
1.3.Docker基本概念
1.3.1.架构
组成 | 描述 |
Image | Docker镜像,用于创建Docker容器的模板 |
Container | Docker容器,独立运行的一个或一组应用 |
Client | Docker客户端,使用Docker Api与Docker的守护进程通信 |
Host | Docker主机,一个物理或者虚拟的机器用于执行Docker守护进程和容器 |
Registry | Docker仓库,用来保护镜像 |
Machine | 一个简化Docker安装的命令行工具,比如VirtualBox、Digital OcEAN、Microsoft Azure |
1.3.2.镜像(Image)
镜像的本质是磁盘上一系列文件的集合。Docker镜像文件,提供了一个快速部署的模板,包含了已经打包好的应用程序和运行环境,基于image可以快速部署多个相同的容器。
Docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置文件外,还包含了一些为运行时准备的一些配置参数,镜像不包含任何动态数据,其内容在构建之后也不会改变。
镜像包含OS完整的Root文件系统,其体积往往是庞大的,因此在Docker设计时,充分利用了Union FS的技术,设计为分层存储的架构,所以严格意义来说,镜像只是一个虚拟的概念,其由多层文件系统联合组成。
镜像构建时,前一层是后一层的基础,每一层构建完不会再发生改变,后一层的任何改变只发生在自己这一层。分层存储的特征还使得镜像的复用、定制变得更加容易。
镜像就是上图中加锁部分的一层层(Image layer)只读层(read-only layer),可以是一层或者多层构成。而容器则只是在镜像上添加一个可写层(read-write-layer)。已经构建的镜像会设置成只读模式。层与层之间不相互影响,除了底层外,其它层都会有一个指针指向下一层,Docker的统一文件系统(union file system)技术将不同的层整合成一个文件系统,为这些层提供了一个统一视角,这样便隐藏了多层的存在,在用户视角看来只存在一个文件系统。
1.3.3.容器(Container)
镜像和容器的关系,类似于面向对象中的类与实例一样,镜像是静态的定义,容器是镜像运行的实体,容器可以被创建、启动、停止、删除、暂停等。
容器的实质是进程,当与直接在宿主机执行的进程不同,容器可以拥有自己的Root文件系统、网络配置、进程空间等。
分层存储, 每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层(可写层)。容器存储层的生命周期与容器一样,当容器消亡时,容器存储层(可写层)也会随着消亡,任何保存于容器存储层的信息都会随着被删除。
容器其实只是在镜像上面添加一个可写层,每当对这个容器进行修改都会在可写层表明与原本镜像的不同之处,当使用 docker commit 命令时,只是提交了一个可写层,将它编成了一个不可写的镜像层,而这个新的镜像和原本的镜像共享原本镜像的所有层,这个就是所谓的Docker分层机制。我们可以简单的概括为:容器 = 镜像 + 可写层。
一个运行态容器(running container)被定义为一个可读写的统一文件系统加上隔离的进程空间和包含其中的进程。下图为一个运行中的容器:
在容器中的进程对文件的创建、修改、删除的改变都会作用于读写层(Read-Write-Layer)如下图所示,创建一个文件过程:
1.3.4.仓库(Registry)
镜像构建完成后,可以很容易地在当前宿主机上运行,但是如果需要在其他机器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Registry就是这样的服务。一个Docker Registry可以包含多个仓库(Repository),每个仓库可以包含多个标签,每个标签对应一个镜像通常一个仓库会包含同一个软件不同版本的镜像。仓库名经常以两段式路径形式出现,如 jwilder/nginx-proxy,前者往往为 Docker Registry 多用户环境下的用户名,后者则对应软件名。
镜像就类似于Java中的Class,镜像层间属于继承关系,容器就类似于 new 实例化的对象。镜像可以通过tar文件导入,或者导出成tar文件,也可以从仓库中拉取或则推往仓库。镜像通过 start 命令后实例化成为容器,容器可以通过 commit 生成镜像,期间的运行关系如图所示。
1.3.5.数据卷(Volume)
在上文容器的介绍中我们了解到,一旦容器消亡时可写层也会随之消亡,如果运行中的数据直接保存在容器可写层那么数据也是会随之丢失。如果需要在Docker中对数据进行持久化,或者需要在多个容器之间进行数据共享,就会涉及到数据管理。Docker提出了Volume概念,简单说Volume 就是目录或者文件,它可以将容器以及容器产生的数据分离开绕过联合文件系统(Union File System),以常规的文件或者目录形式存在于宿主机上。
Docker对数据管理方式有两种:一个是 数据卷(Volumes)将主机操作系统目录直接映射进容器,二是 数据卷容器(Volumes Containers)使用特定容器维护数据卷。Volumes是一个可供容器使用的特殊目录,类似Linux中的mount操作,具有以下几个特点:
(1)数据卷可以在容器之间共享和重用,容器间的数据传递更加高效;
(2)对数据卷进行修改会立马生效,不论是在容器内操作还是在本地操作;
(3)对数据卷的修改不会影响镜像,解耦开应用和数据;
(4)卷会一直存在直到没有容器使用,可以安全地卸载它
二、Docker安装
2.1.CentOS安装Docker
2.1.1.安装Docker-ce
# 准备工作:
# 1.安装系统工具在这里插入图片描述
yum install -y yum-utils device-mapper-persistent-data lvm2
# 2.配置源地址(可选择国内的源地址,我这里配置阿里云)
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 3.更新缓存
yum makecache fast
# 4.安装:
# 4.1方式一:最新版本安装
yum install -y docker-ce docker-ce-cli containerd.io
# 4.2.方式二:指定版本安装
# 列出可用版本
yum list docker-ce --showduplicates | sort -r
# 选择安装指定版本(其中<version>替换为需要安装的版本号如:18.09.9)
yum install docker-ce-<version> docker-ce-cli-<version> containerd.io
# 5.查看版本确认安装结果
docker version
# 6.启动docker
systemctl start docker
# 7.设置开机启动
systemctl enable docker
附:我采用的方式是二,指定版本安装,如下图所示:
(1)列出可用版本
(2)安装指定版本
(2)命令查看版本信息,确认安装成功
2.2.Docker镜像加速
国内从 DockerHub 拉取镜像有时会比较困难,即网速比较慢拉取时间漫长。而Docker 官方和国内很多云服务商都提供了国内加速器服务,例如科大、网易、阿里云、USTC 、 DaoCloud 、七牛云等。为了解决拉取速度过慢的问题,一般会配置镜像加速器或者从国内的一些平台的镜像中心仓库上直接拉取。
2.2.1.方式一:镜像中心仓库拉取(无需配置)
国内平台镜像中心仓库有很多个,如阿里,daoCloud镜像市场、网易云镜像中心等。通过平台搜索需要的镜像获取到镜像拉取地址后可以直接根据地址拉取镜像,省去了配置加速器过程。这里举例daoCloud镜像市场。
(1)进入daoCloud镜像市场 https://hub.daocloud.io/
(2)搜索镜像,根据镜像信息右侧的拉取地址就可以直接拉取镜像了
2.2.2.方式二:配置加速器地址(推荐)
我们可以在配置文件中配置好加速器地址,从而加速dockerhub上拉取所需要的镜像。那加速地址配置哪个呢?我们可以通过daoClould、阿里云等平台注册登录从而免费获取自己专属的加速地址。这里举例daoCloud与阿里云两个平台获取专属加速地址。
1.获取专属加速地址
(1)平台一: daoCloud : https://dashboard.daocloud.io/packages/explore.
# 1.将registry-mirror加入到Docker配置文件 /etc/docker/daemon.json中,注意后面加星号的地址要换成你个人的地址
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://****.m.daocloud.io
# 2.重新加载
sudo systemctl daemon-reload
# 3.重启docker
sudo 3.systemctl restart docker
(2)平台二: 阿里云: https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
2.创建并编辑 daemon.json 文件
# 1.加入配置,这里填写你自己的地址,执行命令前需要把方括号中的地址替换
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://******.mirror.aliyuncs.com"]
}
EOF
# 2.重新加载
sudo systemctl daemon-reload
# 3.重启docker
sudo 3.systemctl restart docker
3.查询验证加速地址配置结果
(1)方式一:可以通过 ll命令 查看 /etc/docker 路径下的daemon.json 是否创建,cat查看文件中配置内容
ll /etc/docker/
cat /etc/docker/daemon.json
对比还未配置前:
配置加速地址后:
(2)方式二:可以通过 docker info 查看详细版本信息,确认配置结果
docker info
对比还未配置前:
配置加速地址后:
三、Docker配置文件认识
3.1.key.json
docker 首次安装后改目录下会自动生成该配置文件,文件默认路径为 /etc/docker/key.json。配置文件是docker在连接到其他TLS服务器(如注册表)时使用的Web格式的TLS连接的dockerd键.它在启动时由docker引擎自动生成。
3.2.daemon.json
docker 安装后默认没有该配置文件,需要进行手动创建,配置文件默认路径 /etc/docker/daemon.json。docker 在启动的时候会去读取该配置文件。如要在配置文件中进行配置,需 docker 版本大于1.1.2。该文件作为 Docker Engine 的配置管理文件, 里面几乎涵盖了所有 docker 命令行启动可以配置的参数。
该–config-file选项允许您以 json 格式为守护程序设置任何配置选项。该文件使用与键相同的标志名称,但允许多个条目的标志除外,它使用标志名称的复数形式,例如,labels用于label标志。
配置文件中设置的选项不得与通过标志设置的选项冲突。如果选项在文件和标志之间重复,无论它们的值如何,docker 守护程序都将无法启动。我们这样做是为了避免静默忽略配置重新加载中引入的更改。例如,如果您在配置文件中设置守护进程标签并通过–label标志设置守护进程标签,守护进程将无法启动。当守护程序启动时,文件中不存在的选项将被忽略。
此外配置文件修改时也要格外注意格式,如果配置冲突或格式有误都将导致 docker 启动失败,所以非特殊需求慎增加或修改配置项。
3.3.1.配置参数详解
Linux 上允许的配置选项的完整示例:
{
"allow-nondistributable-artifacts": [],#用一组新的注册表替换守护程序将不可分发的工件推送到的注册表集
"api-cors-header": "",#在引擎API中设置CORS标头
"authorization-plugins": [],#指定要使用的授权插件
"bip": "",#指定网桥IP,即启动实例时的虚拟ip。例:172.16.0.1/16
"bridge": "",#将容器附加到网桥
"cgroup-parent": "",#为所有容器设置父cgroup
"cluster-advertise": "",#修改重载后公布的地址,要通告的地址或接口名称
"cluster-store": "",#使用新地址重新加载发现存储,分布式存储后端的URL
"cluster-store-opts": {},#使用新选项重新加载发现存储,设置集群存储选项(默认map [])
"containerd": "/run/containerd/containerd.sock",
"containerd-namespace": "docker",
"containerd-plugin-namespace": "docker-plugins",
"data-root": "",#docker运行时使用的根路径,默认/var/lib/docker
"debug": true, #当设置为true时,它将守护进程更改为调试模式,调试模式可以打印更多启动信息,默认为false
"default-address-pools": [
{
"base": "172.80.0.0/16",
"size": 24
},
{
"base": "172.90.0.0/16",
"size": 24
}
],
"default-cgroupns-mode": "private",
"default-gateway": "",
"default-gateway-v6": "",
"default-runtime": "runc",#容器的默认OCI运行时,默认为“ runc”
"default-shm-size": "64M",
"default-ulimits": {
"nofile": {
"Hard": 64000,
"Name": "nofile",
"Soft": 64000
}
},
"dns": [],#设定容器DNS的地址,在容器的 /etc/resolv.conf文件中可查看
"dns-opts": [],#容器 /etc/resolv.conf 文件,其他设置
"dns-search": [],#设定容器的搜索域,当设定搜索域为 .example.com 时,在搜索一个名为 host 的 主机时,DNS不仅搜索host,还会搜索host.example.com。注意:如果不设置,Docker 会默认用主机上的 /etc/resolv.conf来配置容器
"exec-opts": [],#运行时执行选项
"exec-root": "",#执行状态文件的根目录,默认为 /var/run/docker
"experimental": false,
"features": {},
"fixed-cidr": "",#固定IP的IPv4子网
"fixed-cidr-v6": "",#固定IP的IPv6子网
"group": "",#UNIX套接字的组,默认为 docker
"hosts": [],#设置容器hosts
"icc": false,#启用容器间通信,默认为true
"init": false,
"init-path": "/usr/libexec/docker-init",
"insecure-registries": [],#设置私有仓库地址
"ip": "0.0.0.0",#绑定容器端口时的默认IP,默认0.0.0.0
"ip-forward": false,#默认true, 启用 net.ipv4.ip_forward ,进入容器后使用 sysctl -a | grepnet.ipv4.ip_forward 查看
"ip-masq": false,#启用IP伪装,默认为true
"iptables": false,#启用iptables规则添加,默认为true
"ip6tables": false,
"ipv6": false,#启用IPv6网络
"labels": [],#docker主机的标签,很实用的功能,例如定义:–label nodeName=host-121
"live-restore": true,#在容器仍在运行时启用docker的实时还原
"log-driver": "json-file",#容器日志的默认驱动程序,默认为 json-file
"log-level": "",#设置日志记录级别:debug, info, warn, error, fatal,默认为info
"log-opts": {
"cache-disabled": "false",
"cache-max-file": "5",
"cache-max-size": "20m",
"cache-compress": "true",
"env": "os,customer",
"labels": "somelabel",
"max-file": "5",
"max-size": "10m"
},#容器默认日志驱动程序选项
"max-concurrent-downloads": 3,#设置每个请求的最大并发下载量,默认为3
"max-concurrent-uploads": 5,#设置每次推送的最大同时上传数,默认为5
"max-download-attempts": 5,#设置每次拉取的最大下载尝试次数,默认为5
"mtu": 0,#设置容器网络MTU
"no-new-privileges": false,
"node-generic-resources": [
"NVIDIA-GPU=UUID1",
"NVIDIA-GPU=UUID2"
],
"oom-score-adjust": -500,#设置守护程序的oom_score_adj,默认值为-500
"pidfile": "",#docker守护进程的PID文件
"raw-logs": false,#全时间戳机制
"registry-mirrors": [],#私库加速地址
"runtimes": {#更新可用于运行容器的可用 OCI 运行时列表
"cc-runtime": {
"path": "/usr/bin/cc-runtime"
},
"custom": {
"path": "/usr/local/bin/my-runc-replacement",
"runtimeArgs": [
"--debug"
]
}
},
"seccomp-profile": "",
"selinux-enabled": false,#启用selinux支持,默认false
"shutdown-timeout": 15,
"storage-driver": "",#要使用的存储驱动程序
"storage-opts": [],#存储驱动程序选项,如:"overlay2.override_kernel_check=true","overlay2.size=15G"
"swarm-default-advertise-addr": "",#设置默认地址或群集广告地址的接口
"tls": true,#启动TLS认证开关,默认false
"tlscacert": "",#默认 ~/.docker/ca.pem,通过CA认证过的的certificate文件路径
"tlscert": "",#默认 ~/.docker/cert.pem ,TLS的certificate文件路径
"tlskey": "",#默认~/.docker/key.pem,TLS的key文件路径
"tlsverify": true,#默认false,使用TLS并做后台进程与客户端通讯的验证
"userland-proxy": false,#使用userland代理进行环回流量,默认为true
"userland-proxy-path": "/usr/libexec/docker-proxy",
"userns-remap": ""#用户名称空间的用户/组设置
}
以上配置中常用的如下:
{
"bip":"",#指定网桥IP,即启动实例时的虚拟ip。例:172.16.0.1/16
"insecure-registries":"",#设置私有仓库地址
"registry-mirrors":"",#私库加速地址
"data-root":"",#docker运行时使用的根路径,默认/var/lib/docker
"dns":"",#设定容器DNS的地址,在容器的 /etc/resolv.conf文件中可查看
"hosts":[#设置容器hosts
],
"storage-driver":"",#要使用的存储驱动程序
"storage-opts":[
"overlay2.override_kernel_check=true",
"overlay2.size=15G"
],#存储驱动程序选项,如:"overlay2.override_kernel_check=true","overlay2.size=15G"
"log-level":"",#设置日志记录级别:debug, info, warn, error, fatal,默认为info
"log-opts":{
"max-file":"3",
"max-size":"10m"
}#容器默认日志驱动程序选项
}
修改配置后需要重新加载,并重启docker才能生效
# 1.重新加载配置参数
systemctl daemon-reload
# 2.重新启动docker服务
systemctl restart docker
四、Docker基本操作
4.1.docker info|version|帮助命令
docker version #查看docker的版本信息
docker info #查看docker系统信息,包括镜像和容器以及部分配置信息
docker --help #docker帮助命令
4.2.容器声明周期管理命令
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
docker run -i [CONTAINER NAME] #以交互模式运行容器,通常与-t同时使用
docker run -t [CONTAINER NAME] #为容器重新分配一个伪输入终端,通常与-i同时使用
docker run --name [CONTAINER NAME] #设置容器名称
docker run -P #随机端口映射
docker run -p [HOST PORT]:[CONTAINER PORT] #指定端口映射,映射主机和容器内的端口
docker run -e [ENV NAME]=[ENV VALUE] #添加环境变量,如username="admin"
docker run -d #后台运行,并返回容器ID
docker run -v [HOST FOLDER PATH]:[CONTAINER FOLDER PATH] #将主机目录挂在到容器内,可挂载多个目录如:docker run --name nginx81 -d -p 81:80 -v /data/nginx/html:/usr/share/nginx/html -v /data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf -v /data/nginx/logs:/var/log/nginx -v /data/nginx/conf.d:/etc/nginx/conf.d -d nginx:latest
docker start [CONTAINER ID|NAME] #启动容器(指定容器ID或名称)
docker restart [CONTAINER ID|NAME] #重新启动容器
docker stop [CONTAINER ID|NAME] #停止容器
docker kill [CONTAINER ID|NAME] #杀掉一个运行中的容器
docker kill -s [CONTAINER ID|NAME] #向容器发送一个信号,并杀掉运行中容器
docker rm [CONTAINER ID] #删除容器
docker rm -f [CONTAINER ID] #强制删除容器
docker rm -f $(docker ps -a -q) #删除多个容器
docker pause CONTAINER [CONTAINER ID|NAME] #暂停容器中所有的进程
docker unpause CONTAINER [CONTAINER ID|NAME]#恢复容器中所有的进程
docker create --name [NAME] [CONTAINER][:TAG] #创建一个新的容器但不启动它,如 docker create --name myJava java:latest
docker exec -it [CONTAINER NAME|ID] /bin/bash #进入容器内
docker exec -it [CONTAINER NAME|ID] ping [CONTAINER NAME|ID] #一个容器ping另外一个容器
4.3.容器操作
docker ps #列出当前所有正在运行的容器
docker ps -q #列出所有的容器
docker ps -l #列出最近创建的容器
docker ps -n 3 #3列出最近创建的3个容器
docker ps -q #只显示容器ID
docker ps --no-trunc #显示当前所有正在运行的容器完整信息
docker ps -f "status=exited" #显示所有退出的容器
docker ps -a -q #显示所有容器id
docker ps -f "status=exited" -q #显示所有退出容器的id
docker inspect [CONTAINER NAME|ID] #查看容器/镜像的元数据
docker top [CONTAINER ID] #查看容器内运行的进程
docker attach [CONTAINER ID] #连接到正在运行中的容器,直接进入容器终端的命令,不启动新的进程
docker logs [CONTAINER ID] #显示运行容器的日志
docker logs -f [CONTAINER ID] #跟踪实时日志输出
docker logs --since=[TIME][CONTAINER ID] #显示某个开始时间的所有日志,如 --since="2021-01-01" 即指定日期; --since=30m 即最近30分钟; --since="2021-02-08T13:23:37" --until "2021-02-09T12:23:37";--since="2018-02-08T13:23:37"
docker logs -t [CONTAINER ID] #显示时间戳,即查看日志产生日期
docker logs --tail=[N] [CONTAINER ID] #仅列出最新(最后面)N条容器日志 如 docker logs -f -t --since=”2021-07-10” --tail=10 f9e29e8455a5
docker wait [CONTAINER ID] #阻塞运行直到容器停止,然后打印出它的退出代码
docker export [CONTAINER NAME|ID] > xxx.tar #导出的是容器,文件系统作为一个 tar 归档文件
docker export -o xxx.tar [CONTAINER NAME]
docker port [CONTAINER ID|NAME] #列出指定的容器的端口映射
docker stats #显示容器统计信息(正在运行)
docker stats -a #显示所有容器的统计信息(包括没有运行的)
docker stats -a --no-stream #显示所有容器的统计信息(包括没有运行的) ,只显示一次
docker stats --no-stream | sort -k8 -h #统计容器信息并以使用流量作为倒序
docker system
docker system df #显示硬盘占用
docker system events #显示容器的实时事件
docker system info #显示系统信息
docker system prune #清理文件
exit #退出并停止容器
Ctrl+p+q #只退出容器,不停止容器
4.4.容器rootfs命令
docker commit -m "提交备注信息" -a "作者名称" [CONTAINER ID] [TARGET CONTAINER NAME]:[TAG] #提交容器使之成为一个新的镜像,如 docker commit -m "新的tomcat" -a "alone" f9e29e8455a5 mytomcat:1.2
docker cp [CONTAINER ID]:[CONTAINER PATH] [HOST PATH] #从指定容器内路径下文件拷贝到主机指定路径中 如 docker cp 2drf43u1y8dfe:/tmp/test.log /root
docker diff [CONTAINER ID|NAME] #检查容器里文件结构的更改,如 docker diff mymysql
4.5.镜像仓库命令
docker login -u [USER NAME] -p [PASSWORD] [SERVER] #登陆到一个Docker镜像仓库,如果未指定[server]镜像仓库地址,默认为官方仓库 Docker Hub
docker logout [SERVER] #登出一个Docker镜像仓库,如果未指定[SERVER]镜像仓库地址,默认为官方仓库Docker Hub 如 docker logout
docker pull [NAME] #下载镜像
docker pull -a [NAME] #下载REPOSITORY为指定名称的所有镜像
docker push [DOCKER USER NAME]/[REPOSITORY][:TAG] #将本地的镜像上传到镜像仓库,要先登陆到镜像仓库
docker search [NAME] #从仓库中搜索指定镜像,如 docker search nginx
docker search --no-trunc [NAME] #显示完整的镜像描述
docker search -s [NUM] [NAME] #列出收藏数不小于指定值的镜像
docker search --automated [NAME] #只列出 automated build类型的镜像
4.6.本地镜像管理命令
docker images #查看本地主机上的镜像
docker images -a #列出本地所有的镜像(含中间镜像层)
docker images -q #只显示镜像ID
docker images --digests #显示镜像的摘要信息
docker images --no-trunc #显示完整的镜像信息
docker rmi [NAME/ID] #删除镜像(根据镜像名/镜像ID)
docker rmi -f [NAME|ID] #强制删除单个镜像
docker rmi -f [NAME|ID] [NAME|ID] #强制删除多个镜像
docker rmi -f $(docker images -qa) #强制删除全部镜像
docker tag [NAME][:TAG] [REGISTRYHOST/][USERNAME/][NAME][:TAG] #标记本地镜像, 将其归入某一仓库
docker build -t [NAME][:TAG] [PATH] #Dockerfile 创建镜像
docker history [NAME][:TAG] #查看指定镜像的创建历史
docker save [NAME][:TAG] > xxx.tar #将镜像保存成 tar 归档文件
docker save -o xxx.tar [NAME][:TAG]
docker load < xxx.tar #从归档文件加载镜像
docker --input xxx.tar
docker import [file|URL]- [REPOSITORY[:TAG]] #从归档文件中创建镜像,如 docker import http://example.com/exampleimage.tgz;docker import my_ubuntu_v3.tar runoob/ubuntu:v4
五、Docker构建镜像的三种方式
5.1.基于容器构建镜像
5.1.1.构建镜像步骤
基于容器构建镜像首先需要一个正在运行的容器来基于此创建,为此我这里启动了一个python容器,启动后再容器中做修改即创建了一个文件,并提交创建镜像。步骤如下:
(1)查看当前镜像
(2)启动python容器,并进入容器中创建文件,退出
(3)基于当前容器创建镜像
(4)查看创建后的镜像
(5)启动新创建的容器并进入容器查看确认之前创建的文件是否存在
5.1.2.构建部署war包案例
部署war就需要提前部署tomcat,可以是服务器已经安装好的也可以是dockerf方式部署的tomcat。为了简单采用后者,需要先docker部署tomcat后将war上传到tomcat/webapps目录下并提交成为新的镜像,启动新容器。
(1)创建并启动tomcat容器
(2)拷贝war到webapps目录下,并基于当前容器创建镜像,启动容器
(3)测试
5.2.基于本地模板导入
基于本地模板导入方式首先要有本地模板,我们先基于上一步的mytython容器导出为模板文件中在本地中,在利用命令将本地模板文件导入成为镜像。
(1)查看本地运行中的mython:v1容器
(2)基于该容器导出模板文件到本地(如果文件较大会停顿一会不要着急以为挂了)
(3)基于上一步的本地模板文件导入为镜像,这里修改镜像TAG为v2好区分,导入后并查看镜像库确认
5.3.Dockerfile构建
5.3.1.什么是Dockerfile
Dockerfile是一个文本格式的配置文件,用户可以使用Dockerfile快速创建自定义镜像,文本内容包含了一条条构建镜像所需的指令和说明。
Dockerfile的指令分为两种:一是构建指令,构建指令用于构建镜像的时候执行,不会再该镜像的容器上执行。二是设置命令,用于设image的属性,将会在运行的容器里执行。
5.3.2.Dockerfile指令分类
Dockerfile的指令分为两种:
(1)构建指令,构建指令用于构建镜像的时候执行,不会再该镜像的容器上执行。
(2)设置命令,用于设image的属性,将会在运行的容器里执行。
5.3.2.Dockerfile指令说明
FROM
说明:
指定基础镜像,并且必须是第一条指令,不指定基础镜像的指令为:FROM scratch
语法:
FROM <image>
FROM <image>:<tag>
FROM <image>:<digest>
示例:
FROM mysql:5.7
注意:
<tag>与<digest>为可选项,没有选择默认使用值为latest版本
MAINTAINER
说明:
指定维护者(作者)信息
语法:
MAINTAINER <name>
示例:
MAINTAINER alone
RUN
说明:
运行指定命令
语法:
RUN <command> # shell格式,在linux系统上默认 /bin/sh -c windows系统上默认 cmd /S /C
RUN [“executable”, “param1”, “param2”] # exec格式,类似函数调用,可传参
示例:
RUN [“/etc/execfile”, “arg1”, “arg1”]
注意:
每执行一次RUN指令都会在docker上新建一层镜像,从而造成镜像多层、膨胀容易出错,所以多个RUN命令可以合并一起执行(换行符为 \)。
# 原始命令如下:
RUN yum install wget
RUN wget -O redis.tar.gz “http://download.redis.io/releases/redis-5.0.3.tar.gz”
RUN tar -xvf redis.tar.gz
# 合并为:
RUN yum install wget
&& wget -O redis.tar.gz “http://download.redis.io/releases/redis-5.0.3.tar.gz”
&& tar -xvf redis.tar.gz
ADD
说明:
将本地文件添加(复制)到容器中
语法:
ADD <src>… <dest>
ADD [“<src>”,… “<dest>”]
示例:
ADD home* /aloneDir/ # 将home前缀的文件添加到指定目录
ADD test.txt relativeDir # 将txt文件添加到WORKDIR
/relativeDir/
ADD test.txt /absoluteDir/ # 将txt文件添加到 /absoluteDir/目录中
ADD http://foo.com/bar.go /tmp/ # 从url中下载bar.go文件到指定目录
ADD /foo.tar.gz /tmp/ # 添加并解压缩到 /tmp 目录下。如果是url中下载的压缩包是不能解压的,即通过url复制的压缩文件是不会自动解压的
注意:
<src>可以是一个本地文件或者是一个本地压缩文件,还可以为一个url访问网络资源,类似wget。为tar压缩文件格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到目标路径<dest>
COPY
说明:
将本地文件复制到容器中
语法:
COPY <src>… <dest>
COPY [“<src>”,… “<dest>”]
示例:
COPY home* /aloneDir/ # 将home前缀的文件添加到指定目录
注意:
与ADD用法基本一致,但是不支持访问网络资源,以及自动解压缩功能。即复制的资源(文件)只能是本地资源
ENTRYPOINT
说明:
指定容器启动程序及参数
语法:
ENTRYPOINT [“executable”, “param1”, “param2”] # 运行可执行文件,并提供参数
ENTRYPOINT command param1 param2 # shell写法
示例:
ENTRYPOINT [“/bin/echo”, “Hello”]
ENTRYPOINT [“/bin/ls”] # 可搭配CMD
CMD [“-l”, “/tmp”]
注意:
容器运行时执行。类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效
CMD
说明:
类似于 RUN 指令,用于运行程序
语法:
CMD [“executable”,“param1”,“param2”] # 运行可执行文件,并提供参数
CMD [“param1”,“param2”] # 为 ENTRYPOINT 指令指定的程序提供默认参数
CMD command param1 param2 # 执行shell内部命令
示例:
CMD echo “This is a test.” | wc -
CMD [“/usr/bin/wc”,“–help”]
CMD [ “echo”, “$HOME” ]
注意:
CMD与RUN指令都是用于运行程序,但两个命令执行的时间点不同,CMD是在docker run 即容器构建后启动时执行,而RUN是在docker build时执行。如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效
WORKDIR
说明:
指定工作空间,不存在会创建,支持设置多次,后续命令都在该目录下执行,类似于cd命令
语法:
WORKDIR /path/to/workdir
示例:
WORKDIR /a
WORKDIR b
WORKDIR c # 执行以上结果空间地址为/a/b/c
注意:
虽然文件中设置了工作空间,但 docker run 运行容器时候也可以通过 -w 指定路径进行覆盖
ENV
说明:
设置环境变量
语法:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>…
示例:
ENV VERSION 1.0
ENV VERSION=1.0
ENV VERSION=1.0 DEBUG=on
ENV MY_VERSION=$VERSION # 使用上一步定义的变量
ENV ALL_NUMBER=1\ 2\ 3 # 执值包含空格用\ 转义
EXPOSE
说明:
暴露容器端口
语法:
EXPOSE <port> [<port>…]
示例:
EXPOSE 80 443
EXPOSE 8080
EXPOSE 11211/tcp 11211/udp
注意:
EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务,声明只是帮助使用者理解,以方便运行时指定配置映射哪个端口。如要使得端口映射或者暴露生效使其可以访问需要在 docker run 通过参数 -p 来配置发布端口
VOLUME
说明:
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷
语法:
VOLUME [“/path/to/dir”]
示例:
VOLUME [“/data/log”]
VOLUME /data/log
VOLUME [“/var/www”, “/var/log/apache2”, “/etc/apache2”]
注意:
一个卷可以存在于一个或多个容器的指定目录。卷可以容器间共享和重用,对于卷的修改不会对镜像产生影响。
ARG
说明:
指定传递给构建运行时的变量
语法:
ARG <name>[=<default value>]
示例:
ARG build_user=alone
注意:
构建参数,与 ENV 作用一致。但作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖
LABEL
说明:
为镜像添加元数据
语法:
LABEL <key>=<value> <key>=<value> <key>=<value> …
示例:
LABEL version=“1.0” description=“web服务” by=“alone”
LABEL com.example.label-with-value=“foo”
LABEL version=“1.0”
注意:
LABEL会继承基础镜像中的LABEL,如遇到key相同,则值覆盖
USER
说明:
用于指定执行后续命令的用户和用户组
语法:
USER <username>[:<usergroup>]
示例:
USER user
USER user:group
注意:
用户和用户组必须提前已经存在。镜像构建后可通过docker run运行容器时,可以参数-u来覆盖所指定的用户
ONBUILD
说明:
设置镜像触发器,用于延迟构建命令的执行
语法:
ONBUILD [INSTRUCTION]
示例:
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
注意:
该命令只对基于当前镜像的子镜像生效,当前Dockerfile中使用该指令指定的命令在本次构建镜像中不会被执行。即假设此次构建镜像为 test-build,当有新的Dockerfile使用了之前构建的镜像 FROM test-build 此时执行构建时才会执行test-build镜像中Dockerfile里面的ONBULID指定的命令
HEALTHCHECK
说明:
容器健康状况检查命令
语法:
HEALTHCHECK [OPTIONS] CMD command # 在容器内部运行一个命令来检查容器的健康状况
[OPTIONS]的选项支持以下三中选项:
–interval=DURATION 两次检查默认的时间间隔为30秒
–timeout=DURATION 健康检查命令运行超时时长,默认30秒
–retries=N 当连续失败指定次数后,则容器被认为是不健康的,状态为unhealthy,默认次数是3
HEALTHCHECK NONE # 在基础镜像中取消健康检查命令
示例:
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1
CMD后边的命令的返回值决定了本次健康检查是否成功,具体的返回值如下:
0: success - 表示容器是健康的
1: unhealthy - 表示容器已经不能工作了
2: reserved - 保留值
注意:
HEALTHCHECK命令只能出现一次,如果出现了多次,只有最后一个生效
5.3.3.Dockerfile构建案例
5.3.3.1.Dockerfile构建nginx
(1)下载nginx.tar包到指定目录 /usr/src/nginx (这里目录我已提前创建)
wget https://nginx.org/download/nginx-1.14.2.tar.gz
(2)创建Dockerfile文件,与nginx.tar同一路径,文件内容如下:
#基础镜像
FROM centos:centos7
#将nginx包放入/usr/local/src并自动解压
ADD nginx-1.14.2.tar.gz /usr/local/src
#安装依赖包
RUN yum install -y gcc gcc-c++ glibc make autoconf openssl openssl-devel
RUN yum install -y libxslt-devel -y gd gd-devel pcre pcre-devel geoip-devel
#创建用户
RUN useradd -M -s /sbin/nologin nginx
#改变当前目录到nginx安装目录
WORKDIR /usr/local/src/nginx-1.14.2
#编译nginx
RUN ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-file-aio --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module --with-http_image_filter_module --with-http_geoip_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_auth_request_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_stub_status_module && make && make install
#暴露80端口
EXPOSE 80
#添加环境变量
ENV PATH /usr/local/nginx/sbin:$PATH
ENTRYPOINT ["nginx"]
#相当于在容器执行:nginx -g "daemon off;"
CMD ["-g","daemon off;"]
#挂载卷,默认会映射到外部的:/var/lib/docker/volumes/xxxxxx/_data
VOLUME ["/data"]
(3)构建镜像。命令会识别当前路径下Dockerfile文件,自行构建,命令后的 . 符号表示当前路径
docker build -t nginx:v1 .
(4)启动容器
docker run -d -p 85:80 nginx:v1
(5)访问页面确认
5.3.3.2.Dockerfile构建springboot手动打包
这里举例的是手动打包上传.jar并构建成springboot镜像。我们需要对业务项目打包上传服务器,制作成为业务镜像供运维使用,下面讲述下制作的过程:
(1)上传.jar包到指定目录
(2)在同一目录下通过vi命令创建Dockerfile
# jdk基础镜像
FROM openjdk:8
# 添加jar包
ADD ["alone-springboot-server-1.0.0-SNAPSHOT.jar","alone-springboot-server-1.0.0-SNAPSHOT.jar"]
# 服务内部端口
EXPOSE 8082
# 启动
ENTRYPOINT ["java","-jar","/alone-springboot-server-1.0.0-SNAPSHOT.jar"]
(3)构建镜像
docker build -t alone-springboot:v1 .
(4)启动容器
(5)测试
5.3.3.3.Dockerfile构建springboot maven源码打包
(1)上传源码到服务器中(一般是git/svn直接拉取源代码)
(2)maven打包
# 源码根目录下执行打包命令,环境如果没有maven要先安装maven
mvn clean package
(3)构建镜像
构建命令
# 源码根目录下执行docker构建命令
docker build -t alone-maven-source-boot:v1 .
Dockerfile
FROM openjdk:8
# maven打包后生成的jar是在/target 下
ADD ["target/alone-springboot-server-1.0.0-SNAPSHOT.jar","alone-springboot-server-1.0.0-SNAPSHOT.jar"]
EXPOSE 8083
ENTRYPOINT ["java","-jar","/alone-springboot-server-1.0.0-SNAPSHOT.jar"]
(4)启动容器
docker run -d -p 8083:8082 --name alone-maven-source-boot alone-maven-source-boot:v1
(5)测试
5.3.3.3.Dockerfile构建springboot maven插件打包
以上的springboot打包方式都需要手动上传业务jar或者源码到服务器,这对于开发人员日常发布项目极为不便,为此我们可以在项目中pom文件加入docker-maven-plugin插件配置,这样可以更便捷的生成镜像。
在docker-maven-plugin插件的配置项目中你也可以完全不用在创建Dockerfile,直接在配置项中配置进去,它支持配置Dockerfile相关命令,具体格式可以自己去研究下。也可以结合Dockerfile来构建,我这里采用的是后者。
Dockerfile
FROM openjdk:8
ADD ["target/alone-springboot-server-1.0.0-SNAPSHOT.jar","alone-springboot-server-1.0.0-SNAPSHOT.jar"]
EXPOSE 8083
ENTRYPOINT ["java","-jar","/alone-springboot-server-1.0.0-SNAPSHOT.jar"]
pom插件配置
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.4.13</version>
<configuration>
<imageName>alone-springboot-docker</imageName>
<dockerDirectory>${project.basedir}</dockerDirectory>
<skipDockerBuild>false</skipDockerBuild>
<resource>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</configuration>
</plugin>
(1)打包并构建镜像
# 项目根目录下执行打包并构建镜像命令
mvn clean package docker:build
(2)启动容器
# 不指定镜像TAG默认为latest
docker run -d -p 8084:8082 --name alone-boot-docker alone-springboot-docker
(3)测试
六、Docker仓库使用
6.1.Docker官方仓库
6.1.1注册仓库
dockerhub官网: https://hub.docker.com 进入docker官方仓库官网,根据邮箱自由注册,激活并创建自己的仓库
6.1.2.登录仓库
6.1.3.推送镜像
(1)复习下前面的命令 a
# 标记本地镜像, 将其归入某一仓库
docker tag [镜像名:版本] [仓库]/[镜像名:版本]
# 推送镜像到仓库,需要登陆
docker push [仓库]/[镜像名: 版本]
(2)将本地镜像归入指定仓库(alone,这里对应仓库中创建的Repository名称为alone)并推送到镜像仓库
(3)查看仓库是否推送成功
6.1.4.拉取镜像
在仓库中可以查看到拉取镜像的命令,根据命令可以在本地拉取到自己上传到官方仓库的镜像。
# 1.拉取镜像
docker pull alonedockerhub/alone:1.0
# 2.启动实例
docker run -d -p 8084:8082 --name alone-boot-docker alonedockerhub/alone:1.0
测试访问
6.2.私有仓库
6.2.1.搭建仓库
我这里是克隆了一个新的服务(192.168.61.130)用来搭建私有仓库,未配置加速器的可以参考上文配置,下载时就不至于太慢。
# 1.下载仓库镜像
docker pull registry
# 2.启动(–name参数后的名字自己取得,不要纠结),这里暂时没做挂载,容器停止数据就丢失了,下文挂载会再介绍,这里主要方便测试
docker run -d --name aloneregistry -p 5000:5000 registry
6.2.2.配置仓库
配置http传输。私服默认只能使用https,若要推送镜像到私有仓库需要配置开放http,即在推送镜像的服务(192.168.61.129)的配置文件daemon.json加入以下配置项。配置的ip地址是私服仓库的地址(192.168.61.130:5000),由于该配置文件是json格式,如果是新加的配置项一定要遵循格式要求,在后面加个逗号","不然会报错的,如果你不想按照json格式也可以不需要逗号,只要把文件.json后缀改为.conf然后从新加载配置,重启docker即可。我就踩过坑。
# 1.编辑配置文件
vi /etc/docker/daemon.json(1)单个私有仓库配置
“insecure-registries”:[“192.168.61.123:5000”]
(2)多个私有仓库配置
“insecure-registries”:[“registry1_IP:port”,“registry2_IP:port”]
# 2.重新加载配置
systemctl daemon-reload
# 3.重启docker生效
systemctl restart docker
6.2.3.推送镜像
# 1.标记要推送的本地镜像
docker tag alone-springboot:v1 192.168.61.130:5000/alone-springboot:1.0
# 2.推送镜像到私有仓库
docker push 192.168.61.130:5000/alone-springboot:1.0
# 3.可通过接口(在客户端服务上)查看私有仓库中的镜像
curl http://192.168.61.130:5000/v2/_catalog
6.2.4.拉取镜像
如果本机已存在记得先移除镜像,不然从私服在拉取会提示存在了。我这里是在本机测试,所以需要多一步移除操作。
# 1.移除镜像,这里自己替换为自己镜像的id
docker rmi -f [IMAGE_ID]
# 2.从私服拉取指定镜像
docker pull 192.168.61.130:5000/alone-springboot:1.0
七、Docker使用数据卷挂载
在上文中的“数据卷”中有提到,一旦容器消亡时可写层也会随之消亡,如果运行中的数据直接保存在容器可写层那么数据也是会随之丢失,为了能使数据持久化,就需要用到volume来做文件挂载。
先不急着挂载操作,我们来验证下这一过程。即当推送了镜像到私有仓库后将私有仓库服务容器重启,再去查询私有仓库中是否还存在镜像。
通过以上的步骤证明,数据已经随之消亡了,所以在启动私有仓库容器时就需要对其数据进行挂载来保证容器运行过程中产生的数据持久化,容器重启后数据依然存在。而挂载方式已经命令在上文中也提到了,接下来我们就用私有仓库容器来做个实践。
7.1.数据卷普通挂载:-v
-v有以下两种方式,不指定主机目录与指定主机目录
# 查看容器元数据(复习下)
docker inspect [IMAGE]
7.1.1.不指定主机目录
语法:
-v [容器目录]
示例:
docker run -d -v /var/lib/registry --name aloneregistry -p 5000:5000 registry
说明:
不指定主机目录,即指定了容器的目录,而宿主机的目录在实例化容器时Docker会默认在 /var/lib/docker/volumes/ 下生成随机的指定目录,之后容器数据会持久化到该目录下,容器重启后数据依然存在,但是容器即使数据依旧存在于随机生成的目录,但是已经失去意义了,下一次重新启动又是一个新的随机目录
网上有相关博文说该挂载方式一旦容器删除了,/var/lib/docker/volumes/ 目录下随机生成的宿主机目录也会随之被删除,事实证明这个是错误的,记住只要挂载了那数据肯定是存在的。怎么证明呢?当以该方式启动时,我们去查看下容器元数据信息,发现果然是随机生成了一个主机目录,如下图:
而当容器停止并进行删除时,再去查看主机目录,发现之前的主机目录以及数据依旧存在。当然即使存在但已经失去意义了,因为下一次启动新的容器时又以该方式进行挂载的话,那将会生成一个新的主机目录,此时再去查询私有仓库中是否有镜像数据,肯定是查询不到的,因为旧的目录虽然有数据但它一直躺在那,与世界失去联系。所以平时我们挂载一般也不会选择这种方式。
补充一下,如果你 docker run 启动时加入 --rm 参数以上的当我没说,你这是在杠。启动时设置 --rm 这样在容器退出时会自动清理容器内部的文件系统这包括清理容器的匿名data volumes,所以容器一停该目录就被清除了,因为容器都被一起清了。另外顺便提示下 --rm 选项不能与 -d 同时使用(或者说同时使用没有意义),即只能自动清理 foreground 容器,不能自动清理detached容器。
7.1.2.指定主机目录
语法:
-v [主机目录]:[容器目录]
示例:
docker run -d -v /opt/registry:/var/lib/registry --name aloneregistry -p 5000:5000 registry
说明:
指定主机目录即指定指定宿主机上的目录挂载到容器中指定的目录。如果主机目录不存在docker会在主机上自动创建该目录,而同样的如果容器内对应的目录不存在,那docker也会在容器内部创建该目录
相比第一种方式,指定主机目录方式也便于管理和查询数据,在容器被移除镜像重新实例化运行容器时依然可以明确的指定主机目录,这样之前的数据也依然方便查询到不会丢失。
7.2.数据卷容器:volumes-from
如果用户需要在多个容器之间共享一些持续更新的数据,最简单的方式就是使用数据卷容器。数据卷容器也是一个容器,其目的是专门提供数据卷给其他容器挂载。数据卷容器并不需要保持运行状态,它只是专门用来提供数据卷给其它容器挂载的。
7.2.1.基本使用
# 1.创建数据卷容器
docker create --name registrydata -v /opt/data/registry:/var/lib/registry registry
# 2.启动挂载数据卷
docker run -ti -d --volumes-from registrydata --name aloneregistry -p 5000:5000 registry
# 3.数据卷容器可以在多个容器建共享,如可以在启动一个容器进行挂载
docker run -ti -d --volumes-from registrydata --name aloneregistry1 -p 5001:5000 registry
解除容器与数据卷关系
# 1.解除容器与数据卷关系(该方式需容器已经停止运行状态,否则无法删除)
docker rm -v aloneregistry1
# 2.强制解除容器与数据卷关系(会同时停止容器并删除容器及关联关系)
docker rm -v -f aloneregistry1
删除数据卷
docker rm -v -f registrydata
7.2.2.挂载多个
我们在部署多个服务时是不是每一个服务都要创建一个数据容器卷?duck不必,我们可以创建一个专门用来挂载所有服务的数据卷容器,在启动服务时指定对应容器数据卷即多个容器附加到同一个数据卷容器,容器之间可以共享数据。如以下例子中使用 hell-world 来创建一个数据卷容器 data,把所有需要挂载的目录都配置在该数据卷容器上,从而当我们启动一个 mysql 与 nginx 时就可以通过指定该数据卷容器成功挂载。
7.2.2.1.mysql5.7部署准备工作
以下是docker部署 mysql5.7 准备工作,即准备好部署的镜像,创建好宿主机要挂载的目录,创建对应的配置文件。
# 1.拉取mysql镜像
docker pull mysql:5.7
# 2.创建数据目录(用于挂载)
mkdir -p /usr/local/docker/data/mysql57/{conf,logs,mysql}
# 3.查看创建目录
ll /usr/local/docker/data/mysql57/
# 4.创建配置文件(配置文件如下)
vi /usr/local/docker/data/mysql57/conf/my.cnf
[mysql]
#设置mysql客户端默认字符集
default-character-set=utf8
socket=/var/lib/mysql/mysql.sock
[mysqld]
#修改大小写敏感
skip-grant-tables
lower_case_table_names=1
#mysql5.7以后的不兼容问题处理
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
#Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
#允许最大连接数
max_connections=200
#服务端使用的字符集默认为8比特编码的latin1字符集
character-set-server=utf8
#创建新表时将使用的默认存储引擎
default-storage-engine=INNODB
lower_case_table_names=1
max_allowed_packet=16M
#设置时区
default-time_zone=‘+8:00’
[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid
#include all files from the config directory
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/
7.2.2.2.nginx部署准备工作
以下是docker安装 ngxinx:stable 准备工作,即准备好部署的镜像,创建好宿主机要挂载的目录,创建对应的配置文件。
# 1.拉取nginx镜像
docker pull nginx:stable
# 2.创建数据目录(用户挂载)
mkdir -p /usr/local/docker/data/nginx/{conf,conf.d,html,logs}
# 3.查看创建目录
ll /usr/local/docker/data/nginx/
# 4.临时启动一个nginx容器用来拷贝容器中的默认文件(如果你自己创建配置文件这步骤可以忽略)
docker run --name mynginx -d nginx:stable
# 5.拷贝默认配置文件到需要挂载的宿主机目录中
docker cp mynginx:/etc/nginx/nginx.conf /usr/local/docker/data/nginx/conf/nginx.conf
docker cp mynginx:/etc/nginx/conf.d /usr/local/docker/data/nginx
docker cp mynginx:/usr/share/nginx/html /usr/local/docker/data/nginx
# 6.停止删除容器
docker rm -f mynginx
7.2.2.3. 创建数据卷容器
这里就简单的以hello-word镜像作为数据卷容器镜像,启动容器并命名为 data,该名字用于后续指定数据卷容器。分别对 mysql 与 nginx 需要挂载的目录一一挂载。宿主机目录自己指定,这里我以 /user/local/docker/data 为指定目录。数据卷容器其实是一个无需运行的容器,当你启动时再去查看该容器状态时候,它实际已经停止了,但这不影响它为其它容器干活。
docker run \
--name docker-data \
-v /usr/local/docker/data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
-v /usr/local/docker/data/nginx/conf.d:/etc/nginx/conf.d \
-v /usr/local/docker/data/nginx/html:/usr/share/nginx/html \
-v /usr/local/docker/data/nginx/logs:/var/log/nginx \
-v /usr/local/docker/data/mysql57/logs:/logs \
-v /usr/local/docker/data/mysql57/data:/var/lib/mysql \
-v /usr/local/docker/data/mysql57/conf/my.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf \
-d \
alpine
7.2.2.4. 启动容器指定数据卷容器
启动以下容器后,三者之间的关系为:mysql,nginx继承data 这便是容器间继承关系。卷的设计目的不仅是对数据持久化,其完全独立与容器的生命周期,容器之间配置信息的传递,任何一个容器的删除不影响其他容器的使用。
(1)启动mysql
# 启动mysql,使用上一步创建的数据容器卷data
docker run --name mysql57 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=1234 --volumes-from data -d mysql:5.7
(2)启动nginx
# 启动nginx,使用上一步创建的数据容器卷data
docker run --name nginx -d -p 80:80 --volumes-from data nginx:stable
(3)查看是否挂载成功
docker inspect 容器Id
附:docker容器启动失败查看日志
1.方式一
docker inspect --format ‘{{.LogPath}}’ 容器id
cat 上一步中查询到的日志路径(一个很长的路径)
2.方式二(推荐)
docker logs 容器id
7.2.3.数据卷容器备份、迁移、恢复数据
数据卷容器不仅可以实现容器之间数据共享,也可以方便对数据卷容器进行数据的备份、恢复、迁移。下文我们以mysql为例,进行数据备份迁移和在新服务器上恢复。
7.2.3.1.创建数据卷容器
创建名为 docker-data 的数据卷容器,并设置 mysql 相关挂载点
docker run \
--name docker-data \
-v /mydata/mysql/log:/var/log/mysql \
-v /mydata/mysql/data:/var/lib/mysql \
-v /mydata/mysql/conf:/etc/mysql \
-d \
alpine
7.2.3.2.使用数据卷容器
启动 mysql 使用数据卷容器,为了后期验证这里可以使用工具类创建一些库表方便后恢复数据后查看数据是否成功恢复。
docker run --name mysql57 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=1234 --volumes-from docker-data -d mysql:5.7
7.2.3.3.备份数据卷数据
使用一个临时容器完成备份数据容器,命令格式解析如下:
docker run --rm \
--volumes-from <ContainerName> \
-v $(pwd):/backup \
container \
tar cvf /backup/backup.tar /data
参数 | 解析 |
- -rm | 执行完命令之后移除容器,又称临时容器,我们只是为了备份无需保留这个临时容器 |
- -volumes-from <Container> | 要备份的数据卷容器名 |
-v $(pwd):/backup | 挂载当前路径到容器 container,数据将会备份到该路径 |
container | 一个小的镜像用来做数据卷容器或用来备份的临时镜像,这里我用 alpine镜像,没有的可以自己docker pull |
tar cvf /backup/backup.tar /data | 将/data 路径下文件打包成backup.tar,注意这里的/data 是容器中的路径,如mysql 中的 var/lib/mysql 这里支持对多个路径文件进行打包,多个路径则以空格间隔开如 /data1 /data2 |
执行备份 mysql 数据,执行成功会在当前路径下生成backup.tar文件
docker run \
--rm \
--volumes-from docker-data \
-v $(pwd):/backup alpine tar cvf /backup/backup.tar \
/logs \
/var/lib/mysql \
/etc/mysql/
7.2.3.4.备份数据迁移
这里自己使用工具上传到新的服务器上指定目录下,这里我上传路径为 /root
7.2.3.5.恢复数据卷数据
在新的服务器上,同之前一样创建一个数据卷容器 docker-data
docker run \
--name docker-data \
-v /mydata/mysql/log:/var/log/mysql \
-v /mydata/mysql/data:/var/lib/mysql \
-v /mydata/mysql/conf:/etc/mysql \
-d \
alpine
使用临时容器,恢复备份数据到数据卷容器 docker-data 中,在backup.tar所在路径下执行以下命令
docker run --rm --volumes-from docker-data -v $(pwd):/backup alpine tar xvf /backup/backup.tar
在新服务器上启动mysql,挂载新建的数据卷容器,通过工具类可以查看到之前的数据了,至此数据迁移恢复成功
docker run --name mysql57 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=1234 --volumes-from docker-data -d mysql:5.7
下一期发表 docker 集群