简明教程 | Docker篇 · 其一:基础入门
了解Docker
Docker是什么
Docker是指容器化技术,用于支持创建和使用 Linux 容器,同时Docker也是软件容器平台。
什么是容器(container)
容器是主机上与其他进程隔离的一个进程。这种隔离利用了内核对象命名空间(kernel namespaces)和控制组群(CGroup)。这些都是linux早已经存在的技术。Docker的作用就是将这些技术变得更易用。
什么是容器镜像(container image)
当运行容器时,它使用一个独立的文件系统,这个文件系统由容器镜像(container image)所提供。镜像包含了要运行容器需要的一切,包括依赖、配置、脚本、二进制文件等等。同时还包含了容器需要的其他配置,如环境变量和其他元数据。
简单理解Docker、Docker容器、Docker容器镜像
Docker可以简单理解为一个虚拟机平台,就类似于VMware,而容器当然就相当于一台台的虚拟机,所以容器镜像就类似于虚拟机的镜像啦。
为什么使用容器而不是虚拟机(VM)
容器比虚拟机更加"轻量",容器是一个应用层的抽象,多个容器运行时共享操作系统内核,只是作为独立的进程,占用空间少,启动快。而虚拟机是一个硬件层的抽象,多个虚拟机运行时,每个虚拟机都包含独立的操作系统,占用空间大,启动较慢。
Docker的其他优点
模块化
Docker 容器化方法注重在不停止整个应用的情况下,单独截取部分应用进行更改的能力,所以容器天然适合微服务。
易于跨平台
能简单的将一个平台上的应用迁移到另一个平台。
快速部署
启动运行新硬件、实施部署并投入使用往往需要大量的时间。基于 Docker 的容器的部署时间只需几秒不等。因此你可以高效的创建或销毁容器。
简单试试Docker
我们已经知道了Docker是什么了,接下来试试用用它,首先我们知道要创建一个Docker容器,就要先获取一个Docker镜像,这就用到了我们的第一个命令。
docker pull
docker pull [options] name[:tag|@digest]
tag
要获取的image的tag
这个命令会从Docker的默认镜像仓库中获取你想要的镜像,你可以从镜像仓库中选择你需要的tag,下图以 docker hub 中的ubuntu的镜像为例
镜像仓库
用于存放 docker 镜像的地址,官方默认的仓库是 Docker Hub,当然你也使用国内的镜像仓库 阿里云 、网易云 、时速云 、DaoCloud ,又或者你也可以使用自己搭建的私有仓库。
我们如果想获取它,只需要使用以下命令
docker pull ubuntu:20.04
我们可以看到以上有很多的"层",每一层都是可以可以被重用的。
你也许注意到了,我们还可以使用digest的方法拉取image,而刚刚我们拉取完后输出了它的digest,也就是说我们还可以以下方法拉取同样的image。
docker pull ubuntu@sha256:3c9c713e0979e9bd6061ed52ac1e9e1f246c9495aa063619d9d695fb8039aa1f
docker run
docker run [options] IMAGE[:tag|@digest] [command] [arg...]
在拉取后我们就应该运行容器了,而 docker run
指令应该是Docker最复杂的命令了,我们先试着使用刚刚拉取的image
docker run -it ubuntu:20.04 /bin/bash
当运行以上的命令后会发现命令行发生了变化
[root@VM-0-3-centos ~]# docker run -it ubuntu:20.04 /bin/bash
root@b4cc8facbeb7:/#
这就进入了我们创建的ubuntu容器
然后再来看看我们刚才做了什么,-i
的意思是保持输入,-t
的意思是分配一个tty终端,如果难以理解的话,只需知道对于交互式进程,需要带上 -it
。而我们刚刚的使用的 /bin/bash
当然属于交互式进程,对于输入的这条命令,docker会将它作为容器的内部的第一个进程(也就是pid为1)。同时 docker 会监控pid为1的进程,当它退出时,容器也会退出。
现在我们使用 exit
退出终端,使用 docker ps
指令查看所有正在运行的容器(如果还要查看其他状态的容器需要加上 -a
),会发现容器的 status
处于exit状态了。这是因为bash为第一个进程,当docker发现到它退出时便会退出容器。
root@b4cc8facbeb7:/# exit
exit
[root@VM-0-3-centos ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b4cc8facbeb7 ubuntu:20.04 "/bin/bash" 11 minutes ago Exited (0) 5 seconds ago magical_meninsky
[root@VM-0-3-centos ~]#
如果希望exit后自动删除它,可以带上 --rm
标签。
以及如果我们希望容器能在退出的时候,重新启动的话,就要用 --restart
更改重启策略。重启策略主要有以下几种
no
不重启
on-failure[:max-retries]
退出码非为0时重启,最多重启失败"max-retries"次
always
总是重启
在某些时候我们并不希望容器在前台运行,例如Redis、Nginx之类的应用在后台运行就可以了,我们只需要加上 -d
标签,就能在后台运行应用。
--name
能帮助我们为容器命名。不过即使没有命名,Docker也会生成uuid来为唯一标识容器。
在需要设置环境变量的场景下可以使用 -e
指令设置, -e var="var 1"
除了这些必要的标签外,还有其他的标签,我们在后面再讨论。
docker 容器的状态转换
docker create
根据image创建一个容器,但是并不实际启动,使用形式与 run
相似
docker create -it --name my_ubuntu ubuntu:20.04 /bin/bash
docker start
将一个处于 create
或 exited
状态的容器切换为 running
状态
docker start b4cc8facbeb7
等一下,我们似乎没有创建过叫做"b4cc8facbeb7"的容器?
实际上,我们之前说过Docker会生成uuid作为容器的id,当你使用
docker ps
查看容器时,就会发现container id这一列的存在,大部分可以能使用容器名称的场所也可以用容器id代替。同时你并不需要完整的输入容器id,只需要能够唯一确认一个容器即可。所以在这里你甚至可以使用
docker start b
。
docker pause/unpause
你可以使用 pause
和 unpause
对容器进行冻结和解冻,冻结状态下的容器中的所有进程会暂停
docker pause my_ubuntu
docker stop/kill
stop
和 kill
都是让容器退出主进程(即pid为1的进程)。但 stop
比 kill
更加优雅。
stop
会通知所在的容器即将退出,而 kill
会直接关闭容器。而容器会对 stop
传入的信号量进行响应然后退出(根据主程序的设置,也可能不退出),如果程序对信号量不做处理或没有退出才做强制退出。
实际上,在使用了
stop
或kill
后并不是一定退出了,需要用docker ps
命令查看来确保退出。这是因为执行
stop
的时候容器会先对主进程发送sigterm信号,如果主进程没有对sigterm信号做出处理,就不会退出。这样的话就必须等待到stop的超时时间,然后docker引擎会用kill
关闭。而
kill
指令也可能不能立刻杀死主进程,因为它发送的是sigkill信号。而原因属于《操作系统》的内容,所以这里简单略过。
docker rm
删除一个容器,如果要删除镜像的话就是 docker image rm
。这个容器必须要 exit
状态才能删除,否则的话需要带上 -f
(--force
)才能删除。
docker push
在执行push之前需要在对应的仓库 docker login
,docker默认的仓库为docker hub
docker attach
用于进入正在运行的容器。例如使用了以下命令:
docker run -it -d --name my_ubuntu ubuntu:20.04 /bin/bash
此时后台运行后要再次进入只需要:
docker attach my_ubuntu
docker inspect
获取有关Docker对象的信息
docker inspect my_ubuntu
docker exec
在正在运行中的容器中执行命令
docker exec [options] container command [arg...]
需要注意的是,command必须是可执行文件,要执行命令需要:
docker exec -it my_ubuntu sh -c "echo hello"
docker cp
交换容器与宿主机上的文件或文件夹
docker cp [options] 容器名称:容器中的地址 宿主机上的目标地址
docker cp [options] 宿主机上的目标地址 容器名称:容器中的地址
用例:
把主机上/data/fileA放到容器test下的/home/fileA
docker cp /data/fileA test:/home/fileA
docker diff
跟踪容器创建以来更改的文件和目录
用例:
$ docker diff myNginx # 容器名称
# C -> 更改、A -> 添加、D -> 删除
C /dev
C /dev/console
A /run/nginx.pid
C /var/lib/nginx/tmp
A /var/lib/nginx/tmp/client_body
docker 导入和导出
导出容器到压缩文件
docker export myNginx > latest.tar
从压缩文件或网络或输入流流导入
docker import [options] file|url|- [repository[:tag]]
docker import ./lastest.tar
同样可以做导入和导出的命令还有 save
和 load
,他们在使用上和 export
和 import
相同。
而他们的区别在于:
save
用来持久化image,export
用来持久化容器load
用来恢复image,import
恢复容器(但两者最后都会恢复为image)export
只会导出文件系统。也就是说任何元数据,如映射端口、 CMD 和 ENTRYPOINT 配置将会丢失。
基于以上的区别,export
的使用场景更偏向于制作基础镜像,save
的使用场景更偏向于打包复制镜像。
docker logs
查看容器的控制台的输出
先启动一个容器
docker run --name my_ubuntu -itd ubuntu:20.04 echo "hello world"
然后使用 docker logs
命令查看控制台
[root@VM-0-3-centos ~]# docker logs my_ubuntu
hello world
你还可以用 -t
标签输出时间戳和用 -f
跟踪控制台输出
docker stats
监控一个或多个容器的实时数据
[root@VM-0-3-centos ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
5ff9b00bdc08 competent_payne 0.12% 1.461MiB / 1.795GiB 0.08% 13.2kB / 0B 27.4MB / 0B 5
805ebe155e4f clever_turing 0.12% 60.95MiB / 1.795GiB 3.32% 72.9MB / 43.6MB 1.29GB / 2.01MB 32
6fbdf2516b99 mysql 0.13% 94.53MiB / 1.795GiB 5.14% 16.3MB / 27.1MB 2.42GB / 968MB 47
docker top
展示容器的进程
容器间的网络通信
首先,我们可以使用 link 命令
docker --link <container>:<alias>
示例:
docker run -it --link redis:myRedis --name my_ubuntu ubuntu /bin/bash
这个命令创建了一个 ubuntu 的容器,然后连接到已经存在的 redis 容器中。连接后就能在 ubuntu 的容器用 myRedis:3306
直接访问另一个容器中的 redis。
不过需要注意的是,使用这种方式的时候需要考虑容器的启动顺序,如一个 redis 集群的搭建使用
- 首先启动 redis-master 容器节点
- 然后在两个 redis-slave 容器节点启动时使用
--link
连接到 master 节点中 - 最后在 APP 容器节点启动时连接到 redis-master 上
link命令的连接方式的缺点非常明显,当容器的数量巨大的时候则需要使用多个link标签,其管理复杂,所以在官方的示例中使用的是network的方法,并且 link 的方式即将被废弃
network和link的方法差不多
docker network create myNetwork
然后我们可以查看我们创建的network
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
a106580bca09 bridge bridge local
c68edd500b5c host host local
f8ea00182e3a myNetwork bridge local
c120edcc6e0e none null local
除了我们创建的 myNetwork 外,还有三个内置的network,我们会在后面的文章中讨论这三个network
要连接到该网络的容器需要在创建容器时使用 --network
标签选择要添加的network,然后在同一个network下的容器就可以像是在同一个容器中进行连接
容器中的数据管理
数据卷(volume)
最常用的方式
绑定挂载(bind mounts)
不能跨平台,所以并非首选
tmpfs
不常用
数据卷的解释
数据卷是一个或多个容器中专门指定的目录,它能够绕过联合文件系统,也就是说数据卷的本质是容器中一个特殊的目录。
创建数据卷
docker volume create --name "要创建的数据卷名称"
当然你也可以在创建新容器的时候同时创建数据卷,就像这样
docker run -d -v /data ubuntu /bin/bash
这条命令使用"-v"标签添加一个随机名字的数据卷并挂载到了容器中的"/data"目录下,不过你也可以使用指定名字的数据卷
docker run -d -v myVolumn:/data ubuntu /bin/bash
这下我们成功创建了一个数据卷,不过被创建的数据卷被放到哪了呢?我们可以使用以下命令查看我们创建的数据卷,在执行结果中我们从 Mountpoint
中看到数据卷的放置位置
$ docker volume inspect myVolume
[{"CreatedAt": "2021-04-08T21:08:01+08:00","Driver": "local","Labels": {},"Mountpoint": "/var/lib/docker/volumes/myVolume/_data","Name": "myVolume","Options": {},"Scope": "local"}
]
创建完后就应该投入使用了,我们可以使用 --volumes-from
标签指定要共享的容器的名称
docker run --name test1 -d -v /data ubuntu /bin/bash
我们先创建一个新的容器,然后再新建一个共享的volume的容器
docker run -it --volumes-from test1 ubuntu /bin/bash
这样就完成了数据卷的共享
但是数据卷有时候是需要要删除的,不过简单的删除数据卷挂载的容器并不会删除数据卷,所以你需要手动的删除
docker volume rm <数据卷名称>
需要注意的是,这必须在没有容器挂载该数据卷的情况下才能成功
但是如果在创建时没有指定名称怎么办?我们可以这样
docker rm -v <容器名称>
使用上面这条命令可以在删除容器的同时顺便删除它所挂载的数据卷,并且你还可以在 docker run
的时候加上 --rm
标签,这样的话在容器停止运行时会删除容器和它的数据卷,当然,以上两条命令只会删除没有指定名称的数据卷 ,也就是说如果你已为数据卷命名,那就只能被第一种方法删除。
在某些时候我们也可以不创建数据卷,而直接挂载宿主机的目录
docker run -v /data/myData:/data/yourData ubuntu /bin/bash
这似乎和用数据卷的方式没多大区别。在这条命令中,我们将宿主机上的 /data/myData
文件夹绑定到了容器上的 /data/yourData
文件夹。
同时需要注意的是:
- 文件夹必须使用绝对路径
- 如果
/data/myData
不存在,则会创建一个空文件夹 - 而容器中的
/data/yourData
如果已经存在,则原有内容会被隐藏
当然你也可以直接挂载单个文件
docker run -v /data/configA.conf:/data/configA.conf -v /data/configB.conf:/data/configB.conf
ubuntu /bin/bash
当文件夹或文件被挂载时,可以用 :ro
来标记只读,和用 :z
来标记共享,:Z
来标记私有
docker run -v /data/configA.conf:/data/configA.conf:ro -v /data/configB.conf:/data/configB.conf:Z
ubuntu /bin/bash
最后我们还可以对数据卷备份和恢复
数据卷备份:
docker run --rm --volumes-from-v $(pwd):/backup
ubuntu
tar cvf /backup/data.tar /data
数据卷恢复:
docker run -it --name vol_bck -v /data
ubuntu /bin/bashdocker run --rm --volumes-from vol_bak -v $(pwd):/backup
ubuntu
tar xvf /backup/data.tar -C /
简明教程 | Docker篇 · 其一:基础入门相关推荐
- 简明教程 | Docker篇 · 其二:Dockerfile的编写
Dockerfile的构建 Dockerfile是什么 一个包含用于组合 image 的命令的文本文件,docker 通过 dockerfile 和构建环境的上下文来构建 image . 编写Dock ...
- 【docker】docker概述及基础入门
docker概述及基础入门 前言: docker是近年来非常火的一个容器化技术,相比传统的vmware虚拟化技术有着非常大的优势,(vm:小伙子你不讲武德),对于开发人员.测试人员.运维人员,再往上走 ...
- ArcGIS Pro 简明教程(2)基础操作和简单制图
ArcGIS Pro 简明教程(2)基础操作和简单制图 By 李远祥 本章主要介绍ArcGIS Pro如何加载数据并进行简单的地图制作,以基本的操作为主. 上一章节介绍过,ArcGIS Pro是可以直 ...
- 文案层次感文字设计#ps教程#PS抠图学习基础入门
文案层次感文字设计#ps教程#PS抠图学习基础入门
- 跟着王进老师学开发Python篇:基础入门案例讲解-王进-专题视频课程
跟着王进老师学开发Python篇:基础入门案例讲解-166人已学习 课程介绍 共计45个项目案例+项目源码,跟着王进老师尽情玩转Python解释器! 本课程涉及Python的基础语法, ...
- 视频教程-跟着王进老师学开发Python篇:基础入门案例讲解-Python
跟着王进老师学开发Python篇:基础入门案例讲解 教学风格独特,以学员视角出发设计课程,难易适度,重点突出,架构清晰,将实战经验融合到教学中.讲授技术同时传递方法.得到广大学员的高度认可. 王进 ¥ ...
- python3简明教程第二版答案_python入门简明教程?求最新的python简明教程,最好是python3的...
本人对于计算机没有任何基础,只是简单的操作.过两天要学习python语言的基础课,需要如何准备.跪谢! 先看python的简明教程,然后可以再看<dive into python>中文版( ...
- Kafka教程(一)基础入门:基本概念、安装部署、运维监控、命令行使用
Kafka教程(一)基础入门 1.基本概念 背景 领英->Apache 分布式.消息发布订阅系统 角色 存储系统 消息系统 流处理平台-Kafka Streaming 特点 高吞吐.低延迟 cg ...
- 计算机pscs6教程,photoshop CS6零基础入门教程
<photoshop CS6零基础入门教程>针对零基础学员开设,以教案和实际操作演示相结合的方式,详细地介绍adobe photoshop cs6的各项工具和命令.由浅入深.循序渐进地全面 ...
最新文章
- android 打开wifi并链接到制定ip,当设备连接到Android中的WiFi时,如何获取蜂窝网络的IP地址...
- java图形界面设计 swing之JTable表格的创建使用-添加鼠标监听
- HiKey960 开发板 android 编译
- 重塑自己的语音 笔记1
- QQ 一键加群、扫二维码加群 - 腾讯官方API文档接入
- Pandas知识点-索引和切片操作
- 前端集成方案——理论(一)
- 《南溪的目标检测学习笔记》——neck组件的设计笔记
- 品鉴贝叶斯公式里的大道理
- html页面显示代码插件,客户端显示web网页支持html5的第三方内核插件
- 国际贸易基础(六)外贸流程
- css文字闪光特效,利用js css3实现文字闪光滑过动画特效
- iOS非常全的三方库、插件、大牛博客
- Spark优化——推测执行机制
- 只在此山中,云深不知处
- 智能客服,还有多少AI泡沫?
- dubbo(5) Dubbo源码解析之服务调用过程
- Sql server AlwaysOn搭建常见问题
- setContentView 报错空指针异常
- 机器视觉毕业设计 Python图像拼接算法研究与实现 - opencv
热门文章
- MongoDB $unwind保留空数组
- 鲜为人知的训练神经网络技巧
- 自然语言处理的十个发展趋势
- 【数据库基础】Foreign Key的使用及其优缺点
- 机械键盘知识漫谈(三)- 轴体篇
- 指令----win10/mac/linux常用快捷键(指令)整理
- unity转微信小游戏及接api方法
- 嵌入式系统开发教程 - 创新课程设计- “AI人脸识别+扩展系统”
- 小区地下车库怎么进出,怎么用导航找自己停车的位置
- EPICGAMES-导入游戏,只能导入本就是EPIC中下载的游戏,用于EPIC不识别的情况