[Docker] Docker 基础教程(概念/原理/基础操作)
1 概述
1.1 定义
Docker is a platform that allows you to "build ,ship ,and run any app, anywhere. "
- Docker是一个平台,它提供哪些服务呢?任何一台装有Docker的机器上你都可以
构建
、发布
、运行
你的应用程序。
It has come a long way in an incredibly short time and is now considered a standard way of solving one of the costliest aspects of software: deployment.
- Docker在很短的时间内就走得很远,如今它基本是解决软件最昂贵的环节:部署的标准解决方案。
在Docker出现之前,有一堆与软件部署的工具软件,虚拟机、配置管理工具、打包管理工具、复杂的webs库依赖。所有这些工具都需要专业的工程师去管理和维护,多数软件有一套独特的配置方法。
小结:
-
Docker
是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。
开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何支持 docker 的机器上运行。
容器是完全使用沙箱机制,相互之间不会有任何接口调用。 -
Docker
是Docker
公司开源的一个基于轻量级虚拟化技术的容器引擎项目,整个项目基于Google
推出的Go
语言开发,并遵从Apache 2.0
协议。
由于隔离的进程独立于
宿主机(真实机器)
和其它的隔离的进程,因此也称其为容器
。Docker最初实现是基于LXC
。
目前,Docker可以在容器内部快速自动化部署应用,并可以内核虚拟化技术(Linux
的namespaces
及cgroups
等)、AUFS
类的UnionFS
等技术对进程进行封装隔离,以此提供容器的资源隔离与安全保障等。
由于Docker通过操作系统层的虚拟化实现隔离,所以Docker容器在运行时,不需要类似虚拟机(VM)额外的操作系统开销,提高资源利用率,并且提升诸如IO等方面的性能。
由于众多新颖的特性以及项目本身的开放性,Docker在不到两年的时间里迅速获得诸多厂商的青睐,其中更是包括Google、Microsoft、VMware等业界行业领导者。
Kubernetes
,提供Docker
容器的调度服务,而2018年8月Microsoft
宣布Azure
上支持Kubernetes
,随后传统虚拟化巨头VMware
宣布与Docker
强强合作。2018年9月中旬,Docker
更是获得4000万美元的C轮融资,以推动分布式应用方面的发展。
从2018年的形势来看,
Docker
的前景一片大好。但后来的发展,又是另一回事了。
1.2 使用Docker来干什么?
比较一下Docker诞生前和诞生后软件开发的变化就能感受到Docker可以用来干嘛了。
Docker诞生标志着软件工程领域进入新纪元
1.3 为什么要使用Docker?
1.4 优缺点
1.4.1 优点
1)快
运行时的性能快,管理操作(启动,停止,开始,重启等等) 都是以秒或毫秒为单位的。
2)敏捷
像虚拟机一样敏捷,而且会更便宜,在 bare metal(裸机)上布署像点个按钮一样简单。
3)灵活
将应用和系统“容器化”,不添加额外的操作系统
4)轻量
在一台服务器上可以布署 100~1000 个 Containers 容器。
5)便宜
开源的,免费的,低成本的。
1.4.2 缺点
所有容器共用 linux kernel 资源,资源能否实现最大限度利用,所以在安全上也会存在漏洞。
1.5 版本
目前最近的2个版本
- docker-ce
docker-ce-18.06.3.ce-3.el7
- docker-ee
1.6 Docker 应用场景
-
Web 应用的自动化打包和发布。
-
自动化测试和持续集成、发布。
-
在服务型环境中部署和调整数据库或其他的后台应用。
-
从头编译或者扩展现有的 OpenShift 或 Cloud Foundry 平台来搭建自己的 PaaS 环境。
1.X Docker 的安装
- 参见
2 Docker的原理与概念
2.0 Docker的架构与模式
2.0.1 体系结构
- 传统的虚拟机 vs Docker
- VM是在宿主机器操作系统的基础上创建虚拟化的操作系统,需要重新加载一个Guest OS。
- Docker是在宿主操作系统上运行Docker引擎,在引擎的基础上再安装应用。
- Docker是共享【宿主机的内核】,有着比VM更少的抽象层。
- 进程 vs 应用容器/虚拟容器
Docker,从狭义上来讲就是一个进程;
Docker,从广义上来讲是一个虚拟容器,其实更专业的叫法是应用容器(Application Container
),Docker 进程和普通的进程没有任何区别,它就是一个普通的应用进程。不过是用来操作镜像文件的。所以 Docker 进程 + 构建的应用镜像文件就等于 Docker 容器。
- 底层技术:基于 Linux 3.10 +
从 Docker 依赖的底层技术来看,Docker 原生态是不能直接在 Windows 平台上运行的,只支持 linux 系统,原因是 Docker 依赖 linux kernel 三项最基本的技术。
namespaces
充当隔离的第一级,是对 Docker 容器进行隔离,让容器拥有独立的 hostname,ip,pid,同时确保一个容器中运行一个进程而且不能看到或影响容器外的其它进程 ;
Cgroups
是容器对使用的宿主机资源进行核算并限制的关键功能。比如 CPU, 内存, 磁盘等
Union FS
主要是对镜像也就是 image 这一块作支持,采用 copy-on-write 技术,让大家可以共用某一层,对于某些差异层的话就可以在差异的内存存储,Libcontainer 是一个库,是对上面这三项技术做一个封装。
Docker engine
用来控制容器 container 的运行,以及镜像文件的拉取。
由架构图可见,用户是使用Docker Client与Docker Daemon建立通信,并发送请求给后者
详情参见: Docker源码分析(一):Docker架构 - CSDN
- 安装Docker,需注意版本问题
安装之前,我们首先确保自己的 linux 系统内核版本高于
3.10
,并且系统是64
位,才能体验 Docker。
2.0.2 部署架构/运行架构
概念 | 说明 |
---|---|
Docker 镜像(Images) | Docker 镜像是用于创建 Docker 容器的模板,比如 Ubuntu 系统。 类似于 VM 虚拟机里面的快照,但是可比快照轻量化多了。快照不懂?那可以把 images 直接理解成一个文件夹。我们可以通过 ID 或者易识别的名字 + tag 来确认唯一的目标镜像。 ImagesID 是一个 64 位的字符,但是一般我们都是使用前面 12 位就足够区别了。镜像是分层的,有基础镜像,仅仅包含操作系统,比如 centos 镜像;有中间件镜像,比如 redis 等数据库镜像;最后是应用镜像,就是指具体的应用服务了,应用镜像可以非常丰富,随时可以发布,这三者之间依次叠加。 当我们在使用 Docker 构建镜像的时候,每一个命令都会在前一个命令的基础上形成一个新镜像层。如下图,基础镜像就是 centos 镜像,中间件镜像就是两个红色圈,应用镜像就是紫色圈。其中 redis+centos 这样叠加组合的中间件镜像就可以供 A 服务或者 B 服务使用,这样叠加组合更加灵活。仍和一种镜像都可以从 Docker hub 公共仓库中拉取。 |
Docker 容器(Container) | 容器是独立运行的一个或一组应用,是镜像运行时的实体。 容器就是一个个独立的封闭的集装箱,但是也需要对外提供服务的,所以 Docker 允许公开容器的特定端口,在启动 Docker 的时候,我们就可以将容器的特定端口映射到宿主机上面的任意一个端口 |
Docker 客户端(Client) | Docker 客户端通过命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 与 Docker 的守护进程通信。 |
Docker 主机(Host) | 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。 |
Docker 仓库(Registry) | Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。 docker 仓库和存放集装箱的仓库是一样的,不过 docker 使用来存放镜像的。仓库存在公有和私有之分,公有仓库 docker hub 提供了非常多的镜像文件,这些镜像直接拉取下来就可以运行了,你也可以上传自己的镜像到 docker hub 上面。同时也可以自己搭建私有仓库用于团队项目管理。 Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用。一个 Docker Registry 中可以包含多个仓库(Repository );每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。 |
Docker Machine | Docker Machine是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,比如VirtualBox、 Digital Ocean、Microsoft Azure。 |
- Docker 使用了
client
/server
的架构模式,如下图所示 - Docker daemon 是后台总管,对外提供了REST API,当收到 Docker Client 发送的请求时,执行诸如镜像、容器、网络、存储等一系列操作
2.0.3 PUID与PGID
引言
-
前情提要:无Linux、Docker基础的朋友,因过于晦涩,建议跳过本章
-
在 docker 容器创建命令中偶然看到这2个参数。故此,有必要深究一二。
Demo
docker create --name=beets -e PUID=1000 -e PGID=1000 linuxserver/beets
- 参考文献
先来了解下 linux 的 uid 和 gid
uid
和gid
由 Linux 内核负责管理,并通过内核级别的系统调用来决定是否应该为某个请求授予特权。
比如当进程试图写入文件时,内核会检查创建进程的 uid 和 gid,以确定它是否有足够的权限修改文件。注意,内核使用的是 uid 和 gid,而不是用户名和组名。
简单起见,本文中剩下的部分只拿 uid 进行举例,系统对待 gid 的方式和 uid 基本相同。
很多同学简单地把 docker 容器理解为轻量的虚拟机,虽然这简化了理解容器技术的难度,但是也容易带来很多的误解。
事实上,与虚拟机技术存在不同之处:同一主机上运行的所有容器共享【同一个内核(主机的内核)】。
容器化带来的巨大价值之一在于————所有这些独立的容器(其实是进程)可以【共享一个内核】。
这意味着即使由成百上千的容器运行在 docker 宿主机上,但内核控制的uid
和gid
则仍然只有一套。
所以,同一个uid
在宿主机和容器中代表的是同一个用户(即便在不同的地方显示了不同的用户名)。
注意,由于普通的用来显示用户名的
Linux
工具并不属于内核(比如id
等命令)
所以,我们可能会看到同一个uid
在不同的容器中显示为不同的用户名。
但是对于相同的uid
不能有不同的特权,即使在不同的容器中也是如此。
- 如果你已经了解了 Linux 的
user namespace
技术,参考《Linux Namespace : User》
你需要注意的是到目前为止,docker 默认并没有启用
user namesapce
,这也是本文讨论的情况。笔者会在接下来的文章中介绍如何配置 docker 启用 user namespace。
Q1 为什么 Docker 容器需要使用 PUID
和 PGID
?
- 因为Docker需要系统中管理网络、文件系统、进程的权限。所以,通常是以
root
的身份在运行。
这意味着,容器内的用户默认也是以
root
用户运行。
这种高权限的访问,并不是日常使用中所推荐的,除非你对linux运维有着深入的理解。
- 另一个问题就是对容器映射出来的文件的管理。如果进程是以
root
身份运行,那么它所创建的文件的所有者都是root
用户,这有可能会导致你没有权限去修改这些文件(如果你是以非root身份登陆服务器。)
而是用PUID
和PGID
允许我们将容器内的用户权限映射给宿主机上的用户。
我们所有的容器都可以使用这种方法来映射用户权限。
Q2 使用方式
- 当使用我们的镜像创建容器时,确保你是用了
-e PUID
和-e PGID
:
docker create --name=beets -e PUID=1000 -e PGID=1000 linuxserver/beets
- 如果使用
docker-compose
,把他们添加在environment:
下:
environment:
- PUID=1000
- PGID=1000
Q3 如何获知宿主机的 UID
和 GID
?
- 到这里,你很可能希望使用自己的
id
,可以通过下面的命令来查询你当前用户的id。其中uid
和gid
分别对应PUID
和PGID
:
~# id $user
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
深究:Docker 容器中默认使用 root 用户
- 如果不做相关的设置,容器中的进程默认以
root
用户权限启动,下面的 demo 使用 ubuntu 镜像运行sleep
程序:
$ docker run -d --name sleepme ubuntu sleep infinity
注意:上面的命令中并没有使用
sudo
。笔者在宿主机中的登录用户是nick
,uid
为1000
:
- 在宿主机中查看
sleep
进程的信息:
$ ps aux | grep sleep
sleep
进程的有效用户名称是root
,也就是说 sleep 进程具有 root 权限。
然后,进入容器内部看看,看到的情况和刚才一样,sleep 进程也具有 root 权限:
那么,容器内的 root 用户和宿主机上的 root 用户是同一个吗?
答案是:是的,它们对应的是同一个 uid。
原因我们在前面已经解释过了:整个系统共享同一个内核,而内核只管理一套 uid 和 gid。
其实,我们可以通过数据卷来简单的验证上面的结论。在宿主机上创建一个只有 root 用户可以读写的文件:
然后挂载到容器中:
$ docker run --rm -it -w=/testv -v $(pwd)/testv:/testv ubuntu
- 在容器中可以读写该文件:
我们可以通过 Dockerfile 中的 USER
命令或者是 docker run
命令的 --user
参数指定容器中进程的用户身份。下面我们分别来探究这两种情况。
深究:在 Dockerfile 中指定用户身份
我们可以在 Dockerfile
中添加一个用户 appuser
,并使用 USER
命令指定以该用户的身份运行程序,Dockerfile 的内容如下:
FROM ubuntu
RUN useradd -r -u 1000 -g appuser
USER appuser
ENTRYPOINT ["sleep", "infinity"]
- 编译成名称为 test 的镜像:
$ docker build -t test .
- 用 test 镜像启动一个容器:
$ docker run -d --name sleepme test
- 在宿主机中查看 sleep 进程的信息:
这次显示的有效用户是 nick,这是因为在宿主机中,uid 为 1000 的用户的名称为 nick。再进入到容器中看看:
$ docker exec -it sleepme bash
容器中的当前用户就是我们设置的 appuser
,如果查看容器中的 /etc/passwd
文件,你会发现 appuser 的 uid 就是 1000,这和宿主机中用户 nick 的 uid 是一样的。
让我们再创建一个只有用户 nick
可以读写的文件:
- 同样,以数据卷的方式把它挂载到容器中:
$ docker run -d --name sleepme -w=/testv -v $(pwd)/testv:/testv test
- 在容器中 testfile 的所有者居然变成了 appuser,当然 appuser 也就有权限读写该文件。
这里到底发生了什么?而这些又这说明了什么?
- 首先,宿主机系统中存在一个 uid 为 1000 的用户 nick。其次容器中的程序是以 appuser 的身份运行的,这是由我们通过 USER appuser 命令在 Dockerfile 程序中指定的。
- 事实上,系统内核管理的 uid 1000 只有一个,在宿主机中它被认为是用户 nick,而在容器中,它则被认为是用户 appuser。
- 所以,有一点我们需要清楚:在容器内部,用户 appuser 能够获取容器外部用户 nick 的权力和特权。在宿主机上授予用户 nick 或 uid 1000 的特权也将授予容器内的 appuser。
深究:从命令行参数中指定用户身份
- 我们还可以通过
docker run
命令的--user
参数指定容器中进程的用户身份。
比如执行下面的命令:
$ docker run -d --user 1000 --name sleepme ubuntu sleep infinity
- 因为我们在命令行上指令了参数
--user 1000
,所以这里 sleep 进程的有效用户显示为nick
。进入到容器内部看一下:
$ docker exec -it sleepme bash
这是个什么情况?用户名称居然显示为 "I have no name!"!去查看 /etc/passwd 文件,里面果然没有 uid 为 1000 的用户。即便没有用户名称,也丝毫不影响该用户身份的权限,它依然可以读写只有 nick 用户才能读写的文件,并且用户信息也由 uid 代替了用户名:
需要注意的是,在创建容器时通过 docker run --user
指定的用户身份会覆盖掉 Dockerfile
中指定的值。
我们重新通过 test 镜像来运行两个容器:
$ docker run -d test
- 查看 sleep 进程信息:
$ docker run --user 0 -d test
- 再次查看 sleep 进程信息:
指定了 --urser 0
参数的进程显示有效用户为 root
,说明命令行参数 --user 0
覆盖掉了 Dockerfile
中 USER
命令的设置。
小结
从上述示例我们可以了解到,容器中运行的进程同样具有访问主机资源的权限(docker 默认并没有对用户进行隔离),当然一般情况下容器技术会把容器中进程的可见资源封锁在容器中。
但是通过我们演示的对数据卷中文件的操作可以看出,一旦容器中的进程有机会访问到宿主机的资源,它的权限和宿主机上用户的权限是一样的。
所以,比较安全的做法是为容器中的进程指定一个具有合适权限的用户,而不要使用默认的 root 用户。
当然还有更好的方案,就是应用 Linux 的 user namespace 技术隔离用户,如何配置 docker 开启 user namespace 的支持,参见:隔离 docker 容器中的用户 - 博客园/sparkdev。
2.1 镜像(Image) ≈ 容器的静态模板
Docker的
image
可以理解是一个只读的静态模板
,类似于我们在装系统的时候用到的.iso
文件
操作系统分为内核
和用户空间
。
对于Linux而言,内核启动后,会挂载root文件系统为其提供用户空间支持。
而Docker镜像
(Image
),就相当于是一个root文件系统。
现在重新理解一下我们使用一个linux系统的过程:
我们开机时,linux内核会先启动;然后,挂载root文件系统作为用户空间;
而Docker镜像就相当于是一个root文件系统,每开一个就有了一个独立的用户空间。
2.2 容器(Container) ≈ 镜像的动态实例
container
则相对而言是一个动态的instance
。
或说可以理解为我们装好了系统之后的某一台计算机,可以开机,关机,重启等等,也可以被格式化(删除)
如果我们想在另一台计算机上复现我这台计算机的系统,则可以ghost一个新的镜像,然后去安装(虽然这种操作通常不行,因为底层硬件的驱动可能不匹配)。
2.2.1 镜像(Image)与容器(Container)的关系
镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的类,容器是镜像运行时的实体。
容器可以被创建、启动、停止、删除、暂停等 。
容器的实质是进程
,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间。
前面讲过镜像使用的是分层存储,容器也是如此。
按照Docker最佳实践的要求,
容器
不应该向其存储层
内写入任何数据 ,容器存储层
要保持无状态化。
所有的文件写入操作,都应该使用数据卷
(Volume)、或者绑定宿主目录
,在这些位置的读写会跳过容器存储层
,直接对宿主
(或网络存储
)发生读写,其性能和稳定性更高。
所谓“绑定宿主目录”,就是在run一个container的时候使用-v命令把宿主机的存储目录映射进container。
我们可以这样理解:
image是分层存储的,我们每做一次修改就会在原本的Image存储层上多搭一层,记录这个更改;而新搭的这层是静态、且可以持久化存储的。
Container也是相同额存储架构,但是每次修改新搭的一层是动态的,而且并不是持久化存储的;
当容器被remove,或者重启计算机(内存断电)之后,container没了,相应的这些容器存储层也没了。
因此,要尽量保持容器存储层无状态化,所有的contain里产生的数据(比如container里的程序的运行结果)都要通过挂载宿主目录直接写进宿主硬盘里。
2.3 仓库(Repository) ≈ 模板仓库
2.3.1 Docker Hub 和 Docker Registry
-
Docker Hub 是一个公共的镜像注册中心,开发者可以在其中找到大量官方和社区维护的 Docker 镜像。同时,您也可以在 Docker Hub 上创建自己的账户,并上传自己构建的镜像供他人使用。
-
Docker Registry 则是 Docker 镜像的私有仓库,它允许您在自己的服务器上存储和管理镜像。企业和组织通常使用 Docker Registry 来保护和控制访问其内部构建的镜像。
最常使用的
Registry
公开服务是官方的Docker Hub
,这也是默认的Registry
,并拥有大量的高质量的官方镜像
2.3.2 Docker Registry
我们可以把
构建好后的镜像
(Image
)上传到服务器,从而可以在任何地方使用到这个镜像。
- 一个
Docker Registry
中可以包含多个仓库
(Repository
) - 每个
仓库
可以包含多个标签
(Tag
) - 每个
标签
对应一个镜像
(Image
)
通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本 。
我们可以通过<仓库名>:<标签>
的格式来指定具体是这个软件哪个版本的镜像
。
如果不给出标签
,将以latest
作为默认标签
。
2.4 Docker Container 生命周期
Docker 容器的生命周期包括以下几个关键阶段:
- 创建(Create):基于镜像创建一个新的容器实例。
- 启动(Start):启动已创建的容器,使其处于运行状态。
- 运行(Run):在容器中运行应用程序,处理请求等。
- 停止(Stop):停止正在运行的容器,但并不会删除它。
- 删除(Delete):从主机系统中删除已停止的容器实例。
- 监控(Monitor):监控容器的运行状态和资源使用情况。
3 docker的基本用法
3.0 docker服务管理
3.0.1 查看安装信息(CENTOS7)
whereis docker
which docker
3.0.2 版本信息
docker version
3.0.3 服务启停(CENTOS7)
systemctl start docker
systemctl status docker
3.0.4 开启自启(CENTOS7)
systemctl enable docker
3.1 镜像操作
创建镜像
- 创建镜像
Docker build 是一个 Docker 命令,用于构建 Docker 镜像
docker build [OPTIONS] PATH | URL | -
-f,--file
指定Dockerfile文件的路径。不指定时,默认会读取上下文路径下的 dockerfile-t,--tag
指定构建的镜像名和 tag。例如,构建的镜像指定多个 tag:docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .
--add-host
可以使用一个或多个--add-host
标志将其他主机添加到容器的/etc/hosts
文件中。如:docker build --add-host=docker:10.180.0.1 .
--no-cache
构建镜像时不使用缓存--network
在构建过程中为 RUN 指令设置网络模式
更多参数可以看官方文档: https://docs.docker.com/engine/reference/commandline/build/
[case 1] 使用当前目录的 Dockerfile 创建镜像,标签为 runoob/ubuntu:v1
format:docker build -t <image_name>[:<tag, defaultValue=latest>] .
docker build -t runoob/ubuntu:v1 .
[case 2] 使用URL github.com/creack/docker-firefox 的 Dockerfile 创建镜像
docker build github.com/creack/docker-firefox
[case 3] 可以通过 -f Dockerfile 文件的位置:
$ docker build -f /path/to/a/Dockerfile .
[case 4] 在 Docker 守护进程执行
Dockerfile
中的指令前,首先会对 Dockerfile 进行语法检查,有语法错误时会返回:
$ docker build -t test/myapp .
Sending build context to Docker daemon 2.048 kB
Error response from daemon: Unknown instruction: RUNCMD
从 dockerhub 查找镜像
- 方法1:基于 dockerhub 官网 或 github dockerhub 官方镜像库 【推荐】
这样能搜索支持的具体版本有哪些、使用文档、注意事项等 (以 mysql 镜像为例)
https://hub-stage.docker.com/_/mysql
https://github.com/docker-library/mysql/blob/3288a66368f16deb6f2768ce373ab36f92553cfa/5.7/Dockerfile
- 方法2: search 命令行方式:
docker search [options] {某个镜像的名称}
- 查找对应DockerHub仓库中的镜像
--filter=stars=50
: 列出收藏数不小于指定值的镜像
docker search tomcat
...
docker search centos
解释说明:
NAME
: 镜像仓库源的名称DESCRIPTION
: 镜像的描述OFFICIAL
: 是否docker 官方发布stars
: 类似Github 里面的star,表示点赞、喜欢的意思。AUTOMATED: 自动构建。
补充
[root@guoweixin ~]# docker search --help
Usage: docker search [OPTIONS] TERM
Search the Docker Hub for images
Options:
-f, --filter filter Filter output based on conditions provided
根据提供的条件过滤器输出
--format string Pretty-print search using a Go template
⽤Go模板打印出漂亮的搜索结果
--limit int Max number of search results (default 25)
搜索结果的最⼤数量(默认值为25)
--no-trunc Don't truncate output
不要截断输出
下载镜像
docker pull [选项] [Docker Registey 地址[:端口号]/] 仓库名[:标签]
从 Docker 镜像仓库获取镜像
- Docker 镜像仓库地址: 地址的格式一般是
< 域名 /IP>[: 端口号 ]
。默认地址是Docker Hub
。- 仓库名:这里的仓库名是两段式名称, 即
< 用户名 >/< 软件名 >
。对于 Docker Hub ,如果不给出用户名,则默认为 library ,也就是官方镜像。
docker pull centos
又例如:我们需要一个tomcat的镜像来作为我们的web服务。通过 docker pull获取镜像
docker pull tomcat:版本号 //不写 :版本号 代表laster版本
查看本地镜像
要想列出已下载下来的镜像,可以使用 docker image ls 命令
列表包含了 仓库名、标签、镜像 ID、创建时间 以及 所占用的空间。其中,仓库名、标签在之前的基础概念已经介绍过了。
镜像 ID 则是镜像的唯一标识,一个镜像可以对应多个标签。
因此,如果拥有相同的 ID,因为它们对应的是同一个镜像。
docker images
-a
:--all
,列出所有镜像-q
:--quiet
,只显示镜像的id--digests
: 显示镜像的摘要信息
REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像的 ID
CREATED 镜像创建时间
SIZE 镜像大小
同一个仓库源可以有多个 TAG,代表这个仓库源的不同版本,我们使用REPOSITORY:TAG 定义不同的镜像;
如果你不定义镜像的标签版本,docker将默认使用 lastest 镜像!
将镜像做成离线压缩包/将Docker镜像导出到本地
- 将Docker镜像导出到本地
format:
docker save -o <保存路径/文件名.tar> <镜像名:标签>
docker save -o centos.tar.gz centos
ls ./
加载镜像到本地Docker引擎
- 将Docker镜像加载到本地Docker引擎中
format:
docker load -i <path to image tar file>
- 其中
-i
参数指定要加载的镜像tar文件的路径
docker load -i centos.tar.gz
更新容器
docker update
命令可以用于更新一个或多个 Docker容器 的配置。该命令后面的CONTAINER
可以是容器Id
,或是容器名
。
您可以使用此命令来防止容器消耗 Docker 主机的过多资源。使用单个命令,您可以对单个容器或多个容器进行限制。要指定多个容器,请提供以空格分隔的容器名称或 ID 列表。
- 语法格式
# docker update [OPTIONS] CONTAINER [CONTAINER...]
注:
Windows
容器不支持docker update
命令
-
命令参数
| 参数 | 描述 |
| -------------- | -------------- |
| --cpu-rt-runtime | 将CPU实时运行时间限制在微秒级 |
| --cpu-rt-period | 限制CPU实时周期(以微秒为单位) |
| --cpu-quota | 限制CPU CFS(完全公平调度程序)配额 |
| --cpu-period | 限制CPU CFS(完全公平调度程序)周期 |
| --blkio-weight | 块 IO(相对权重),介于 10 到 1000 之间,或 0 禁用(默认 0) |
| --cpu-shares,-c | 更新 cpu-shares。 |
| --cpus | cpu数量 |
| --cpuset-cpus | 允许执行的 CPU (0-3, 0,1) |
| --cpuset-mems | 允许执行的 MEM (0-3, 0,1) |
| --kernel-memory | 更新内核内存限制。 |
| --memory,-m | 更新内存限制。 |
| --memory-reservation | 内存软限制 |
| --memory-swap | 交换限制等于内存加交换:-1 启用无限制交换 |
| --pids-limit | API 1.40+ 调整容器 pid 限制(设置 -1 表示无限制) |
| --restart | 更新重启策略。(容器退出时应用的重新启动策略) | -
案例:更新
cpu-shares
使用
docker create -it
命令,创建一个 dokcer 容器。
# docker create -it --name cnter centos
efb5ecbf143c4e1a7e62c0d7d55a4d271923c5e37148837d3b11ae23ad886d40
使用 docker update 命令,更新容器的 cpu-shares。
# docker update --cpu-shares 512 cnter
使用
docker kill
和docker rm
命令,删除所有容器。
docker kill `docker ps -qa` ; docker rm `docker ps -aq`
- 案例:更新内存限制
使用
docker create -it
命令,创建一个dokcer
容器。
docker create -it --name cnter centos
efb5ecbf143c4e1a7e62c0d7d55a4d271923c5e37148837d3b11ae23ad886d40
使用 docker update 命令,更新容器的内存限制。
docker update -m 512M cnter
使用 docker kill 和 docker rm 命令,删除所有容器。
docker kill `docker ps -qa` ; docker rm `docker ps -aq`
- 案例
要将容器的 cpu 份额限制为 512,请首先确定容器名称或 ID。您可以使用 docker ps 来查找这些值。您还可以使用从命令返回的 ID docker run 。然后,执行以下操作:
docker update --cpu-shares 512 abebf7571666
- 案例
要更新多个容器的多个资源配置:
$ docker update --cpu-shares 512 -m 300M abebf7571666 hopeful_morse
删除镜像
- 根据镜像的 ID 或名称删除指定镜像
format:
docker rmi <镜像ID 或 名称>
docker rmi -f centos:latest
3.2 容器操作
创建 + 运行容器(run)
- 命令格式
docker [container] run [OPTIONS] IMAGE [COMMAND] [ARG...]
Usage: Run a command in a new container
意译:通过run命令创建一个新的容器(container)
注:container
参数可省略之
- 常用选项说明
- -d, --detach=false, 指定容器运行于前台还是后台,默认为false
- -i, --interactive=false, 打开STDIN,用于控制台交互
- -t, --tty=false, 分配tty设备,该可以支持终端登录,默认为false
-itd
: 以交互模式(i)运行容器,支持命令交互(i)、支持终端登录(t)、容器以后台方式(d)运行
- -u, --user="", 指定容器的用户
- -a, --attach=[], 登录容器(必须是以docker run -d启动的容器)
- -w, --workdir="", 指定容器的工作目录
- -c, --cpu-shares=0, 设置容器CPU权重,在CPU共享场景使用
- -e, --env=[], 指定环境变量,容器中可以使用该环境变量
- -m, --memory="", 指定容器的内存上限
- -P, --publish-all=false, 指定容器暴露的端口
- -p, --publish=[], 指定容器暴露的端口
- -h, --hostname="", 指定容器的主机名
- -v, --volume=[], 给容器挂载存储卷,挂载到容器的某个目录
- --volumes-from=[], 给容器挂载其他容器上的卷,挂载到容器的某个目录
- --cap-add=[], 添加权限,权限清单详见:http://linux.die.net/man/7/capabilities
- --cap-drop=[], 删除权限,权限清单详见:http://linux.die.net/man/7/capabilities
- --cidfile="", 运行容器后,在指定文件中写入容器PID值,一种典型的监控系统用法
- --cpuset="", 设置容器可以使用哪些CPU,此参数可以用来容器独占CPU
- --device=[], 添加主机设备给容器,相当于设备直通
- --dns=[], 指定容器的dns服务器
- --dns-search=[], 指定容器的dns搜索域名,写入到容器的/etc/resolv.conf文件
- --entrypoint="", 覆盖image的入口点
- --env-file=[], 指定环境变量文件,文件格式为每行一个环境变量
- --expose=[], 指定容器暴露的端口,即修改镜像的暴露端口
- --link=[], 指定容器间的关联,使用其他容器的IP、env等信息
- --lxc-conf=[], 指定容器的配置文件,只有在指定--exec-driver=lxc时使用
- --name="", 指定容器名字,后续可以通过名字进行容器管理,links特性需要使用名字
- --net="bridge", 容器网络设置:
- bridge 使用docker daemon指定的网桥
- host //容器使用主机的网络
- container:NAME_or_ID >//使用其他容器的网路,共享IP和PORT等网络资源
- none 容器使用自己的网络(类似--net=bridge),但是不进行配置
- --privileged=false, 指定容器是否为特权容器,特权容器拥有所有的capabilities
- --restart="no", 指定容器停止后的重启策略:
- no:容器退出时不重启
- on-failure:容器故障退出(返回值非零)时重启
- always:容器退出时总是重启
- --rm=false, 指定容器停止后自动删除容器(不支持以docker run -d启动的容器)
- --sig-proxy=true, 设置由代理接受并处理信号,但是SIGCHLD、SIGSTOP和SIGKILL不能被代理
- 示例
- 运行一个在后台执行的容器,同时,还能用控制台管理:
docker run -i -t -d ubuntu:latest
-i
,--interactive
,以交互模式运行容器,并保持终端激活。
注:交互就是用户输入命令,机器执行命令,并提供返回结果。那么在哪里输入命令呢?得有一个终端吧,所以这个命令必须与
-a
或-t
命令配合使用。
-a
选项用于指定将容器的标准输出连接到终端。使用-t
选项创建的容器会分配一个伪终端,并将容器的标准输入、输出和错误连接到该终端。
-t
,--tty
:为容器分配一个伪终端。
补充(网友观点,尚未验证):
docker exec -it ...
中的-it
参数和docker run -it
中相同。
但docker exec
中的-it
不会受docker run
的参数影响。他们是两个工具,只要docker run
把容器启动了,docker exec
执行什么命令是它的事。
- 创建、并运行容器,同时在镜像内执行shell命令
# ↓ 仅用于调试 (用于容器运行后,通过 docker logs baili-web 来查验镜像内 /app 的目录结构)
# docker run -it --name xxxx-web -d -p 8003:3003 xxxx-web:latest /bin/sh -c "ls -la /app"
- 运行一个带命令在后台不断执行的容器,不直接展示容器内部信息:
docker run -d ubuntu:latest ping www.docker.com
- 运行一个在后台不断执行的容器,同时带有命令,程序被终止后还能重启继续跑,还能用控制台管理:
docker run -d --restart=always ubuntu:latest ping www.docker.com
- 为容器指定一个名字
docker run -d --name=ubuntu_server ubuntu:latest
- 容器暴露80端口,并指定宿主机80端口与其通信(: 之前是宿主机端口,之后是容器需暴露的端口)
docker run -d --name=ubuntu_server -p 80:80 ubuntu:latest
- 指定容器内目录与宿主机目录共享(: 之前是宿主机文件夹,之后是容器需共享的文件夹)
docker run -d --name=ubuntu_server -v /etc/www:/var/www ubuntu:latest
操纵容器/容器内执行命令(exec)
- 官方文档
docker exec
命令用于在运行中的容器内执行命令。
使用
docker exec
命令可以无需进入容器,在容器内执行命令,方便管理复杂多容器环境。
- 语法
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
说明:
- OPTIONS:可选项,用于指定一些选项,具体可以查看docker exec --help命令获取;
- CONTAINER:必选项,指定容器名称或容器ID;
- COMMAND:必选项,指定要在容器内执行的命令;
- ARG:可选项,指定命令要使用的参数。
常用选项:
- -i,--interactive:以交互模式运行容器。
- -t,--tty:为容器分配一个虚拟终端/tty。
- -d,--detach:在后台模式下运行容器。
- -u,--user[=""]:以指定的用户名或UID运行容器中的命令。
- -w,--workdir=" ":指定命令的工作目录。
- 举例:
- 【综合案例】在宿主机中执行 mysql 容器 的 命令
- 方法1
docker exec -it mysql bash
> mysql -uroot -p${MYSQL_ROOT_PASSWORD} --port=3306 -h127.0.0.1 -e 'show databases;'
> exit
- 方法2:
docker exec -it mysql sh -c "mysql -uroot -p${MYSQL_ROOT_PASSWORD} --port=3306 -h127.0.0.1 -e 'show databases;'"
注: MYSQL_ROOT_PASSWORD 也是 mysql container 内的内置环境变量
- 执行一个交互式的bash终端:
docker exec -it container_name bash
docker exec -it container_name /bin/bash
- 执行一个命令:
docker exec container_name ls -a
docker exec container_name /path/to/my_script.sh
- 在后台模式下执行命令:
docker exec -d container_name ls -a
- 在指定用户下执行命令:
docker exec -u user_name container_name ls -a
- 指定命令工作目录:
docker exec -w /usr/src/myapp container_name ls -a
- 容器间通信
我们可以使用docker exec -it
命令在不同的容器之间进行通信。例如,假设我们有两个容器container1
和container2
,我们可以通过以下命令在container1
中执行一个命令,并将结果发送到container2
:
docker exec -it container1 sh -c "echo 'Hello' > /tmp/message.txt"
docker exec -it container2 cat /tmp/message.txt
总结:docker exec命令是一个很好的容器管理工具,使用起来非常简单方便。掌握这个命令可以更好地管理容器的生命周期和维护运行环境。
查看容器
- 查看容器
# 查看运行中的容器
docker [container] ps
# 查看全部容器
docker [container] ps -a
注:
container
参数可省略之
输出详情介绍:
- CONTAINER ID: 容器 ID。
- IMAGE: 使用的镜像。
- COMMAND: 启动容器时运行的命令。
- CREATED: 容器的创建时间。
- STATUS: 容器状态。
状态有7种:
- created(已创建)
- restarting(重启中)
- running 或 Up(运行中)
- removing(迁移中)
- paused(暂停)
- exited(停止)
- dead(死亡)
- PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。
- NAMES: 自动分配的容器名称。
查看容器的COMMAND详情
在显示容器列表的命令后面加上--no-trunc
(大意:不省略)
docker ps -a --no-trunc
查看容器的运行日志
- 查看日志
在宿主主机内使用docker logs <containerId>
命令,查看容器内的标准输出:
root@xxx:~$ docker logs 2b1b7a428627
root@xxx:~$ docker logs nginx
- 实时查看/跟踪日志
docker logs -f nginx
- 实时查看/跟踪最近的10条日志
docker logs -f --tail {lineNum} {containerName/containerId}
- 查看最近XX分钟的日志
docker logs --since {xxm} {containerName/containerId}
如最近1分钟:docker logs --since 1m nginx
- 查看指定日期至今的所有日志
如:查看2023-01-16至今的所有日志
docker logs -f --since "2023-01-16" nginx
启动/停止容器
- 启动停止容器
format:
docker start/stop {containerName | containerId}
停止容器(stop container),并不意味着容器物理上不存在了,其实它依旧存在。如果此时,新建同名容器时,将报类似如下错误:
docker: Error response from daemon: Conflict. The container name "/mysql" is already in use by container "c08e6zzzzd274e5fxxxxcb883d55f3yyyy5b54efff". You have to remove (or rename) that container to be able to reuse that name.
- demo
docker stop nginx
删除容器
- 删除容器
如果容器为运行状态,则:需停止容器成功后才能被成功删除
# 删除指定的容器
docker rm [-f] <containerid|containerName>
# 删除未启动成功的容器
docker rm $(docker ps -a|grep Created|awk '{print $1}')
或
docker rm $(docker ps -qf status=created)
# 删除退出状态的容器
docker rm $(docker ps -a|grep Exited|awk '{print $1}')
或
docker rm $(docker ps -qf status=exited)
# 删除所有未运行的容器
# 注:正在运行的删除不了,所有未运行的都被删除了
docker rm $(docker ps -a -q)
或
# 注:Docker 1.13版本以后,可以使用 docker containers prune 命令,删除孤立的容器 (prune ,修剪之意)
docker container prune
查看容器(元)信息(inspect)
docker inspect <containerName|containerId>
docker inspect [OPTIONS] NAME|ID [NAME|ID...]
-f 指定返回值的模板文件
-s 如果类型为容器,则显示文件总大小
--type 返回指定类型的JSON
- 案例
# 获取容器 IP
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $CONTAINER_ID
# 获取IP地址
docker inspect tomcat7 | grep IPAddress
# 获取日志路径
docker inspect --format='{{.LogPath}}' $CONTAINER_ID
卷标管理(volume)
# 新增卷标
docker volume create my-vo
# 查看所有卷标
docker volume ls
# 查看批量的卷标
docker volume ls | grep mysql
# 查看具体的volume对应的真实地址
docker volume inspect my-vo
# 删除卷标
docker volume rm my-vol
容器与主机间的数据拷贝(cp)
- 语法
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
OPTIONS说明:
-L
: 保持源目标中的链接
- 案例1:将主机/www/a 目录拷贝到容器96f7f14e99ab的/www目录下
docker cp /www/a 96f7f14e99ab:/www/
- 案例2:将主机/www/a目录拷贝到容器96f7f14e99ab中,目录重命名为www
docker cp /www/a 96f7f14e99ab:/www
- 案例3:将容器96f7f14e99ab的/www目录拷贝到主机的/tmp目录中
docker cp 96f7f14e99ab:/www /tmp/
//docker cp mysql:/var/log/mysqld.log /opt/mysql/log/mysqld.log
//docker cp mysql:/var/lib/mysql /opt/mysql/data
//docker cp mysql:/etc/mysql/conf.d /opt/mysql/conf
//docker cp mysql:/etc/my.cnf /opt/mysql
3.3 Docker 仓库管理
- 仓库(Repository)是集中存放镜像的地方。
3.3.1 配置镜像仓库
- step1 配置镜像仓库
# vi /etc/docker/daemon.json
{
"registry-mirrors": [
"https://mirrors.docker.io/",
"https://registry.cn-hangzhou.aliyuncs.com/",
""http://hub-mirror.c.163.com""
]
}
- step2 重启docker进程
sudo systemctl restart docker
3.3.1 查看镜像仓库
可以使用 docker info
命令查看Docker的配置信息,其中包括镜像仓库地址。例如:
docker info
关键词
Registry Mirrors
:
[root@xxx ~]# docker info
Client: Docker Engine - Community
Version: 25.0.3
Context: default
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc.)
Version: v0.12.1
Path: /usr/libexec/docker/cli-plugins/docker-buildx
compose: Docker Compose (Docker Inc.)
Version: v2.24.5
Path: /usr/libexec/docker/cli-plugins/docker-compose
Server:
Containers: 17
Running: 6
Paused: 0
Stopped: 11
Images: 16
Server Version: 25.0.3
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Using metacopy: false
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: cgroupfs
Cgroup Version: 1
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
Swarm: inactive
Runtimes: io.containerd.runc.v2 runc
Default Runtime: runc
Init Binary: docker-init
containerd version: ae07eda36dd25f8a1b98dfbf587313b99c0190bb
runc version: v1.1.12-0-g51d5e94
init version: de40ad0
Security Options:
seccomp
Profile: builtin
Kernel Version: 3.10.0-1160.90.1.el7.x86_64
Operating System: CentOS Linux 7 (Core)
OSType: linux
Architecture: x86_64
CPUs: 2
Total Memory: 1.794GiB
Name: iZ2vc3en6658r8vwdlz5s3Z
ID: 95c8a460-14cc-49cf-ac8e-37ccb6b19679
Docker Root Dir: /var/lib/docker
Debug Mode: false
Experimental: false
Insecure Registries:
127.0.0.0/8
Registry Mirrors:
https://mirrors.docker.io/
https://registry.cn-hangzhou.aliyuncs.com/
Live Restore Enabled: false
3.3.3 登录/登出镜像仓库
- 前情提要
docker pull xx
时,报"Error response from daemon: pull access denied for sqlite, repository does not exist or may require 'docker login': denied: requested access to the resource is denied ..."
如果你在拉取 Docker Hub 上的 XXX 镜像时遇到了这类错误,可能是因为 Docker Hub/镜像仓库 的政策变化导致了匿名用户无法再访问部分镜像。
此时,就需要在Docker Hub或镜像仓库中注册账号,再通过docker login登录后,进行操作了。
- 登录镜像仓库
- 登录背景;若目标镜像 或 镜像仓库需要认证,需使用
docker login
命令并输入你的Docker Hub的凭证信息。- 前提条件:确保你的网络能够访问到Docker Hub,你可以尝试ping或者在浏览器中访问Docker Hub来检查网络。
- 例子。以阿里云为例,需要提前在阿里云【容器镜像服务】的控制台创建【个人版(免费)/企业版(付费)】实例、设置固定密码。(参见:登录阿里云镜像仓失败(unauthorized: authentication required)的解决方法 - CSDN)
# 登录到 docker hub
docker login
docker login --username=xxxxaliyunyyyyy@@163.com registry.cn-hangzhou.aliyuncs.com
docker login --username=<你的Access Key ID> --password=<你的Access Key Secret> registry.cn-hangzhou.aliyuncs.com
- 查看当前登录的镜像仓库情况
cat $HOME/.docker/config.json
{
"auths": {
"registry.cn-chengdu.aliyuncs.com": {
"auth": "xxxxxxxxxx"
}
}
}
- 本命令将列出已登录的所有镜像仓库
auh
的内容格式:base64(username:password)
- 登出镜像仓库
docker logout [SERVER]
其中,SERVER
参数指定要退出登录的远程镜像仓库的地址。如果未指定SERVER
参数,则默认退出当前登录的所有远程镜像仓库。
例如:
# 退出当前登录的Docker Hub
docker logout
# 退出登录指定的镜像仓库
docker logout my.private.registry.com
# 以退出阿里云的镜像仓库为例:
[root@xxx ~]# docker logout registry.cn-chengdu.aliyuncs.com
Removing login credentials for registry.cn-chengdu.aliyuncs.com
[root@xxx ~]# cat $HOME/.docker/config.json
{
"auths": {}
}
3.3.3 从指定的镜像仓库中拉取镜像
- 拉取镜像
# docker pull registry.cn-hangzhou.aliyuncs.com/acs-sample/nginx-web-server:latest
# docker pull registry.cn-hangzhou.aliyuncs.com/mysql:8.0
# docker pull registry.cn-beijing.aliyuncs.com/mysql:8.0
# docker pull registry.cn-chengduu.aliyuncs.com/mysql:8.0
3.3.X Docker Hub(官方公共仓库)
目前 Docker 官方维护了一个公共仓库 ·Docker Hub·。
大部分需求都可以通过在 Docker Hub 中直接下载镜像来实现。
- Step1 注册
在
https://hub.docker.com
免费注册一个 Docker 账号。
- Step2 登录和退出
登录需要输入用户名和密码,登录成功后,我们就可以从 docker hub 上拉取自己账号下的全部镜像。
$ docker login
- Step3 退出
退出
docker hub
可以使用以下命令:
$ docker logout
- Step4 拉取镜像
你可以通过 docker search 命令来查找官方仓库中的镜像,并利用 docker pull 命令来将它下载到本地。
以 ubuntu 为关键词进行搜索:
$ docker search ubuntu
- Step4 使用 docker pull 将官方 ubuntu 镜像下载到本地:
$ docker pull ubuntu
- Step5 推送镜像
用户登录后,可以通过 docker push 命令将自己的镜像推送到 Docker Hub。
以下命令中的 username 请替换为你的 Docker 账号用户名。
$ docker tag ubuntu:18.04 username/ubuntu:18.04
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED ...
ubuntu 18.04 275d79972a86 6 days ago ...
username/ubuntu 18.04 275d79972a86 6 days ago ...
$ docker push username/ubuntu:18.04
$ docker search username/ubuntu
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
username/ubuntu
3.4 Docker Dockerfile
3.4.1 什么是 Dockerfile?
Dockerfile
是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
DockerFile
是Docker
的一个配置文件,本质上来说它只是一个文本文件,它是用来构建【Docker镜像】的。
DockerFile
配置文件中包含了一系列的指令
和配置信息
,用于描述如何构建镜像以及如何运行容器。
通过编写Dockerfile
,我们可以将构建 Docker 镜像的【过程】自动化,实现应用程序的快速部署和迭代。
3.4.2 Dockerfile的基本结构
Dockerfile
由一行行命令语句组成,并且支持以#
开头的注释行。一般而言,Dockerfile,分为四部分:
- 基础镜像信息;
- 维护者信息;
- 镜像操作指令;
- 和容器启动时执行指令
例如:
# This Dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: docker_user
# Command format: Instruction [arguments / command] ..
# Base image to use, this must be set as the first line
FROM ubuntu
# Maintainer: docker_user <docker_user at email.com> (@docker_user)
MAINTAINER docker_user docker_user@email.com
# Commands to update the image
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/
sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
# Commands when creating a new container
CMD /usr/sbin/nginx
其中,一开始必须指明【所基于的镜像名称】,接下来一般是说明维护者信息,后面则是镜像操作指令,例如 RUN 指令,RUN 指令将对镜像执行跟随的命令。每运行一条 RUN 指令,镜像就添加新的一层,并提交。最后是 CMD 指令,用来指定运行容器时的操作命令。
3.4.3 Dockerfile 如何编写与使用?(详解)
3.4.x Dockerfile/DockerComposeYml中Service的expose和ports的区别
- 背景描述
形如: 对宿主机开放 3307 端口,容器内部使用 3306 端口的 mysql container:
# docker-compose.yml
...
services:
mysql:
container_name: openmetadata_mysql
image: docker.getcollate.io/openmetadata/db:1.3.0
command: "--sort_buffer_size=10M"
restart: always
environment:
MYSQL_ROOT_PASSWORD: password
expose:
- 3306
ports:
- "3307:3306"
volumes:
- ./docker-volume/db-data:/var/lib/mysql
networks:
- app_net
healthcheck:
test: mysql --user=root --password=$$MYSQL_ROOT_PASSWORD --silent --execute "use openmetadata_db"
interval: 15s
timeout: 10s
retries: 10
...
- 解释/辨析:
expose
和ports
在Docker中都用于容器的网络配置,但它们的用途和方式略有不同。
expose
: 这是Dockerfile的指令,用于在创建镜像时声明容器打算使用的端口。它是对构建服务的人的一种文档性的声明,意味着运行的容器会监听某个端口。然而,只有当容器启动时使用了-P(大写)或-p(小写)参数,这些端口才会在主机上映射。此外,EXPOSE不会让容器的端口对外界可见。ports
: 这是docker-compose.yml文件中的一个字段,用于定义容器的端口映射。这实际上在主机上打开了端口,使得外部世界可以访问到容器的网络服务。它的格式通常为: 。例如,如果你想在主机的8080端口上运行一个在80端口上运行的web服务器,你可以使用ports配置如下:- "8080:80"。
总的来说,expose主要用于在构建阶段声明容器需要使用的端口,而ports主要用于在运行阶段定义主机和容器之间的端口映射关系。
形如:
ports 3307:3306
, 是指 宿主机的端口(3307)映射到容器的端口(3306)
- 参考文献
4 综合应用场景
4.1 docker 环境下,设置容器自动启动
- 方法1:使用 docker run 命令运行时
增加
--restart=always
参数即可
- 方法2:使用 docker-compose 命令运行时
在 yml 文件中,需要自启动的 service 下
增加 restart: always 项目即可
- 方法3:已运行的容器修改其自启动策略
执行命令:
docker update --restart=always {容器名或容器ID}
docker container update --restart=【容器策略】 容器名称
容器策略:
# no 容器退出时不重启容器
# on-failure 只有在非零状态退出时才重新启动容器
--restart=on-failure:【重启次数】
# always 无论退出状态如何都
K FAQ/问题集
Q1 配置docker镜像加速器?
- Step1 登陆阿里云镜像仓库
https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
如果没有开通,可开通阿里云的镜像服务
编辑
/etc/docker/daemon.json
- Step2 重启docker
systemctl daemon-reload
systemctl restart docker
Q2 docker hub官网进不去?
问题分析
docker hub进不去是因为“hub.docker.com”是在国外的,所以访问速度很慢,导致无法访问该网址。
解决方法
- 1、找到“daemon.json”文件
- 2、使用vim命令将其打开
- 3、添加“{ "registry-mirrors" :["https://docker.mirrors.ustc.edu.cn"]}”内容
- 4、重启docker即可
参考文献
Q3 怎么理解docker中的registry(注册表) 和repository(仓库)?
- Registry:(英译:注册表、登记处)
A service responsible for hosting and distributing images. The default registry is the Docker Hub.
Docker registry 能够被第三方组织host,作为共有或者私有的registry,下面就是一些registries:
- Repository:(英译:仓库)
A collection of related images (usually providing different versions of the same application or service).
相关映像的集合(通常提供相同应用程序或服务的不同版本)。
Docker repository is a collection of different docker images with same name, that have different tags.
Docker存储库是不同Docker映像的集合,具有相同的名称,具有不同的标签。
也就是说repository是关于同一种镜像(如python)的不同版本”tag“的“集合地”,例如 https://hub.docker.com/r/library/python/tags/。这里有许多不同tag的官方python镜像,官方python repository中所有的版本都位于Docker hub这个registry内!
- Tag:(英译:标签)
An alphanumeric identifier (字母数字的标志符)attached to images within a repository (e.g., 14.04 or stable ).
对于 [image name] = [repository] : [tag] ,其中的“repository”是对镜像而言,某一个镜像可以有好多的tag。
所以有一种“仓库”的概念在里面,看某些书的时候会发现,有这样的的语句“每个repository可以有多个tag”。
有过创建自己的私有registry经历的就会知道,我们会重新“命名”我们的本地的image,例如:myregistryhost:5000/namespace/repo-name:tag;
此外,我们在docker hub 上面上传自己的docker 镜像的时候也会填上自己的 namespace(用户名),即你在docker hub上面注册的账号。
Y 推荐资源
Y.1 核心资源/核心链接
- Docker 官网主页
- Docker 官方博客:
- Docker 官方文档:
- Docker github
https://hub.docker.com
https://hub-stage.docker.com
https://github.com/moby/moby 【Docker 源代码仓库】
https://docs.docker.com/release-notes/ 【Docker 发布版本的历史】
- Dockerhub 镜像站官网
https://hub-stage.docker.com/
https://registry.hub.docker.com
- Docker 官方 registry 镜像加速
- Docker Store:
- Docker Cloud:
- Docker 常见问题:
- Docker 远端应用 API:
Y.2 Docker Hub 镜像加速器列表
- Docker 官方镜像
镜像加速器 | 镜像加速器地址URL | 专属加速器 | 其他加速 |
---|---|---|---|
Docker 中国官方镜像站 | https://registry.docker-cn.com | ... | Docker Hub |
Dao Cloud 镜像站 | http://f136db2.m.daocloud.io/ https://www.daocloud.io/mirror#accelerator-doc |
可登录,系统分配 | Docker Hub |
Azure 中国镜像站 | https://dockerhub.azk8s.cn | Docker Hub / GCR / Quay | |
科大镜像站 | https://docker.mirrors.ustc.edu.cn | ... | Docker Hub / GCR / Quay |
阿里云(ACR) | registry.cn-hangzhou.aliyuncs.com registry.cn-beijing.aliyuncs.com registry.cn-chengdu.aliyuncs.com ... |
需登录,系统分配(https://<阿里云容器镜像服务为你随机分配的ID>.mirror.aliyuncs.com ) |
Docker Hub |
七牛云 | https://reg-mirror.qiniu.com | ... | Docker Hub / GCR / Quay |
网易云 | https://hub-mirror.c.163.com | ... | Docker Hub |
腾讯云(TCR) | https://mirror.ccs.tencentyun.com https://ccr.ccs.tencentyun.com |
...(参见:https://mirrors.cloud.tencent.com/ ) |
Docker Hub |
中国科学技术大学镜像 | https://docker.mirrors.ustc.edu.cn | ... | -- |
Y.3 其他
-
容器镜像服务/制品中心 - 阿里云
https://cr.console.aliyun.com/cn-hangzhou/instances/artifact
X 参考文献
- Docker Compose 基础教程 - 博客园/千千寰宇
- Docker 官网
- Docker容器基础 - CSDN
- Docker镜像 - CSDN
- docker run 参数详解 - 博客园
- Docker基本概念和原理理解 - Zhihu
- Docker build 命令 - 菜鸟教程
- Docker Dockerfile - 菜鸟教程
- 怎么理解docker中的registry 和repository? - CSDN
- Docker 教程 - 菜鸟教程
- docker update 命令及用法详解 - 脚本之家
- Docker说了这么多 最全的一篇在这里 - Souhu
待阅读
本文链接: https://www.cnblogs.com/johnnyzen
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!