简明教程 | 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/bash
docker run
--rm
--volumes-from vol_bak
-v $(pwd):/backup
ubuntu
tar xvf /backup/data.tar -C /
简明教程 | Docker篇 · 其一:基础入门的更多相关文章
- 简明教程 | Docker篇 · 其二:Dockerfile的编写
Dockerfile是什么 一个包含用于组合 image 的命令的文本文件,docker 通过 dockerfile 和构建环境的上下文来构建 image . 编写Dockerfile FROM 首先 ...
- ArcGIS Pro 简明教程(2)基础操作和简单制图
ArcGIS Pro 简明教程(2)基础操作和简单制图 By 李远祥 本章主要介绍ArcGIS Pro如何加载数据并进行简单的地图制作,以基本的操作为主. 上一章节介绍过,ArcGIS Pro是可以直 ...
- 【Python教程】《零基础入门学习Python》(小甲鱼)
[Python教程]<零基础入门学习Python>(小甲鱼) 讲解通俗易懂,诙谐. 哈哈哈. https://www.bilibili.com/video/av27789609
- docker容器技术基础入门
目录 docker容器技术基础入门 容器(Container) 传统虚拟化与容器的区别 Linux容器技术 Linux Namespaces CGroups LXC docker基本概念 docker ...
- Docker 系列之 基础入门
安装 Docker Windows 10 专业版以上版本 Docker for Windows Installer 在安装前,需要确保目标机器已经开启了硬件虚拟化和 HyperV :在安装的过程中建议 ...
- Python 简明教程 --- 3,Python 基础概念
微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 控制复杂性是计算机编程的本质. -- Brian Kernighan 了解了如何编写第一个Pytho ...
- 推荐csdn里的几篇activiti基础入门及提高的博客
昨天有个网友加qq询问我有没有非maven搭建的activiti项目的demo,因为我博客中写了一个用maven,我当时没有,于是晚上回家尝试了一下,结果比较容易就实现了. 之后和那个网友聊了一下,他 ...
- 1、docker容器技术基础入门
Docker和传统虚拟机的区别 参考文章: https://lwn.net/Articles/531114/ 操作中的命名空间详解 https://blog.yadu ...
- Python unittest第一篇:基础入门+命令行编译
unittest单元测试框架最初受JUnit启发,与其他语言的主要单元测试框架具有相似的风格. 它支持测试自动化,支持开启或关闭某个测试,支持结合测试.另外它可以生成各个单元测试的报告.为了实现以上功 ...
随机推荐
- 如何解决浮动元素高度塌陷---CSS
解决高度塌陷问题的方法: 方法一. //给父元素添加声明 overflow:hidden; 缺点:回隐藏溢出的元素: 方法二. 在浮动的元素下添加空div标签,并给该元素添加声明: clear:bot ...
- 找不到方法:“Void System.Data.Objects.ObjectContextOptions.set_UseConsistentNullReferenceBehavior(Boolean)
找不到方法:"Void System.Data.Objects.ObjectContextOptions.set_UseConsistentNullReferenceBehavior(Boo ...
- pip国内源设置
在目录 C:\Users\Administrator下新建pip目录 C:\Users\Administrator\pip 添加 pip.ini 文件 pip.ini内容设置为 [global] in ...
- 洛谷P1090——合并果子(贪心)
https://www.luogu.org/problem/show?pid=1090 题目描述 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合 ...
- Jmeter扩展组件开发(10) - 自定义扩展函数助手的开发
CODE package com.functions;import org.apache.jmeter.engine.util.CompoundVariable;import org.apache.j ...
- P1013 [NOIP1998 提高组] 进制位
解析 看到这道题时,有没有想到搜索?然后就是一通码......然后过了. 但是,真的要用搜索吗? 我们可以观察一下.对于n进制中的数ii,如果ii加上某一个数jj会变成两位数,那么可以得到如下不等式: ...
- Loj#2880-「JOISC 2014 Day3」稻草人【CDQ分治,单调栈,二分】
正题 题目链接:https://loj.ac/problem/2880 题目大意 给出平面上的\(n\)个点,然后求有多少个矩形满足 左下角和右上角各有一个点 矩形之间没有其他点 \(1\leq n\ ...
- CF204E-Little Elephant and Strings【广义SAM,线段树合并】
正题 题目链接:https://www.luogu.com.cn/problem/CF204E 题目大意 \(n\)个字符串的一个字符串集合,对于每个字符串求有多少个子串是这个字符串集合中至少\(k\ ...
- Keras函数——keras.callbacks.ModelCheckpoint()及模型的训练
keras.callbacks.ModelCheckpoint(filepath, monitor='val_loss', verbose=0, save_best_only=False, save_ ...
- CRM是什么,你有认真了解过CRM吗?
这是CRM的一个简单定义 客户关系管理 (CRM)是一种用于管理公司与客户和潜在客户的所有关系和互动的技术.目标很简单:改善业务关系.CRM 系统可帮助公司与客户保持联系.简化流程并提高盈利能力. 当 ...