Docker概述
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows操作系统的机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
为什么要有Docker
传统:发布一个项目时无法将环境一起打包,部署时配置环境十分麻烦,费时费力。
现代:开发打包部署上线一套完成,打包项目时带上环境,称为镜像。使用时下载发布的镜像直接运行即可。
在容器化技术出现以前,一机多用通过虚拟机技术实现
虚拟机:虚拟出一套硬件,运行一个完整的操作系统,然后在这个系统中安装和运行软件,代码还没运行就已经占了庞大的系统资源,非常笨重。
Docker容器技术:也是一种虚拟化技术,但Docker镜像只包括最核心的环境,十分小巧,运行时直接运行镜像就可以了。每个容器间使用沙箱机制相互隔离,互不影响。
使用Docker的好处
更快速的交付和部署应用
传统:一堆帮助文档、安装复杂的环境和程序
Docker:打包镜像、发布测试、一键运行
更便捷的升级和扩缩容
如果一个服务器性能达到瓶颈,可以直接在另一台服务器上运行镜像进行扩展
更高效的计算资源利用
保证了线上线下环境的一致性
实现了沙箱机制,提高了安全性
Docker为什么比VM快
1.docker 有着比虚拟机更少的抽象层
由于docker不需要Hypervisor(虚拟机)实现硬件资源虚拟化,运行在docker容器上的程序直接试用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显的优势。。
2.docker利用的是宿主机的内核,而不需要加载操作系统的OS内核
当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。进而避免引寻、加载操作系统内核返回等比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载OS,返回新建的过程时分钟级别的,而docker由于直接利用宿主机的操作系统,则省略了返回过程,因此新建一个docker容器只需要几秒钟。
Docker基本组成
镜像(image):
相当于是一个模板,可以通过这个模板来创建一个或多个容器,最终服务或项目运行就是在容器中的
容器(container):
Docker通过容器独立运行一个或一组应用,可以执行启动、停止、删除等基本命令
仓库(repository):
仓库就是存放镜像的地方,分公有仓库和私有仓库
Docker是怎么工作的?
Docker是一个C/S结构的系统,Docker的守护进程运行在主机上,通过Socket从客户端访问
DockerServer接收到DockerClient的命令,就会执行这个命令
Docker常用命令
帮助命令
docker version #显示docker的版本信息
docker info #显示docker系统详细信息
docker 命令 --help #帮助命令
容器生命周期管理
docker run #创建一个新的容器并运行一个命令
docker start #启动一个或多个已经被停止的容器
docker stop #停止一个运行中的容器
docker restart #重启容器
docker kill #杀死一个运行中的容器。
docker rm #删除一个或多个容器。如果要删除一个运行中的容器,可以添加 -f 参数。
docker prune #删除所有处于终止状态的容器
docker pause #暂停容器中所有的进程。
docker unpause #恢复容器中所有的进程。
docker create #创建一个新的容器但不启动它
容器操作
docker ps #列出容器
docker inspect #获取容器、镜像的元数据
docker top #查看容器中运行的进程信息
docker exec #在运行的容器中执行命令,进入容器后开启一个新的终端,可以在里面操作,退出应用时不会导致容器停止
docker attach #连接到正在运行中的容器,进入容器正在执行的任务,不会启动新的进程。退出应用时会导致容器停止
docker events #从服务器获取实时事件
docker logs #获取容器的日志
docker wait #阻塞运行直到容器停止,然后打印出它的退出代码。
docker export #将文件系统作为一个tar归档文件导出到STDOUT。
docker port #列出指定的容器的端口映射,或者查找将PRIVATE_PORT NAT到面向公众的端口。
docker commit #从容器创建一个新的镜像。
docker cp #用于容器与主机之间的数据拷贝。
docker diff #检查容器里文件结构的更改。
镜像仓库
docker login #登陆到一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub
docker logout :#登出一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub
docker pull #从镜像仓库中拉取或者更新指定镜像
docker push #将本地的镜像上传到镜像仓库,要先登陆到镜像仓库
docker search #从Docker Hub查找镜像
本地镜像管理
docker images #列出本地镜像
docker rmi #删除本地一个或多个镜像
docker tag #标记本地镜像,将其归入某一仓库
docker build #使用 Dockerfile 创建镜像
docker history # 查看指定镜像的创建历史
docker save #将指定镜像保存成 tar 归档文件
docker load #导入使用 docker save 命令导出的镜像
docker import #从归档文件中创建镜像
Docker镜像
什么是镜像?
- 镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,他包含运行某个软件所需的所有内容,包括代码、运行时库、环境变量和配置文件。只有通过镜像文件才能生成容器实例。
- 将所有的应用和环境,直接打包为docker镜像,就可以直接运行。
- 如何得到镜像:
- 从远处仓库下载
- 拷贝
- 自己制作一个镜像 DockerFile
Docker镜像加载原理
-
Docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统就是 UnionFS
- **UnionFS(联合文件系统):**Union文件系统是一种分层、轻量级并且高性能的文件系统,他支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Union文件系统是 Docker镜像的基础,**可以通过分层来继承基础镜像,提高文件的复用。**说白了就是把一个镜像分成很多层,多个镜像可以共用相同的一层,避免了文件的重复加载。
- 特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
-
bootfs(boot file system)主要包含bootloader加载器和kernel内核。bootloader主要是引导加载kernel,完成后整个内核就都在内存中了。此时内存的使用权已由bootfs转交给内核,系统卸载bootfs。可以被不同的Linux发行版公用。
-
rootfs(root file system),包含典型Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。rootfs就是各种不同操作系统发行版(Ubuntu,Centos等)。因为底层直接用Host的kernel,rootfs只包含最基本的命令,工具和程序就可以了。所以虚拟机启动是分钟级,而docker能做到秒级。docker 的镜像文件相当于=只拥有自己的bootfs+简单的rootfs+镜像本身的依赖+镜像本身
-
Docker镜像都是只读的,当容器启动时, 一个新的可写层被加载到镜像的顶部!这一层就是我们通常说的容器层, 容器之下的都叫做镜像层。
commit镜像
docker commit 提交容器成为一个新的镜像 和Git原理类似
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[tag]
使用
docker commit
命令虽然可以比较直观的帮助理解镜像分层存储的概念,但是实际环境中并不会这样使用。除了真正想要修改的文件外,由于命令的执行,还有很多文件被改动或添加。如果是安装软件包、编译构建,那会有大量的无关内容被添加进来,将会导致镜像极为臃肿。
此外,使用
docker commit
意味着所有对镜像的操作都是黑箱操作,生成的镜像也被称为 黑箱镜像,换句话说,就是除了制作镜像的人知道执行过什么命令、怎么生成的镜像,别人根本无从得知。而且,即使是这个制作镜像的人,过一段时间后也无法记清具体的操作。这种黑箱镜像的维护工作是非常痛苦的。
容器数据卷
目的:为了实现数据持久化,并且使容器之间能够共享数据。可以将容器内的目录,挂载到宿主机上或其他容器内,实现同步和共享的操作。即使将容器删除,挂载到本地的数据卷也不会丢失。
使用数据卷
-
直接使用命令来挂载 -v,挂载成功后其实是双向绑定,无论在哪一端修改文件内容都可以同步到另一端
docker run -it -v 主机目录:容器内目录
使用docker inspect命令查看容器的详细信息,可以看到下面这张图,表示挂载成功
好处:以后修改数据直接在本地和容器内修改都可以,另一端会自动同步,并且删除容器之后,本地的数据依旧存在,做到了容器数据的持久化
匿名挂载和具名挂载
匿名挂载
-v 容器内路径 #只指定容器内路径,本地路径由docker自动配置
[root@localhost ~]# docker run -d -P --name nginx01 -v /etc/nginx nginx
[root@localhost ~]# docker volume ls #查看所有数据卷
local 45de0c847c7ff79692f4bd0aabd7936e11a9dc91bc85fab00eae323cc65cd1d0
-
补充:docker volume 命令 操作数据卷
create Create a volume inspect Display detailed information on one or more volumes ls List volumes prune Remove all unused local volumes rm Remove one or more volumes
具名挂载
-v 卷名:容器内路径
[root@localhost ~]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
673298470e5e9d5d8c2e51e638372fd166f35873e7b960b3c00e780f972288dd
[root@localhost ~]# docker volume ls
local juming-nginx
使用docker volume inspect 命令查看数据卷详细信息:
在没有指定目录的情况下,所有docker容器的卷都是在 /var/lib/docker/volumes/xxxx/_data
查看一下这个目录:
通过具名挂载可以方便的找到我们的一个卷,大多数情况下使用具名挂载
#小结
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:/容器内路径 #指定路径挂载
#拓展:通过-v 容器内路径:ro(只读) rw(读写) 改变读写权限
#一旦设置了这个容器的权限,容器对挂载出来的内容就有限定了
#如果设置了ro,那容器就只有只读权限了,只能通过宿主机才能进行写操作
[root@localhost ~]# docker run -d -P --name nginx01 -v /etc/nginx:ro nginx
此外,在使用DockerFile构建镜像时也可以挂载,在下一节具体说明
DockerFile
DockerFile就是用来构建Docker镜像的文件 其实就是一段命令脚本
看一看官方的dockerfile:
很多官方的镜像都只有基础包,我们通常会搭建自己的镜像
构建步骤:
- 编写一个DockerFile文件
- docker build 将dockerfile构建为一个镜像
- docker run运行镜像
- docker push发布镜像(DockerHub、阿里云镜像仓库)
DockerFile指令
FROM #指定基础镜像,一切从这里开始构建,必需指令,而且必须是第一条指令
MAINTAINER #镜像作者,姓名+邮箱
RUN #执行命令行命令
COPY #复制文件
ADD #复制文件,会自动解压,除非需要解压,否则更推荐用COPY
WORKDIR #镜像的工作目录
VOLUME #挂载的目录
EXPOSE #保留端口配置
CMD #指定默认的容器主进程的启动命令,只有最后一个会生效,可被替代
ENTRYPOINT #指定容器启动的时候要运行的命令,可以追加命令
构建一个自己的centos
#1.编写dockerfile文件
vim dockerfile-centos #文件名可以随意,但最好是dockerfile
FROM centos:7
MAINTAINER linhongwei<1332009068@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim #官方的centos是没有vim功能的,这里我们把它加进去
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "---end---"
CMD /bin/bash
#2.通过这个文件构建dockerfile对象
#docker build -f dockerfile文件路径 -t 镜像名:[tag版本号] .
docker build -f dockerfile-centos -t mycentos . #一定要注意这里还有个.
build好之后就可以使用docker images查看镜像
使用docker run命令创建一个容器
然后进入这个容器,使用vim命令创建一个新文件,可以看到我们自己构建的centos镜像拥有了vim功能
可以使用docker history命令来查看镜像的构建过程
Docker网络
理解Docker网络
我们进入一个Tomcat容器,看一看它的host信息
172.17.0.2就是docker分配给这个Tomcat容器的地址,那么我们能在容器外ping通这个地址吗?
可以看到,是可以ping通的。说明Linux可以ping通docker容器内部
原理:
- 我们每启动一个docker容器,docker就会给容器分配一个ip,我们只要安装了docker,就会有一个docker0网卡,使用桥接模式,使用的技术是veth-pair技术
- veth-pair就是一对虚拟设备接口,成对出现,一端连着协议,一端彼此相连,充当一个桥梁。
那么,再新建一个容器tomcat02,我们能在tomcat02内ping通tomcat01吗?
这里有可能会出现没有ping命令的情况,原因是我们下载的tomcat版本是精简版,阉割掉了ping命令,我们可以在容器内使用下面的几条命令安装进去。
先apt update
然后apt install -y net-tools
apt install -y iproute2
apt install -y iputils-ping
可以看到,也能ping通。说明容器之间也可以互相ping通
容器之间是通过docker0网卡连接的,docker0就相当于是容器1和容器2之间的一个交换机。docker内部的所有网络接口都是虚拟的,转发效率高。
容器互联 --link
在启动容器时使用–link
[root@localhost ~]# docker run -d -P tomcat03 --link tomcat02 tomcat
用tomcat03ping一下tomcat02试试
查看tomcat03的host配置,发现–link其实就是在tomcat03 的host中增加一条tomcat02的配置
–link缺点:不支持自定义网络,所以不建议使用
自定义网络
查看所有的docker网络
网络模式
bridge:桥接 docker默认
none:不配置网络
host:和宿主机共享网络
container:容器网络连通,局限大,很少用
# 我们直接启动的命令其实默认有一个 --net bridge 这个其实就是docker0
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomcat
#docker0 特点:默认,域名不能访问,--link可以打通网络
自定义网络
[root@localhost ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
d5c23a994ae84cb543d87aea0a789013f59690949c0f25e4dee5ad6c28a13c04
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
becd1cb6fe8a bridge bridge local
67bcc99d7c78 host host local
d5c23a994ae8 mynet bridge local
38d15644633c none null local
查看我们自己创建的网络mynet的详细信息
在mynet中创建两个容器
再查看网络的详细信息,可以看到我们创建的两个容器都在网络里面了
可以看到,自定义的网络内的容器可以ping分配的IP,也可以直接ping容器名
网络连通
测试连通tomcat02 - mynet(不同虚拟网卡(网段)之间不能直接连通,但是容器可以和虚拟网卡连通)
[root@localhost ~]# docker network connect mynet tomcat02
[root@localhost ~]# docker network inspect mynet
连通方式非常简单粗暴,就是直接在mynet网络中给tomcat02分了一个IP地址
可以看到:tomcat02可以ping通mynet里的其他容器了,但是tomcat03不能ping通
Docker Compose
Compose是Docker的官方开源项目,可以进行批量容器编排,轻松高效地管理Docker容器集群。你需要定义一个yaml配置文件docker-compose.yml,写好多个容器之间的调用关系,然后,只需要一个命令就可以同事启动/关闭这些容器。Compose解决了容器与容器之间如何管理编排的问题。
术语
-
服务 (
service
):当我们运行某个镜像时,其实就产生了一个镜像实例,这个实例我们把它叫做容器,接下来我们对它做个升级,比如一些配置负载均衡,配置域名解析映射等,最终它以web服务的形式运行,那么这个升级版的容器就是Docker服务。 -
项目 (
project
):Compose允许用户通过一个单独的docker-compose.yml模板文件来定义一组关联的应用容器为一个项目。可见,一个项目可以由多个服务(容器)关联而成,
Compose
面向项目进行管理。
#yaml文件示例
version: "3.9" # optional since v1.27.0
services:
web:
build: .
ports:
- "8000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}
容器,接下来我们对它做个升级,比如一些配置负载均衡,配置域名解析映射等,最终它以web服务的形式运行,那么这个升级版的容器就是Docker服务。
-
项目 (
project
):Compose允许用户通过一个单独的docker-compose.yml模板文件来定义一组关联的应用容器为一个项目。可见,一个项目可以由多个服务(容器)关联而成,
Compose
面向项目进行管理。
#yaml文件示例
version: "3.9" # optional since v1.27.0
services:
web:
build: .
ports:
- "8000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}