docker为什么会出现?
一款产品:开发---->运维,两套环境!应用环境,应用配置!
常见问题:我的电脑可以运行,版本更新,导致服务不可用。
环境配置十分的麻烦,每个机器都需要部署环境(redis集群,es等。。。。)。
不能跨平台。
发布项目(jar+mysql+redis
。。。),项目能不能带上环境去发布。
传统:开发jar
,运维来做!
现在:开发打包部署上线,一套流程。
以上问题,docker
提出解决方法。
java
—>jar
(环境)---->(打包项目带上环境)镜像---->(docker
)---->下载镜像---->运行。
docker的核心思想:隔离,打包装箱,每个箱子互相隔离
。
文档:https://docs.docker.com/
仓库:https://hub.docker.com/
Docker的优点如下:
1、简化程序:Docker让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,使开发者可以直接将自己的成果放入Docker中进行管理。
2、节省开支
docker能干嘛
之前的虚拟机技术
缺点:
- 资源占用多;
- 冗余步骤多;
- 启动慢。
容器化技术
与传统的虚拟机不同:
- 传统的虚拟机:运行一个完成的操作系统,在这个系统中安装和运行。
- 容器化:应用直接运行在宿主机的内核上,容器自己没有内核, 每个容器间,相互隔离,互不影响。
docker的组成
- 镜像(Images): docker镜像相当于模板
(对象)
,通过镜像来创建容器。镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。 - 容器(Containers): docker镜像相当于
(对象的实例化)
,独立运行一个或一组应用,服务最终运行在容器里面。容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的root
文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器运行时,以镜像为基础层,在其上创建一个当前容器的存储层,这个为容器运行时读写而准备的存储层为容器存储层。容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。 - 仓库(Registry): 存放镜像的地方。
docker是怎么工作的?
docker
是一个client-server
的服务,docker
的守护进程运行在主机上,通过socket
从客户端访问。docker-server
是接受docker-client
的指令。
docker为什么比vm快?
docker
有着比虚拟机更少的抽象层;docker
利用的是宿主机的内核,vm
需要的是Guest OS
。
所以运行容器的时候,docker不需要像虚拟机一样重新加载一个操作系统内核。
docker常用指令
万能指令
docker version # 版本信息
docker info # 系统信息,镜像和容器数
docker --help # 帮助指令
帮助文档:https://docs.docker.com/engine/reference/commandline/
镜像命令
docker image [选项] 显示本地镜像
- -a --all 显示所有镜像
- -q --quit 只显示id
REPOSITORY : 镜像仓库源>
TAG:标签
IMAGE ID:镜像id
CREATED:创建时间
SIZE:大小 选项
搜索镜像 docker search 镜像名 [选项]
- –filter=STARS=3000 搜索出来的命令大于3000
- NAME:镜像仓库名称。
- DESCRIPTION:镜像仓库描述。
- STARS:镜像仓库收藏数,表示该镜像仓库的受欢迎程度,ars0
- OFFICAL:表示是否为官方仓库,该列标记为[0K]的镜像均由各软件的官方项目组创建和维护。
- AUTOMATED:表示是否是自动构建的镜像仓库。
拉取镜像 docker pull 镜像名[:tag]
[root@Centos7 /]# docker pull mysql
Using default tag: latest # 不写tag,默认最新
latest: Pulling from library/mysql
d67a603b911a: Pull complete #分层下载 docker image 核心 联合系统
0cf69c8f1492: Pull complete
a5ee239a0d3a: Pull complete
0f166cb3e327: Pull complete
882d294bf188: Pull complete
2649fc7eb806: Pull complete
bddb3394e2e3: Pull complete
93c83d9a2206: Pull complete
99d7f45787c0: Pull complete
234663a2e3ee: Pull complete
74531487bb7b: Pull complete
Digest: sha256:d4055451e7f42869e64089a60d1abc9e66eccde2910629f0dd666b53a5f230d8 #签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest # 真实地址
- docker rmi -f 镜像名/镜像id 删除镜像
- 删除所有 docker rmi -f $(docker images -q) 删除所有镜像。
骚操作:
- docker image prune #删除没有使用的镜像
- docker image inspect #显示一个或多个镜像的元数据
构建镜像 docker build
- -f #通过什么文件来构建,后面接构建文件的地址
- -t #生成文件的版本
容器命令
说明:有对象才可以实例化,有了对象才可以创建容器。
启动和停止容器
docker start 容器id #启动容器
docker restart 容器id #重启容器
docker stop 容器id #停止当前正在运行的容器
docker kill 容器id #强制停止当前容器
docker container prune 删除所有未使用容器
docker inspect 容器id (可查看容器的ip和基本信息)
新建并启动容器 docker run [可选参数] 镜像id
分析run指令
–name=“容器名” # 容器名字 区分容器
-d # 后台运行
-it # 交互模式,进入容器
-p 主机端口:容器端口 # -p 8000:8000 指定容器端口
-P # 随机端口
-v 主机目录:容器目录 # 挂在数据卷
–net选项:指定网络模式,该选项有以下可选参数:
- –net=bridge:默认选项,表示连接到默认的网桥(桥接)。(docker有自己的ip,可以在宿主机上通过curl docker容器ip:端口来访问容器类项目,浏览器上不行,,相当于内网)
–net=host:容器使用宿主机的网络(和宿主机共用一个网络,比如宿主机:192.168.10.21,docker:192.168.10.1)。
–net=container:NAME-or-ID:告诉Docker让新建的容器使用已有容器的网络配置。
–net=none:不配置该容器的网络,用户可自定义网络配置。例子:
1.docker run -d mysql #后台启动容器(docker容器使用后台启动,必须有前台进程(比如:进入容器-it
,docker发现容器没有应用,会退出)
2. docker run -it -d mysql /bin/bash #后台启动并进入容器
3.docker run --name=“mysql” -p 3306:3306 -d mysql #后台启动一个name=mysql,port=3306
的容器
查看运行的容器 docker ps [选项] 容器
- -a # 查看运行过的容器
- -n=? #最近创建的容器
退出容器
- exec #直接退出并停止容器
- ctrl+p+q #直接退出,但不停止容器
删除停止的容器 docker rm 容id
该命令只能删除已停止的容器,如需删除正在运行的容器,可使用-f参数
- docker ps -f $(docker ps ‐a -q) # 删除所有容器,包括停止的。
进入容器
- docker exec -it 容器id /bin/bash #进入容器打开一个新的终端。
- docker attach 容器id # 进入容器正在执行的终端。
容器与宿主机相互复制文件
从容器里面拷文件到宿主机:
- docker cp 容器id:要拷贝的文件在容器里面的路径 宿主机的相应路径
从宿主机拷文件到容器里面:
- docker cp 要拷贝的宿主机文件路径 容器id:要拷贝到容器里面对应的路径
其他指令
- docker logs -tf --tail n 容器id # 查看尾部
n
行日志- tf 显示日志
- tail 尾部
- docker top 容器id # 查看docker内部的进程信息
- docker [image/container] inspect 容器id/镜像id # 查看容器或者镜像元数据
- docker volume --help #查看一下卷的帮助文档
- docker volume ls # 查看一下所有本地的volume卷
容器可视化面版
方式一
#搜索并下载镜像
docker search portainer
docker pull portainer/portainer
#单机方式运行
docker run -d \
-p 9000:9000 \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
--name Prtainer portainer/portainer
方式二
docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/dokcer.sock --privileged=true portainer/portainer
镜像详解
镜像是什么
镜像是一种轻量级,可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码,运行时,库,环境,配置文件等。所有的应用,直接打包docker
镜像,就可以直接运行。
如何得到镜像:
- 从远程仓库下载
- 朋友拷贝
- 自己制作一个Dockerfile
docker镜像加载的原理
我们下载镜像的时候看到是一层层。
UnionFS(联合文件系统):分层,轻量并且高性能的文件系统,它支持文件系统的修改作为一次提交来一层层的叠加,同时可以将不同的目录挂载到同一个虚拟文件系统下。Union文件系统时docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次通过加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有的底层的文件和目录。
举例:
比如下载mysql镜像
和redis镜像
,由上图可知,两个镜像都依赖A文件系统
。所以下载**mysql镜像
**会下载A,B,C文件系统
,而下载redis镜像
的时候,因为A文件系统
已经下载过,不会下载,只会加载D,R文件系统
,和已经下载好的文件系统组成redis镜像
。
docker镜像是一层层的文件系统。
bootfs(boot file system
)主要包含bootloader
和kernel
,bootloader主要是引导加载
kernel,
linux刚启动时会加载
bootfs文件系统,在docker镜像
的最底层就是bootfs
。这一层与我们典型的linux
系统是一样的,包含加载器和内核
。当bootfs
加载完成之后整个内核就会存在内存中,此时内存的使用权已由bootfs
转交内核,此时系统也会卸载bootfs
。(可以理解成系统开机加载的过程)
rootfs(root file system)
在bootfs
之上,包含就是典型的linux系统
中的/dev,/proc,/bin,etc等标准目录和文件
。rootfs
就是各种不同的操作系统发行版,比如Ubuntu,Centos等。
对于一个精简的os
(生成的容器),rootfs
可以很小,只需要包含最基本的命令
,工具和程序库就可以了。因为底层直接用host
的kernel(内核)
,自己只需要提供rootfs
就可以了。
docker分层理解
上面我们说docker
镜像由多个文件系统组成,由上图也可知,已经下载的文件系统不会被再次下载。
思考:为什么docker需要采用这样的分层方法?
查看镜像元数据: docker images inspect redis:latest
。
所有的docker镜像都起始于一个基础的镜像层,当进行修改或者新增内容时,就会在当前镜像层之上,创建新的镜像层。
举例:基于Ubuntu Linux16.04创建一个新的镜像,这就是新镜像的第一层。如果在镜像中加入python包,就会在基础镜像层之上创建第二个镜像层,如果继续添加一个安全补丁,就会创建第三层镜像层。
在添加额外的镜像时,镜像始终保持是当前所有镜像的组合。
例如:每个镜像层包含三个文件,这个镜像包含6个文件
这种情况下,上层镜像中的文件覆盖了底层镜像中的文件,这样使得文件的更新版本作为一个新的镜像层添加到镜像中。docker通过快照的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。
最终表现如下图。
注意
docker镜像默认都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部。这一层就是我们通常说的容器层,容器层之下的都叫镜像层。
容器数据管理
什么是容器数据卷?
docker
的理念回顾:将应用和环境
打包成一个镜像,如果数据都在容器中,那么当我们容器被删除的时候,数据就会丢失。需求:数据可以持久化。假如MYSQL数据库,如果容器被删除了,那么数据库内的数据就会丢失,因此我们希望:MySQL数据库中的数据可以存储在本地。
容器之间可以有一个数据共享的技术,docker容器中产生的数据可以同步到本地。这就是数据卷,目录的挂载:就是将容器内的目录挂载到Linux上面。
容器数据卷: 一个或多个容器专门指定绕过 Union File System
的目录,为持续性或共享数据提供一些有用的功能:
- 数据卷可以在容器间共享和重用;
- 数据卷数据改变是直接修改的(双向的);
- 数据卷是持续性的,直到没有容器使用它们;
挂在容器卷方式
一: docker run -v
- 第一步:docker run -v 主机目录:容器目录
例如:docker run -it -v /home/ceshi:/home centos /bin/bash
做完以上的操作,这个时候我们在容器内对/home
目录下的操作会被同步到Linux
的/home/ceshi
目录下。
- 第二步:当容器启动起来的时候,我们在
Linux
的操作命令窗口处通过docker inspect 容器id
去查看卷的挂载信息。
以上两个目录的数据会进行同步,例如我在主机内的ceshi目录下做一些操作增、删、改等等会同步到docker容器内的home目录下。
注意:容器挂了,可能导致部分数据没有挂在到宿主机目录上。
我就遇到这个问题。
具名挂载和匿名挂载
匿名挂载
通过**-v 容器内路径而没有指定卷名或者指定主机路径的挂载方式。
命令:docker run -d -P --name nginx02 -v /etc/nginx nginx
**
docker volume --help # 查看一下卷的帮助文档
分别是:创建卷、查看卷、查看所有的卷、移除卷、移除卷
我们使用以下命令查看一下所有本地的volume卷信息:
命令:docker volume ls
通过以上我们发现,我们刚刚创建的匿名卷挂载,就是没有给它起名字,这是因为我们在运行的时候只指定了容器内的路径而没有指定容器外的路径和卷名,这里发现,这种就是匿名挂载,我们在**-v只写了容器内的路径**,没有写容器外的路径!
具名挂载
通过**-v 卷名:容器内路径而没有指定主机路径的挂载方式。
命令:docker run -d -P --name nginx03 -v juming-nginx:/etc/nginx nginx
**
我们使用以下命令查看一下所有本地的volume卷信息。
命令:docker volume ls
我们通过**docker volume inspect juming-nginx
命令查看一下这个卷的详细信息。
我们发现所有的docker容器内的卷,在没有指定目录的情况下都是在/var/lib/docker/volumes/xxxx/_data**。
通过具名挂载可以方便的找到我们的一个卷,大多数情况在使用的具名挂载。
# 如何锁定是具名挂载还是匿名挂载,还是指定路径挂载
-v 容器内路径 # 匿名挂载
-v 卷名:容器内路径 # 具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载
扩展
# 通过 -v 容器内路径:ro rw 改变读写权限
ro readonly # 只读
rw readwrite # 可读可写
# 一旦设置了容器权限,容器对我们挂载出的内容就会有限定了
docker run -d -p --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -p --name nginx02 -v juming-nginx:/etc/nginx:rw nginx
# ro 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作的。
二:数据卷之初识Dockerfile
Dockerfile
就是用来创建docker镜像
的构建文件,是一个命令脚本,下面我们来初步体验一下Dockerfile
。
通过这个脚本可以生成镜像,镜像是一层一层的,脚本也是一个一个的命令,每个命令都是一层
(重要)。
- 第一步:在
home
目录下创建一个docker-test-volume
目录用于存放脚本测试文件。
命令:mkdir docker-test-volume # 创建一个目录
命令:cd docker-test-volume # 进入该目录
# 创建一个dockerfile文件,名字可以随意,建议Dockerfile
命令:vim Dockerfile01 # 编写脚本
# 文件中的内容,指令需要大写
FROM centos # 用什么作为基础
VOLUME ["volume01","volume02"] # 挂载卷的目录,这里没有指定
CMD echo "-------end-------" # 生成完之后发一段消息
CMD /bin/bash # 生成完之后默认是走的控制台
# 这里的每个命令就是镜像的一层 4层
- 第二步:构建脚本生成镜像
docker build -f /home/docker-test-volume/dockerfile01 -t oldou/centos:1.0 .
- -f 通过什么文件来构建,后面接构建文件的地址
- -t 生成文件的版本
-
第三步:启动自己的容器
docker run -it db89686baa5c /bin/bash
-
第四步:查看一下卷挂载的路径
- 命令:docker ps # 先查看一下启动的id
- 命令:docker inspect 启动的id # 根据容器启动的ID查看信息
- 第五步:进入这个路径查看一下卷信息,
cd /var/lib/docker/volumes/642be56674ca60230a61455cdb8b06e8968ea7dd11236129a906c1cafaa7fe73/_data
结论:Dockerfile
这种方式的使用非常多见,因为我们通常会构建自己的镜像。假如我们构建镜像的时候没有挂载卷,这个时候就需要手动镜像挂载,就需要使用**-v 卷名:容器内路径**。
DockerFile的学习
dockerfile
的介绍
Dockerfile
是用来构建dokcer镜像
的文件,是一个命令参数脚本。
构建步骤∶
- 编写一个dockerfile文件
- docker build构建成为一个镜像
- docker run运行镜像
- docker push发布镜像(DockerHub、阿里云镜像仓库)
DockerFile
的构建过程
- 每个保留关键字(指令)都必须是大写字母;
- 执行顺序是从上往下依次执行;
#
表示注释;- 每一个指令都会创建提交一个新的镜像层,并提交。
Dockfile的指令
FROM
:指定基础镜像,一切都是从这里开始构建;
MAINTAINER
:指定维护者信息;
RUN
:镜像构建的时候需要运行的命令;
ADD
:步骤,添加内容;
WORKDIR
:镜像的工作目录;
VOLUME
:挂载的目录;
EXPOSE
:保留端口配置;
CMD
:指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代;
ENTRYPOINT
:指定这个容器启动的时候要运行的命令,可以追加命令;
ONBUILD
:当构建一个被继承,DockerFile 这个时候就会运行 ONBUILD 的指令,触发指令;
COPY
:类似ADD,将我们文件拷贝到镜像中;
ENV
:构建的时候设置环境变量;
以前的话我们都是用的别人的镜像,现在我们知道了这些指令以后就开始自己来制作一个镜像。
实战:
CMD 和 ENTRYPOINT区别【了解】
CMD: 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT: 指定这个容器启动的时候要运行的命令,可以追加命令。
发布镜像到DockerHub
-
DockerHub地址:https://hub.docker.com/ 需要注册自己的账号。
-
我们在服务器上登录完毕后,就可以提交自己的镜像了,就是一步,如下所示:查看登录命令:
docker login --help
-
登录一下:
docker login -u 用户名 回车输出密码
-
登录成功之后就开始push我们的镜像到服务器上。首先我们先给镜像改个名字:命令:
docker tag 镜像id oldou/diytomcat:1.0
-
接下来便开始上传格式:
docker push 作者名/需要上传的镜像名:版本号
-
登出命令:docker logout