目录
[一、Docker 概述](#一、Docker 概述)
[1.1、什么是 Docker](#1.1、什么是 Docker)
[1.2、Docker 的优势](#1.2、Docker 的优势)
[二、安装 Docker](#二、安装 Docker)
[2.1、安装 Docker 依赖版本环境](#2.1、安装 Docker 依赖版本环境)
[2.2、安装 Docker 并设置为开机自启](#2.2、安装 Docker 并设置为开机自启)
[2.3、通过检查 Docker 版本查看 Docker 服务](#2.3、通过检查 Docker 版本查看 Docker 服务)
[三、Docker 镜像操作](#三、Docker 镜像操作)
[四、Docker 容器操作](#四、Docker 容器操作)
[五、Docker 镜像管理](#五、Docker 镜像管理)
[5.1、Docker 镜像结构](#5.1、Docker 镜像结构)
[5.2、Dockerfile 介绍](#5.2、Dockerfile 介绍)
[六、案例:构建各类 Docker 镜像服务](#六、案例:构建各类 Docker 镜像服务)
[6.4.1、构建 sshd 容器服务](#6.4.1、构建 sshd 容器服务)
[6.4.2、构建 nginx 容器服务](#6.4.2、构建 nginx 容器服务)
[6.4.3、构建 MySQL 容器服务](#6.4.3、构建 MySQL 容器服务)
[6.4.4、构建 LNMP 容器服务](#6.4.4、构建 LNMP 容器服务)
[七、Docker 的数据管理](#七、Docker 的数据管理)
随着计算机近几十年的蓬勃发展,产生了大量优秀系统和软件。软件开发人员可以自由选择各种软件应用。但同时带来的问题就是需要维护一个非常庞大的开发、测试和生产环境。 面对这种情况,Docker 容器技术横空出世,提供了简单、灵活、高效的解决方案,不需要过多地改变现有的使用习惯,就可以和已有的工具,如 OpenStack 等配合使用。因此,掌握 Docker 相关技术也是 途经云计算的必经之路。
本章将依次介绍 Docker 的三大核心概念------镜像、容器、仓库,以及安装 Docker 与介绍围绕镜像和容器的具体操作。
一、Docker 概述
因为 Docker 轻便、快速的特性,可以使应用达到快速迭代的目的。每次小的变更,马上就可以看到效果,而不用将若干个小变更积攒到一定程度再变更。每次变更一小部分其实是一种非常安全的方式,在开发环境中能够快速提高工作效率。
Docker 容器能够帮助开发人员、系统管理员、质量管理和版本控制工程师在一个生产环节中 一起协同工作。制定一套容器标准能够使系统管理员更改容器的时候,程序员不需要关心容器的变 化,而更专注自己的应用程序代码。从而隔离开了开发和管理,简化了开发和部署的成本。
Docker 产品的 Logo
1.1、什么是 Docker
如果要方便的创建运行在云平台上的应用,必须要脱离底层的硬件,同时还需要任何时间地点可获取这些资源,这正是 Docker 所能提供的。Docker 的容器技术可以在一台主机上轻松为任何应用创建一个轻量级的、可移植的、自给自足的容器。通过这种容器打包应用程序,意味着简化了重新部署、调试这些琐碎的重复工作,极大的提高了工作效率。
1.2、Docker 的优势
Docker 容器运行速度很快,启动和停止可以在秒级实现,比传统虚拟机要快很多;Docker 核心解决的问题是利用容器来实现类似虚拟机的功能,从而利用更加节省的硬件资源提供给用户更多的计算资源。因此,Docker 容器除了运行其中的应用之外,基本不消耗额外的系统资源,在保证应用性能的同时,又减小了系统开销,使得一台主机上同时运行数千个 Docker 容器成为可能。 Docker 操作方便,可以通过 Dockerfile 配置文件支持灵活的自动化创建和部署。下表将 Docker 容器技术与传统虚拟机的特性进行了比较。
|-----------|---------------|-----------|
| 特性 | Docker 容器 | 虚拟机 |
| 启动速度 | 秒级 | 分钟级 |
| 计算能力损耗 | 几乎无 | 损耗 50% 左右 |
| 性能 | 接近原生 | 弱于 |
| 系统支持量(单机) | 上千个 | 几十个 |
| 隔离性 | 资源限制 | 完全隔离 |
Docker 容器与传统虚拟机的区别
Docker 之所以拥有众多优势,与操作系统虚拟化自身的特点是分不开的。传统虚拟机需要有额外的虚拟机管理程序和虚拟机操作系统层,而 Docker 容器则是直接在操作系统层面之上实现的虚拟化。下图是 Docker 与传统虚拟机架构。
Docker 与传统虚拟机架构
1.3、镜像
镜像、容器、仓库是 Docker 的三大核心概念。其中 Docker 的镜像是创建容器的基础,类似虚拟机的快照,可以理解为一个面向 Docker 容器引擎的只读模板。例如:一个镜像可以是一个完整的 CentOS 操作系统环境,称为一个 CentOS 镜像;也可以是一个安装了 MySQL 的应用程序,称之为一个 MySQL 镜像等等。
Docker 提供了简单的机制来创建和更新现有的镜像,用户也可以从网上下载已经创建好的镜像直接使用。
1.4、容器
Docker 的容器是从镜像创建的运行实例,它可以被启动、停止和删除。所创建的每一个容器都是相互隔离、互不可见,以保证安全性的平台。可以将容器看作是一个简易版的 Linux 环境, Docker 利用容器来运行和隔离应用。
1.5、仓库
Docker 仓库是用来集中保存镜像的地方,当创建了自己的镜像之后,可以使用 push 命令将它上传到公有仓库(Public)或者私有仓库(Private)。当下次要在另外一台机器上使用这个镜像时,只需从仓库获取。
仓库注册服务器(Registry)是存放仓库的地方,其中包含了多个仓库。每个仓库集中存放某一类镜像,并且使用不同的标签(tag)来区分它们。目前最大的公共仓库是 docker Hub,存放了数量庞大的镜像供用户下载使用。
二、安装 Docker
Docker 支持在主流的操作系统平台上进行使用,包括 Windows 系统、Linux 系统、以及 Mac OS 系统等。目前最新的 RHEL、CentOS 以及 Ubuntu 系统官方软件源中都已经默认自带了 Docker 包,可直接安装使用,也可以用 Docker 自己的 YUM 源进行配置。
CentOS 系统下安装 Docker 可以有两种方式:一种是使用 CURL 获得 Docker 的安装脚本进行安装,另一种是使用 YUM 仓库来安装 Docker。
注意:目前 Docker 只能支持 64 位系统。
2.1、安装 Docker 依赖版本环境
bash
[root@centos7-13 ~]# yum install -y yum-utils device-mapper-persistent-data lvm2
[root@centos7-13 ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
2.2、安装 Docker 并设置为开机自启
bash
[root@centos7-13 ~]# yum -y install docker-ce-19.03.15 docker-ce-cli-19.03.15
[root@centos7-13 ~]# systemctl start docker
[root@centos7-13 ~]# systemctl enable docker
安装好的 Docker 系统有两个程序,Docker 服务端和 Docker 客户端。其中 Docker 服务端是一个服务进程,负责管理所有容器。Docker 客户端则扮演着 Docker 服务端的远程控制器,可以用来控制 Docker 的服务端进程。大部分情况下 Docker 服务端和客户端运行在一台机器上。
2.3、通过检查 Docker 版本查看 Docker 服务
bash
[root@centos7-13 ~]# docker version
Client: Docker Engine - Community
Version: 19.03.15
API version: 1.40
Go version: go1.13.15
Git commit: 99e3ed8919
Built: Sat Jan 30 03:17:57 2021
OS/Arch: linux/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 19.03.15
API version: 1.40 (minimum version 1.12)
Go version: go1.13.15
Git commit: 99e3ed8919
Built: Sat Jan 30 03:16:33 2021
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.6.32
GitCommit: 8b3b7ca2e5ce38e8f31a34f35b2b68ceb8470d89
runc:
Version: 1.1.12
GitCommit: v1.1.12-0-g51d5e94
docker-init:
Version: 0.18.0
GitCommit: fec3683
三、Docker 镜像操作
运行 Docker 容器前需要本地存在对应的镜像。如果不存在本地镜像,Docker 就会尝试从默认镜像仓库下载。镜像仓库是由 Docker 官方维护的一个公共仓库,可以满足用户的绝大部分需求。 用户也可以通过配置来使用自定义的镜像仓库。
下面具体介绍如何操作 Docker 镜像。
3.1、搜索镜像
在使用下载镜像前,可以使用 docker search 命令搜索远端官方仓库中的共享镜像。
命令格式:docker search 关键字
例如:搜索关键字为 nginx 的镜像的执行命令和结果如下:
bash
[root@centos7-13 ~]# docker search nginx
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
nginx Official build of Nginx. 19876 [OK]
bitnami/nginx Bitnami container image for NGINX 187 [OK]
nginxinc/nginx-unprivileged Unprivileged NGINX Dockerfiles 149
nginxproxy/nginx-proxy Automated nginx proxy for Docker containers ... 137
nginxproxy/acme-companion Automated ACME SSL certificate generation fo... 133
ubuntu/nginx Nginx, a high-performance reverse proxy & we... 112
nginx/nginx-ingress NGINX and NGINX Plus Ingress Controllers fo... 90
nginx/unit This repository is retired, use the Docker o... 63
nginx/nginx-prometheus-exporter NGINX Prometheus Exporter for NGINX and NGIN... 40
bitnami/nginx-ingress-controller Bitnami container image for NGINX Ingress Co... 33 [OK]
unit Official build of NGINX Unit: Universal Web ... 29 [OK]
nginxproxy/docker-gen Generate files from docker container meta-da... 17
rancher/nginx-ingress-controller 13
kasmweb/nginx An Nginx image based off nginx:alpine and in... 7
nginxinc/nginx-s3-gateway Authenticating and caching gateway based on ... 6
bitnami/nginx-exporter Bitnami container image for NGINX Exporter 5
nginxinc/ingress-demo Ingress Demo 4
rancher/nginx-ingress-controller-defaultbackend 2
nginx/nginx-ingress-operator NGINX Ingress Operator for NGINX and NGINX P... 2
nginx/nginx-quic-qns NGINX QUIC interop 1
nginxinc/amplify-agent NGINX Amplify Agent docker repository 1
nginxinc/ngx-rust-tool 0
nginxinc/mra_python_base 0
nginxinc/mra-fakes3 0
执行 docker search nginx 命令后,返回很多包含 nginx 关键字的镜像,其中返回信息包括镜像名称(NAME)、描述(DESCRIPTION)、星级(STARS)、是否官方创建(OFFICIAL)、是否主动创建(AUTOMATED)。默认的输出结果会按照星级评价进行排序,表示该镜像受欢迎程 度。在下载镜像时,可以参考星级。在搜索时,还可以使用 -s 或者 --stars=x 显示指定星级以上的镜像,星级越高表示越受欢迎;是否官方创建是指是否是由官方项目组创建和维护的镜像,一般官方项目组维护的镜像使用单个单词作为镜像名称,称为基础镜像或者根镜像。像 bitnami/nginx 这种命名方式的镜像,表示是由 docker Hub 的用户 bitnami 创建并维护的镜像,带有用户名为前缀; 是否主动创建是指是否允许用户验证镜像的来源和内容。
使用 docker search 命令只能查找镜像,镜像的标签无法查找,因此如果需要查找 Docker 标签,需要从网页上访问镜像仓库进行查找。
3.2、获取镜像
搜索到符合需求的镜像,可以使用 docker pull 命令从网络下载镜像到本地使用。
命令格式:Docker pull 仓库名称[:标签]
对于 Docker 镜像来说,如果下载镜像时不指定标签,则默认会下载仓库中最新版本的镜像,即选择标签为 latest 标签,也可通过指定的标签来下载特定版本的某一镜像。这里标签 (tag)就是用来区分镜像版本的。
例如:下载镜像 nginx 的执行命令和结果如下:
bash
[root@centos7-13 ~]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
09f376ebb190: Pull complete
a11fc495bafd: Pull complete
933cc8470577: Pull complete
999643392fb7: Pull complete
971bb7f4fb12: Pull complete
45337c09cd57: Pull complete
de3b062c0af7: Pull complete
Digest: sha256:a484819eb60211f5299034ac80f6a681b06f89e65866ce91f356ed7c72af059c
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
从整个下载的过程可以看出,镜像文件是由若干层(Layer)组成,称之为 AUFS(联合文件系统),是实现增量保存与更新的基础,下载过程中会输出镜像的各层信息。镜像下载到本地之后就可以随时使用该镜像了。
用户也可以选择从其他注册服务器仓库下载,这时需要在仓库名称前指定完整的仓库注册服务器地址。
3.3、查看镜像信息
用户可以使用 docker images 命令查看下载到本地的所有镜像。
命令格式:docker images 仓库名称:[标签]
例如:查看本地所有镜像的执行命令和结果如下:
bash
[root@centos7-13 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest e784f4560448 3 weeks ago 188MB
从显示的情况可以读出以下信息:
- REPOSITORY:镜像属于的仓库;
- TAG:镜像的标签信息,标记同一个仓库中的不同镜像;
- IMAGE ID:镜像的唯一 ID 号,唯一标识一个镜像;
- CREATED:镜像创建时间;
- VIRTUAL SIZE:镜像大小;
用户还可以根据镜像的唯一标识 ID 号,获取镜像详细信息。
命令格式:dockerinspect 镜像ID号
例如:获取镜像 nginx 详细信息的执行命令和结果如下。
bash
[root@centos7-13 ~]# docker inspect e784f4560448
[
{
"Id": "sha256:e784f4560448b14a66f55c26e1b4dad2c2877cc73d001b7cd0b18e24a700a070",
"RepoTags": [
"nginx:latest"
],
"RepoDigests": [
"nginx@sha256:a484819eb60211f5299034ac80f6a681b06f89e65866ce91f356ed7c72af059c"
],
"Parent": "",
"Comment": "buildkit.dockerfile.v0",
"Created": "2024-05-03T19:49:21Z",
"Container": "",
"ContainerConfig": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": null,
"Cmd": null,
"Image": "",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"DockerVersion": "",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"80/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NGINX_VERSION=1.25.5",
"NJS_VERSION=0.8.4",
"NJS_RELEASE=3~bookworm",
"PKG_RELEASE=1~bookworm"
],
"Cmd": [
"nginx",
"-g",
"daemon off;"
],
"ArgsEscaped": true,
"Image": "",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"/docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {
"maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
},
"StopSignal": "SIGQUIT"
},
"Architecture": "amd64",
"Os": "linux",
"Size": 187659947,
"VirtualSize": 187659947,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/23e6b4372301c8654880e24d81b7c9064b0314f6edfa32f5525d7af7e2562856/diff:/var/lib/docker/overlay2/4ed796ffeaf0f1755f5ac0268d9fe86ef79d9c7663f57ee56384daa8753c9abd/diff:/var/lib/docker/overlay2/71367932d92b2d8b5c85ef6cbbb94a3e50b805cb920a9e71ddecd7e06a9caa97/diff:/var/lib/docker/overlay2/4b04aead5281d8c5c54f1ab4c4f9fa8a7d66296197c4167f058f92760f0c3bb1/diff:/var/lib/docker/overlay2/1752c48f78525ebd77309a1a9ae572df3e0bef6e4633b93fe4ec4c77b2a23e0f/diff:/var/lib/docker/overlay2/79635f1eb7b7161c80695dea91540288518cdf1b3a576fabf20ff9cdee27d829/diff",
"MergedDir": "/var/lib/docker/overlay2/f99c7bc00a3a44612deb54971c7b3dd582283face8f4aa65ae47c133be1fd71b/merged",
"UpperDir": "/var/lib/docker/overlay2/f99c7bc00a3a44612deb54971c7b3dd582283face8f4aa65ae47c133be1fd71b/diff",
"WorkDir": "/var/lib/docker/overlay2/f99c7bc00a3a44612deb54971c7b3dd582283face8f4aa65ae47c133be1fd71b/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:5d4427064ecc46e3c2add169e9b5eafc7ed2be7861081ec925938ab628ac0e25",
"sha256:fc1cf9ca5139883943cc519cc3c57f0855395618f56d6431490fa735461156f1",
"sha256:747b290aeba888738176dcbf7382eb0f660f27e785b839592918b8ed291d5792",
"sha256:9f4d73e635f122031c04047f0e87fb224bef098a28700439bb4e72d0619aaad6",
"sha256:56f8fe6aedcdee31bdee17249b1e18434ce7ab5a1814e2193773b54d7f9db39a",
"sha256:7d2fd59c368c60f74214fc47399dcc35ef8513e26890a0c6004835bceabeb4c6",
"sha256:14773070094ddc0debcea4f38f0daa7dd8116858387e0c238fa96ae8047bc07e"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]
为了在后续工作中使用镜像,可以用 docker tag 命令来为本地的镜像添加新的标签。
命令格式:docker tag 名称:[标签]新名称:[新标签]
例如:本地镜像 nginx 添加新的名称为 centos/nginx,新的标签为 1.26.0。
bash
[root@centos7-13 ~]# docker tag nginx:latest centos/nginx:1.26.0
[root@centos7-13 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos/nginx 1.26.0 e784f4560448 3 weeks ago 188MB
nginx latest e784f4560448 3 weeks ago 188MB
3.4、删除镜像
可以使用 docker rmi 命令删除多余的镜像。删除镜像的操作有两种方法:使用镜像的标签删除镜像;使用镜像的 ID 删除镜像。
命令格式:docker rmi 仓库名称:标签
或者
docker rmi 镜像 ID 号
例如:要删除掉 centos/nginx:1.26.0 镜像,可以使用如下命令:
bash
[root@centos7-13 ~]# docker rmi centos/nginx:1.26.0
Untagged: centos/nginx:1.26.0
[root@centos7-13 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest e784f4560448 3 weeks ago 188MB
当一个镜像有多个标签的时候,docker rmi 命令只是删除该镜像多个标签中的指定标签,不会影响镜像文件,相当于只删除了镜像 e784f4560448 的一个标签而已。但当该镜像只剩下一个标签的时候,再使用删除命令就会彻底删除该镜像。
例如:删除 nginx 镜像,它会删除整个镜像文件的所有层。
bash
[root@centos7-13 ~]# docker rmi nginx
Untagged: nginx:latest
Untagged: nginx@sha256:a484819eb60211f5299034ac80f6a681b06f89e65866ce91f356ed7c72af059c
Deleted: sha256:e784f4560448b14a66f55c26e1b4dad2c2877cc73d001b7cd0b18e24a700a070
Deleted: sha256:38ecd4de01b55beb32c596678b061db27f8ecb586096f031e4553869e52a1dc2
Deleted: sha256:168e1116c229abdf6cd9c0f07f82d40d53e358b1da4e1242a15101ece28ccb28
Deleted: sha256:0b7dc712f354a2312c1f1bb6380d8e23919baf0cc09f32a5a4595afb6c3a440b
Deleted: sha256:3ecb32a94af1f9a46cc259bf6cc677acd1fef2023f746e973862d1a8c9e31fe3
Deleted: sha256:b4c8fa0ae3e9f4f7d0ee49a9ac13d8aebd6f2d4a53e204e75f74e4bcb143132f
Deleted: sha256:cd5b03306052e1a435b98a34cd2579dc48f8f0ca280a147f19f066ddb6a0b81d
Deleted: sha256:5d4427064ecc46e3c2add169e9b5eafc7ed2be7861081ec925938ab628ac0e25
[root@centos7-13 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
[root@centos7-13 ~]#
当使用 docker rmi 命令后面指定了某个镜像 ID 时,必须确保该镜像当前没有被任一容器使用才能进行。删除时系统会先删除掉所有指向该镜像的所有标签,然后删除该镜像文件本身。如果该镜像已经被容器使用,正确的做法是先删除依赖该镜像的所有容器,再去删除镜像。
3.5、存出镜像和载入镜像
当需要把一台机器上的镜像迁移到另一台机器上的时候,需要将镜像保存成为本地文件,这一过程叫做存出镜像,可以使用 docker save 命令进行存出操作,之后就可以拷贝该文件到其他机器。
命令格式:docker save -o 存储文件名 存储的镜像
例如:将存出本地的 nginx 镜像为文件 nginx:
bash
[root@centos7-13 ~]# docker save -o nginx nginx
[root@centos7-13 ~]# ll
总用量 187328
-rw-------. 1 root root 1473 4月 12 15:55 anaconda-ks.cfg
-rw------- 1 root root 191817728 5月 27 15:45 nginx
将存出的镜像从机器 A 拷贝到机器 B 后,需要在机器 B 上使用该镜像,就可以将该文件导入到机器 B 的镜像库中,这一过程叫做载入镜像。使用 docker load 或者 docker --input 进行载入操作。
命令格式:docker load < 存出的文件 或者 docker load -i 存出的文件
例如:从文件 nginx 中载入镜像到本地镜像库中。
bash
[root@centos7-13 ~]# docker load < nginx
5d4427064ecc: Loading layer [==================================================>] 77.88MB/77.88MB
fc1cf9ca5139: Loading layer [==================================================>] 113.9MB/113.9MB
747b290aeba8: Loading layer [==================================================>] 3.584kB/3.584kB
9f4d73e635f1: Loading layer [==================================================>] 4.608kB/4.608kB
56f8fe6aedcd: Loading layer [==================================================>] 2.56kB/2.56kB
7d2fd59c368c: Loading layer [==================================================>] 5.12kB/5.12kB
14773070094d: Loading layer [==================================================>] 7.168kB/7.168kB
Loaded image: nginx:latest
[root@centos7-13 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest e784f4560448 3 weeks ago 188MB
四、Docker 容器操作
容器是 Docker 的另一个核心概念。简单说,容器是镜像的一个运行实例,是独立运行的一个或一组应用以及它们所必需的运行环境,包括文件系统、系统类库、shell 环境等。镜像是只读模板,而容器会给这个只读模板添加一个额外的可写层。
下面具体介绍 Docker 容器的操作。
4.1、容器的创建与启动
Docker 的创建就是将镜像加载到容器的过程。Docker 的容器十分轻量级,用户可以随时创建或者删除。新创建的容器默认处于停止状态,不运行任何程序,需要在其中发起一个进程来启动容器,这个进程是该容器的唯一进程,所以当该进程结束时,容器也会完全停止。停止的容器可以重新启动并保留原来的修改。可以使用 docker create 命令新建一个容器。
命令格式:docker create [选项] 镜像
运行的程序常用选项:
- -i 让容器的输入保持打开;
- -t 让 Docker 分配一个伪终端;
例如:使用 docker create 命令创建新容器。
bash
[root@centos7-13 ~]# docker create -it nginx /bin/bash
bfc8ece4e82ae960aaede7f439831f8387ab2906c5d9b7b95ff2dee00d7e6759
使用 docker create 命令创建新容器后会返回一个唯一的 ID。
可以使用 docker ps 命令查看所有容器的运行状态。添加 -a 选项可以显示所有的容器,包括未运行的。
bash
[root@centos7-13 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bfc8ece4e82a nginx "/docker-entrypoint...." 9 seconds ago Created sweet_ritchie
docker ps -a 命令的输出信息显示了容器的 ID 号、加载的镜像、运行的程序、创建时间、目前所处的状态、端口映射。其中状态一栏为空表示当前的容器处于停止状态。
启动停止状态的容器可以使用 docker start 命令。
命令格式:docker start 容器的 ID /名称
例如:使用 docker start 命令启动新创建的容器。
bash
[root@centos7-13 ~]# docker start bfc8ece4e82a
bfc8ece4e82a
[root@centos7-13 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bfc8ece4e82a nginx "/docker-entrypoint...." 6 minutes ago Up 5 seconds 80/tcp sweet_ritchie
启动容器后,可以看到容器状态一栏已经变为 UP,表示容器已经处于启动状态。如果用户想创建并启动容器, 可以直接执行 docker run 命令, 等同于先执行 docker create 命令,再执行 docker start 命令。
注意:容器是一个与其中运行的 shell 命令共存亡的终端,命令运行容器运行, 命令结束容器退出。
当利用 docker run 来创建容器时, Docker 在后台的标准运行过程是:
- 检查本地是否存在指定的镜像。当镜像不存在时,会从公有仓库下载;
- 利用镜像创建并启动一个容器;
- 分配一个文件系统给容器,在只读的镜像层外面挂载一层可读写层;
- 从宿主机配置的网桥接口中桥接一个虚拟机接口到容器中;
- 分配一个地址池中的 IP 地址给容器;
- 执行用户指定的应用程序,执行完毕后容器被终止运行。
例如:创建容器并启动执行一条 shell 命令:
bash
[root@centos7-13 ~]# docker run nginx /usr/bin/bash -c 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
这和在本地直接执行命令几乎没有区别。
bash
[root@centos7-13 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1ce7f9d0da4 nginx "/docker-entrypoint...." 34 seconds ago Exited (0) 33 seconds ago crazy_heisenberg
查看容器的运行状态, 可以看出容器在执行"/usr/bin/bash -c ls" 命令之后就停止了。
有时候需要在后台持续的运行这个容器, 就需要让 Docker 容器以守护形式在后台运行。可以在 docker run 命令之后添加-d 选项来实现。但是需要注意容器所运行的程序不能结束。
例如,下面的容器会持续在后台进行运行:
bash
[root@centos7-13 ~]# docker run -d nginx /usr/bin/bash -c "while true;do echo hello;done"
e7e0cd12ff192bc1224f308d76c5ad8d5005531dcc393786890cd236b18dc87b
[root@centos7-13 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e7e0cd12ff19 nginx "/docker-entrypoint...." 6 seconds ago Up 5 seconds 80/tcp zealous_chatelet
查看容器的运行状态, 可以看出容器始终处于 UP,运行状态。
4.2、容器的运行与终止
如果需要终止运行的容器,可以使用 docker stop 命令完成。
命令格式:docker stop 容器的 ID/名称
停止运行的容器,例如停止容器 e7e0cd12ff19:
bash
[root@centos7-13 ~]# docker stop e7e0cd12ff19
e7e0cd12ff19
[root@centos7-13 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e7e0cd12ff19 nginx "/docker-entrypoint...." 2 minutes ago Exited (137) 3 seconds ago zealous_chatelet
查看容器的运行状态, 可以看出容器处于 Exited,终止状态。
4.3、容器的进入
需要进入容器进行相应操作时,可以使用 docker exec 命令进入运行着的容器。
命令格式:docker exec -it 容器 ID /名称 /bin/bash
其中:
- -i 选项表示让容器的输入保持打开;
- -t 选项表示让 Docker 分配一个伪终端。
例如:进入正在运行着的容器 bfc8ece4e82a。
bash
[root@centos7-13 ~]# docker exec -it bfc8ece4e82a /bin/bash
root@bfc8ece4e82a:/#
用户可以通过所创建的终端来输入命令,通过 exit 命令退出容器。
bash
root@bfc8ece4e82a:/# 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
root@bfc8ece4e82a:/# exit
exit
[root@centos7-13 ~]#
4.4、容器的导出与导入
用户可以将任何一个docker 容器从一台机器迁移到另一台机器。在迁移过程中, 可以使用 docker export 命令将已经创建好的容器导出为文件,无论这个容器是处于运行状态还是停止状态均可导出。可将导出文件传输到其他机器,通过相应的导入命令实现容器的迁移。
命令格式:docker export 容器 ID/名称 > 文件名
例如:导出 bfc8ece4e82a 容器到文件 nginx.tar。
bash
[root@centos7-13 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bfc8ece4e82a nginx "/docker-entrypoint...." 54 minutes ago Up 47 minutes 80/tcp sweet_ritchie
[root@centos7-13 ~]# docker export bfc8ece4e82a > nginx.tar
[root@centos7-13 ~]# ls -l nginx.tar
-rw-r--r-- 1 root root 190052864 5月 27 16:52 nginx.tar
导出的文件从 A 机器拷贝到 B 机器, 之后使用 docker import 命令导入, 成为镜像。
命令格式:cat 文件名 | docker import -- 生成的镜像名称:标签
例如:导入文件 nginx.tar 成为本地镜像。
bash
[root@centos7-13 ~]# cat nginx.tar | docker import - nginx:test
sha256:3db1cca22ef64bd928e5a2fb289f6a8504d68d094ebf6708ed813699efbb62b5
[root@centos7-13 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx test 3db1cca22ef6 3 seconds ago 186MB
4.5、容器的删除
可以使用 docker rm 命令将一个已经终止状态的容器进行删除。
命令格式:docker rm 容器 ID/名称
例如:删除 ID 号为 e7e0cd12ff19 的容器。
bash
[root@centos7-13 ~]# docker rm e7e0cd12ff19
e7e0cd12ff19
[root@centos7-13 ~]# docker ps -a | grep e7e0cd12ff19
[root@centos7-13 ~]#
如果删除一个正在运行的容器,可以添加 -f 选项强制删除。建议先将容器停止在做删除操作。
Docker 默认的存储目录在 /var/lib/docker 下,Docker 的镜像、容器、日志等内容全部都存储在此目录中,可以单独使用大容量的分区来存储这些内容,一般选择建立 LVM 逻辑卷,从而避免 Docker 运行过程中存储目录容量不足。
五、Docker 镜像管理
Docker 镜像除了是 Docker 的核心技术之外,也是应用发布的标准格式。一个完整的 Docker 镜像可以支撑一个 Docker 容器的运行,在 Docker 的整个使用过程中,进入一个已经定型的容器之后,就可以在容器中进行操作,最常见的操作就是在容器中安装应用服务。 如果要把已经安装的服务进行迁移,就需要把环境以及搭建的服务生成新的镜像。本案例将介绍如何创建 Docker 镜像。
5.1、Docker 镜像结构
镜像不是一个单一的文件,而是有多层构成。可以通过 docker history 命令查看镜像中各层内容及大小,每层对应着 Dockerfile 中的一条指令。Docker 镜像默认存储在 /var/lib/docker/<storage-driver> 目录中。容器其实是在镜像的最上面加了一层读写层, 在运行容器里做的任何文件改动,都会写到这个读写层。如果删除了容器,也就删除了其最上面的读写层,文件改动也就丢失了。Docker 使用存储驱动管理镜像每层内容及可读写层的容器层。Docker 镜像是分层的,下面这些知识点非常重要。
- Dockerfile 中的每个指令都会创建一个新的镜像层;
- 镜像层将被缓存和复用;
- 当 Dockerfile 的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同 了,对应的镜像层缓存就会失效;
- 某一层的镜像缓存失效,它之后的镜像层缓存都会失效;
- 镜像层是不可变的,如果在某一层中添加一个文件,然后在下一层中删除它,则镜像中依然会包含该文件,只是这个文件在 Docker 容器中不可见了。
5.2、Dockerfile 介绍
Dockfile 是一种被 Docker 程序解释的脚本,Dockerfile 由多条的指令组成,每条指令对应 Linux 下面的一条命令。Docker 程序将这些 Dockerfile 指令翻译成真正的 Linux 命令。 Dockerfile 有自己书写格式和支持的命令,Docker 程序解决这些命令间的依赖关系,类似于 Makefile。Docker 程序将读取 Dockerfile,根据指令生成定制的镜像。相比镜像这种黑盒子, Dockerfile 这种显而易见的脚本更容易被使用者接受,它明确的表明镜像是怎么产生的。有了 Dockerfile,当有定制额外的需求时,只需在 Dockerfile 上添加或者修改指令, 重新生成镜像。
六、案例:构建各类 Docker 镜像服务
6.1、案例环境
本案例环境如下表所示。
|--------|-------------------|------------------------|--------------------|
| 主机 | 操作系统 | 主机名/IP 地址 | 主要软件及版本 |
| 服务器 | CentOS 7.9 x86-64 | local / 192.168.23.213 | docker-ce-19.03.15 |
Docker 镜像管理案例环境
6.2、案例拓扑原理
通过 Dockerfile 创建常见应用镜像,Dockerfile 的构成如下图所示。
Dockerfile 构成图
6.3、案例需求
- 基于容器(现有镜像)创建镜像;
- 基于 Dockerfile 创建常用基础服务。
6.4、案例实施
创建镜像有三种方法, 分别为基于已有镜像创建、基于本地模板创建以及基于 Dockerfile 创建。下面着重介绍这三种创建镜像的方法。
1)基于现有镜像创建
基于现有镜像创建主要使用 docker commit 命令,即把一个容器里面运行的程序以及该程序的运行环境打包起来生成新的镜像。
命令格式:docker commit [选项] 容器 ID/名称 仓库名称:[标签] 常用选项:
- -m 说明信息;
- -a 作者信息;
- -p 生成过程中停止容器的运行。
首先启动一个镜像,在容器里做修改,然后将修改后的容器提交为新的镜像。需要记住该容器的 ID 号,如:
bash
[root@local ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1400c2c139c4 nginx "/docker-entrypoint...." 10 seconds ago Created sad_hermann
之后,可以使用docker commit命令创建一个新的镜像,如:
bash
[root@local ~]# docker commit -m "new" -a "my_nginx" 1400c2c139c4 my_nginx:test
sha256:22a3849d48a021989d049beb703043d047647200d998328b77f641e64553de44
创建完成后,会返回新创建镜像的 ID 信息。查看本地镜像列表时,可以看到新创建的镜像信息。
bash
[root@local ~]# docker images | grep my_nginx
my_nginx test 22a3849d48a0 About a minute ago 188MB
2)基于 Dockerfile 创建
除了手动生成 Docker 镜像之外,可以使用 Dockerfile 自动生成镜像。Dockerfile 是由一组指令组成的文件,其中每条指令对应 Linux 中的一条命令,Docker 程序将读取 Dockerfile 中的指令生成指定镜像。
Dockerfile 结构大致分为四个部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。Dockerfile 每行支持一条指令,每条指令可携带多个参数,支持使用以"#"号开头的注释。
Dockerfile 有十几条命令可用于构建镜像,下表中是常用的 Dockerfile 操作指令。
|--------------------------------|-----------------------------------------------------------|
| 指令 | 含义 |
| FROM 镜像 | 指定新镜像所基于的镜像,第一条指令必须为 FROM 指令,每创建一个镜像就需要一条 FROM 指令 |
| MAINTAINER 名字 | 说明新镜像的维护人信息 |
| RUN 命令 | 在所基于的镜像上执行命令,并提交到新的镜像中 |
| CMD ["要运行的程序","参数 1","参数 2"] | 启动容器时要运行的命令或者脚本,Dockerfile 只能有一条CMD 命令。如果指定多条命令,只执行最后一条命令 |
| EXPOSE 端口号 | 指定新镜像加载到 Docker 时要开启的端口 |
| ENV 环境变量 变量值 | 设置一个环境变量的值,会被后面的 RUN 使用 |
| ADD 源文件/目录 目标文件/目录 | 将源文件复制到目标文件,源文件要与 Dockerfile 位于相同目录中,或者是一个 URL |
| COPY 源文件/目录 目标文件/目录 | 将本地主机上的文件/目录复制到目标地点,源文件/目录要与 Dockerfile 在相同的目录中 |
| VOLUME ["目录"] | 在容器中创建一个挂载点 |
| USER 用户名/UID | 指定运行容器时的用户 |
| WORKDIR 路径 | 为后续的 RUN、CMD、ENTRYPOINT 指定工作目录 |
| ONBUILD 命令 | 指定所生成的镜像作为一个基础镜像时所要运行的命令 |
| HEALTHCHECK | 健康检查 |
在编写 Dockerfile 时,有严格的格式需要遵循:第一行必须使用 FROM 指令指明所基于的镜像名称;之后使用 MAINTAINER 指令说明维护该镜像的用户信息;然后是镜像操作相关指令,如 RUN 指令。每运行一条指令,都会给基础镜像添加新的一层。最后使用 CMD 指令指定启动容器时要运行的命令操作。
下面是使用 Dockerfile 创建镜像并在容器中运行的案例。
首先需要建立目录,作为生成镜像的工作目录,然后分别创建并编写 Dockerfile 文件、 需要运行的脚本文件以及要复制到容器中的文件。
6.4.1、构建 sshd 容器服务
下面是构建SSHD容器服务的操作步骤。
1)建立工作目录
bash
[root@local ~]# mkdir sshd
[root@local ~]# cd sshd
2)创建并编写 Dockerfile 文件
bash
[root@local sshd]# vim sshd-dockerfile
FROM centos:7.9.2009
RUN yum -y install openssh-server && echo "root:cisco@123" | chpasswd && sed -i '/^#PermitRootLogin/s/#//g' /etc/ssh/sshd_config && /usr/sbin/sshd-keygen -A && yum clean all
CMD [ "/usr/sbin/sshd","-D" ]
EXPOSE 22
3)生成镜像
bash
[root@local sshd]# docker build -t sshd:v1 -f sshd-dockerfile .
4)查看镜像
bash
[root@local sshd]# docker images | grep sshd
sshd v1 a10d5ea1a6fd 23 seconds ago 231MB
5)启动容器
bash
[root@local sshd]# docker run -d --name sshv1 -P sshd:v1
83a5cd0af3ace21da920d86ab7245beee98142fedab714fbe9f008d99e56349b
[root@local sshd]# docker ps -a | grep sshv1
83a5cd0af3ac sshd:v1 "/usr/sbin/sshd -D" 15 seconds ago Up 15 seconds 0.0.0.0:32768->22/tcp sshv1
[root@local sshd]# ssh -p 32768 root@192.168.23.213
The authenticity of host '[192.168.23.213]:32768 ([192.168.23.213]:32768)' can't be established.
ECDSA key fingerprint is SHA256:dq8lYWLlqVjVmA2cr+v30NUT4UKCt/+XAdyhjbq9OBs.
ECDSA key fingerprint is MD5:ae:19:a3:8d:30:73:5d:be:d7:fe:da:e3:4e:4b:17:36.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[192.168.23.213]:32768' (ECDSA) to the list of known hosts.
root@192.168.23.213's password:
[root@83a5cd0af3ac ~]# ls
anaconda-ks.cfg
6.4.2、构建 nginx 容器服务
1)建立工作目录
bash
[root@local ~]# mkdir nginx
[root@local ~]# cd nginx
2)创建并编写 Dockerfile 文件
bash
[root@local nginx]# vim nginx-dockerfile
FROM centos:7.9.2009
RUN yum -y install epel-release
RUN yum -y install nginx && yum clean all
CMD [ "nginx","-g","daemon off;" ]
VOLUME [ "/usr/share/nginx/html" ]
EXPOSE 80
3)生成镜像
bash
[root@local nginx]# docker build -t nginx:v1 -f nginx-dockerfile .
4)查看镜像
bash
[root@local nginx]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx v1 999927f8e265 10 seconds ago 512MB
5)启动容器
bash
[root@local nginx]# docker run -d --name web01 -P -v /root/wwwroot:/usr/share/nginx/html nginx:v1
99a0ec4661979605e0e30c96b66bc63004d3ee20f068770620193f1d1c57f279
[root@local nginx]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
99a0ec466197 nginx:v1 "nginx -g 'daemon of..." 3 seconds ago Up 2 seconds 0.0.0.0:32771->80/tcp web01
716a18a3118f eeb6ee3f44bd "/bin/sh -c 'yun -y ..." 19 minutes ago Exited (127) 19 minutes ago keen_pascal
83a5cd0af3ac sshd:v1 "/usr/sbin/sshd -D" 13 hours ago Exited (0) 13 hours ago sshv1
1400c2c139c4 nginx "/docker-entrypoint...." 16 hours ago Created sad_hermann
[root@local nginx]# cd /root/wwwroot/
[root@local wwwroot]# echo "web01" > index.html
-P 表示将容器的80端口发布到宿主机的随机端口
-v 表示将容器的网站根目录挂载到本地 /root/wwwroot 目录
6)浏览器访问
6.4.3、构建 MySQL 容器服务
MySQL 是当下最流行的关系型数据库, 所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 具有体积小、速度快、成本低的优势,成为中小型企业首选的数据库。下面使用 Dockerfile 文件的方式来创建带有 MySQL 服务的 Docker 镜像。
1)建立工作目录
bash
[root@local ~]# mkdir mysql
[root@local ~]# cd mysql
2)编写并创建 Dockerfile 文件
bash
[root@local mysql]# vim mysql-dockerfile
FROM centos:7.9.2009
RUN echo -e '[mysql57-community]\nname=MySQL 5.7 Community Server\nbaseurl=http://repo.mysql.com/yum/mysql-5.7-community/el/7/$basearch/\nenabled=1\ngpgcheck=0' > /etc/yum.repos.d/mysql57.repo && yum -y install mysql-community-server && /usr/sbin/mysqld --initialize-insecure && yum clean all
CMD [ "/usr/sbin/mysqld","--user=root" ]
EXPOSE 3306
3)生成镜像
bash
[root@local mysql]# docker build -t mysql:v1 -f mysql-dockerfile .
4)查看镜像
bash
[root@local mysql]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql v1 a3930119081a 18 seconds ago 1.37GB
5)启动容器
bash
[root@local mysql]# docker run -d --name mysqlv1 -P mysql:v1
cb6fad176bc36340b3fbf0e849c3d363a5552128cda60ea9e85518ea13daac64
[root@local mysql]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cb6fad176bc3 mysql:v1 "/usr/sbin/mysqld --..." 3 seconds ago Up 2 seconds 0.0.0.0:32772->3306/tcp mysqlv1
6)测试
bash
[root@local mysql]# docker exec -it mysqlv1 /bin/bash //进入容器
[root@cb6fad176bc3 /]# mysql -u root -p //登录数据库
Enter password:
mysql> grant all on *.* to root@'%' identified by 'cisco@123'; //给root用户远程连接权限
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> exit
Bye
[root@cb6fad176bc3 /]# exit
[root@local mysql]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cb6fad176bc3 mysql:v1 "/usr/sbin/mysqld --..." 11 minutes ago Up 10 minutes 0.0.0.0:32772->3306/tcp mysqlv1
[root@local mysql]# mysql -u root -h 192.168.23.213 -P 32772 -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.7.44 MySQL Community Server (GPL)
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [(none)]>
6.4.4、构建 LNMP 容器服务
LNMP 是代表 Linux 系统下的 Nginx、MySQL、PHP 相结合而构建成的动态网站服务器架构。下面使用 Dockerfile 文件的方式来创建带有 LNMP 架构的 Docker 镜像。
1)创建工作目录
bash
[root@local ~]# mkdir lnmp
[root@local ~]# cd lnmp
2)编写 Dockerfile 文件
bash
[root@local lnmp]# vim lnmp-dockerfile
FROM centos:7.9.2009
RUN yum -y install epel-release
RUN yum -y install nginx php php-mysql php-fpm && mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak && cp /etc/nginx/nginx.conf.default /etc/nginx/nginx.conf && sed -i '65,71s/#//g' /etc/nginx/nginx.conf && sed -i '65,71s/\/scripts/$document_root/g' /etc/nginx/nginx.conf && yum clean all
RUN echo -e '[mysql57-community]\nname=MySQL 5.7 Community Server\nbaseurl=http://repo.mysql.com/yum/mysql-5.7-community/el/7/$basearch/\nenabled=1\ngpgcheck=0' > /etc/yum.repos.d/mysql57.repo && yum -y install mysql-community-server && /usr/sbin/mysqld --initialize-insecure && yum clean all
ADD run.sh /root/run.sh
RUN chmod +x /root/run.sh
VOLUME [ "/usr/share/nginx/html" ]
CMD [ "/root/run.sh" ]
EXPOSE 80
3)编写启动脚本
bash
[root@local lnmp]# vim run.sh
#!/bin/bash
/usr/sbin/nginx
sleep 3
/usr/sbin/php-fpm &
sleep 3
/usr/sbin/mysqld --user=root
4)生成镜像
bash
[root@local lnmp]# docker build -t lnmp:v1 -f lnmp-dockerfile .
5)查看镜像
bash
[root@local lnmp]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
lnmp v1 31f27e9a3174 30 seconds ago 1.75GB
6)启动容器
bash
[root@local lnmp]# docker run -d --name lnmpv1 -P -v /root/wwwroot:/usr/share/nginx/html lnmp:v1
ba8d3aba40d70aada71aeacd42128397c0b7f75b2669a947f8cd361eb84918af
[root@local lnmp]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ba8d3aba40d7 lnmp:v1 "/root/run.sh" 3 seconds ago Up 2 seconds 0.0.0.0:32774->80/tcp lnmpv1
7)测试
bash
[root@local lnmp]# echo "lnmp-test" > /root/wwwroot/index.html
在浏览器访问
测试 php
bash
[root@local wwwroot]# vim test.php
<?php
$link=mysql_connect("localhost","root","");
if ($link) echo "MySQL is OK!";
mysql_close($link);
?>
在浏览器访问
七、Docker 的数据管理
在 Docker 中,为了方便查看容器内产生的数据或者共享多个容器之间的数据,就涉及到容器的数据管理操作。
管理 Docker 容器中数据主要有两种方式:数据卷(Data Volumes)和数据卷容器(Data Volumes Containers)。
7.1、数据卷
数据卷是一个供容器使用的特殊目录,位于容器中。可将宿主机的目录挂载到数据卷上,对数据卷的修改操作立刻可见,并且更新数据不会影响镜像,从而实现数据在宿主机与容器之间的迁移。数据卷的使用类似于 Linux 下对目录进行的 mount 操作。
7.2、创建数据卷
在 docker run 命令中使用 -v 选项可以在容器内创建数据卷。多次使用 -v 选项可创建多个数据 卷。使用 --name 选项可以给容器创建一个友好的自定义名称。
例如:使用 nginx 镜像创建一个名为 web 的容器,并且创建两个数据卷分别挂载到 /data1 与 /data2 目录上。
bash
[root@local ~]# docker run -d --name web -v /data1 -v /data2 nginx
e9f0d494052f0ef22b886470defad742e07b2de838fa48d559adfeb9f730f238
进入容器中,可以看到两个数据卷已经创建成功,并分别挂载到 /data1 与 /data2 目录上。
bash
[root@local ~]# docker exec -it web /bin/bash
root@e9f0d494052f:/# ls -l
total 4
lrwxrwxrwx 1 root root 7 May 13 00:00 bin -> usr/bin
drwxr-xr-x 2 root root 6 Jan 28 21:20 boot
drwxr-xr-x 2 root root 6 May 28 03:28 data1
drwxr-xr-x 2 root root 6 May 28 03:28 data2
7.3、挂载主机目录作为数据卷
使用 docker run 命令的 -v 选项可以在创建数据卷的同时,将宿主机的目录挂载到数据卷上使用,以实现宿主机与容器之间的数据迁移。
注意:宿主机本地目录的路径必须是使用绝对路径。如果路径不存在,Docker 会自动创建相应的路径。
例如:使用 nginx 镜像创建一个名为 web-1 的容器,并且将宿主机的 /var/www 目录挂载到容器的 /data1 目录上。
bash
[root@local ~]# docker run -d --name web-1 -v /var/www:/data1 nginx
f4fd58c01db368cba4dfedba2f38a6c9f4a944dce4f4cc97860a592ad948a091
在宿主机本地 /var/www 目录中创建一个文件 file,进入运行的容器中。在挂载目录下可以看到之前创建的文件 file,实现从宿主机到容器的数据迁移。
bash
[root@local ~]# cd /var/www/
[root@local www]# touch file
[root@local www]# ls
file
[root@local www]# docker exec -it web-1 /bin/bash
root@f4fd58c01db3:/# ls
bin boot data1 dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@f4fd58c01db3:/# ls /data1/
file
root@f4fd58c01db3:/#
同理,在宿主机相应的挂载目录中也可以访问容器数据卷中创建的数据。
7.4、数据卷容器
如果需要在容器之间共享一些数据,最简单的方法就是使用数据卷容器。数据卷容器是一个普通的容器,专门提供数据卷给其他容器挂载使用。使用方法如下:首先,需创建一个容器作为数据卷容器,之后在其他容器创建时用 --volumes-from 挂载数据卷容器中的数据卷使用。
例如:使用前面预先创建好的数据卷容器 web,其中所创建的数据卷分别挂载到了 /data1 与 /data2 目录上,使用 --volumes-from 来挂载 web 容器中的数据卷到新的容器,新的容器名为 db1。
bash
[root@local ~]# docker run -it --volumes-from web --name db1 nginx /bin/bash
root@3f281c82a069:/# ls
bin boot data1 data2 dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
在 db1 容器数据卷 /data1 目录中创建一个文件 file。在 web 容器中的 /data1 目录中,可以查看到它。
bash
root@3f281c82a069:/# cd data1
root@3f281c82a069:/data1# touch file
root@3f281c82a069:/data1# ls
file
root@3f281c82a069:/data1# exit
exit
[root@local ~]# docker exec -it web /bin/bash
root@e9f0d494052f:/# ls /data1
file
root@e9f0d494052f:/#