什么是Docker?
- 官方文档:https://docs.docker.com/
- docker是Go语言开发的应用容器引擎
- 以前一个产品从开发到上线,开发人员将项目打包后给运维人员部署,结果运维人员经常跑不起来,于是docker应运而生,将应用的操作系统、运行环境、配置等一起打包,解决了开发与运维的冲突!
- 虽然以前是通过虚拟机来解决这种问题,但是虚拟机是模拟硬件实现资源消耗非常大,而docker则是虚拟OS粒度更小
Docker的基本组成
Docker 是C/S架构,通过操作本地docker Engine 使用镜像(模板)来创建对应容器(实例),可以从远程仓库中推送自己制作的镜像或者拉取自己想要的镜像
镜像
镜像是我们的软件与环境打包成的模板(分层构建),用这个镜像可以创建多个容器
容器
容器就是我们软件运行的实例,里面包括了一个虚拟的操作系统、可以运行独立的应用软件,每个容器是互相隔离的
仓库
官方仓库 https://hub.docker.com/ 是最大的镜像仓库、我们可以去注册账号发布自己的镜像,也可以搭建自己的镜像仓库
一张图了解docker的常用命令
安装/配置docker
安装
基于CentOS安装,版本至少要 centos7: https://docs.docker.com/engine/install/centos/
卸载旧的版本
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine安装环境、软件包、配置镜像地址
yum install -y yum-utils
# 配置镜像地址
# 官方地址(可能比较慢):--add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo安装docker引擎
# docker-ce 社区版本, docker-ee 企业版本
yum install -y docker-ce docker-ce-cli containerd.io启动docker
systemctl start docker
配置镜像仓库
默认在官方的 https://hub.docker.com/ 去下载镜像可能非常慢,登录阿里云搜索 容器镜像服务
可查看自己的镜像加速地址
sudo mkdir -p /etc/docker |
Docker 底层原理
Docker与虚拟机VM
虚拟机:创建 GuestOS,模拟硬件,粒度很大重型的虚拟技术,性能只能达到宿主机的80%
Docker:不需要再去虚拟化硬件资源,资源开销直接使用宿主机的,性能没有损耗
优劣势对比:
Docker镜像
什么是镜像?
- 镜像就是一个轻量级的,独立的软件包!
- 将
软件 + 运行环境 + linux
进行打包,只要运行这个容器即可提供服务! - 以前需要在每台linux系统上安装软件所需环境,现在只需安装docker,直接运行集成了环境的镜像即可!
镜像的加载原理
联合文件系统(Union FS)
核心:分层
bootfs与rootfs
- bootfs(boot file system):bootloader + kernel ,bootloader进行引导加载 kernel 内核!此时内核已经在内存中了,内存的使用权从bootfs转交给了kernel,这时候就会自动卸载bootfs!在最底层Linux/Unix操作系统都是一样的!
- rootfs(root file system):在bootfs之上,包含基本目录 /dev /bin /etc …. 等标准目录文件!市面上不同的操作系统发行版的区别就在于rootfs,所以底层都是bootfs!
以bootfs的基础的docker,镜像就可以只提供rootfs文件管理系统(只要包含一些基本的命令、工具、库即可),所有镜像统一使用宿主机上的kernel,大大缩小了镜像的大小,我们pull一个centOS的镜像也只需230M左右!也同时代表着所有的镜像底层都是linux系统!
分层概念
- docker中的镜像也是分层的,从底层一层层往上构建起来,只要增加一层就会形成一个新的镜像
如果镜像毎发生一次变化,一旦被提交就会产生一个新的镜像,并且在上一个镜像增加一层
# 可以将一个容器再次提交成镜像
# -a 作者信息
# -m 提交信息
# -c 可使用dockerfile的指令来创建这个镜像
# -p 提交期间暂停容器(默认true)
docekr commit container newImgName[:tag]- commit之后使用
docker inspect img
对比原来镜像与最新镜像
- commit之后使用
每个容器做的改变其实都发生在最上层
writeable
层,提交时writeable
就会变成新镜像的最新层!
分层的好处:资源共享,每一层就像一个个组件存储在宿主机上,将需要的组件进行组装就可以组成一个镜像!如果已经有相同的组件多个镜像就可以共享一份!
Docker 基本使用
帮助命令
# 列出docker所有命令 |
镜像命令
# 查看镜像 |
容器命令
# 查看所有容器,默认只看处于运行状态的容器 |
其它命令
# 登录到远程仓库 |
Docker 数据卷
什么是数据卷?
- 我们毎运行一个容器,文件都在容器内部的系统中,如果运行一些持久化软件,容器被删除了那么持久化文件也同时被删除!所以我们需要卷来将文件挂载到宿主机的文件系统中,这样即使删除容器挂载的文件依然存在!
- 卷可以在一个或者多个容器内进行通信、共同存储文件。不属于联合文件系统。
- 关键作用:只要挂载了的目录,无论在容器内修改还是在宿主机上修改,两边都会同步!
目录挂载
# 使用-v来进行挂载,指定 宿主机的目录 挂载到-> 容器内的目录 |
匿名挂载
匿名挂载的方式会在宿主机 /var/lib/docker/volumes/
下随机分配一个目录名字进行挂载,缺点是不好维护,所以一般会使用具名挂载。
# 匿名挂载,只指定一个容器内目录 |
具名挂载
# 查看所有卷 |
- 具名挂载同样是在宿主机
/var/lib/docker/volumes/
下创建
指定具名卷进行挂载
# 具名卷redisVolume 挂载到-> 容器内的目录/home
docker run -d -v redisVolume:/home redis
DockerFile
什么是DockerFile?
DockerFile是用于构建镜像的文本文件,内容包含了一条条要构建一个镜像所需的指令!
构建镜像的指令
FROM
指定基于哪个镜像开始构建。(scratch是一个空的镜像,可以说是真正的从零开始构建自己的镜像)RUN
编译镜像时运行的脚本,一般用于安装一些基础工具、依赖CMD
指定要执行的命令但是只会执行最后一条命令。- 并且docker run img xxx 后面跟的xxx命令会覆盖这个
CMD
命令。 - 比如一个redis的镜像
ENTRYPOINT
为redis-server,我们可以这么Run:docker run redis redis-server -raw -h localhost xxx -p 6380) - (注意:与
ENTRYPOINT
有细节上的区别 )
- 并且docker run img xxx 后面跟的xxx命令会覆盖这个
ENTRYPOINT
同样指定要执行的命令但是只会执行最后一条命令。- 并且docker run img xxx 后面跟的命令会与这个
CMD
命令进行拼接。 - 比如一个redis的镜像
ENTRYPOINT
为 [“redis-server”] ,我们可以这么Run:docker run redis -raw -h localhost xxx -p 6380
- 并且docker run img xxx 后面跟的命令会与这个
WORKDIR
指定工作目录,进入容器后或使用exec执行的命令的默认路径ADD
可以将一个.tar.gz
(不是这种压缩包就是直接复制)压缩包自动解压到镜像中指定目录COPY
复制一个文件到镜像中指定目录EXPOESE
暴漏容器运行时的监听端口给外部,但是EXPOSE并不会使容器访问主机的端口,如果想使得容器与主机的端口有映射关系,必须在容器启动的时候加上 -P 或 -p 参数
编写Dockerfile
尝试自己写一个Dockerfile
FROM centos:latest |
构建镜像
# 使用Dockerfile构建镜像 |
- 我们编写的每一条指令最后都会commit变成一层层镜像
注意:如果容器中没有正在运行的终端,容器运行完启动命令则会自动停止!所以在这里run的时候执行脚本保证容器不被停止
docker run -it -d test-my-docker-file /bin/sh -c "while true; do sleep 1; done"
Docker网络
- 不同操作系统docker的网络实现有所不同,这里以linux系统为例。
- 了解docker网络可以使我们更加了解容器与容器之间如何进行通信
docker0 网卡
- 创建容器时不指定网卡默认为docker0,不能使用类似域名或者网卡名字进行联通
- 使用
ip address
查看docker有独立的网卡管理docker的网段172.17.0.1/16 (一个网卡大概可以创建16位=255*255-1=65024个容器)
运行一个tomcat容器随机暴露端口
docker run -d -P --name tomcat1 tomcat
并查看容器内的网卡docker exec -it tomcat1 ip address
,可以发现容器内的的ip在同一网段,并且得出结论可以在主机上ping通容器内部此时,在主机上再次查看网卡信息,可以发现多个一个网卡,并且与容器内部形成了配对关系
在linux中只要是这类成对出现的网卡一般都是veth-pair技术
veth-pair
顾名思义,veth-pair 就是一对的虚拟设备接口,和 tap/tun 设备不同的是,它都是成对出现的。一端连着协议栈,一端彼此相连着。可以使容器内的网卡与主机网卡形成一个整体,就像是在同一个网络当中。
正常情况下容器之间是互相隔离ping不通的,但是有了veth-pair技术,使我们在容器tomcat1中可以ping通tomcat2的ping!
Docker网络命令
网络模式
Docker网络模式 | 配置 | 说明 |
---|---|---|
host模式 | –net=host | 容器和宿主机共享Network namespace。主机! |
container模式 | –net=container:NAME_or_ID | 容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。 |
none模式 | –net=none | 容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair 和网桥连接,配置IP等。自己设置 |
bridge模式 | –net=bridge | (默认为该模式)路由器,自动划分ip! |
# 查看doker所有网络 |
使用
docker network inspect
查看bridge桥接模式的网络可以看到所有容器的网卡信息及对应ip
–link 单向连接
创建docker3
docker run -d -P --name tomcat3 --link tomcat2 tomcat
指定连通tomcat2此时tomcat3已经被单向连接到了tomcat2,而单相连接顾名思义tomcat2并不会连通tomcat3
进入tomcat3容器,发现其实就是修改了hosts文件实现的域名解析!
自定义网卡
创建自定义网卡
创建容器使用
--net
指定自定义的网卡:docker run -d -P --name tomcat4 --net HTH tomcat
再查看自定义网卡信息,发现分配了新的网段、网关(可自定),及网段中容器的网络信息!
此时在同一个网络下的多个容器即可使用容器名进行通信!
Redis集群配置
# 创建网卡 |
Docker Compose
简介
- 官方文档: https://docs.docker.com/compose/
- 微服务场景下,需要部署多个服务实例,如果每个服务一个个手动操作将会非常麻烦!
- Docker Compose是Docker官方的开源项目,用来批量管理服务的工具。
- Docker Compose核心就是配置一个yaml文件,配置在一个文件中的服务即可使用一键启停等高校方便的操作!
- 一个docker-compose.yml编排多个容器为一个项目(project),其中每个容器(可能有多个副本)称为服务(service)。
- 使用compose分为三步:
- 编写Dockerfile用于打包镜像(如果你的镜像已经存在或来自官网,就省略这步)
- 在docker-compose.yml里定义自己想要的服务(包括容器、网络、环境变量、挂载等)
- 通过docker-compose up 命令启动服务
安装
# 下载 |
docker-compose.yml
- 官方文件关键字详细说明https://docs.docker.com/compose/compose-file/
- docker-compose可分为3个部分
version
第一个部分指定版本(⤴️连接有version与docker引擎的对照表),向下兼容services
第二个部分是编排的服务,可写多个- 第三部分分为其它命令,比如:
networks
、volumes
、secrets
、config
等等…
docker-compose 常用命令
# 启动所有服务,如果镜像不存在则先pull镜像或者buil镜像 |
部署一个简单的web项目
构建服务镜像
编写一个web服务,用redis实现毎访问一次累加,并且返回累加后的值
"/") (
public class HelloController {
private RedisTemplate redisTemplate;
public Long hello() {
return redisTemplate.opsForValue().increment(1);
}
}- application.yml
server:
port: 8091
spring:
main:
allow-bean-definition-overriding: true
redis:
# 让环境变量进行覆盖
host: ${SPRING_REDIS_HOST:localhost}
port: 6379用maven打成jar包
编写Dockerfile构建镜像
# 指定java8基础镜像
FROM java:8
# 指定工作目录
WORKDIR /home
# 将web服务jar包复制到镜像工作目录中(Dockerfile所在文件夹中存放了刚刚打的jar包)
COPY . .
# 运行容器时使用java -jar 运行服务
CMD ["java", "-jar","web-server-1.0-SNAPSHOT.jar"]
编写docker-compose
- 编写docker-compose.yml
version: '3.8' |
启动web服务
一切准备就绪只需 docker-compose up
即可将所有服务一键启动!
Docker Swarm
什么是Docker Swarm?
- Swarm是Docker公司推出的用来管理docker集群的平台, 它是将一群Docker宿主机变成一个单一的虚拟主机,Swarm通过Docker客户端为入口进行工作
- Docker Swarm 和 Docker Compose 一样,都是 Docker 官方容器编排项目,但不同的是,Docker Compose 是一个在单个服务器或主机上创建多个容器的工具,而 Docker Swarm 则可以在多个服务器或主机上创建容器集群服务,对于微服务的部署,显然 Docker Swarm 会更加适合
- Swarm自己不运行容器,它是接收docker客户端发来的执行去调度适合的节点去执行任务
Swarm 架构
- Worker:主要职责是接收
Manager
分派的任务 - Manager:主要职责是维护集群的状态和信息、分派任务给合适的
Worker
Raft一致性协议
- Swarm 遵循Raft一致性协议
- Raft一致性协议保证绝大多数节点存活才可以使用
- 如果有两个Manager节点,挂了一个,那么集群将不可用!所以一般配置Manager节点为奇数
创建/管理一个Swarm集群
搭建集群所需条件
- 至少要3个能进行网络通信节点(买3台服务器)
- 每个节点上都安装了安装了Docker 1.12或更高版本
开始搭建
# 初始化一个集群 |
docker告诉我们已经创建了一个Manager,接下来可以使用
docker swarm join --token TOKEN
命令在别的节点上加入集群成为Worker,或者使用docker swarm join-token manager
查看管理者的join token:# 可以再次查看swarm加入集群所需的token
docker swarm join-token manager|worker在其它两个节点上执行了join之后,在Manager上使用
docker node ls
可以查看集群节点列表
详细命令整理
# 初始化一个集群 |
使用Swarm集群管理服务
创建nginx集群
使用
docker service
可以向Swarm集群节点分配任务创建一个服务
docker service create -p 8888:80 --name myNginx nginx
查看服务列表
如此简单的配置,此时所有节点都可访问该服务
当前是一个容器副本,使用
docker service update
来动态扩容查看服务所有容器
此时,Swarm将容器随机分发到不同节点中运行,一个节点可运行多个容器互相隔离。整个集群服务对外暴露的只有一个8888端口,无论请求打在了哪个节点上Swarm会使用负载均衡算法分发到不同的节点上!
详细命令整理
# 创建服务 |