docker学习笔记
一、Docker概述
1、Docker历史
更详细的关于Docker历史详见百度百科
Docker 公司起初是一家名为 dotCloud
的平台即服务(Platform-as-a-Service, PaaS)提供商。底层技术上,dotCloud平台利用了 Linux 容器技术。2013年,dotCloud 的 PaaS 业务并不景气,公司需要寻求新的突破。2013 年 3 月,dotCloud 公司的创始人之一,Docker 之父,28 岁的 Solomon Hykes 正式决定,将 Docker 项目开源。开源当月, Docker 0.1 版本发布。此后的每一个月, Docker 都会发布一个版本。到 2014 年 6 月 9 日, Docker 1.0 版本正式发布。而在Docker火了之后,dotCloud
公司干脆把公司名字也改成了 Docker Inc
。
2、Docker介绍
Docker是基于Go语言实现的云开源项目。Docker的主要目标是“Build,Ship and Run Any App , Anywhere”,也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的APP(可以是一个WEB应用或数据库应用等等)及其运行环境能够做到“一次封装,到处运行”。
3、Docker与虚拟机对比
-
虚拟机属于虚拟化技术;而Docker这样的容器技术,也是虚拟化技术,属于轻量级的虚拟化。
-
虚拟机虽然可以隔离出很多“子电脑”,但占用空间更大,启动更慢;而容器技术恰好没有这些缺点。它不需要虚拟出整个操作系统,只需要虚拟一个小规模的环境(类似“沙箱”)。
-
Docker启动时间很快,几秒钟就能完成,而且,它对资源的利用率很高(一台主机可以同时运行几千个Docker容器);此外,它占的空间很小,虚拟机一般要几GB到几十GB的空间,而容器只需要MB级甚至KB级。
-
传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
-
每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。
Docker官网:http://www.docker.com
Docker中文网站:https://www.docker-cn.com
Docker Hub官网:https://hub.docker.com (仓库)
4、Docker平台架构
Docker 运行的基本流程为:
-
用户是使用 Docker Client 与 Docker Daemon 建立通信,并发送请求给后者。
-
Docker Daemon 作为 Docker 架构中的主体部分,首先提供 Docker Server 的功能使其可以接受 Docker Client 的请求。
-
Docker Engine 执行 Docker 内部的一系列工作,每一项工作都是以一个 Job 的形式的存在。
-
Job 的运行过程中,当需要容器镜像时,则从 Docker Registry 中下载镜像,并通过镜像管理驱动 Graph driver将下载镜像以Graph的形式存储。
-
当需要为 Docker 创建网络环境时,通过网络管理驱动 Network driver 创建并配置 Docker 容器网络环境。
-
当需要限制 Docker 容器运行资源或执行用户指令等操作时,则通过 Execdriver 来完成。
-
Libcontainer是一项独立的容器管理包,Network driver以及Exec driver都是通过Libcontainer来实现具体对容器进行的操作。
二、Docker安装
1、Docker的基本组成
Docker架构图
-
Docker 本身是一个容器运行载体或称之为管理引擎。我们把应用程序和配置依赖打包好形成一个可交付的运行环境,这个打包好的运行环境就是 image镜像文件。只有通过这个镜像文件才能生成 Docker 容器。image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。
-
image 文件生成的容器实例,本身也是一个文件,称为镜像文件。
-
一个容器运行一种服务,当我们需要的时候,就可以通过docker客户端创建一个对应的运行实例,也就是我们的容器
-
仓库是放了一堆镜像的地方,我们可以把镜像发布到仓库中,需要的时候从仓库中拉下来就可以了。
2、Docker安装
2.1 Centos安装
Centos官网安装手册:https://docs.docker.com/engine/install/centos/
常规安装
1 | # linux内核推荐3.8及以上,这里我使用了centos8 |
在线安装和离线安装
1 | #==============在线安装====================== |
服务启动
1 | #启动 |
Docker卸载
1 | #先停止docker |
2.2 Ubuntu安装
Ubuntu官网安装手册:https://docs.docker.com/engine/install/ubuntu/
通过脚本快速安装
1 | # 文本处理的流编辑器 -i直接修改读取的文件内容,而不是输出到终端 |
3、阿里云镜像加速
进入阿里云搜索镜像容器服务,选择管理控制台,找到镜像工具下的镜像加速器,找到相应版本的,每个人都有自己的加速器地址
1 | # 阿里云的镜像是从docker hub来的,我们配置了加速,默认是从阿里云(缓存)下载 |
三、Docker常用命令
1、帮助命令
官方文档:https://docs.docker.com/engine/reference/commandline/docker/
1 | docker version # 显示 Docker 版本信息 |
docker相关基础命令
命令 | 作用 |
---|---|
attach | 绑定到运行中容器的标准输入, 输出,以及错误流(这样也能进入容器内容,但是一定小心,他们操作的就是控制台,控制台的退出命令会生效,比如redis,nginx…) |
build | 从一个 Dockerfile 文件构建镜像 |
commit | 把容器的改变 提交创建一个新的镜像 |
cp | 容器和本地文件系统间 复制 文件/文件夹 |
create | 创建新容器,但并不启动(注意与docker run 的区分)需要手动启动。start\stop |
diff | 检查容器里文件系统结构的更改【A:添加文件或目录 D:文件或者目录删除 C:文件或者目录更改】 |
events | 获取服务器的实时事件 |
exec | 在运行时的容器内运行命令 |
export | 导出容器的文件系统为一个tar文件。commit是直接提交成镜像,export是导出成文件方便传输 |
history | 显示镜像的历史 |
images | 列出所有镜像 |
import | 导入tar的内容创建一个镜像,再导入进来的镜像直接启动不了容器。/docker-entrypoint.sh nginx -g ‘daemon o?;’ docker ps --no-trunc 看下之前的完整启动命令再用他 |
info | 显示系统信息 |
inspect | 获取docker对象的底层信息 |
kill | 杀死一个或者多个容器 |
load | 从 tar 文件加载镜像 |
login | 登录Docker registry |
logout | 退出Docker registry |
logs | 获取容器日志;容器以前在前台控制台能输出的所有内容,都可以看到 |
pause | 暂停一个或者多个容器 |
port | 列出容器的端口映射 |
ps | 列出所有容器 |
pull | 从registry下载一个image 或者repository |
push | 给registry推送一个image或者repository |
rename | 重命名一个容器 |
restart | 重启一个或者多个容器 |
rm | 移除一个或者多个容器 |
rmi | 移除一个或者多个镜像 |
run | 创建并启动容器 |
save | 把一个或者多个镜像保存为tar文件 |
search | 去docker hub寻找镜像 |
start | 启动一个或者多个容器 |
stats | 显示容器资源的实时使用状态 |
stop | 停止一个或者多个容器 |
tag | 给源镜像创建一个新的标签,变成新的镜像 |
top | 显示正在运行容器的进程 |
unpause | pause的反操作 |
update | 更新一个或者多个docker容器配置 |
version | 显示docker的相关信息 |
container | 管理容器 |
image | 管理镜像 |
network | 管理网络 |
volume | 管理卷 |
2、镜像相关命令
docker images
1 | # 列出本地主机上的镜像 |
docker search
1 | #搜索镜像 |
docker pull
1 | #拉取镜像,不写tag,默认是latest |
docker rmi
1 | # 删除镜像 |
docker tag
1 | # 给镜像重新打标签 |
docker commit
1 | # 一般运行中的容器会常年修改,我们要使用最终的新镜像,把新的镜像放到远程docker hub,方便后来在其他机器下载 |
docker save、load
1 | # 把busybox镜像保存成tar文件 |
docker prune
1 | # 移除游离镜像 dangling:游离镜像(没有镜像名字的) |
3、容器相关命令
==注意:有镜像才能创建容器==
新建容器并启动
1 | #首先拉取一下镜像 |
列出所有运行的容器
1 | # 命令 |
退出容器
1 | exit # 容器停止退出 |
创建容器
1 | # 创建容器 |
启动停止容器
1 | docker start (容器id or 容器名) # 启动容器 |
删除容器
1 | docker rm 容器id # 删除指定容器 |
docker port
1 | # 查看容器端口映射 |
docker rename
1 | # 重命名容器 |
docker logs
1 | # 查看容器运行日志 |
docker stats
1 | # 查看容器资源的实时使用状态 |
docker update
1 | # 更新容器配置 |
docker inspect
1 | # 查看镜像详细信息 |
进入运行的容器(docker exec)
1 | # 进容器 绑定的是控制台. 可能导致容器停止。不要用这个 |
docker export、import
1 | # 导出镜像 |
4、Docker典型命令
4.1 容器状态
Created
(新建)、Up
(运行中)、Pause
(暂停)、Exited
(退出)
4.2 docker run
-
-d: 后台运行容器,并返回容器ID;
-
-i: 以交互模式运行容器,通常与 -t 同时使用;
-
-P: 随机端口映射,容器内部端口随机映射到主机的端口
-
-p:指定端口映射,格式为:主机(宿主)端口:容器端口
-
-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用
-
–name=“nginx-lb”:为容器指定一个名称;
-
–dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;
-
–dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;
-
-h “mars”: 指定容器的hostname;
-
-e username=“ritchie”: 设置环境变量;
-
–env-file=[]: 从指定文件读入环境变量;
-
–cpuset=“0-2” or --cpuset=“0,1,2”: 绑定容器到指定CPU运行;
-
-m :设置容器使用内存最大值;
-
–net=“bridge”: 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;
-
–link=[]: 添加链接到另一个容器;
-
–expose=[]: 开放一个端口或一组端口;
-
–restart , 指定重启策略,可以写–restart=awlays 总是故障重启
-
–volume , -v: 绑定一个卷。一般格式 主机文件或文件夹:虚拟机文件或文件夹
启动容器
1 | # 命令 |
容器的重启策略
Docker容器的重启策略如下:
-
no,默认策略,在容器退出时不重启容器
-
on-failure,在容器非正常退出时(退出状态非0),才会重启容器
-
on-failure:3,在容器非正常退出时重启容器,最多重启3次
-
always,在容器退出时总是重启容器
-
unless-stopped,在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器
docker run的退出状态码如下:
-
0,表示正常退出
-
非0,表示异常退出(退出状态码采用chroot标准)
-
125,Docker守护进程本身的错误
-
126,容器启动后,要执行的默认命令无法调用
-
127,容器启动后,要执行的默认命令不存在
-
其他命令状态码,容器启动后正常执行命令,退出命令时该命令的返回状态码作为容器的退出状态码
4.3 其他常用命令
1 | # 查看日志 |
5、Docker简单实例
DockerHub:https://hub.docker.com
5.1 Docker安装nginx
1 | #搜索stars大于等于1000的nginx镜像 |
5.2 Docker安装tomcat
1 | # 官方文档解释 |
四、Docker镜像和容器数据卷
1、Docker镜像
1.1 镜像加载原理
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
bootfs(boot file system) 主要包含bootloader和kernel,bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!这一层就是我们通常说的容器层,容器之下的都叫镜像层。
1.2 镜像与容器
-
容器和镜像之间的主要区别是可写顶层。
-
在容器中添加新数据或修改现有数据的所有写操作都存储在此可写层中。
-
删除容器后,可写层也会被删除。 基础图像保持不变。 因为每个容器都有其自己的可写容
器层,并且所有更改都存储在该容器层中,所以多个容器可以共享对同一基础映像的访问,
但具有自己的数据状态。
1.3 Docker镜像挑选
-
busybox:是一个集成了一百多个最常用Linux命令和工具的软件。linux工具里的瑞士军刀
-
alpine:Alpine操作系统是一个面向安全的轻型Linux发行版经典最小镜像,基于busybox,功能比
Busybox完善。
-
slim:docker hub中有些镜像有slim标识,都是瘦身了的镜像。也要优先选择
无论是制作镜像还是下载镜像,优先选择alpine类型
1.4 磁盘容量预估
多个容器可以共享部分或全部只读图像数据。从同一图像开始的两个容器共享100%的只读数据,而具有不同图像的两个容器(具有相同的层)共享这些公共层。 因此,不能只对虚拟大小进行总计。这高估了总磁盘使用量,可能是一笔不小的数目。
1 | # size:用于每个容器的可写层的数据量(在磁盘上) |
1.5 Copy On Write
-
写时复制是一种共享和复制文件的策略,可最大程度地提高效率
-
如果文件或目录位于映像的较低层中,而另一层(包括可写层)需要对其进行读取访问,则它仅使用现有文件
-
另一层第一次需要修改文件时(在构建映像或运行容器时),将文件复制到该层并进行修改。 这样可以将I / O和每个后续层的大小最小化
1.6 镜像commit命令
1 | #提交容器副本使之成为一个新的镜像! |
2、镜像的发布
2.1 发布到Docker Hub官网
1 | #查看docker login 命令 |
2.2 发布到阿里云
登录阿里云>找到容器镜像服务>创建命名空间>创建镜像仓库>点击进入这个镜像仓库
1 | #登录 |
3、Docker Registry镜像私服
3.1 概述
docker registry官方API的地址:Registry API,然后还有使用手册:Docker Registry
官方的 Docker Hub 是一个用于管理公共镜像的地方,我们可以在上面找到我们想要的镜像,也可以把我们自己的镜像推送上去。但是,有时候我们的服务器无法访问互联网,或者你不希望将自己的镜像放到公网当中,那么你就需要 Docker Registry,它可以用来存储和管理自己的镜像
3.2 本地基础使用
1 | # 启动容器 |
相关API的使用
1 | # 查看API是否可用 |
3.3 配置外网可访问registry
外网访问registry需要使用https协议做安全认证,不然docker pull/docker push
都会失败。下面是几种配置方式
方法一:配置参数–insecure-registry
1 | # (如果没有该文件就创建一个) |
方法二:配置https服务
ssl证书,可以向CA机构申请。也可以配置自签名证书;使用CA证书访问远程registry使用域名访问,没有域名的可以vim /etc/hosts
做实验
注意这里有些自签名ssl可能会失效,因为docker 版本20.10.8 版本编译使用的go 版本过高(>1.15.1)。是因为 go 1.15 版本开始废弃 CommonName 需要使用SAN证书,参考:https://www.dounaite.com/article/6278dadeac359fc91326a730.html
1 | # ssl自签,自己颁发证书 |
方法三:nginx代理https(推荐)
使用nginx做https服务器,将数据转发给registry服务。这样,registry服务就不用配置ssl了
1 | server { |
- 如果需要鉴权,在nginx.conf中配置访问权限
1 | auth_basic "Registry realm"; |
3.4 Web registry
web界面的管理容器
1 | docker run -itd -p 8080:8080 --name registry_web --link registry \ |
说明
- -d,后台运行容器
- -p 8080:8080,映射容器8080端口至宿主机8080端口
- -restart always,设置重新启动策略,在docker重新启动时自动重新启动容器my-registry
- -name my-registry 给容器命名
- –link ,设置连接的仓库
- -e REGISTRY_URL,设置仓库URL,如果使用证书创建容器,仓库URL以https开头
- -e REGISTRY_NAME,设置仓库主机
- -e REGISTRY_READONLY ,设置web界面是否显示读写、删除按钮
- -e REGISTRY_TRUST_ANY_SSL,设置信任任何SSL的连接
当然还有harbor, Harbor是由VMWare公司开源的容器镜像仓库。事实上,Harbor是在Docker Registry上进行了相应的企业级扩展,可以参考:实战:使用harbor搭建Docker私有仓库
3、容器数据卷
3.1 容器挂载
容器的数据持久化,以及容器间的继承和数据共享,相当于双向绑定
-
Volumes(卷) :存储在主机文件系统的一部分中,该文件系统由Docker管理(在Linux上是"
/var/lib/docker/volumes/
")。 非Docker进程不应修改文件系统的这一部分。 卷是在Docker中持久存储数据的最佳方法 -
Bind mounts(绑定挂载) 可以在任何地方 存储在主机系统上。 它们甚至可能是重要的系统文件或目录。 Docker主机或Docker容器上的非Docker进程可以随时对其进行修改
-
**tmpfs mounts(临时挂载) **仅存储在主机系统的内存中,并且永远不会写入主机系统的文件系统
3.2 volume(卷)
如果将空卷装入存在文件或目录的容器中的目录中,则容器中的内容(复制)到该卷中;如果启动一个容器并指定一个尚不存在的卷,则会创建一个空卷
1 | # ==============匿名卷使用========== |
3.3 bind mount
如果将绑定安装或非空卷安装到存在某些文件或目录的容器中的目录中,则这些文件或目录会被安装遮盖,就像将文件保存到Linux主机上的/mnt中一样,然后将USB驱动器安装到/mnt中。在卸载USB驱动器之前,/mnt的内容将被USB驱动器的内容遮盖。 被遮盖的文件不会被删除或更改,但是在安装绑定安装或卷时将无法访问。
总结:外部目录覆盖内部容器目录内容,但不是修改。所以谨慎,外部空文件夹挂载方式也会导致容器内部是空文件夹
1 | # bind mount和 volumes 的方式写法区别在于 |
3.4 volume和bind mount总结
volume
-
多个运行的容器之间共享数据,因为挂载点如果一样存储是一样的
-
当容器停止或者删除,该卷依然存在,数据不会丢失
-
多个容器可以同时挂载相同的卷
-
当明确删除卷时,卷才会被删除
-
将容器数据存储在远程主机上或者其他存储
-
将数据从一台docker主机迁移到另一台时,先停止容器,然后备份卷的目录(
/var/lib/docker/volumes/
)
bind mount
-
从主机共享配置文件到容器,默认情况下,挂载主机
/etc/resolv.conf
到每个容器,提供dns解析 -
在docker主机上开发环境和容器之间共享源代码,例如,可以将maven tag目录挂在到容器中,每次在docker主机上构建maven项目时,容器都可以访问构建的项目包
-
当docker主机的文件或者目录结构保证与容器所需的绑定挂在一致时
区别
volume 是docker的宿主机文件系统一部分,只有docker可以进行更改,其他进程不能修改;bind mounts 是挂载在宿主机文件系统的任意位置,除了docker所有进程都可以进行修改。
-
如果自己开发测试,用 -v 绝对路径的方式
-
如果是生产环境建议用卷
-
除非特殊 /bin/docker 需要挂载主机路径的则操作绝对路径挂载
3.5 docker cp
1 | # 把容器里面的复制出来 |
3.6 rw、ro 和 不指定的区别
-
不指定(默认)
-
文件:
-
宿主机 修改该文件后容器里面看不到变化
-
容器 里面修改该文件,宿主机也看不到变化
-
-
文件夹:不管是宿主机还是容器内 修改、新增、删除文件 都会相互同步
-
-
ro
-
文件:容器内不能修改,会提示read-only
-
文件夹:容器内不能修改、新增、删除文件夹中的文件,会提示read-only
-
-
rw
-
文件:不管是宿主机还是容器内修改,都会相互同步;但容器内不允许删除,会提示Device or resource busy;宿主机删除文件,容器内的不会被同步
-
文件夹:不管是宿主机还是容器内修改、新增、删除文件,都会相互同步
-
五、DockerFile
dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本
文档地址:https://docs.docker.com/engine/reference/builder/
1、DockerFile构建
1.1 介绍
基础知识:
1、每条保留字指令都必须为大写字母且后面要跟随至少一个参数
2、指令按照从上到下,顺序执行
3、# 表示注释
4、每条指令都会创建一个新的镜像层,并对镜像进行提交
构建流程:
1、docker从基础镜像运行一个容器
2、执行一条指令并对容器做出修改
3、执行类似 docker commit
的操作提交一个新的镜像层
4、Docker再基于刚提交的镜像运行一个新容器
5、执行dockerfile中的下一条指令直到所有指令都执行完成!
1.2 DockerFile指令
**指令 ** | 说明 |
---|---|
FROM | 指定基础镜像 |
MAINTAINER | 指定维护者信息,已经过时,可以使用LABEL maintainer=xxx 来替代 |
LABEL | 指定维护者信息 maintainer=xxx auth=xueqimiao a=b (语法 k=v ) |
RUN | 运行命令,代表镜像构建过程中运行的命令 |
CMD | 指定启动容器时默认的命令 容器启动时要执行的命令 |
ENTRYPOINT | 指定镜像的默认入口,运行命令 |
EXPOSE | 声明镜像内服务监听的端口 |
ENV | 指定环境变量,可以在docker run的时候使用-e改变 会被固话到image的config里面 |
ADD | 复制指定的src路径下的内容到容器中的dest路径下,src可以为url会自动下载,可以为tar文件,会自动解压 |
COPY | 复制本地主机的src路径下的内容到镜像中的dest路径下,但不会自动解压等 |
LABEL | 指定生成镜像的元数据标签信息 |
VOLUME | 创建数据卷挂载点 |
USER | 指定运行容器时的用户名或UID |
WORKDIR | 配置工作目录,为后续的RUN、CMD、ENTRYPOINT指令配置工作目录 |
ARG | 指定镜像内使用的参数(如版本号信息等),可以在build的时候,使用–build-args改变 |
OBBUILD | 配置当创建的镜像作为其他镜像的基础镜像是,所指定的创建操作指令 |
STOPSIGNAL | 容器退出的信号值 |
HEALTHCHECK | 健康检查 |
SHELL | 指定使用shell时的默认shell类型 |
2、常用保留字
2.1 FROM与LABEL
FROM
指定基础镜像,最好挑一些apline,slim之类的基础小镜像.指定一个已经存在的镜像作为模板,第一条必须是from;scratch镜像是一个空镜像,常用于多阶段构建
LAVBEL
和MAINTAINER
标注镜像的一些说明信息。镜像维护者的姓名和邮箱地址
-
Java应用当然是java基础镜像(SpringBoot应用)或者Tomcat基础镜像(War应用)
-
JS模块化应用一般用nodejs基础镜像
-
其他各种语言用自己的服务器或者基础环境镜像,如python、golang、java、php等
1 | # 注释 |
2.2 RUN
-
RUN
指令在当前镜像层顶部的新层执行任何命令,并提交结果,生成新的镜像层。 -
生成的提交映像将用于Dockerfile中的下一步。 分层运行RUN指令并生成提交符合Docker的核心概念,就像源代码控制一样。
-
exec
形式可以避免破坏shell字符串,并使用不包含指定shell可执行文件的基本映像运行RUN命令。可以使用SHELL命令更改shell
形式的默认shell。 在shell形式中,您可以使用\(反斜杠)将一条RUN指令继续到下一行 -
RUN是在
docker build
时运行
1 | # shell格式 |
举例
1 | RUN <command> ( shell 形式, /bin/sh -c 的方式运行,避免破坏shell字符串) |
2.3 CMD和ENTRYPOINT
-
Dockerfile中只能有一条
CMD
指令。 如果您列出多个CMD
,则只有最后一个CMD
才会生效 -
CMD
的主要目的是为执行中的容器提供默认值。 这些默认值可以包含可执行文件,也可以省略可执行文件,在这种情况下,您还必须指定指令 -
会被 之后的参数替换,是在** 时运行**
-
RUN
是在docker build
时运行 -
类似于
CMD
指令,但ENTRYPOINT
不会被docker run
后面的命令覆盖,而且这些命令行参数会被当作参数送给ENTRYPOINT
指令指定的程序 -
在执行
docker run
的时候可以指定ENTRYPOINT
运行所需的参数 -
如果 Dockerfile 中如果存在多个
ENTRYPOINT
指令,仅最后一个生效
1 | # ====================CMD 的三种写法=================== |
CMD为ENTRYPOINT组合使用
如果使用
CMD
为ENTRYPOINT
指令提供默认参数,则CMD
和ENTRYPOINT
指令均应使用JSON数组格式指定。ENTRYPOINT
可以和CMD
一起用,一般是变参才会使用 ,这里的 等于是在给****传参。当指定了ENTRYPOINT
后,CMD
的含义就发生了变化,不再是直接运行其命令而是将CMD
的内容作为参数传递给ENTRYPOINT
指令,他两个组合会变成 <><>
1 | FROM nginx |
2.4 ARG和ENV
-
ARG指令定义了一个变量,用户可以在构建时使用
--build-arg =
传递,docker build命令会将其传递给构建器 -
--build-arg
指定参数会覆盖Dockerfile 中指定的同名参数 -
如果用户指定了 未在Dockerfile中定义的构建参数 ,则构建会输出警告
-
ARG
只在构建期有效,运行期无效 -
在构建阶段中所有后续指令的环境中使用,并且在许多情况下也可以内联替换。
-
引号和反斜杠可用于在值中包含空格。
-
ENV
可以使用key value
的写法,但是这种不建议使用了,后续版本可能会删除 -
docker run --env
可以修改这些值 -
容器运行时
ENV
值可以生效 -
ENV在image阶段就会被解析并持久化(
docker inspect image
查看)
1 | FROM alpine |
2.5 ADD和COPY
COPY详解
-
--chown
功能仅在用于构建Linux容器的Dockerfiles上受支持,而在Windows容器上不起作用 -
COPY
指令从 src 复制新文件或目录,并将它们添加到容器的文件系统中,路径为 dest -
可以指定多个 src 资源,但是文件和目录的路径将被解释为相对于构建上下文的源
-
每个 src 都可以包含通配符,并且匹配将使用Go的filepath.Match规则进行
1 | COPY [--chown=<user>:<group>] <src>... <dest> |
ADD详解
同COPY
用法,不过 ADD
拥有自动下载远程文件和解压的功能
-
src 路径必须在构建的上下文中; 不能使用
../something/something
这种方式,因为docker构建的第一步是将上下文目录(和子目录)发送到docker守护程序 -
如果 src 是URL,并且 dest 不以斜杠结尾,则从URL下载文件并将其复制到 dest ;如果 dest 以斜杠结尾,将自动推断出url的名字(保留最后一部分),保存到 dest
-
如果 src 是目录,则将复制目录的整个内容,包括文件系统元数据
1 | FROM alpine |
2.6 WORKDIR
-
指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
-
WORKDIR
指令为Dockerfile中跟随它的所有RUN
,CMD
,ENTRYPOINT
,COPY
,ADD
指令设置工作目录。 如果WORKDIR
不存在,即使以后的Dockerfile指令中未使用它也将被创建 -
WORKDIR
指令可在Dockerfile中多次使用。 如果提供了相对路径,则它将相对于上一个WORKDIR
指令的路径
1 | FROM alpine |
2.7 VOLUME
把容器的某些文件夹映射到主机外部
1 | #可以是JSON数组 |
2.8 USER
USER
指令设置运行映像时要使用的用户名(或UID)以及可选的用户组(或GID),以及Dockerfile中USER
后面所有RUN
,CMD
和ENTRYPOINT
指令
1 | USER <user>[:<group>] |
2.9 EXPOSE
-
EXPOSE
指令通知Docker容器在运行时在指定的网络端口上进行侦听。 可以指定端口是侦听TCP还是UDP,如果未指定协议,则默认值为TCP -
EXPOSE
指令实际上不会发布端口。 它充当构建映像的人员和运行容器的人员之间的一种文档,即有关打算发布哪些端口的信息。 要在运行容器时实际发布端口,请在docker run上使用-p标志发布并映射一个或多个端口,或使用-P标志发布所有公开的端口并将其映射到高阶端口
1 | EXPOSE <port> [<port>/<protocol>...] |
3、构建自定义mycentosjava8镜像
3.1 编写Dockerfile文件
1 | FROM centos |
3.2 构建镜像
1 | #. 表示当前目录,如果名字是Dockerfile,则可以不需要命令-f dockerfile地址 |
3.3 虚悬镜像
仓库名、标签都是<none>的镜像,俗称dangling image。在创建或删除出现的问题,最好不要出现
1 | from ubuntu |
3.4 构建自己的tomcat镜像
1、准备文件
1 | # 准备好以下文件,创建Dockerfile文件,用这个文件名构建时默认不用指定文件了 |
2、构建Dockerfile文件
1 | FROM centos |
3、构建镜像以及启动挂载
1 | #构建镜像 |
4、多阶段构建
4.1 multi-stage builds
https://docs.docker.com/develop/develop-images/multistage-build/
多阶段构建解决的是如何让一个镜像变得更小; 多阶段构建的典型示例
1 | #以下所有前提 保证Dockerfile和项目在同一个文件夹 |
4.2 Images瘦身实践
-
选择最小的基础镜像
-
合并RUN环节的所有指令,少生成一些层
-
RUN期间可能安装其他程序会生成临时缓存,要自行删除
-
使用 .dockerignore 文件,排除上下文中无需参与构建的资源,比如
*.iml
,target/*
-
使用多阶段构建
-
合理使用构建缓存加速构建。–no-cache
-
学习更多Dockerfile的写法:https://github.com/docker-library/
1 | # SpringBoot应用最终写法 |
六、Docker网络
1、docker网络详解
1.1 网络介绍
docker网络作用:容器间的互联和通信以及端口映射;容器IP变动时候可以通过服务名直接网络通信而不受到影响。在同一个网络中相互之间的服务可以使用容器名进行访问
查看本地ip地址ip addr
,docker 采用了veth-pair协议,docker每启动一个容器都会生成一对虚拟接口进行通信(这样一对接口叫veth pair);如同路由器一样进行与容器间的通信。
1 | lo 127.0.0.1 # 本机回环地址 |
1.2 网络常用命令
1 | # 所有命令 |
1.3 网络模式
Docker网络模式 | 配置 | 说明 |
---|---|---|
host模式(常用) | –net=host | 容器和宿主机共享Network namespace |
container模式 | -net=container:NAME_or_ID | 容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace |
Docker网络模式 | –net=none | 容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair 和网桥连接,配置IP等 |
bridge模式**(常用)** | –net=bridge | (默认为该模式),默认使用docker0 |
自定义模式 | -net=自定义 | 用户自己使用network相关命令定义网络,创建容器的时候可以指定为自己定 |
-
bridge模式:使用–network bridge指定,默认使用docker0
-
host模式:使用–network host指定
-
none模式:使用–network none指定
-
container模式:使用–network container:NAME或者容器ID指定
注:docker容器内部的ip是有可能会发生改变的
2、docker四种经典网络
2.1 bridge
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在 内核层 连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到 同一个物理网络 。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码, 让主机和容器之间可以通过网桥相互通信。
1 | # 查看 bridge 网络的详细信息,并通过 grep 获取名称项 |
-
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
-
docker run 的时候,没有指定network的话默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig,就可以看到docker0和自己create的network
-
网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配
-
整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
-
每个容器实例内部也有一块网卡,每个接口叫eth0;
-
docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配
-
2.2 host
直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。容器将 不会获得 一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。 容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。
1 | # 无需进行端口映射,否则会警告 |
2.3 none
在none模式下,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo需要我们自己为Docker容器添加网卡、配置IP等。禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)
1 | docker run -d -p 8084:8080 --network none --name tomcat84 billygoo/tomcat8-jdk8 |
2.4 container
新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
3、自定义网络与网络连通
3.1 自定义网络
因为使用默认网络创建的容器不能ping通容器名,而使用自定义网络可以ping通
1 | # 查看所有网络,默认桥接 |
创建自定义网络
1 | # 创建 |
3.2 网络连通
默认的docker01网络和自定义的网络无法连通,这就是网络隔离,若要一个网段的容器与另一个网段进行通信,则需要使用docker network connect
命令
1 | # 查看帮助文档,发现connect以及详情 |
七、Docker Compose
1、Docker Compose简介
1.1 介绍
Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml, 写好多个容器之间的调用关系 。然后,只要一个命令,就能同时启动/关闭这些容器。Docker-Compose是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。
Compose是一个用于定义和运行多容器Docker应用程序的工具,使用Compose可以使用YAML文件来配置应用程序的服务。然后使用一个命令,从配置中创建并启动所有服务。Compose适用于所有环境:生产、暂存、开发、测试以及CI工作流。
官网地址:https://docs.docker.com/compose/
文档手册地址:https://docs.docker.com/compose/compose-file/compose-file-v3/
安装地址:https://docs.docker.com/compose/install/
1.2 核心概念
一文件
docker-compose.yml
两要素
-
服务(service) 一个个应用容器实例,比如订单微服务、库存微服务、mysql容器、nginx容器或者redis容器
-
工程(project) 由一组关联的应用容器组成的一个完整业务单元,在
docker-compose.yml
文件中定义
1.3 Compose使用的三个步骤
-
编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
-
使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中的各个容器服务
-
最后,执行docker-compose up命令 来启动并运行整个应用程序,完成一键部署上线
2、Compoese安装与使用
2.1 Compose的安装与卸载
1 | #因为compose是docker开源第三方软件,需要额外下载 |
2.2 docker-compose常用命令
docker-compose up/down 和 restart 的区别
-
只要xxx.yaml文件(默认是
docker-compose.yaml
文件)有任何修改,一定要执行docker-compose up
才会生效,执行docker-compose restart
是不会生效的; -
如果是code发生变化,执行
docker-compose restart
是有效的
1 | #查看配置文件 |
compose命令大全
1 | docker-compose -h # 查看帮助 |
3、yaml配置文件规则
docker-compose.yml
配置文件作为核心文件。详细配置文件官网:https://docs.docker.com/compose/compose-file/compose-file-v3/
1 | #yaml文件是三层 |
其他具体可以参考:Docker-compose指令详解 / docker compose 配置文件 .yml 全面指南
4、Compose体验
官网demo地址:https://docs.docker.com/compose/gettingstarted/
1、前期准备
1 | mkdir composetest |
1 | #在py文件里写入以下内容,这里是一个简单的web服务 |
之后vim requirements.txt
文件,写入
1 | flask |
2、创建Dockerfile
1 | # syntax=docker/dockerfile:1 |
3、定义Compose服务(docker-compose.yml)
1 | version: "3.9" |
4、输入****运行Compose服务,停止服务
1 | #这是生成后的四个文件 |
到如图所示情况后,最后在浏览器输入
http://MACHINE_VM_IP:5000
即可访问(注意端口的开放)
5、Compose实战
快速搭建wordpress的demo:https://docs.docker.com/samples/wordpress/
对于springboot实战如下
1、创建springboot项目
1 | <!-- pom.xml的依赖,要选择web和redis依赖--> |
2、编写文件
1 | server: |
3、编写java文件
1 |
|
4、maven打包
5、在根目录编写dockerfile文件
1 | FROM java:8 |
6、在根目录编写文件
1 | version: "3.9" |
7、上传部署,启动服务
将docker-compose.yml
,dockerfile
和jar包上传服务器,启动后即可访问
1 | #前台启动 |
6、docker-compose简单示例
1 | version: "3.7" |
docker-entrypoint.sh
是docker入口点脚本,在hub的github可以看到,比如mysql的入口脚本:
1 |
|
八、Docker Swarm
Docker Swarm 是 Docker 的集群管理工具。它将 Docker 主机池转变为单个虚拟 Docker 主机。 Docker Swarm 提供了标准的 Docker API,所有任何已经与 Docker 守护程序通信的工具都可以使用 Swarm 轻松地扩展到多个主机,Docker Swarm代码开源在https://github.com/docker/swarm。Docker Swarm 和 Docker Compose 一样,都是 Docker 官方容器编排项目,但不同的是,Docker Compose 是一个在单个服务器或主机上创建多个容器的工具,而 Docker Swarm 则可以在多个服务器或主机上创建容器集群服务,对于微服务的部署,Docker Swarm 会更加适合。
swarm分为管理节点和工作结点,所有操作都在manager节点上,并且集群的管理节点数量至少为3,manager节点使用raft协议进行管理。
官网:https://docs.docker.com/engine/swarm/
1、服务器的购买和docker安装
因为至少购买4台云服务器,考虑经济成本,这里我选择了腾讯云的按量计费,云以及按使用流量计费,操作系统使用centos8,云服务器硬件配置为1核2G。
1 | yum -y install gcc |
四台云服务器可以一个命令同时执行,这里我使用了finalShell,打开四个不同的服务器后同时进行操作
2、Swarm集群搭建
1 | #查看网络 |
搭建完主节点后,会自动进行提示如何加入工作节点和新的管理节点,在新的服务器上运行即可成为work或manager节点。
3、Raft协议
Raft协议:保证大多数节点存活;当存活节点数>1时能正常运行,故集群数量必须>3台,保证高可用
1 | #双主双从时,当停止一个manager节点时,另一个也无法正常使用 |
4、Service服务实例
使用swarm的优点是可以弹性的进行扩缩容集群,因为可以使用名字作为host主机,可以随时增加或者缩减容器;而docker-compose 是单机项目
1 | #容器启动!不具有扩缩容器 |
5、服务、任务简单小结
Swarm
集群的管理和编号。 docker可以初始化一个 swarm 集群,其他节点可以加入。(管理、工作者)
Node
就是一个docker节点。多个节点就组成了一个网络集群。(管理、工作者)
Service
服务 (Services) 是指一组任务的集合,服务定义了任务的属性。服务有两种模式:
-
replicated services
按照一定规则在各个工作节点上运行指定个数的任务。 -
global services
每个工作节点上运行一个任务
两种模式通过 docker service create
的 --mode
参数指定。
Task
任务 (Task)是Swarm中的最小的调度单位,目前来说就是一个单一的容器。
6、Docker Stack
docker-compose.yml 来一次配置、启动多个容器,在 Swarm集群中也可以使用 compose 文件 (
docker-compose.yml
) 来配置、启动多个服务。而docker service create
一次只能部署一个服务,使用stack部署docker-compose.yml
我们可以一次启动多个关联的服务。
首先创建docker-compose.yml
文件,首先要启动swarm集群服务,其中的 visualizer
服务提供一个可视化页面,我们可以从浏览器中很直观的查看集群中各个服务的运行节点。
1 | version: "3" |
1 | #帮助命令 |
7、Docker Secret
用户可以在 Swarm 集群中安全地管理密码、密钥证书等敏感数据,并允许在多个 Docker 容器实例之间共享访问指定的敏感数据。
8、Docker Config
Config无需将配置文件放入镜像或挂载到容器中就可实现对服务的配置,提高了集群的通用性。
九、Docker监控与可视化
1、轻量级容器可视化—Portainer
Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便的管理Docker环境,包括单机环境和集群环境,下面我们将用Portainer来管理Docker容器中的应用
Portainer官网安装
普通docker运行
1 | #新建卷 |
docker-compose安装运行
1 | version: '3' |
2、Docker容器日志查看
Dozzle 是 一款基于接口来监视Docker日志的轻量级的应用,它不存储任何日志文件,而仅仅是实时监视你的容器日志。文档:https://github.com/amir20/dozzle
1 | # 处于安全考虑,建议将挂载的权限设为 : read-only |
3、Docker容器监控
3.1 自带监控命令
使用Docker自带的docker stats命令可以很方便地看到主机上所有容器的 CPU、内存、网络 IO、磁盘 IO、PID 资源的使用情况。但是它的缺点也很明显,因为它只能获取本机数据,无法查看历史监控数据,没有可视化展示面板
1 | docker stats |
3.2 CAdvisor监控
CAdvisor 是谷歌开源的一款通用的容器监控解决方案。cAdvisor 不仅可以采集机器上所有运行的容器信息,还提供了基础的查询界面和 HTTP 接口,更方便与外部系统结合。所以,cAdvisor很快成了容器指标监控最常用组件,并且 Kubernetes 也集成了 cAdvisor 作为容器监控指标的默认工具
1 | docker run \ |
docker-compose文件
1 | cadvisor: |
3.3 Prometheus监控
cAdvisor 已经内置了对 prometheus 的支持,我们只需要访问http://localhost:8080/metrics
即可以获取到标准的 prometheus 监控样本的输出
1 | # 修改prometheus.yml文件 |
4、CAdvisor+InfluxDB+Granfana(CIG容器监控)
4.1 简介
CAdvisor监控收集+InfluxDB存储数据+Granfana展示图表
4.2 CAdvisor
CAdvisor是一个容器资源监控,包括容器的内存,CPU,网络IO,磁盘IO等监控,同时提供了一个WEB页面用于查看容器的实时运行状态。CAdvisor默认存储2分钟的数据,而且只是针对单物理机。不过,CAdvisor提供了很多数据集成接口。支持InfluxDB, Redis, Kafka, Elasticsearch等集成可以加 上对应配置将监控数据发往这些数据库存储起来
CAdvisor功能主要有两点:
-
展示Host和容器两个层次的监控数据
-
展示历史变化数据。
4.3 InfluxDB
InfluxDB是用Go语言编写的一个开源分布式时序、事件和指标数据库无需外部依赖。CAdvisor默认只在本机保存最近2分钟的数据,为了持款化存储数据和统一收集展示监控数据,需要将数据存储到InfluxDB中。InfluxDB是一个时序数据库,专门用于存储时序相关数据,很适合存储CAdvisor的数据。而且, CAdvisor本身 已经提供了InfluxDB的集成方法,启动容器时指定配置即可。
InfluxDB主要功能:
-
基于时间序列,支持与时间有关的相关函数(如最大、最小求和等)
-
可度量性:你可以实时对大量数据进行计算
-
基于事件:它支持任意的事件数据
4.3 Granfana
Grafana是一个开源的数据监控分析可视化平台,支持多种数据源配置(支持的数据源包括InfluxDB,MySQL,Elasticsearch,OpenTSDB, Graphite等)和丰富的插件及模板功能支持图表权限控制和报警
Grafan主要特性:
-
灵活丰富的图形化选项
-
可以混合多种风格
-
支持白天和夜间模式
-
多个数据源
4.4 CIG安装
1 | version: '3.1' |
启动docker-compose文件docker-compose up
后
1 | # 浏览cAdvisor收集服务,http://ip:8080/ |
配置步骤可以参考:https://blog.xueqimiao.com/docker/3f3228/
参考文章:
https://yeasy.gitbook.io/docker_practice/
https://www.bilibili.com/video/BV1og4y1q7M4